Skip to content

Commit f0c8588

Browse files
committed
Update control widget representations to use generic 'disable style' method
... in parent for consistent and uniform behaviour across widgets. Some widgets were being disabled which removes the context menu so these have been switched ot just apply the style. In addition some widgets were still trying to write to 'no_write' PVs causing exceptions in the log. These have been fixed by changing whether the widget is enabled first.
1 parent 712b5ca commit f0c8588

File tree

11 files changed

+114
-96
lines changed

11 files changed

+114
-96
lines changed

app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/BoolButtonRepresentation.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ public class BoolButtonRepresentation extends RegionBaseRepresentation<Pane, Boo
8383
private volatile String value_label;
8484
private volatile ImageView[] state_images;
8585
private volatile ImageView value_image;
86+
protected volatile boolean enabled = true;
8687

8788
private final UntypedWidgetPropertyListener imagesChangedListener = this::imagesChanged;
8889
private final UntypedWidgetPropertyListener representationChangedListener = this::representationChanged;
@@ -138,8 +139,10 @@ protected void attachTooltip()
138139
*/
139140
private void handlePress(final boolean pressed)
140141
{
141-
logger.log(Level.FINE, "{0} pressed", model_widget);
142-
Platform.runLater(() -> confirm(pressed));
142+
if (enabled) {
143+
logger.log(Level.FINE, "{0} pressed", model_widget);
144+
Platform.runLater(() -> confirm(pressed));
145+
}
143146
}
144147

145148
/** Check for confirmation, then perform the button action
@@ -403,10 +406,9 @@ public void updateChanges()
403406
}
404407
if (dirty_enablement.checkAndClear())
405408
{
406-
final boolean enabled = model_widget.propEnabled().getValue() &&
409+
enabled = model_widget.propEnabled().getValue() &&
407410
model_widget.runtimePropPVWritable().getValue();
408-
button.setDisable(! enabled);
409-
Styles.update(button, Styles.NOT_ENABLED, !enabled);
411+
setDisabledLook(enabled, jfx_node.getChildren());
410412
}
411413
if (update_value)
412414
{

app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/CheckBoxRepresentation.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ public void updateChanges()
229229
// Just apply a style that matches the disabled look.
230230
enabled = model_widget.propEnabled().getValue() &&
231231
model_widget.runtimePropPVWritable().getValue();
232-
Styles.update(jfx_node, Styles.NOT_ENABLED, !enabled);
232+
setDisabledLook(enabled, jfx_node.getChildrenUnmodifiable());
233233
if (model_widget.propAutoSize().getValue())
234234
sizeChanged(null, null, null);
235235
}

app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/ChoiceButtonRepresentation.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,14 @@ private void selectionChanged(final ObservableValue<? extends Toggle> obs, final
181181
{
182182
active = false;
183183
}
184+
}
185+
else if (!enabled && newval == null)
186+
{
187+
// If the choice button is not enabled (no write allowed)
188+
// we still have to ensure the 'oldval' stays selected
189+
// as otherwise clicking on the same value will set an
190+
// unselected look on the ChoiceButton.
191+
toggle.selectToggle(oldval);
184192
}
185193
}
186194

@@ -332,8 +340,7 @@ public void updateChanges()
332340
// Just apply a style that matches the disabled look.
333341
enabled = model_widget.propEnabled().getValue() &&
334342
model_widget.runtimePropPVWritable().getValue();
335-
Styles.update(jfx_node, Styles.NOT_ENABLED, !enabled);
336-
jfx_node.setCursor(enabled ? Cursor.DEFAULT : Cursors.NO_WRITE);
343+
setDisabledLook(enabled, jfx_node.getChildren());
337344
for (Node node : jfx_node.getChildren())
338345
{
339346
final ButtonBase b = (ButtonBase) node;

app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/ComboRepresentation.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -296,8 +296,7 @@ public void updateChanges()
296296
// and the cursor will be ignored
297297
// jfx_node.setDisable(! enabled);
298298
// So keep enabled, but indicate that trying to operate the widget is futile
299-
Styles.update(jfx_node, Styles.NOT_ENABLED, !enabled);
300-
jfx_node.setCursor(enabled ? Cursor.DEFAULT : Cursors.NO_WRITE);
299+
setDisabledLook(enabled, jfx_node.getChildrenUnmodifiable());
301300
if (model_widget.propEditable().getValue())
302301
{
303302
jfx_node.getEditor().setEditable(enabled ? model_widget.propEditable().getValue() : false);

app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/RadioRepresentation.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ public void updateChanges()
299299
// Just apply a style that matches the disabled look.
300300
enabled = model_widget.propEnabled().getValue() &&
301301
model_widget.runtimePropPVWritable().getValue();
302-
Styles.update(jfx_node, Styles.NOT_ENABLED, !enabled);
302+
setDisabledLook(enabled, jfx_node.getChildren());
303303
for (Node rb_node : jfx_node.getChildren())
304304
{
305305
final RadioButton rb = (RadioButton) rb_node;

app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/ScaledSliderRepresentation.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,8 +407,11 @@ private void valueChanged(final WidgetProperty<? extends VType> property, final
407407
public void updateChanges()
408408
{
409409
super.updateChanges();
410-
if (dirty_enablement.checkAndClear())
410+
if (dirty_enablement.checkAndClear()) {
411411
slider.setDisable(!enabled);
412+
setDisabledLook(enabled, jfx_node.getChildrenUnmodifiable());
413+
}
414+
412415
if (dirty_layout.checkAndClear())
413416
{
414417
final boolean horizontal = model_widget.propHorizontal().getValue();

app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/ScrollBarRepresentation.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -335,8 +335,7 @@ public void updateChanges()
335335
// Don't disable the widget, because that would also remove the
336336
// context menu etc.
337337
// Just apply a style that matches the disabled look.
338-
Styles.update(jfx_node, Styles.NOT_ENABLED, !enabled);
339-
jfx_node.setCursor(enabled ? Cursor.DEFAULT : Cursors.NO_WRITE);
338+
setDisabledLook(enabled, jfx_node.getChildrenUnmodifiable());
340339
}
341340
if (dirty_size.checkAndClear())
342341
{

app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/SlideButtonRepresentation.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ public void updateChanges ( ) {
9999
// Just apply a style that matches the disabled look.
100100
enabled = model_widget.propEnabled().getValue() && model_widget.runtimePropPVWritable().getValue();
101101

102-
Styles.update(jfx_node, Styles.NOT_ENABLED, !enabled);
102+
setDisabledLook(enabled, jfx_node.getChildren());
103103

104104
// Since jfx_node.isManaged() == false, need to trigger layout
105105
jfx_node.layout();

app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/SpinnerRepresentation.java

Lines changed: 51 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ public class SpinnerRepresentation extends RegionBaseRepresentation<Spinner<Stri
4949
{
5050
/** Is user actively editing the content, so updates should be suppressed? */
5151
private volatile boolean active = false;
52+
private volatile boolean enabled = true;
5253

