Skip to content

Commit dd1ebc7

Browse files
authored
Merge pull request #3173 from ControlSystemStudio/PR-3071-fix
Fix display context menu entries for open display action
2 parents 005fa83 + 4d92922 commit dd1ebc7

File tree

4 files changed

+68
-17
lines changed

4 files changed

+68
-17
lines changed

app/display/actions/src/main/java/org/csstudio/display/actions/OpenDisplayAction.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import org.csstudio.display.builder.model.persist.ModelWriter;
1616
import org.csstudio.display.builder.model.persist.XMLTags;
1717
import org.csstudio.display.builder.model.properties.ActionInfoBase;
18+
import org.csstudio.display.builder.model.spi.ActionHandler;
1819
import org.csstudio.display.builder.model.spi.ActionInfo;
1920
import org.csstudio.display.builder.representation.javafx.actionsdialog.ActionsDialog;
2021
import org.phoebus.framework.macros.Macros;
@@ -30,6 +31,8 @@
3031
import java.util.Objects;
3132
import java.util.Optional;
3233
import java.util.ResourceBundle;
34+
import java.util.ServiceLoader;
35+
import java.util.concurrent.ExecutorService;
3336
import java.util.logging.Level;
3437
import java.util.logging.Logger;
3538

@@ -215,17 +218,22 @@ public void setModifiers(final MouseEvent event) {
215218
}
216219

