Skip to content

Commit 881c757

Browse files
committed
Fix alarm tree update issue
#2611
1 parent cfd7461 commit 881c757

File tree

3 files changed

+65
-12
lines changed

3 files changed

+65
-12
lines changed

app/alarm/ui/src/main/java/org/phoebus/applications/alarm/ui/tree/AlarmTreeView.java

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import static org.phoebus.applications.alarm.AlarmSystem.logger;
1111

12+
import java.util.ArrayList;
1213
import java.util.Arrays;
1314
import java.util.Collections;
1415
import java.util.LinkedHashSet;
@@ -41,7 +42,6 @@
4142
import org.phoebus.ui.javafx.PrintAction;
4243
import org.phoebus.ui.javafx.Screenshot;
4344
import org.phoebus.ui.javafx.ToolbarHelper;
44-
import org.phoebus.ui.javafx.TreeHelper;
4545
import org.phoebus.ui.javafx.UpdateThrottle;
4646
import org.phoebus.ui.selection.AppSelection;
4747
import org.phoebus.ui.spi.ContextMenuEntry;
@@ -466,9 +466,10 @@ public void itemUpdated(final AlarmTreeItem<?> item)
466466
}
467467

468468
/** Called by throttle to perform accumulated updates */
469+
@SuppressWarnings("unchecked")
469470
private void performUpdates()
470471
{
471-
final TreeItem<?>[] view_items;
472+
final TreeItem<AlarmTreeItem<?>>[] view_items;
472473
synchronized (items_to_update)
473474
{
474475
// Creating a direct copy, i.e. another new LinkedHashSet<>(items_to_update),
@@ -480,8 +481,38 @@ private void performUpdates()
480481
items_to_update.clear();
481482
}
482483

483-
for (final TreeItem<?> view_item : view_items)
484-
TreeHelper.triggerTreeItemRefresh(view_item);
484+
// How to update alarm tree cells when data changed?
485+
// `setValue()` with a truly new value (not 'equal') should suffice,
486+
// but there are two problems:
487+
// Since we're currently using the alarm tree model item as a value,
488+
// the value as seen by the TreeView remains the same.
489+
// We use a model item wrappers class as the cell value
490+
// and replace it (still referencing the same model item!)
491+
// for the TreeView to see a different wrapper value, but
492+
// as shown in org.phoebus.applications.alarm.TreeItemUpdateDemo,
493+
// replacing a tree cell value fails to trigger refreshes
494+
// for certain hidden items.
495+
// Only replacing the TreeItem gives reliable refreshes.
496+
for (final TreeItem<AlarmTreeItem<?>> view_item : view_items)
497+
// Top-level item has no parent, and is not visible, so we keep it
498+
if (view_item.getParent() != null)
499+
{
500+
// Locate item in tree parent
501+
final TreeItem<AlarmTreeItem<?>> parent = view_item.getParent();
502+
final int index = parent.getChildren().indexOf(view_item);
503+
504+
// Create new TreeItem for that value
505+
final AlarmTreeItem<?> value = view_item.getValue();
506+
final TreeItem<AlarmTreeItem<?>> update = new TreeItem<>(value);
507+
// Move child links to new item
508+
final ArrayList<TreeItem<AlarmTreeItem<?>>> children = new ArrayList<>(view_item.getChildren());
509+
view_item.getChildren().clear();
510+
update.getChildren().addAll(children);
511+
update.setExpanded(view_item.isExpanded());
512+
513+
path2view.put(value.getPathName(), update);
514+
parent.getChildren().set(index, update);
515+
}
485516
}
486517

487518
/** Context menu, details depend on selected items */

