Skip to content

Commit da2ee2e

Browse files
author
Thomas Lohnert
authored
Merge pull request #1347 from ISISComputingGroup/Ticket5238_hide_perspectives
Ticket 5238: Show/hide perspectives
2 parents d3da41b + 1e486af commit da2ee2e

File tree

34 files changed

+1303
-284
lines changed

34 files changed

+1303
-284
lines changed

base/uk.ac.stfc.isis.ibex.e4.client/Application.e4xmi

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
<children xsi:type="menu:HandledMenuItem" xmi:id="_kIsJQGcTEeeM7uzkT_ViHQ" elementId="uk.ac.stfc.isis.ibex.e4.client.handledmenuitem.colours.standard" label="Standard colour scheme" tooltip="Switch to standard colour scheme" selected="true" type="Radio" command="_J1L8EKkFEeeR15ll_ruI0A"/>
4141
<children xsi:type="menu:HandledMenuItem" xmi:id="_lr4aUGcTEeeM7uzkT_ViHQ" elementId="uk.ac.stfc.isis.ibex.e4.client.handledmenuitem.colours.alternative" label="Alternative colour scheme 1" tooltip="Switch to alternative colour scheme 1" type="Radio" command="_aKnSYKkFEeeR15ll_ruI0A"/>
4242
</children>
43+
<children xsi:type="menu:HandledMenuItem" xmi:id="_HiUXAN2tEeuW2_9QCiQ-XA" elementId="uk.ac.stfc.isis.ibex.e4.client.handledmenuitem.selectvisibleperspectives" label="Select visible perspectives" tooltip="Select which perspectives are visible" command="_4hYR8N2tEeuW2_9QCiQ-XA"/>
4344
</children>
4445
<children xsi:type="menu:Menu" xmi:id="_EQzKoGcTEeeM7uzkT_ViHQ" elementId="uk.ac.stfc.isis.ibex.e4.client.menu.help" label="Help" mnemonics="">
4546
<children xsi:type="menu:HandledMenuItem" xmi:id="_n7iv0GcTEeeM7uzkT_ViHQ" elementId="uk.ac.stfc.isis.ibex.e4.client.handledmenuitem.about" label="About" tooltip="All about IBEX" command="_hj--kKkDEeeNUPQOsQF40g"/>
@@ -116,6 +117,7 @@
116117
<handlers xmi:id="_JRFiEJlbEeiJWOfXjwtf9A" elementId="uk.ac.stfc.isis.ibex.e4.client.handler.0" contributionURI="bundleclass://uk.ac.stfc.isis.ibex.e4.ui.perspectiveswitcher/uk.ac.stfc.isis.ibex.e4.ui.perspectiveswitcher.commands.SwitchPerspective" command="_UJcx8IOSEeizju06Crxm-g"/>
117118
<handlers xmi:id="_7P65YJZlEeilnu5vNzjU3w" elementId="uk.ac.stfc.isis.ibex.e4.client.handler.resetperspectives" contributionURI="bundleclass://uk.ac.stfc.isis.ibex.e4.ui.perspectiveswitcher/uk.ac.stfc.isis.ibex.e4.ui.perspectiveswitcher.commands.ResetPerspective" command="_NufGcJZmEeilnu5vNzjU3w"/>
118119
<handlers xmi:id="_1OjPMLs4EeiDDI01_3WoHA" elementId="uk.ac.stfc.isis.ibex.e4.client.command.iconlicence" contributionURI="bundleclass://uk.ac.stfc.isis.ibex.ui.help/uk.ac.stfc.isis.ibex.ui.help.IconLicencesHandler" command="_oZBHMLs4EeiDDI01_3WoHA"/>
120+
<handlers xmi:id="_u6Iq4N2tEeuW2_9QCiQ-XA" elementId="uk.ac.stfc.isis.ibex.e4.client.handler.selectperspectives" contributionURI="bundleclass://uk.ac.stfc.isis.ibex.e4.ui.perspectiveswitcher/uk.ac.stfc.isis.ibex.e4.ui.perspectiveswitcher.commands.SelectVisiblePerspectives" command="_4hYR8N2tEeuW2_9QCiQ-XA"/>
119121
<bindingTables xmi:id="_5WjMoIOQEeizju06Crxm-g" elementId="IBEX_key_scheme" bindingContext="_no3QoIOVEeizju06Crxm-g">
120122
<tags>type:user</tags>
121123
<bindings xmi:id="_5zdyIIOQEeizju06Crxm-g" elementId="uk.ac.stfc.isis.ibex.e4.client.keybindings" keySequence="M2+M3+A" command="_UJcx8IOSEeizju06Crxm-g">
@@ -622,6 +624,7 @@
622624
<tags>type:user</tags>
623625
</commands>
624626
<commands xmi:id="_oZBHMLs4EeiDDI01_3WoHA" elementId="uk.ac.stfc.isis.ibex.e4.client.command.iconlicence" commandName="Icon Licence" description="View IBEX gui icon licences"/>
627+
<commands xmi:id="_4hYR8N2tEeuW2_9QCiQ-XA" elementId="uk.ac.stfc.isis.ibex.e4.client.command.selectperspectives" commandName="Select visible perspectives" description="Selects the perspectives which are visible"/>
625628
<addons xmi:id="_2jV5MWGNEeeR5ozUwT3tEw" elementId="org.eclipse.e4.core.commands.service" contributionURI="bundleclass://org.eclipse.e4.core.commands/org.eclipse.e4.core.commands.CommandServiceAddon"/>
626629
<addons xmi:id="_2jV5MmGNEeeR5ozUwT3tEw" elementId="org.eclipse.e4.ui.contexts.service" contributionURI="bundleclass://org.eclipse.e4.ui.services/org.eclipse.e4.ui.services.ContextServiceAddon"/>
627630
<addons xmi:id="_2jV5M2GNEeeR5ozUwT3tEw" elementId="org.eclipse.e4.ui.bindings.service" contributionURI="bundleclass://org.eclipse.e4.ui.bindings/org.eclipse.e4.ui.bindings.BindingServiceAddon"/>

