use of org.csstudio.display.builder.model.macros.Macros in project org.csstudio.display.builder by kasemir.
the class DisplayNavigationTest method testNavigation.
@Test
public void testNavigation() {
final DisplayNavigation navigation = new DisplayNavigation();
final Listener listener = nav -> changes.incrementAndGet();
navigation.addListener(listener);
// No history
assertThat(navigation.getBackwardDisplays().size(), equalTo(0));
assertThat(navigation.getForwardDisplays().size(), equalTo(0));
assertThat(changes.get(), equalTo(0));
// Current display, still no history
DisplayInfo display = new DisplayInfo("/path/a.opi", "A", new Macros());
navigation.setCurrentDisplay(display);
System.out.println(navigation);
assertThat(navigation.getBackwardDisplays().size(), equalTo(0));
assertThat(navigation.getForwardDisplays().size(), equalTo(0));
assertThat(changes.get(), equalTo(0));
// Open new displays: Now 5 items available to go back
for (int i = 1; i <= 5; ++i) navigation.setCurrentDisplay(new DisplayInfo("/path/N" + i + ".opi", "N" + i, new Macros()));
System.out.println(navigation);
assertThat(navigation.getBackwardDisplays().size(), equalTo(5));
assertThat(navigation.getForwardDisplays().size(), equalTo(0));
assertThat(changes.get(), equalTo(5));
display = navigation.goBackward(2);
System.out.println(navigation);
assertThat(display.getName(), equalTo("N3"));
assertThat(navigation.getBackwardDisplays().size(), equalTo(3));
assertThat(navigation.getForwardDisplays().size(), equalTo(2));
assertThat(changes.get(), equalTo(6));
// Informing navigation about the display that's already current
// (equal, not necessarily identical) has no impact on history
navigation.setCurrentDisplay(new DisplayInfo(display.getPath(), display.getName(), new Macros()));
assertThat(navigation.getBackwardDisplays().size(), equalTo(3));
assertThat(navigation.getForwardDisplays().size(), equalTo(2));
assertThat(changes.get(), equalTo(6));
// Navigate back to the first display
display = navigation.goBackward(3);
System.out.println(navigation);
assertThat(display.getName(), equalTo("A"));
assertThat(navigation.getBackwardDisplays().size(), equalTo(0));
assertThat(navigation.getForwardDisplays().size(), equalTo(5));
assertThat(changes.get(), equalTo(7));
// Navigate forward to "N1"
display = navigation.goForward(1);
System.out.println(navigation);
assertThat(display.getName(), equalTo("N1"));
assertThat(navigation.getBackwardDisplays().size(), equalTo(1));
assertThat(navigation.getForwardDisplays().size(), equalTo(4));
assertThat(changes.get(), equalTo(8));
// Clear forward chain by opening different display
display = new DisplayInfo("/path/x.opi", "X", new Macros());
navigation.setCurrentDisplay(display);
System.out.println(navigation);
assertThat(navigation.getBackwardDisplays().size(), equalTo(2));
assertThat(navigation.getForwardDisplays().size(), equalTo(0));
assertThat(changes.get(), equalTo(9));
navigation.removeListener(listener);
}
use of org.csstudio.display.builder.model.macros.Macros in project org.csstudio.display.builder by kasemir.
the class ArrayWidget method getEffectiveMacros.
/**
* Array widget extends parent macros
*
* @return {@link Macros}
*/
@Override
public Macros getEffectiveMacros() {
final Macros base = super.getEffectiveMacros();
final Macros my_macros = propMacros().getValue();
return Macros.merge(base, my_macros);
}
use of org.csstudio.display.builder.model.macros.Macros in project org.csstudio.display.builder by kasemir.
the class ActionUtil method executeCommand.
/**
* Execute external command
* @param source_widget Widget from which the action is invoked
* @param action Command action to execute
*/
private static void executeCommand(final Widget source_widget, final ExecuteCommandActionInfo action) {
try {
// Path to resolve, after expanding macros
final Macros macros = source_widget.getEffectiveMacros();
final String command = MacroHandler.replace(macros, action.getCommand());
logger.log(Level.FINER, "{0}, effective macros {1} ({2})", new Object[] { action, macros, command });
// Resolve command relative to the source widget model (not 'top'!)
final DisplayModel widget_model = source_widget.getDisplayModel();
final String parent_file = widget_model.getUserData(DisplayModel.USER_DATA_INPUT_FILE);
final String parent_dir = ModelResourceUtil.getDirectory(ModelResourceUtil.getLocalPath(parent_file));
// Execute (this is already running on background thread)
logger.log(Level.FINE, "Executing command {0} in {1}", new Object[] { command, parent_dir });
final CommandExecutor executor = new CommandExecutor(command, new File(parent_dir));
executor.call();
} catch (final Throwable ex) {
logger.log(Level.WARNING, action + " failed", ex);
ScriptUtil.showErrorDialog(source_widget, "Cannot execute " + action + ".\n\nSee log for details.");
}
}
use of org.csstudio.display.builder.model.macros.Macros in project org.csstudio.display.builder by kasemir.
the class WidgetPropertySubscriptionUnitTest method testMacroizedValueChanges.
@Test
public void testMacroizedValueChanges() {
// Group widget supports macros
final GroupWidget widget = new GroupWidget();
final Macros macros = new Macros();
macros.add("NAME", "Fred");
widget.propMacros().setValue(macros);
final MacroizedWidgetProperty<String> name_prop = (MacroizedWidgetProperty<String>) widget.propName();
final AtomicInteger updates = new AtomicInteger();
final AtomicReference<String> received_value = new AtomicReference<String>(null);
name_prop.addPropertyListener((prop, old_value, new_value) -> {
System.out.println(prop.getName() + " changes from " + old_value + " to " + new_value);
updates.incrementAndGet();
received_value.set(new_value);
});
assertThat(updates.get(), equalTo(0));
// Setting the specification triggers a notification
name_prop.setSpecification("$(NAME)");
assertThat(updates.get(), equalTo(1));
// The listener received null, because only the specification
// was set, and the value has not been resolved
assertThat(received_value.get(), nullValue());
// Fetching the value will resolve macros,
// but that does _not_ trigger another update
assertThat(name_prop.getValue(), equalTo("Fred"));
assertThat(updates.get(), equalTo(1));
// Setting the value (not the description) to something
// that doesn't contain macros will just set the value.
name_prop.setValue("New Name");
assertThat(updates.get(), equalTo(2));
assertThat(received_value.get(), equalTo("New Name"));
// Fetching that value does not trigger macro resolution
// and another value update
assertThat(name_prop.getValue(), equalTo("New Name"));
assertThat(updates.get(), equalTo(2));
// Setting the specification to something that does
// not contain macros will set the value right away
name_prop.setSpecification("Plain Text");
assertThat(updates.get(), equalTo(3));
assertThat(name_prop.getSpecification(), equalTo("Plain Text"));
// Fetching the value does _not_ trigger another update
assertThat(name_prop.getValue(), equalTo("Plain Text"));
assertThat(updates.get(), equalTo(3));
}
use of org.csstudio.display.builder.model.macros.Macros in project org.csstudio.display.builder by kasemir.
the class ActionUtil method openDisplay.
/**
* Open a display
*
* <p>Depending on the target of the action,
* this will open a new display or replace
* an existing display
*
* @param source_widget Widget from which the action is invoked
* Used to resolve the potentially relative path of the
* display specified in the action
* @param action Information on which display to open and how
*/
private static void openDisplay(final Widget source_widget, final OpenDisplayActionInfo action) {
if (action.getFile().isEmpty()) {
logger.log(Level.WARNING, "Action without file: {0}", action);
return;
}
try {
// Path to resolve, after expanding macros of source widget and action
final Macros macros = Macros.merge(source_widget.getEffectiveMacros(), action.getMacros());
final String expanded_path = MacroHandler.replace(macros, action.getFile());
logger.log(Level.FINER, "{0}, effective macros {1} ({2})", new Object[] { action, macros, expanded_path });
// Resolve new display file relative to the source widget model (not 'top'!)
final DisplayModel widget_model = source_widget.getDisplayModel();
final String parent_file = widget_model.getUserData(DisplayModel.USER_DATA_INPUT_FILE);
// Load new model. If that fails, no reason to continue.
final DisplayModel new_model = ModelLoader.resolveAndLoadModel(parent_file, expanded_path);
// Model is standalone; source_widget (Action button, ..) is _not_ the parent,
// but it does add macros to those already defined in the display file.
final Macros combined_macros = Macros.merge(macros, new_model.propMacros().getValue());
new_model.propMacros().setValue(combined_macros);
// Schedule representation on UI thread...
final DisplayModel top_model = source_widget.getTopDisplayModel();
final ToolkitRepresentation<Object, Object> toolkit = ToolkitRepresentation.getToolkit(top_model);
final Future<Object> wait_for_ui;
if (action.getTarget() == OpenDisplayActionInfo.Target.TAB) {
wait_for_ui = toolkit.submit(() -> {
// Create new panel
final ToolkitRepresentation<Object, Object> new_toolkit = toolkit.openPanel(new_model, ActionUtil::handleClose);
RuntimeUtil.hookRepresentationListener(new_toolkit);
return null;
});
} else if (action.getTarget() == OpenDisplayActionInfo.Target.WINDOW) {
wait_for_ui = toolkit.submit(() -> {
// Create new top-level window
final ToolkitRepresentation<Object, Object> new_toolkit = toolkit.openNewWindow(new_model, ActionUtil::handleClose);
RuntimeUtil.hookRepresentationListener(new_toolkit);
return null;
});
} else if (action.getTarget() == OpenDisplayActionInfo.Target.STANDALONE) {
wait_for_ui = toolkit.submit(() -> {
final ToolkitRepresentation<Object, Object> new_toolkit = toolkit.openStandaloneWindow(new_model, ActionUtil::handleClose);
RuntimeUtil.hookRepresentationListener(new_toolkit);
return null;
});
} else {
// Default to OpenDisplayActionInfo.Target.REPLACE
// Stop old runtime.
RuntimeUtil.stopRuntime(top_model);
wait_for_ui = toolkit.submit(() -> {
// Close old representation
final Object parent = toolkit.disposeRepresentation(top_model);
// Tell toolkit about new model to represent
toolkit.representModel(parent, new_model);
return null;
});
}
wait_for_ui.get();
// Back in background thread, create new runtime
RuntimeUtil.startRuntime(new_model);
} catch (final Exception ex) {
logger.log(Level.WARNING, "Error handling " + action, ex);
ScriptUtil.showErrorDialog(source_widget, "Cannot open " + action.getFile() + ".\n\nSee log for details.");
}
}
Aggregations