app/alarm/ui/src/main/java/org/phoebus/applications/alarm/ui/tree/AlarmTreeViewCell.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,27 @@ class AlarmTreeViewCell extends TreeCell<AlarmTreeItem<?>>
3838
private final Label label = new Label();
3939
private final ImageView image = new ImageView();
4040
private final HBox content = new HBox(image, label);
41-
41+
42+
// TreeCell optimizes redraws by suppressing updates
43+
// when old and new values match.
44+
// Since we use the model item as a value,
45+
// the cell sees no change, in fact an identical reference.
46+
// In the fullness of time, a complete redesign might be useful
47+
// to present changing values to the TreeCell, but also note
48+
// the issue shown in org.phoebus.applications.alarm.TreeItemUpdateDemo
49+
//
50+
// So for now we simply force redraws by always indicating a change
51+
@Override
52+
protected boolean isItemChanged(AlarmTreeItem<?> before, AlarmTreeItem<?> after)
53+
{
54+
return true;
55+
}
56+
4257
@Override
4358
protected void updateItem(final AlarmTreeItem<?> item, final boolean empty)
4459
{
4560
super.updateItem(item, empty);
46-
61+
4762
if (empty || item == null)
4863
setGraphic(null);
4964
else

app/alarm/ui/src/test/java/org/phoebus/applications/alarm/TreeItemUpdateDemo.java

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,8 @@
77
*******************************************************************************/
88
package org.phoebus.applications.alarm;
99

10-
import java.time.Instant;
11-
import java.util.concurrent.TimeUnit;
12-
1310
import org.phoebus.ui.javafx.ApplicationWrapper;
1411

15-
import javafx.application.Platform;
1612
import javafx.scene.Scene;
1713
import javafx.scene.control.Button;
1814
import javafx.scene.control.TreeItem;
@@ -23,6 +19,11 @@
2319
import javafx.stage.Stage;
2420

2521
/** Demo of alarm tree cell update
22+
*
23+
* Demonstrates refresh issue for tree cells that are
24+
* not visible because they scrolled below the window bottom.
25+
*
26+
* Only replacing the TreeItem results in reliable tree updates.
2627
*
2728
* 1) Start this program, click the "On" and "Off" buttons, and observe how item "Two" is updated
2829
* 2) Click "Off", reduce the window height so that the items under "Top" are hidden,
@@ -33,12 +34,14 @@
3334
* click "Off", increase window height to again show all items.
3435
* Tree should indeed show "Off".
3536
*
36-
* Conclusion is that TreeItem.setValue() does not trigger updates of hidden items.
37+
* Conclusion is that TreeItem.setValue() does not trigger updates of certain hidden items.
3738
* Basic google search suggests that the value must change, but "On" and "Off"
3839
* are different object references and they are not 'equal'.
3940
*
4041
* When instead replacing the complete TreeItem, the tree is always updated.
4142
*
43+
* Tested with JavaFX 15, 19, 20
44+
*
4245
* @author Kay Kasemir
4346
*/
4447
public class TreeItemUpdateDemo extends ApplicationWrapper
@@ -61,6 +64,8 @@ public void start(final Stage stage)
6164
tree_view.getRoot().getChildren().set(1, new TreeItem<>("Off"));
6265
});
6366
final HBox bottom = new HBox(on, off);
67+
on.setMaxWidth(1000);
68+
off.setMaxWidth(1000);
6469
HBox.setHgrow(on, Priority.ALWAYS);
6570
HBox.setHgrow(off, Priority.ALWAYS);
6671

@@ -70,7 +75,9 @@ public void start(final Stage stage)
7075
TreeItem<String> top = new TreeItem<>("Top");
7176
tree_view.setRoot(top);
7277

73-
top.getChildren().addAll(new TreeItem<>("One"), new TreeItem<>("Two"), new TreeItem<>("Three"));
78+
top.getChildren().add(new TreeItem<>("One"));
79+
top.getChildren().add(new TreeItem<>("Two"));
80+
top.getChildren().add(new TreeItem<>("Three"));
7481
top.setExpanded(true);
7582

7683
final Scene scene = new Scene(root, 300, 300);

0 commit comments

Comments
 (0)