base/uk.ac.stfc.isis.ibex.e4.ui.perspectiveswitcher/META-INF/MANIFEST.MF

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,28 @@ Require-Bundle: javax.inject;bundle-version="1.0.0",
1616
org.eclipse.core.databinding.beans,
1717
org.eclipse.jface.databinding,
1818
org.eclipse.jface;bundle-version="3.12.2",
19-
org.eclipse.osgi.services;bundle-version="3.5.100",
20-
org.eclipse.e4.core.services;bundle-version="2.0.100",
2119
org.eclipse.core.databinding.property;bundle-version="1.6.0",
22-
uk.ac.stfc.isis.ibex.preferences,
2320
org.eclipse.e4.ui.di,
2421
uk.ac.stfc.isis.ibex.dae;bundle-version="1.0.0",
2522
uk.ac.stfc.isis.ibex.ui.dae,
26-
uk.ac.stfc.isis.ibex.nicos
23+
uk.ac.stfc.isis.ibex.nicos,
24+
uk.ac.stfc.isis.ibex.epics;bundle-version="1.0.0",
25+
uk.ac.stfc.isis.ibex.epics.switching;bundle-version="1.0.0",
26+
uk.ac.stfc.isis.ibex.instrument,
27+
org.eclipse.e4.core.contexts;bundle-version="1.8.400",
28+
org.eclipse.e4.core.di;bundle-version="1.7.600",
29+
org.eclipse.e4.ui.services;bundle-version="1.3.700",
30+
org.eclipse.osgi.services;bundle-version="3.9.0",
31+
org.eclipse.e4.core.services;bundle-version="2.2.400",
32+
uk.ac.stfc.isis.ibex.ui.widgets;bundle-version="1.0.0",
33+
uk.ac.stfc.isis.ibex.ui;bundle-version="1.0.0",
34+
uk.ac.stfc.isis.ibex.managermode,
35+
org.eclipse.core.runtime;bundle-version="3.19.0",
36+
uk.ac.stfc.isis.ibex.logger;bundle-version="1.0.0"
2737
Bundle-ActivationPolicy: lazy
2838
Bundle-RequiredExecutionEnvironment: JavaSE-11
29-
Export-Package: uk.ac.stfc.isis.ibex.e4.ui.perspectiveswitcher
39+
Export-Package: uk.ac.stfc.isis.ibex.e4.ui.perspectiveswitcher,
40+
uk.ac.stfc.isis.ibex.e4.ui.perspectiveswitcher.views
3041
Automatic-Module-Name: uk.ac.stfc.isis.ibex.e4.ui.perspectiveswitcher
3142
Import-Package: uk.ac.stfc.isis.ibex.epics.switching,
3243
uk.ac.stfc.isis.ibex.instrument,

