From 7088d0d96b11c9b75f8c685c4a7d2df742ab69a5 Mon Sep 17 00:00:00 2001 From: kasemir Date: Mon, 18 Mar 2024 11:59:42 -0400 Subject: [PATCH 1/2] Handle newlines in inline editor by escaping them as '\n' --- .../editor/tracker/SelectedWidgetUITracker.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/app/display/editor/src/main/java/org/csstudio/display/builder/editor/tracker/SelectedWidgetUITracker.java b/app/display/editor/src/main/java/org/csstudio/display/builder/editor/tracker/SelectedWidgetUITracker.java index 7010fa1682..bbe452cf83 100644 --- a/app/display/editor/src/main/java/org/csstudio/display/builder/editor/tracker/SelectedWidgetUITracker.java +++ b/app/display/editor/src/main/java/org/csstudio/display/builder/editor/tracker/SelectedWidgetUITracker.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2015-2020 Oak Ridge National Laboratory. + * Copyright (c) 2015-2024 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 @@ -301,7 +301,8 @@ else if (widget instanceof GroupWidget) // Create text field, aligned with widget, but assert minimum size final MacroizedWidgetProperty property = (MacroizedWidgetProperty)check.get(); - inline_editor = new TextField(property.getSpecification()); + // Allow editing newlines as '\n' + inline_editor = new TextField(property.getSpecification().replace("\n", "\\n")); // 'Managed' text field would assume some default size, // but we set the exact size in here inline_editor.setManaged(false); @@ -320,8 +321,9 @@ else if (widget instanceof GroupWidget) { if (! focused) { - if (!property.getSpecification().equals(inline_editor.getText())) - undo.execute(new SetMacroizedWidgetPropertyAction(property, inline_editor.getText())); + final String new_text = inline_editor.getText().replace("\\n", "\n"); + if (!property.getSpecification().equals(new_text)) + undo.execute(new SetMacroizedWidgetPropertyAction(property, new_text)); // Close when focus lost closeInlineEditor(); } @@ -329,7 +331,9 @@ else if (widget instanceof GroupWidget) inline_editor.setOnAction(event -> { - undo.execute(new SetMacroizedWidgetPropertyAction(property, inline_editor.getText())); + final String new_text = inline_editor.getText().replace("\\n", "\n"); + if (!property.getSpecification().equals(new_text)) + undo.execute(new SetMacroizedWidgetPropertyAction(property, new_text)); inline_editor.focusedProperty().removeListener(focused_listener); closeInlineEditor(); }); From 6852bd110a939a688f231ef0d633e9d6b7f3c61d Mon Sep 17 00:00:00 2001 From: kasemir Date: Mon, 18 Mar 2024 12:09:40 -0400 Subject: [PATCH 2/2] Inline editor: Focus listener was not removed when leaving focus ... because `focused_listener` could not be used inside the lambda that initialized the `focused_listener`. Now atomicref is used to hold that value, allowing its use inside the `focused_listener` --- .../editor/tracker/SelectedWidgetUITracker.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/app/display/editor/src/main/java/org/csstudio/display/builder/editor/tracker/SelectedWidgetUITracker.java b/app/display/editor/src/main/java/org/csstudio/display/builder/editor/tracker/SelectedWidgetUITracker.java index bbe452cf83..4d95c72882 100644 --- a/app/display/editor/src/main/java/org/csstudio/display/builder/editor/tracker/SelectedWidgetUITracker.java +++ b/app/display/editor/src/main/java/org/csstudio/display/builder/editor/tracker/SelectedWidgetUITracker.java @@ -14,6 +14,7 @@ import java.util.Objects; import java.util.Optional; import java.util.concurrent.RecursiveTask; +import java.util.concurrent.atomic.AtomicReference; import java.util.logging.Level; import java.util.stream.Collectors; @@ -317,24 +318,27 @@ else if (widget instanceof GroupWidget) PVAutocompleteMenu.INSTANCE.attachField(inline_editor); // On enter or lost focus, update the property. On Escape, just close. - final ChangeListener focused_listener = (prop, old, focused) -> + // Using atomic ref as holder so that focused_listener can remove itself + final AtomicReference> focused_listener = new AtomicReference<>(); + focused_listener.set((prop, old, focused) -> { if (! focused) { final String new_text = inline_editor.getText().replace("\\n", "\n"); if (!property.getSpecification().equals(new_text)) undo.execute(new SetMacroizedWidgetPropertyAction(property, new_text)); + inline_editor.focusedProperty().removeListener(focused_listener.get()); // Close when focus lost closeInlineEditor(); } - }; + }); inline_editor.setOnAction(event -> { final String new_text = inline_editor.getText().replace("\\n", "\n"); if (!property.getSpecification().equals(new_text)) undo.execute(new SetMacroizedWidgetPropertyAction(property, new_text)); - inline_editor.focusedProperty().removeListener(focused_listener); + inline_editor.focusedProperty().removeListener(focused_listener.get()); closeInlineEditor(); }); @@ -344,13 +348,13 @@ else if (widget instanceof GroupWidget) { case ESCAPE: event.consume(); - inline_editor.focusedProperty().removeListener(focused_listener); + inline_editor.focusedProperty().removeListener(focused_listener.get()); closeInlineEditor(); default: } }); - inline_editor.focusedProperty().addListener(focused_listener); + inline_editor.focusedProperty().addListener(focused_listener.get()); inline_editor.selectAll(); inline_editor.requestFocus();