1
1
package org .jabref .gui .util ;
2
2
3
3
import java .util .List ;
4
+ import java .util .function .Predicate ;
4
5
import java .util .stream .Collectors ;
5
6
7
+ import javafx .beans .binding .Bindings ;
6
8
import javafx .beans .property .BooleanProperty ;
9
+ import javafx .beans .property .ObjectProperty ;
10
+ import javafx .beans .property .SimpleObjectProperty ;
11
+ import javafx .beans .value .ObservableValue ;
7
12
import javafx .collections .ListChangeListener ;
8
13
import javafx .collections .ObservableList ;
14
+ import javafx .collections .transformation .FilteredList ;
9
15
import javafx .scene .Node ;
10
16
import javafx .scene .control .TreeItem ;
11
17
import javafx .util .Callback ;
@@ -17,20 +23,29 @@ public class RecursiveTreeItem<T> extends TreeItem<T> {
17
23
18
24
private final Callback <T , BooleanProperty > expandedProperty ;
19
25
private Callback <T , ObservableList <T >> childrenFactory ;
26
+ private ObjectProperty <Predicate <T >> filter = new SimpleObjectProperty <>();
27
+ private FilteredList <T > children ;
20
28
21
29
public RecursiveTreeItem (final T value , Callback <T , ObservableList <T >> func ) {
22
- this (value , func , null );
30
+ this (value , func , null , null );
23
31
}
24
32
25
- public RecursiveTreeItem (final T value , Callback <T , ObservableList <T >> func , Callback <T , BooleanProperty > expandedProperty ) {
26
- this (value , ( Node ) null , func , expandedProperty );
33
+ public RecursiveTreeItem (final T value , Callback <T , ObservableList <T >> func , Callback <T , BooleanProperty > expandedProperty , ObservableValue < Predicate < T >> filter ) {
34
+ this (value , null , func , expandedProperty , filter );
27
35
}
28
36
29
- public RecursiveTreeItem (final T value , Node graphic , Callback <T , ObservableList <T >> func , Callback <T , BooleanProperty > expandedProperty ) {
37
+ public RecursiveTreeItem (final T value , Callback <T , ObservableList <T >> func , ObservableValue <Predicate <T >> filter ) {
38
+ this (value , null , func , null , filter );
39
+ }
40
+
41
+ private RecursiveTreeItem (final T value , Node graphic , Callback <T , ObservableList <T >> func , Callback <T , BooleanProperty > expandedProperty , ObservableValue <Predicate <T >> filter ) {
30
42
super (value , graphic );
31
43
32
44
this .childrenFactory = func ;
33
45
this .expandedProperty = expandedProperty ;
46
+ if (filter != null ) {
47
+ this .filter .bind (filter );
48
+ }
34
49
35
50
if (value != null ) {
36
51
addChildrenListener (value );
@@ -40,7 +55,7 @@ public RecursiveTreeItem(final T value, Node graphic, Callback<T, ObservableList
40
55
valueProperty ().addListener ((obs , oldValue , newValue )->{
41
56
if (newValue != null ){
42
57
addChildrenListener (newValue );
43
- bindExpandedProperty (value , expandedProperty );
58
+ bindExpandedProperty (newValue , expandedProperty );
44
59
}
45
60
});
46
61
}
@@ -52,17 +67,14 @@ private void bindExpandedProperty(T value, Callback<T, BooleanProperty> expanded
52
67
}
53
68
54
69
private void addChildrenListener (T value ){
55
- final ObservableList <T > children = childrenFactory .call (value );
70
+ children = new FilteredList <>(childrenFactory .call (value ));
71
+ children .predicateProperty ().bind (Bindings .createObjectBinding (() -> this ::showNode , filter ));
56
72
57
- children .forEach (child -> RecursiveTreeItem . this . getChildren (). add ( new RecursiveTreeItem <>( child , getGraphic (), childrenFactory , expandedProperty )) );
73
+ children .forEach (this :: addAsChild );
58
74
59
75
children .addListener ((ListChangeListener <T >) change -> {
60
76
while (change .next ()){
61
77
62
- if (change .wasAdded ()){
63
- change .getAddedSubList ().forEach (t -> RecursiveTreeItem .this .getChildren ().add (new RecursiveTreeItem <>(t , getGraphic (), childrenFactory , expandedProperty )));
64
- }
65
-
66
78
if (change .wasRemoved ()){
67
79
change .getRemoved ().forEach (t ->{
68
80
final List <TreeItem <T >> itemsToRemove = RecursiveTreeItem .this .getChildren ().stream ().filter (treeItem -> treeItem .getValue ().equals (t )).collect (Collectors .toList ());
@@ -71,7 +83,28 @@ private void addChildrenListener(T value){
71
83
});
72
84
}
73
85
86
+ if (change .wasAdded ()) {
87
+ change .getAddedSubList ().forEach (this ::addAsChild );
88
+ }
74
89
}
75
90
});
76
91
}
92
+
93
+ private boolean addAsChild (T child ) {
94
+ return RecursiveTreeItem .this .getChildren ().add (new RecursiveTreeItem <>(child , getGraphic (), childrenFactory , expandedProperty , filter ));
95
+ }
96
+
97
+ private boolean showNode (T t ) {
98
+ if (filter .get () == null ) {
99
+ return true ;
100
+ }
101
+
102
+ if (filter .get ().test (t )) {
103
+ // Node is directly matched -> so show it
104
+ return true ;
105
+ }
106
+
107
+ // Are there children (or children of children...) that are matched? If yes we also need to show this node
108
+ return childrenFactory .call (t ).stream ().anyMatch (this ::showNode );
109
+ }
77
110
}
0 commit comments