5354
private final DirtyFlag dirty_style = new DirtyFlag();
5455
private final DirtyFlag dirty_content = new DirtyFlag();
@@ -167,40 +168,42 @@ private void restore()
167168
/** Submit value entered by user */
168169
private void submit()
169170
{
170-
//The value factory retains the old values, and will be updated as scheduled below.
171-
final String text = jfx_node.getEditor().getText();
172-
Object value =
173-
FormatOptionHandler.parse(model_widget.runtimePropValue().getValue(), text, model_widget.propFormat().getValue());
174-
if (value instanceof Number)
175-
{
176-
if (((Number)value).doubleValue() < value_min)
177-
value = value_min;
178-
else if (((Number)value).doubleValue() > value_max)
179-
value = value_max;
171+
if (enabled) {
172+
//The value factory retains the old values, and will be updated as scheduled below.
173+
final String text = jfx_node.getEditor().getText();
174+
Object value =
175+
FormatOptionHandler.parse(model_widget.runtimePropValue().getValue(), text, model_widget.propFormat().getValue());
176+
if (value instanceof Number)
177+
{
178+
if (((Number)value).doubleValue() < value_min)
179+
value = value_min;
180+
else if (((Number)value).doubleValue() > value_max)
181+
value = value_max;
182+
}
183+
logger.log(Level.FINE, "Writing '" + text + "' as " + value + " (" + value.getClass().getName() + ")");
184+
toolkit.fireWrite(model_widget, value);
185+
186+
// Wrote value. Expected is either
187+
// a) PV receives that value, PV updates to
188+
// submitted value or maybe a 'clamped' value
189+
// --> We'll receive contentChanged() and update the value factory.
190+
// b) PV doesn't receive the value and never sends
191+
// an update. The value factory retains the old value,
192+
// --> Schedule an update to the new value.
193+
//
194+
// This could result in a little flicker:
195+
// User enters "new_value".
196+
// We send that, but retain "old_value" to handle case b)
197+
// PV finally sends "new_value", and we show that.
198+
//
199+
// In practice, this rarely happens because we only schedule an update.
200+
// By the time it executes, we already have case a.
201+
// If it does turn into a problem, could introduce toolkit.scheduleDelayedUpdate()
202+
// so that case b) only restores the old 'value_text' after some delay,
203+
// increasing the chance of a) to happen.
204+
dirty_content.mark();
205+
toolkit.scheduleUpdate(this);
180206
}
181-
logger.log(Level.FINE, "Writing '" + text + "' as " + value + " (" + value.getClass().getName() + ")");
182-
toolkit.fireWrite(model_widget, value);
183-
184-
// Wrote value. Expected is either
185-
// a) PV receives that value, PV updates to
186-
// submitted value or maybe a 'clamped' value
187-
// --> We'll receive contentChanged() and update the value factory.
188-
// b) PV doesn't receive the value and never sends
189-
// an update. The value factory retains the old value,
190-
// --> Schedule an update to the new value.
191-
//
192-
// This could result in a little flicker:
193-
// User enters "new_value".
194-
// We send that, but retain "old_value" to handle case b)
195-
// PV finally sends "new_value", and we show that.
196-
//
197-
// In practice, this rarely happens because we only schedule an update.
198-
// By the time it executes, we already have case a.
199-
// If it does turn into a problem, could introduce toolkit.scheduleDelayedUpdate()
200-
// so that case b) only restores the old 'value_text' after some delay,
201-
// increasing the chance of a) to happen.
202-
dirty_content.mark();
203-
toolkit.scheduleUpdate(this);
204207
}
205208

206209
private SpinnerValueFactory<String> createSVF()
@@ -349,18 +352,20 @@ public void increment(int steps)
349352

350353
private void writeResultingValue(double change)
351354
{
352-
double value;
353-
if (!(getVTypeValue() instanceof VNumber))
354-
{
355-
scheduleContentUpdate();
356-
return;
355+
if (enabled) {
356+
double value;
357+
if (!(getVTypeValue() instanceof VNumber))
358+
{
359+
scheduleContentUpdate();
360+
return;
361+
}
362+
value = ((VNumber)getVTypeValue()).getValue().doubleValue();
363+
if (Double.isNaN(value) || Double.isInfinite(value)) return;
364+
value += change;
365+
if (value < getMin()) value = getMin();
366+
else if (value > getMax()) value = getMax();
367+
toolkit.fireWrite(model_widget, value);
357368
}
358-
value = ((VNumber)getVTypeValue()).getValue().doubleValue();
359-
if (Double.isNaN(value) || Double.isInfinite(value)) return;
360-
value += change;
361-
if (value < getMin()) value = getMin();
362-
else if (value > getMax()) value = getMax();
363-
toolkit.fireWrite(model_widget, value);
364369
}
365370
};
366371

@@ -505,11 +510,10 @@ public void updateChanges()
505510
jfx_node.resize(model_widget.propWidth().getValue(), model_widget.propHeight().getValue());
506511

507512
// Enable if enabled by user and there's write access
508-
final boolean enabled = model_widget.propEnabled().getValue() &&
513+
enabled = model_widget.propEnabled().getValue() &&
509514
model_widget.runtimePropPVWritable().getValue();
510-
Styles.update(jfx_node, Styles.NOT_ENABLED, !enabled);
515+
setDisabledLook(enabled, jfx_node.getChildrenUnmodifiable());
511516
jfx_node.setEditable(!toolkit.isEditMode() && enabled);
512-
jfx_node.getEditor().setCursor(enabled ? Cursor.DEFAULT : Cursors.NO_WRITE);
513517

514518
jfx_node.getEditor().setFont(JFXUtil.convert(model_widget.propFont().getValue()));
515519

app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/TextEntryRepresentation.java

Lines changed: 35 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ public class TextEntryRepresentation extends RegionBaseRepresentation<TextInputC
4949
* but also read when receiving new value
5050
*/
5151
private boolean active = false;
52+
private volatile boolean enabled = true;
5253

5354
private final DirtyFlag dirty_size = new DirtyFlag();
5455
private final DirtyFlag dirty_style = new DirtyFlag();
@@ -236,35 +237,37 @@ private void restore()
236237
/** Submit value entered by user */
237238
private void submit()
238239
{
239-
// Strip 'units' etc. from text
240-
final String text = jfx_node.getText();
241-
242-
final Object value = FormatOptionHandler.parse(model_widget.runtimePropValue().getValue(), text,
243-
model_widget.propFormat().getValue());
244-
logger.log(Level.FINE, "Writing '" + text + "' as " + value + " (" + value.getClass().getName() + ")");
245-
toolkit.fireWrite(model_widget, value);
246-
247-
// Wrote value. Expected is either
248-
// a) PV receives that value, PV updates to
249-
// submitted value or maybe a 'clamped' value
250-
// --> We'll receive contentChanged() and display PV's latest.
251-
// b) PV doesn't receive the value and never sends
252-
// an update. JFX control is stuck with the 'text'
253-
// the user entered, not reflecting the actual PV
254-
// --> Request an update to the last known 'value_text'.
255-
//
256-
// This could result in a little flicker:
257-
// User enters "new_value".
258-
// We send that, but restore "old_value" to handle case b)
259-
// PV finally sends "new_value", and we show that.
260-
//
261-
// In practice, this rarely happens because we only schedule an update.
262-
// By the time it executes, we already have case a.
263-
// If it does turn into a problem, could introduce toolkit.scheduleDelayedUpdate()
264-
// so that case b) only restores the old 'value_text' after some delay,
265-
// increasing the chance of a) to happen.
266-
dirty_content.mark();
267-
toolkit.scheduleUpdate(this);
240+
if (enabled) {
241+
// Strip 'units' etc. from text
242+
final String text = jfx_node.getText();
243+
244+
final Object value = FormatOptionHandler.parse(model_widget.runtimePropValue().getValue(), text,
245+
model_widget.propFormat().getValue());
246+
logger.log(Level.FINE, "Writing '" + text + "' as " + value + " (" + value.getClass().getName() + ")");
247+
toolkit.fireWrite(model_widget, value);
248+
249+
// Wrote value. Expected is either
250+
// a) PV receives that value, PV updates to
251+
// submitted value or maybe a 'clamped' value
252+
// --> We'll receive contentChanged() and display PV's latest.
253+
// b) PV doesn't receive the value and never sends
254+
// an update. JFX control is stuck with the 'text'
255+
// the user entered, not reflecting the actual PV
256+
// --> Request an update to the last known 'value_text'.
257+
//
258+
// This could result in a little flicker:
259+
// User enters "new_value".
260+
// We send that, but restore "old_value" to handle case b)
261+
// PV finally sends "new_value", and we show that.
262+
//
263+
// In practice, this rarely happens because we only schedule an update.
264+
// By the time it executes, we already have case a.
265+
// If it does turn into a problem, could introduce toolkit.scheduleDelayedUpdate()
266+
// so that case b) only restores the old 'value_text' after some delay,
267+
// increasing the chance of a) to happen.
268+
dirty_content.mark();
269+
toolkit.scheduleUpdate(this);
270+
}
268271
}
269272

270273
@Override
@@ -399,14 +402,14 @@ public void updateChanges()
399402
jfx_node.setFont(JFXUtil.convert(model_widget.propFont().getValue()));
400403

401404
// Enable if enabled by user and there's write access
402-
final boolean enabled = model_widget.propEnabled().getValue() &&
405+
enabled = model_widget.propEnabled().getValue() &&
403406
model_widget.runtimePropPVWritable().getValue();
404407
// Don't disable the widget, because that would also remove the
405408
// context menu etc.
406409
// Just apply a style that matches the disabled look.
407410
jfx_node.setEditable(enabled);
408-
Styles.update(jfx_node, Styles.NOT_ENABLED, !enabled);
409-
jfx_node.setCursor(enabled ? Cursor.DEFAULT : Cursors.NO_WRITE);
411+
setDisabledLook(enabled, jfx_node.getChildrenUnmodifiable());
412+
410413

411414
if(jfx_node instanceof TextField){
412415
((TextField)jfx_node).setAlignment(pos);

0 commit comments

Comments
 (0)