base/uk.ac.stfc.isis.ibex.e4.ui.perspectiveswitcher/src/uk/ac/stfc/isis/ibex/e4/ui/perspectiveswitcher/CopyPerspectiveSnippetProcessor.java

Lines changed: 158 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
package uk.ac.stfc.isis.ibex.e4.ui.perspectiveswitcher;
22

3+
import java.lang.reflect.Type;
4+
import java.util.HashMap;
5+
import java.util.List;
6+
import java.util.Map;
7+
8+
import org.apache.logging.log4j.Logger;
39
import org.eclipse.e4.core.di.annotations.Execute;
410
import org.eclipse.e4.core.services.events.IEventBroker;
511
import org.eclipse.e4.ui.model.application.MApplication;
@@ -11,11 +17,21 @@
1117
import org.eclipse.e4.ui.workbench.UIEvents.EventTags;
1218
import org.eclipse.e4.ui.workbench.modeling.EModelService;
1319
import org.eclipse.e4.ui.workbench.modeling.EPartService;
20+
import org.eclipse.swt.widgets.Display;
1421
import org.osgi.service.event.Event;
1522
import org.osgi.service.event.EventHandler;
1623

24+
import com.google.gson.Gson;
25+
import com.google.gson.reflect.TypeToken;
26+
1727
import uk.ac.stfc.isis.ibex.e4.ui.perspectiveswitcher.controls.ResetLayoutButtonModel;
18-
import uk.ac.stfc.isis.ibex.preferences.PreferenceSupplier;
28+
import uk.ac.stfc.isis.ibex.epics.observing.BaseObserver;
29+
import uk.ac.stfc.isis.ibex.epics.switching.ObservableFactory;
30+
import uk.ac.stfc.isis.ibex.epics.switching.OnInstrumentSwitch;
31+
import uk.ac.stfc.isis.ibex.epics.switching.SwitchableObservable;
32+
import uk.ac.stfc.isis.ibex.instrument.InstrumentUtils;
33+
import uk.ac.stfc.isis.ibex.instrument.channels.CompressedCharWaveformChannel;
34+
import uk.ac.stfc.isis.ibex.logger.IsisLog;
1935