217220
@Override
218-
public List<MenuItem> getContextMenuItems(Widget widget) {
221+
public List<MenuItem> getContextMenuItems(ExecutorService executorService, Widget widget) {
222+
ActionHandler handler = getActionHandler();
219223
List<MenuItem> items = new ArrayList<>();
220224

221-
items.add(createMenuItem(widget, description));
225+
// Default item
226+
items.add(createMenuItem(executorService, widget, description));
222227

223228
// Add variant for all the available Target types: Replace, new Tab, ...
224229
for (OpenDisplayAction.Target target : OpenDisplayAction.Target.values()) {
225230
if (target == OpenDisplayAction.Target.STANDALONE || target == this.target)
226231
continue;
227232
// Mention non-default targets in the description
228-
items.add(createMenuItem(widget, description + " (" + target + ")"));
233+
MenuItem additionalItem = createMenuItem(widget, description + " (" + target + ")");
234+
OpenDisplayAction openDisplayAction = new OpenDisplayAction(description, file, macros, target);
235+
additionalItem.setOnAction(ae -> executorService.execute(() -> handler.handleAction(widget, openDisplayAction)));
236+
items.add(additionalItem);
229237
}
230238

231239
return items;

app/display/model/src/main/java/org/csstudio/display/builder/model/properties/ActionInfoBase.java

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@
1111
import org.csstudio.display.builder.model.WidgetProperty;
1212
import org.csstudio.display.builder.model.macros.MacroHandler;
1313
import org.csstudio.display.builder.model.persist.XMLTags;
14+
import org.csstudio.display.builder.model.spi.ActionHandler;
1415
import org.csstudio.display.builder.model.spi.ActionInfo;
1516

1617
import javax.xml.stream.XMLStreamWriter;
1718
import java.util.ArrayList;
1819
import java.util.List;
1920
import java.util.Optional;
21+
import java.util.concurrent.ExecutorService;
2022
import java.util.logging.Level;
2123
import java.util.logging.Logger;
2224

@@ -46,6 +48,31 @@ public String getType() {
4648
return type;
4749
}
4850

51+
/**
52+
* Creates a {@link MenuItem} for this action and configures the <code>onAction</code> handler
53+
* to use associated {@link ActionHandler}.
54+
*
55+
* @param executorService A non-null {@link ExecutorService} used to execute the action using the associated {@link ActionHandler}.
56+
* @param widget Widget associated with the action
57+
* @param description Description set as text for the {@link MenuItem}
58+
* @return A {@link MenuItem} ready to insert in a {@link javafx.scene.control.ContextMenu}.
59+
* @throws RuntimeException if an {@link ActionHandler} cannot be located for the action.
60+
*/
61+
protected MenuItem createMenuItem(final ExecutorService executorService, final Widget widget, final String description) {
62+
ActionHandler actionHandler = getActionHandler();
63+
MenuItem item = createMenuItem(widget, description);
64+
item.setOnAction(ae -> executorService.execute(() -> actionHandler.handleAction(widget, this)));
65+
return item;
66+
}
67+
68+
/**
69+
* Creates a {@link MenuItem} for this action, but does not configure the <code>onAction</code> handler.
70+
*
71+
* @param widget Widget associated with the action
72+
* @param description Description set as text for the {@link MenuItem}
73+
* @return A {@link MenuItem} ready to insert in a {@link javafx.scene.control.ContextMenu}, but caller
74+
* must define <code>onAction</code>.
75+
*/
4976
protected MenuItem createMenuItem(final Widget widget, final String description) {
5077
// Expand macros in action description
5178
String desc;
@@ -68,8 +95,6 @@ protected MenuItem createMenuItem(final Widget widget, final String description)
6895
return item;
6996
}
7097

71-
72-
7398
@Override
7499
public String toString() {
75100
return description;
@@ -92,13 +117,14 @@ protected void writeDescriptionToXML(final XMLStreamWriter writer, String descri
92117
/**
93118
* Adds a single menu item corresponding to the action's description. If the {@link ActionInfo} implementation
94119
* needs additional items, it should override this method.
120+
*
95121
* @param widget Widget associated with the context menu.
96122
* @return A list of {@link MenuItem}s.
97123
*/
98124
@Override
99-
public List<MenuItem> getContextMenuItems(Widget widget) {
125+
public List<MenuItem> getContextMenuItems(ExecutorService executorService, Widget widget) {
100126
List<MenuItem> items = new ArrayList<>();
101-
items.add(createMenuItem(widget, description));
127+
items.add(createMenuItem(executorService, widget, description));
102128

103129
return items;
104130
}

app/display/model/src/main/java/org/csstudio/display/builder/model/spi/ActionInfo.java

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,17 @@
2929
import org.w3c.dom.Element;
3030

3131
import javax.xml.stream.XMLStreamWriter;
32-
import java.util.Comparator;
3332
import java.util.List;
33+
import java.util.Optional;
34+
import java.util.ServiceLoader;
35+
import java.util.concurrent.ExecutorService;
3436

3537
public interface ActionInfo extends Comparable<ActionInfo> {
3638

3739
/**
3840
* If action type is not sufficient to determine match, implementations may add additional logic
3941
* to resolve match. For instance: legacy display formats may use a different string to define the action type.
42+
*
4043
* @param actionId Action id, e.g. open_display.
4144
* @return <code>true</code> if the input string is implemented by the {@link ActionInfo}.
4245
*/
@@ -64,8 +67,7 @@ default boolean matchesAction(String actionId) {
6467
String getDescription();
6568

6669
/**
67-
*
68-
* @return
70+
* @return Integer used to order actions in the display builder editor
6971
*/
7072
default Integer getPriority() {
7173
return 100;
@@ -103,13 +105,18 @@ default void setModifiers(MouseEvent event) {
103105
}
104106

105107
/**
106-
* @return A {@link List} of {@link MenuItem}s for the action in a widget's context menu.
108+
* @param executorService The {@link ExecutorService} responsible for running the action(s) defined
109+
* by the returned {@link MenuItem}s.
110+
* @param widget The {@link Widget} defining the actions.
111+
* @return A {@link List} of {@link MenuItem}s for the action in a widget's context menu. All {@link MenuItem}s
112+
* must define the <code>onAction()</code>onAction() handler.
107113
* Defaults to <code>null</code>.
108114
*/
109-
default List<MenuItem> getContextMenuItems(Widget widget) {
115+
default List<MenuItem> getContextMenuItems(ExecutorService executorService, Widget widget) {
110116
return null;
111117
}
112118

119+
113120
/**
114121
* @param widget The {@link Widget} associated with the action(s).
115122
* @return The editor UI particular for the {@link ActionInfo} implementation
@@ -130,15 +137,27 @@ default List<MenuItem> getContextMenuItems(Widget widget) {
130137

131138
/**
132139
* Comparator for the sake of sorting {@link ActionInfo}s. Uses {@link ActionInfo#getDescription()}.
140+
*
133141
* @param other the object to be compared.
134142
* @return Any occurrence of <code>null</code> in the {@link ActionInfo#getDescription()}
135143
* fields will return 0. Otherwise, comparison of {@link ActionInfo#getDescription()}.
136144
*/
137145
@Override
138-
default int compareTo(ActionInfo other){
139-
if(getDescription() == null || other.getDescription() == null){
146+
default int compareTo(ActionInfo other) {
147+
if (getDescription() == null || other.getDescription() == null) {
140148
return 0;
141149
}
142150
return getDescription().compareTo(other.getDescription());
143151
}
152+
153+
/**
154+
* @return An {@link ActionHandler} matching the action. If none can be found, a {@link RuntimeException} is thrown.
155+
*/
156+
default ActionHandler getActionHandler() {
157+
Optional<ServiceLoader.Provider<ActionHandler>> handler = ServiceLoader.load(ActionHandler.class).stream().filter(p -> p.get().matches(this)).findFirst();
158+
if (handler.isEmpty()) {
159+
throw new RuntimeException("No ActionHandler found for action " + getDescription());
160+
}
161+
return handler.get().get();
162+
}
144163
}

app/display/runtime/src/main/java/org/csstudio/display/builder/runtime/app/ContextMenuSupport.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
import org.csstudio.display.builder.model.spi.ActionInfo;
2222
import org.csstudio.display.builder.representation.ToolkitListener;
2323
import org.csstudio.display.builder.representation.javafx.widgets.JFXBaseRepresentation;
24-
import org.csstudio.display.builder.runtime.ActionUtil;
2524
import org.csstudio.display.builder.runtime.Messages;
2625
import org.csstudio.display.builder.runtime.RuntimeAction;
2726
import org.csstudio.display.builder.runtime.RuntimeUtil;
@@ -129,9 +128,8 @@ private void fillMenu(Runnable setFocus, final Widget widget) {
129128

130129
// Widget actions
131130
for (ActionInfo info : widget.propActions().getValue().getActions()) {
132-
List<MenuItem> actionMenuItems = info.getContextMenuItems(widget);
131+
List<MenuItem> actionMenuItems = info.getContextMenuItems(RuntimeUtil.getExecutor(), widget);
133132
if (actionMenuItems != null) {
134-
actionMenuItems.forEach(i -> i.setOnAction(e -> ActionUtil.handleAction(widget, info)));
135133
items.addAll(actionMenuItems);
136134
}
137135
}

0 commit comments

Comments
 (0)