use of org.csstudio.display.builder.model.MacroizedWidgetProperty in project org.csstudio.display.builder by kasemir.
the class TooltipSupport method attach.
/**
* Attach tool tip
* @param node Node that should have the tool tip
* @param tooltip_property Tool tip to show
*/
public static void attach(final Node node, final WidgetProperty<String> tooltip_property) {
// Patch legacy tool tips that defaulted to pv name & value,
// even for static widgets
final StringWidgetProperty ttp = (StringWidgetProperty) tooltip_property;
if (legacy_tooltip.matcher(ttp.getSpecification()).matches() && !tooltip_property.getWidget().checkProperty("pv_name").isPresent())
ttp.setSpecification("");
// Avoid listener and code to remove/add tooltip at runtime.
if (tooltip_property.getValue().isEmpty())
return;
final Tooltip tooltip = new Tooltip();
tooltip.setWrapText(true);
// Evaluate the macros in tool tip specification each time
// the tool tip is about to show
tooltip.setOnShowing(event -> {
final String spec = ((MacroizedWidgetProperty<?>) tooltip_property).getSpecification();
final Widget widget = tooltip_property.getWidget();
final MacroValueProvider macros = widget.getMacrosOrProperties();
String expanded;
try {
expanded = MacroHandler.replace(macros, spec);
tooltip.setText(expanded);
} catch (Exception ex) {
logger.log(Level.WARNING, "Cannot evaluate tooltip of " + widget, ex);
tooltip.setText(spec);
}
});
Tooltip.install(node, tooltip);
if (!initialized_behavior) {
// Unfortunately, no API to control when tooltop shows, and for how long.
// http://stackoverflow.com/questions/26854301/control-javafx-tooltip-delay
// has the hack used in here, which only needs to be applied once
// because it changes a static BEHAVIOR inside the Tooltip.
// Java 9 will offer API, https://bugs.openjdk.java.net/browse/JDK-8090477
hack_behavior(tooltip);
initialized_behavior = true;
}
}
use of org.csstudio.display.builder.model.MacroizedWidgetProperty in project org.csstudio.display.builder by kasemir.
the class MacroizedWidgetPropertyBinding method submit.
private void submit() {
undo.execute(new SetMacroizedWidgetPropertyAction(widget_property, jfx_node.getText()));
if (!other.isEmpty()) {
final String path = widget_property.getPath();
for (Widget w : other) {
final MacroizedWidgetProperty<?> other_prop = (MacroizedWidgetProperty<?>) w.getProperty(path);
undo.execute(new SetMacroizedWidgetPropertyAction(other_prop, jfx_node.getText()));
}
}
}
use of org.csstudio.display.builder.model.MacroizedWidgetProperty in project org.csstudio.display.builder by kasemir.
the class PropertyPanelSection method bindSimplePropertyField.
/**
* Some 'simple' properties are handled
* in static method to allow use in the
* RulesDialog
* @param undo
* @param bindings
* @param property
* @param other
* @return
*/
public static Node bindSimplePropertyField(final UndoableActionManager undo, final List<WidgetPropertyBinding<?, ?>> bindings, final WidgetProperty<?> property, final List<Widget> other) {
final Widget widget = property.getWidget();
Node field = null;
if (property.isReadonly()) {
// If "Type", use a label with an icon.
if (property.getName().equals(CommonWidgetProperties.propType.getName())) {
final String type = widget.getType();
try {
final Image image = new Image(WidgetFactory.getInstance().getWidgetDescriptor(type).getIconStream());
final ImageView icon = new ImageView(image);
final String name = WidgetFactory.getInstance().getWidgetDescriptor(type).getName();
field = new Label(name, icon);
} catch (Exception ex) {
// Some widgets have no icon (e.g. DisplayModel).
field = new Label(String.valueOf(property.getValue()));
}
} else {
final TextField text = new TextField();
text.setText(String.valueOf(property.getValue()));
text.setDisable(true);
field = text;
}
} else if (property instanceof ColorWidgetProperty) {
final ColorWidgetProperty color_prop = (ColorWidgetProperty) property;
final WidgetColorPropertyField color_field = new WidgetColorPropertyField();
final WidgetColorPropertyBinding binding = new WidgetColorPropertyBinding(undo, color_field, color_prop, other);
bindings.add(binding);
binding.bind();
field = color_field;
} else if (property instanceof FontWidgetProperty) {
final FontWidgetProperty font_prop = (FontWidgetProperty) property;
final Button font_field = new Button();
font_field.setMaxWidth(Double.MAX_VALUE);
final WidgetFontPropertyBinding binding = new WidgetFontPropertyBinding(undo, font_field, font_prop, other);
bindings.add(binding);
binding.bind();
field = font_field;
} else if (property instanceof EnumWidgetProperty<?>) {
final EnumWidgetProperty<?> enum_prop = (EnumWidgetProperty<?>) property;
final ComboBox<String> combo = new ComboBox<>();
combo.setPromptText(property.getDefaultValue().toString());
combo.getItems().addAll(enum_prop.getLabels());
combo.setMaxWidth(Double.MAX_VALUE);
combo.setMaxHeight(Double.MAX_VALUE);
final ToggleButton macroButton = new ToggleButton("$");
try {
macroButton.setGraphic(new ImageView(new Image(ResourceUtil.openPlatformResource("platform:/plugin/org.csstudio.display.builder.editor/icons/macro-edit.png"))));
} catch (Exception ex) {
logger.log(Level.WARNING, "Cannot load macro edit image.", ex);
}
macroButton.getStyleClass().add("macro_button");
macroButton.setTooltip(new Tooltip(Messages.MacroEditButton));
BorderPane.setMargin(macroButton, new Insets(0, 0, 0, 3));
BorderPane.setAlignment(macroButton, Pos.CENTER);
final EnumWidgetPropertyBinding binding = new EnumWidgetPropertyBinding(undo, combo, enum_prop, other);
bindings.add(binding);
binding.bind();
final EventHandler<ActionEvent> macro_handler = event -> {
final boolean use_macro = macroButton.isSelected() || MacroHandler.containsMacros(enum_prop.getSpecification());
combo.setEditable(use_macro);
// now that the combo has become editable.
if (use_macro && combo.getEditor().getText().isEmpty())
binding.restore();
};
macroButton.setOnAction(macro_handler);
macroButton.setSelected(MacroHandler.containsMacros(enum_prop.getSpecification()));
macro_handler.handle(null);
field = new BorderPane(combo, null, macroButton, null, null);
// When used in RulesDialog, field can get focus.
// In that case, forward focus to combo
field.focusedProperty().addListener((ob, o, focused) -> {
if (focused) {
combo.requestFocus();
if (combo.isEditable())
combo.getEditor().selectAll();
}
});
} else if (property instanceof BooleanWidgetProperty) {
final BooleanWidgetProperty bool_prop = (BooleanWidgetProperty) property;
final ComboBox<String> combo = new ComboBox<>();
combo.setPromptText(property.getDefaultValue().toString());
combo.getItems().addAll("true", "false");
combo.setMaxWidth(Double.MAX_VALUE);
combo.setMaxHeight(Double.MAX_VALUE);
combo.setEditable(true);
// BooleanWidgetPropertyBinding makes either check or combo visible
// for plain boolean vs. macro-based value
final CheckBox check = new CheckBox();
StackPane.setAlignment(check, Pos.CENTER_LEFT);
final ToggleButton macroButton = new ToggleButton("$");
try {
macroButton.setGraphic(new ImageView(new Image(ResourceUtil.openPlatformResource("platform:/plugin/org.csstudio.display.builder.editor/icons/macro-edit.png"))));
} catch (Exception ex) {
logger.log(Level.WARNING, "Cannot load macro edit image.", ex);
}
macroButton.getStyleClass().add("macro_button");
macroButton.setTooltip(new Tooltip(Messages.MacroEditButton));
BorderPane.setMargin(macroButton, new Insets(0, 0, 0, 3));
BorderPane.setAlignment(macroButton, Pos.CENTER);
final BooleanWidgetPropertyBinding binding = new BooleanWidgetPropertyBinding(undo, check, combo, macroButton, bool_prop, other);
bindings.add(binding);
binding.bind();
field = new BorderPane(new StackPane(combo, check), null, macroButton, null, null);
// For RulesDialog, see above
field.focusedProperty().addListener((ob, o, focused) -> {
if (focused) {
if (combo.isVisible()) {
combo.requestFocus();
combo.getEditor().selectAll();
} else if (check.isVisible())
check.requestFocus();
}
});
} else if (property instanceof ColorMapWidgetProperty) {
final ColorMapWidgetProperty colormap_prop = (ColorMapWidgetProperty) property;
final Button map_button = new Button();
map_button.setMaxWidth(Double.MAX_VALUE);
final ColorMapPropertyBinding binding = new ColorMapPropertyBinding(undo, map_button, colormap_prop, other);
bindings.add(binding);
binding.bind();
field = map_button;
} else if (property instanceof WidgetClassProperty) {
final WidgetClassProperty widget_class_prop = (WidgetClassProperty) property;
final ComboBox<String> combo = new ComboBox<>();
combo.setPromptText(property.getDefaultValue().toString());
combo.setEditable(true);
// List classes of this widget
final String type = widget.getType();
final Collection<String> classes = WidgetClassesService.getWidgetClasses().getWidgetClasses(type);
combo.getItems().addAll(classes);
combo.setMaxWidth(Double.MAX_VALUE);
final WidgetClassBinding binding = new WidgetClassBinding(undo, combo, widget_class_prop, other);
bindings.add(binding);
binding.bind();
field = combo;
} else if (property instanceof FilenameWidgetProperty) {
final FilenameWidgetProperty file_prop = (FilenameWidgetProperty) property;
final TextField text = new TextField();
text.setPromptText(file_prop.getDefaultValue().toString());
text.setMaxWidth(Double.MAX_VALUE);
final Button select_file = new Button("...");
select_file.setOnAction(event -> {
try {
final String filename = FilenameSupport.promptForRelativePath(widget, file_prop.getValue());
if (filename != null)
undo.execute(new SetMacroizedWidgetPropertyAction(file_prop, filename));
} catch (Exception ex) {
logger.log(Level.WARNING, "Cannot prompt for " + file_prop, ex);
}
});
final MacroizedWidgetPropertyBinding binding = new MacroizedWidgetPropertyBinding(undo, text, file_prop, other);
bindings.add(binding);
binding.bind();
field = new HBox(text, select_file);
HBox.setHgrow(text, Priority.ALWAYS);
// For RulesDialog, see above
field.focusedProperty().addListener((ob, o, focused) -> {
if (focused)
text.requestFocus();
});
} else if (property instanceof PVNameWidgetProperty) {
final PVNameWidgetProperty pv_prop = (PVNameWidgetProperty) property;
final TextField text = new TextField();
text.setPromptText(pv_prop.getDefaultValue().toString());
final MacroizedWidgetPropertyBinding binding = new MacroizedWidgetPropertyBinding(undo, text, pv_prop, other) {
@Override
public void bind() {
super.bind();
autocomplete_menu.attachField(text);
}
@Override
public void unbind() {
super.unbind();
autocomplete_menu.removeField(text);
}
};
bindings.add(binding);
binding.bind();
// Allow editing long PV names, including loc://text("Log text with newlines"),
// in dialog
final Button open_editor = new Button("...");
open_editor.setOnAction(event -> {
final MultiLineInputDialog dialog = new MultiLineInputDialog(pv_prop.getSpecification());
DialogHelper.positionDialog(dialog, open_editor, -600, 0);
final Optional<String> result = dialog.showAndWait();
if (!result.isPresent())
return;
undo.execute(new SetMacroizedWidgetPropertyAction(pv_prop, result.get()));
for (Widget w : other) {
final MacroizedWidgetProperty<?> other_prop = (MacroizedWidgetProperty<?>) w.getProperty(pv_prop.getName());
undo.execute(new SetMacroizedWidgetPropertyAction(other_prop, result.get()));
}
});
field = new HBox(text, open_editor);
HBox.setHgrow(text, Priority.ALWAYS);
// For RulesDialog, see similar code elsewhere
field.focusedProperty().addListener((ob, o, focused) -> {
if (focused)
text.requestFocus();
});
} else if (property instanceof MacroizedWidgetProperty) {
// MacroizedWidgetProperty needs to be checked _after_ subclasses like PVNameWidgetProperty, FilenameWidgetProperty
final MacroizedWidgetProperty<?> macro_prop = (MacroizedWidgetProperty<?>) property;
final TextField text = new TextField();
text.setPromptText(macro_prop.getDefaultValue().toString());
final MacroizedWidgetPropertyBinding binding = new MacroizedWidgetPropertyBinding(undo, text, macro_prop, other);
bindings.add(binding);
binding.bind();
if (CommonWidgetProperties.propText.getName().equals(property.getName()) || CommonWidgetProperties.propTooltip.getName().equals(property.getName())) {
// Allow editing multi-line text in dialog
final Button open_editor = new Button("...");
open_editor.setOnAction(event -> {
final MultiLineInputDialog dialog = new MultiLineInputDialog(macro_prop.getSpecification());
DialogHelper.positionDialog(dialog, open_editor, -600, 0);
final Optional<String> result = dialog.showAndWait();
if (!result.isPresent())
return;
undo.execute(new SetMacroizedWidgetPropertyAction(macro_prop, result.get()));
for (Widget w : other) {
final MacroizedWidgetProperty<?> other_prop = (MacroizedWidgetProperty<?>) w.getProperty(macro_prop.getName());
undo.execute(new SetMacroizedWidgetPropertyAction(other_prop, result.get()));
}
});
field = new HBox(text, open_editor);
HBox.setHgrow(text, Priority.ALWAYS);
// For RulesDialog, see above
field.focusedProperty().addListener((ob, o, focused) -> {
if (focused)
text.requestFocus();
});
} else
field = text;
} else if (property instanceof PointsWidgetProperty) {
final PointsWidgetProperty points_prop = (PointsWidgetProperty) property;
final Button points_field = new Button();
points_field.setMaxWidth(Double.MAX_VALUE);
final PointsPropertyBinding binding = new PointsPropertyBinding(undo, points_field, points_prop, other);
bindings.add(binding);
binding.bind();
field = points_field;
}
return field;
}
use of org.csstudio.display.builder.model.MacroizedWidgetProperty in project org.csstudio.display.builder by kasemir.
the class SelectedWidgetUITracker method createInlineEditor.
/**
* Create an inline editor
*
* <p>Depending on the widget's properties, it will edit
* the PV name or the text.
*
* @param widget Widget on which to create an inline editor
*/
private void createInlineEditor(final Widget widget) {
// Check for an inline-editable property
Optional<WidgetProperty<String>> check;
// Add Widget#getInlineEditableProperty()
if (widget instanceof ActionButtonWidget)
check = Optional.of(((ActionButtonWidget) widget).propText());
else if (widget instanceof GroupWidget)
check = Optional.of(((GroupWidget) widget).propName());
else
check = widget.checkProperty(CommonWidgetProperties.propPVName);
if (!check.isPresent())
check = widget.checkProperty(CommonWidgetProperties.propText);
if (!check.isPresent())
return;
// Create text field, aligned with widget, but assert minimum size
final MacroizedWidgetProperty<String> property = (MacroizedWidgetProperty<String>) check.get();
inline_editor = new TextField(property.getSpecification());
// 'Managed' text field would assume some default size,
// but we set the exact size in here
inline_editor.setManaged(false);
// Not really shown since TextField will have focus
inline_editor.setPromptText(property.getDescription());
inline_editor.setTooltip(new Tooltip(property.getDescription()));
inline_editor.relocate(tracker.getX(), tracker.getY());
inline_editor.resize(Math.max(100, tracker.getWidth()), Math.max(20, tracker.getHeight()));
getChildren().add(inline_editor);
// add autocomplete menu if editing property PVName
if (property.getName().equals(CommonWidgetProperties.propPVName.getName()))
autocomplete_menu.attachField(inline_editor);
// On enter, update the property. On Escape, just close
inline_editor.setOnKeyPressed(event -> {
switch(event.getCode()) {
case ENTER:
undo.execute(new SetMacroizedWidgetPropertyAction(property, inline_editor.getText()));
// Fall through, close editor
case ESCAPE:
event.consume();
closeInlineEditor();
default:
}
});
// Close when focus lost
inline_editor.focusedProperty().addListener((prop, old, focused) -> {
if (!focused)
closeInlineEditor();
});
inline_editor.selectAll();
inline_editor.requestFocus();
}
Aggregations