2036
/**
2137
* Copies all snippet perspectives to perspective stack called
@@ -25,27 +41,46 @@
2541
*/
2642
public class CopyPerspectiveSnippetProcessor {
2743

44+
private static final Logger LOG = IsisLog.getLogger(CopyPerspectiveSnippetProcessor.class);
45+
2846
private PerspectivesProvider perspectivesProvider;
2947
private MPerspectiveStack perspectiveStack;
48+
private SwitchableObservable<String> perspectiveSettings;
49+
50+
private final PerspectivePreferenceSupplier preferenceSupplier = new PerspectivePreferenceSupplier();
51+
52+
private static final Gson GSON = new Gson();
53+
private static final Type SERVER_IOC_DATA_FORMAT = new TypeToken<Map<String, Boolean>>() { }.getType();
54+
55+
private ObservableFactory switchingObsFactory = new ObservableFactory(OnInstrumentSwitch.SWITCH);
3056

57+
private static final String PERSPECTIVE_CONFIG_PV = "CS:PERSP:SETTINGS";
58+
private static final String PERSPECTIVE_CONFIG_PV_DISCONNECTED_MSG = "Remote perspective PV disconnected, using last known good value.";
59+
private static final String PERSPECTIVE_CONFIG_PV_ERROR_MSG = "Remote perspective PV in error, using last known good value.";
60+
61+
/* We are expecting the PV to take a while to connect after starting the client.
62+
* This is to prevent excessive logging on the client startup.
63+
*/
64+
private final long connectionCheckTimeout = 10000;
65+
private boolean connectionCheck = false;
66+
3167
/**
32-
* Clone each snippet that is a perspective and add the cloned perspective
33-
* to the main PerspectiveStack.
68+
* Clone each snippet that is a perspective and add the cloned perspective to
69+
* the main PerspectiveStack.
3470
*
35-
* @param app
36-
* The MApplication used.
37-
* @param partService
38-
* The EPartService used.
39-
* @param modelService
40-
* The EModelService used.
41-
* @param broker
42-
* The IEventBroker used.
71+
* @param app The MApplication used.
72+
* @param partService The EPartService used.
73+
* @param modelService The EModelService used.
74+
* @param broker The IEventBroker used.
4375
*/
4476
@Execute
45-
public void execute(MApplication app, EPartService partService, EModelService modelService, IEventBroker broker) {
77+
public void execute(MApplication app, EModelService modelService, EPartService partService, IEventBroker broker) {
4678
perspectivesProvider = new PerspectivesProvider(app, partService, modelService);
4779
perspectiveStack = perspectivesProvider.getTopLevelStack();
4880

81+
perspectiveSettings = switchingObsFactory.getSwitchableObservable(new CompressedCharWaveformChannel(),
82+
InstrumentUtils.addPrefix(PERSPECTIVE_CONFIG_PV));
83+
4984
// Only do this when no other children, or the restored workspace state
5085
// will be overwritten.
5186
if (!perspectiveStack.getChildren().isEmpty()) {
@@ -56,36 +91,110 @@ public void execute(MApplication app, EPartService partService, EModelService mo
5691
// perspective into the main PerspectiveStack
5792
boolean isFirst = true;
5893
for (MPerspective perspective : perspectivesProvider.getInitialPerspectives()) {
59-
if (!new PreferenceSupplier().perspectivesToHide().contains(perspective.getElementId())) {
60-
perspectiveStack.getChildren().add(perspective);
61-
if (isFirst) {
62-
perspectiveStack.setSelectedElement(perspective);
63-
isFirst = false;
64-
}
94+
95+
perspectiveStack.getChildren().add(perspective);
96+
if (isFirst) {
97+
perspectiveStack.setSelectedElement(perspective);
98+
isFirst = false;
6599
}
66100
subscribeChangedElement(broker, perspective);
67101
subscribeSelectedPerspective(broker, perspective);
68102
}
103+
104+
perspectiveSettings.subscribe(new BaseObserver<String>() {
105+
@Override
106+
public void onValue(String value) {
107+
if (!preferenceSupplier.getUseLocalPerspectives()) {
108+
Map<String, Boolean> visiblePerspectives = GSON.fromJson(value, SERVER_IOC_DATA_FORMAT);
109+
setVisiblePerspectivesAsync(visiblePerspectives);
110+
}
111+
}
112+
113+
@Override
114+
public void onError(Exception e) {
115+
LOG.error(PERSPECTIVE_CONFIG_PV_DISCONNECTED_MSG);
116+
}
117+
118+
@Override
119+
public void onConnectionStatus(boolean isConnected) {
120+
if (!isConnected && connectionCheck) {
121+
LOG.error(PERSPECTIVE_CONFIG_PV_ERROR_MSG);
122+
}
123+
}
124+
});
125+
setupConnectionCheckTimeout(connectionCheckTimeout);
126+
127+
preferenceSupplier.addUseLocalPerspectivesListener(useLocal -> {
128+
if (useLocal) {
129+
setVisiblePerspectives(preferenceSupplier.perspectivesToHide());
130+
} else {
131+
Map<String, Boolean> visiblePerspectives = GSON.fromJson(perspectiveSettings.getValue(), SERVER_IOC_DATA_FORMAT);
132+
setVisiblePerspectivesAsync(visiblePerspectives);
133+
}
134+
});
135+
136+
preferenceSupplier.addHiddenPerspectivesListener(hiddenPerspectives -> {
137+
if (preferenceSupplier.getUseLocalPerspectives()) {
138+
setVisiblePerspectives(hiddenPerspectives);
139+
}
140+
});
141+
69142
ResetLayoutButtonModel.getInstance().reset(perspectiveStack.getSelectedElement());
70143
}
71144

145+
/**
146+
* Set which perspectives are visible based on a list of the ones that are hidden.
147+
* @param hiddenPerspectives The list of hidden perspectives
148+
*/
149+
private void setVisiblePerspectives(List<String> hiddenPerspectives) {
150+
Map<String, Boolean> visibilityMap = new HashMap<String, Boolean>();
151+
for (MPerspective perspective : perspectivesProvider.getInitialPerspectives()) {
152+
visibilityMap.put(perspective.getElementId(), !hiddenPerspectives.contains(perspective.getElementId()));
153+
}
154+
setVisiblePerspectivesAsync(visibilityMap);
155+
}
156+
157+
/**
158+
* Set which perspectives are visible based on a map of the perspective ID against and true if visible, false if hidden.
159+
* @param visiblePerspectiveMap A map of perspective ID vs true if visible, false if hidden.
160+
*/
161+
private void setVisiblePerspectivesAsync(Map<String, Boolean> visiblePerspectiveMap) {
162+
Display.getDefault().asyncExec(new Runnable() {
163+
@Override
164+
public void run() {
165+
List<MPerspective> perspectives = perspectiveStack.getChildren();
166+
if (perspectives.size() > 0) {
167+
perspectives.forEach(c -> c.setVisible(true));
168+
perspectives.forEach(c -> c.setVisible(visiblePerspectiveMap.getOrDefault(c.getElementId(), true)));
169+
if (!perspectiveStack.getSelectedElement().isVisible()) {
170+
// If selected perspective is no longer visible then
171+
// find first visible perspective and set it as current
172+
perspectiveStack.setSelectedElement(perspectives.stream()
173+
.filter(c -> c.isVisible()).findFirst().orElse(perspectives.get(0)));
174+
}
175+
} else {
176+
LOG.error("No perspectives available to show.");
177+
}
178+
}
179+
});
180+
}
181+
72182
/**
73183
* Listen to perspective changes and set the new perspective as current
74184
* perspective in ResetLayoutButtonModel.
75185
*
76-
* @param broker
77-
* IEventBroker
78-
* @param perspective
79-
* The new current perspective
186+
* @param broker IEventBroker
187+
* @param perspective The new current perspective
80188
*/
81-
public void subscribeSelectedPerspective(IEventBroker broker, MPerspective perspective) {
189+
private void subscribeSelectedPerspective(IEventBroker broker, MPerspective perspective) {
82190

83191
EventHandler handler = new EventHandler() {
84192
@Override
85193
public void handleEvent(Event event) {
86194
MUIElement element = (MUIElement) event.getProperty(EventTags.NEW_VALUE);
87195

88-
if (!perspectiveStack.getSelectedElement().equals(perspective)) {
196+
if (perspectiveStack.getSelectedElement() != null
197+
&& !perspectiveStack.getSelectedElement().equals(perspective)) {
89198
return;
90199
}
91200

@@ -105,12 +214,10 @@ public void handleEvent(Event event) {
105214
* Listen to perspective content changes set the current perspective in
106215
* ResetLayoutButtonModel to changed.
107216
*
108-
* @param broker
109-
* IEventBroker
110-
* @param perspective
111-
* The new current perspective
217+
* @param broker IEventBroker
218+
* @param perspective The new current perspective
112219
*/
113-
public void subscribeChangedElement(IEventBroker broker, MPerspective perspective) {
220+
private void subscribeChangedElement(IEventBroker broker, MPerspective perspective) {
114221

115222
EventHandler handler = new EventHandler() {
116223
boolean alreadyCalled = false;
@@ -140,4 +247,26 @@ public void handleEvent(Event event) {
140247

141248
broker.subscribe(UIEvents.UIElement.TOPIC_CONTAINERDATA, handler);
142249
}
250+
251+
/**
252+
* Enables checking the connection of perspective PV after a variable time. After that, performs
253+
* an additional connection check.
254+
* @param time Time in milliseconds of how long to wait before enabling PV connection check.
255+
*/
256+
private void setupConnectionCheckTimeout(long time) {
257+
Thread connectionTimeoutThread = new Thread() {
258+
public void run() {
259+
try {
260+
Thread.sleep(time);
261+
connectionCheck = true;
262+
if (!perspectiveSettings.isConnected()) {
263+
LOG.error(PERSPECTIVE_CONFIG_PV_DISCONNECTED_MSG);
264+
}
265+
} catch (InterruptedException e) {
266+
LOG.error("Connection timeout interrupted.");
267+
}
268+
}
269+
};
270+
connectionTimeoutThread.start();
271+
}
143272
}

0 commit comments

Comments
 (0)