Skip to content

Commit

Permalink
Merge pull request #2302 from ControlSystemStudio/display_array_class…
Browse files Browse the repository at this point in the history
…_2297

Display: Support 'class' for array/struct properties
  • Loading branch information
kasemir authored Jun 21, 2022
2 parents a3f8c5d + 34ca18f commit 161d97a
Show file tree
Hide file tree
Showing 8 changed files with 217 additions and 90 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2017-2020 Oak Ridge National Laboratory.
* Copyright (c) 2017-2022 Oak Ridge National Laboratory.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
Expand All @@ -22,6 +22,7 @@
import org.csstudio.display.builder.editor.EditorGUI;
import org.csstudio.display.builder.editor.EditorUtil;
import org.csstudio.display.builder.editor.Messages;
import org.csstudio.display.builder.editor.WidgetSelectionHandler;
import org.csstudio.display.builder.editor.actions.ActionDescription;
import org.csstudio.display.builder.model.DisplayModel;
import org.csstudio.display.builder.model.ModelPlugin;
Expand Down Expand Up @@ -386,9 +387,20 @@ void loadWidgetClasses()
ModelThreadPool.getExecutor().execute(() ->
{
// get widget classes and apply to model
// (which triggers editor UI updates, so perform in UI thread)
final DisplayModel model = editor_gui.getDisplayEditor().getModel();
if (model != null)
WidgetClassesService.getWidgetClasses().apply(model);
Platform.runLater( () ->
{
// Save/restore selection to force update of property panel
final WidgetSelectionHandler selection = editor_gui.getDisplayEditor().getWidgetSelectionHandler();
final List<Widget> save = selection.getSelection();
selection.clear();
// Apply class settings
WidgetClassesService.getWidgetClasses().apply(model);
// Restore selection
selection.setSelection(save);
});
});
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2015-2018 Oak Ridge National Laboratory.
* Copyright (c) 2015-2022 Oak Ridge National Laboratory.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
Expand Down Expand Up @@ -499,19 +499,22 @@ else if (property instanceof PointsWidgetProperty)
* @param property Property (on primary widget)
* @param other Zero or more additional widgets that have same type of property
* @param structureIndex Index of the array structure (element) being added. It is meaningful
* only for properties instance of {@link StructuredWidgetProperty}.
* only for properties instance of {@link StructuredWidgetProperty}
* @param indentationLevel Indentation level
*/
private void createPropertyUI(
final UndoableActionManager undo,
final WidgetProperty<?> property,
final List<Widget> other,
final int structureIndex,
final int indentationLevel
) {
final int indentationLevel)
{
// Skip runtime properties
if (property.getCategory() == WidgetPropertyCategory.RUNTIME)
return;

// System.out.println("Index " + structureIndex + ", level " + indentationLevel + ": " + property.getPath());

final Label label = new Label(property.getDescription());
label.setMaxWidth(Double.MAX_VALUE);
final String tooltip = property.getDescription() + " (" + property.getPath() + ")";
Expand Down Expand Up @@ -567,9 +570,7 @@ else if (property instanceof RulesWidgetProperty)
field = rules_field;
}
else if (property instanceof StructuredWidgetProperty)
{ // Don't allow editing structures and their elements in class mode
if (class_mode)
return;
{
final StructuredWidgetProperty struct = (StructuredWidgetProperty) property;
final Label header = new Label(struct.getDescription() + ( structureIndex > 0 ? " " + String.valueOf(1 + structureIndex) : ""));
header.getStyleClass().add("structure_property_name");
Expand All @@ -589,9 +590,7 @@ else if (property instanceof StructuredWidgetProperty)
return;
}
else if (property instanceof ArrayWidgetProperty)
{ // Don't allow editing arrays and their elements in class mode
if (class_mode)
return;
{
@SuppressWarnings("unchecked")
final ArrayWidgetProperty<WidgetProperty<?>> array = (ArrayWidgetProperty<WidgetProperty<?>>) property;

Expand All @@ -611,6 +610,28 @@ else if (property instanceof ArrayWidgetProperty)

fillHeaderIndent(indentationLevel, row);
add(label, indentationLevel, row, 4 - indentationLevel, 1);

if (class_mode)
{ // Checkbox to select if array is included in class definition
final CheckBox check = new CheckBox();
check.setPadding(new Insets(0, 5, 0, 0));
check.setTooltip(use_class_tooltip);
final WidgetPropertyBinding<?,?> binding = new UseWidgetClassBinding(undo, check, spinner, property, other);
bindings.add(binding);
binding.bind();
add(check, 3, row);
}
else
{ // Show if property is set by the class, not editable.
final Label indicator = new Label();
indicator.setPadding(new Insets(0, 5, 0, 0));
indicator.setTooltip(using_class_tooltip);
final WidgetPropertyBinding<?,?> binding = new ShowWidgetClassBinding(spinner, property, indicator);
bindings.add(binding);
binding.bind();
add(indicator, 3, row);
}

add(spinner, 4, row, 2 - indentationLevel, 1);

Separator separator = new Separator();
Expand Down Expand Up @@ -683,14 +704,20 @@ else if (property instanceof ArrayWidgetProperty)
{
if (class_mode)
{ // Class definition mode:
// Check box for 'use_class'
final CheckBox check = new CheckBox();
check.setPadding(new Insets(0, 5, 0, 0));
check.setTooltip(use_class_tooltip);
final WidgetPropertyBinding<?,?> binding = new UseWidgetClassBinding(undo, check, field, property, other);
bindings.add(binding);
binding.bind();
add(check, 3, row);
// Check box for 'use_class', but only on the top level
// For nested properties inside an array or struct,
// the class behavior is controlled at the top-level
// for the complete array or struct
if (indentationLevel == 0)
{
final CheckBox check = new CheckBox();
check.setPadding(new Insets(0, 5, 0, 0));
check.setTooltip(use_class_tooltip);
final WidgetPropertyBinding<?,?> binding = new UseWidgetClassBinding(undo, check, field, property, other);
bindings.add(binding);
binding.bind();
add(check, 3, row);
}
}
else
{ // Display file mode:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2015-2017 Oak Ridge National Laboratory.
* Copyright (c) 2015-2022 Oak Ridge National Laboratory.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
Expand Down Expand Up @@ -55,13 +55,14 @@ public void bind()
updateFromModel();
jfx_node.setOnAction(event ->
{
final boolean use_class = jfx_node.isSelected();
updating = true;
property_field.setDisable(! jfx_node.isSelected());
undo.execute(new UseClassAction(widget_property, jfx_node.isSelected()));
property_field.setDisable(! use_class);
undo.execute(new UseClassAction(widget_property, use_class));
for (Widget w : other)
{
final WidgetProperty<?> other_prop = w.getProperty(widget_property.getName());
undo.execute(new UseClassAction(other_prop, jfx_node.isSelected()));
undo.execute(new UseClassAction(other_prop, use_class));
}
updating = false;
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2015-2016 Oak Ridge National Laboratory.
* Copyright (c) 2015-2022 Oak Ridge National Laboratory.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
Expand Down Expand Up @@ -111,15 +111,6 @@ protected ArrayWidgetProperty(final Descriptor<WPE> descriptor,
value = new CopyOnWriteArrayList<>(elements);
}

@Override
public boolean isUsingWidgetClass()
{ // Array uses class if any elements use it
for (WidgetProperty<?> element : value)
if (element.isUsingWidgetClass())
return true;
return false;
}

@Override
public boolean isDefaultValue()
{
Expand All @@ -130,6 +121,15 @@ public boolean isDefaultValue()
value.get(0).isDefaultValue();
}

@Override
public void useWidgetClass(boolean use_class)
{
// Update overall array as well as each element
super.useWidgetClass(use_class);
for (WPE element : value)
element.useWidgetClass(use_class);
}

@Override
protected List<WPE> restrictValue(final List<WPE> requested_value)
{
Expand Down Expand Up @@ -195,6 +195,8 @@ public WPE removeElement()
/** @param element Element to add to end of list */
public void addElement(final WPE element)
{
// New elements get same class behavior as the array
element.useWidgetClass(use_class);
value.add(element);
firePropertyChange(null, Arrays.asList(element));
}
Expand Down Expand Up @@ -239,8 +241,7 @@ public void setValueFromObject(final Object value) throws Exception
element.setValueFromObject(el_value);
}

// Notify listeners of the whole array
firePropertyChange(this, null, this.value);
// Listeners already received remove/add/set events
}
catch (Throwable ex)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2015-2016 Oak Ridge National Laboratory.
* Copyright (c) 2015-2022 Oak Ridge National Laboratory.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
Expand Down Expand Up @@ -66,16 +66,6 @@ protected StructuredWidgetProperty(final Descriptor descriptor,
super(descriptor, widget, elements);
}

/** @return <code>true</code> if any element is using class support */
@Override
public boolean isUsingWidgetClass()
{
for (WidgetProperty<?> element : value)
if (element.isUsingWidgetClass())
return true;
return false;
}

/** @return <code>true</code> if all elements have default value */
@Override
public boolean isDefaultValue()
Expand All @@ -86,6 +76,15 @@ public boolean isDefaultValue()
return true;
}

@Override
public void useWidgetClass(boolean use_class)
{
// Update overall structure as well as each element
super.useWidgetClass(use_class);
for (WidgetProperty<?> element : value)
element.useWidgetClass(use_class);
}

/** @return <code>true</code> if all elements are read-only */
@Override
public boolean isReadonly()
Expand Down Expand Up @@ -142,35 +141,42 @@ public void setValue(final List<WidgetProperty<?>> value)
@Override
public void setValueFromObject(final Object new_value) throws Exception
{
if (new_value instanceof List)
{ // Allow assignment of another structure's value, i.e. list with same elements
final List<?> new_elements = (List<?>)new_value;
if (new_elements.size() != value.size())
throw new Exception("Elements of structure " + getName() + " must provide " + value.size() + " elements, got " + new_elements.size());
for (int i=0; i<value.size(); ++i)
{
final WidgetProperty<?> element = value.get(i);
final Object new_object = new_elements.get(i);
if (element.getClass() != new_object.getClass())
throw new Exception("Cannot set structure " + getName() + "." + element.getName() + " to " + new_object);

final WidgetProperty<?> new_element = (WidgetProperty<?>)new_object;
if (element.getName() != new_element.getName())
throw new Exception("Cannot set structure " + getName() + "." + element.getName() + " to " + new_element.getName());
try
{
element.setValueFromObject(new_element.getValue());
}
catch (Exception ex)
{
throw new Exception("Cannot set structure " + getName() + "." + element.getName() + " to " + new_element, ex);
}
}
// Notify listeners of the whole array
firePropertyChange(this, null, this.value);
final List<?> new_elements;

// May use other struct or list with elements
if (new_value instanceof StructuredWidgetProperty)
{
final StructuredWidgetProperty other = (StructuredWidgetProperty) new_value;
new_elements = other.value;
}
else if (new_value instanceof List)
new_elements = (List<?>)new_value;
else
throw new Exception("Elements of structure " + getName() + " cannot be assigned from " + new_value);

// Either way, element count and names of elements must match this struct
if (new_elements.size() != value.size())
throw new Exception("Elements of structure " + getName() + " must provide " + value.size() + " elements, got " + new_elements.size());
for (int i=0; i<value.size(); ++i)
{
final WidgetProperty<?> element = value.get(i);
final Object new_object = new_elements.get(i);
if (element.getClass() != new_object.getClass())
throw new Exception("Cannot set structure " + getName() + "." + element.getName() + " to " + new_object);

final WidgetProperty<?> new_element = (WidgetProperty<?>)new_object;
if (element.getName() != new_element.getName())
throw new Exception("Cannot set structure " + getName() + "." + element.getName() + " to " + new_element.getName());
try
{
element.setValueFromObject(new_element.getValue());
}
catch (Exception ex)
{
throw new Exception("Cannot set structure " + getName() + "." + element.getName() + " to " + new_element, ex);
}
}
// Listeners have been notified about each element in setValueFromObject
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2015-2016 Oak Ridge National Laboratory.
* Copyright (c) 2015-2022 Oak Ridge National Laboratory.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
Expand Down Expand Up @@ -227,15 +227,7 @@ public boolean isDefaultValue()
*/
public void useWidgetClass(final boolean use_class)
{
if (this.use_class == use_class)
return;

this.use_class = use_class;

// Editor for class model needs update, runtime doesn't
final DisplayModel model = getWidget().checkDisplayModel();
if (model != null && model.isClassModel())
firePropertyChange(null, null);
}

/** @return Is value of this property following
Expand Down
Loading

0 comments on commit 161d97a

Please sign in to comment.