15
15
import org .baderlab .csplugins .enrichmentmap .view .creation .genemania .StringDialogParameters ;
16
16
import org .baderlab .csplugins .enrichmentmap .view .heatmap .HeatMapParams .Distance ;
17
17
import org .cytoscape .property .CyProperty ;
18
+ import org .cytoscape .property .PropertyUpdatedEvent ;
19
+ import org .cytoscape .property .PropertyUpdatedListener ;
18
20
19
21
import com .google .inject .Inject ;
20
22
import com .google .inject .Singleton ;
21
23
22
24
/**
23
25
* Manages the CyProperties for EnrichmentMap.
26
+ * The CyProperty API is very limited, and it doesn't fire events when you programmatically
27
+ * update a property. This manager provides a nicer interface for managing properties and it
28
+ * actually fires events when you expect it to.
24
29
*/
25
30
@ Singleton
26
- public class PropertyManager {
31
+ public class PropertyManager implements PropertyUpdatedListener {
27
32
28
- @ FunctionalInterface
29
- public interface PropertyListener <T > {
30
- void propertyChanged (Property <T > prop , T value );
31
- }
32
-
33
- private final Map <Property <?>,List <PropertyListener <?>>> listeners = new HashMap <>();
33
+ @ Inject private CyProperty <Properties > emCyProps ;
34
34
35
+ // To add a new property just add a declaration below, reflection is used to read these static fields...
35
36
36
37
public static final Property <Boolean > HEATMAP_AUTOFOCUS = Property .of ("heatmapAutofocus" , false );
37
38
public static final Property <Boolean > HEATMAP_DATASET_SYNC = Property .of ("heatmapDatasetSync" , true );
@@ -55,37 +56,57 @@ public interface PropertyListener<T> {
55
56
public static final Property <String > GENEMANIA_COLUMN_ANN_NAME = Property .of ("genemania.column.annname" , GenemaniaDialogParameters .ANNOTATION_NAME_COLUMN_DEF );
56
57
57
58
59
+ @ FunctionalInterface
60
+ public interface PropertyListener <T > {
61
+ void propertyChanged (Property <T > prop , T value );
62
+ }
63
+
64
+ private final Map <Property <?>,List <PropertyListener <?>>> listeners = new HashMap <>();
58
65
59
- @ Inject private CyProperty <Properties > cyProps ;
60
66
61
67
@ AfterInjection
62
68
private void initializeProperties () {
63
69
getAllProperties ()
64
70
.stream ()
65
- .filter (prop -> !cyProps .getProperties ().containsKey (prop .key ))
71
+ .filter (prop -> !emCyProps .getProperties ().containsKey (prop .key ))
66
72
.forEach (this ::setDefault );
67
73
}
68
74
75
+
76
+ @ SuppressWarnings ({ "unchecked" , "rawtypes" })
77
+ @ Override
78
+ public void handleEvent (PropertyUpdatedEvent e ) {
79
+ // This only fires when the user updates a property using the Edit > Preferences > Properties dialog.
80
+ // The API for this doesn't give enough information, we don't know which property actually changed,
81
+ // so need to update all of them.
82
+ if (e .getSource () == emCyProps ) {
83
+ for (Property p : getAllProperties ()) {
84
+ fire (p , getValue (p ));
85
+ }
86
+ }
87
+ }
88
+
69
89
public <T > void addListener (Property <T > property , PropertyListener <T > listener ) {
70
90
listeners .computeIfAbsent (property , k -> new ArrayList <>()).add (listener );
71
91
}
72
92
93
+ public <T > void removeListener (Property <T > property , PropertyListener <T > listener ) {
94
+ listeners .get (property ).remove (listener );
95
+ }
96
+
73
97
public <T > void setValue (Property <T > property , T value ) {
74
- cyProps .getProperties ().setProperty (property .key , String .valueOf (value ));
75
-
76
- for (PropertyListener <?> listener : listeners .getOrDefault (property , Collections .emptyList ())) {
77
- ((PropertyListener <T >)listener ).propertyChanged (property , value );
78
- }
98
+ emCyProps .getProperties ().setProperty (property .key , String .valueOf (value ));
99
+ fire (property , value );
79
100
}
80
101
81
102
public <T > void setDefault (Property <T > property ) {
82
103
setValue (property , property .def );
83
104
}
84
105
85
106
public <T > T getValue (Property <T > property ) {
86
- if (cyProps == null ) // happens in JUnits
107
+ if (emCyProps == null ) // happens in JUnits
87
108
return property .def ;
88
- Properties properties = cyProps .getProperties ();
109
+ Properties properties = emCyProps .getProperties ();
89
110
if (properties == null )
90
111
return property .def ;
91
112
String string = properties .getProperty (property .key );
@@ -119,6 +140,13 @@ public static List<Property<?>> getAllProperties() {
119
140
}
120
141
121
142
143
+ @ SuppressWarnings ("unchecked" )
144
+ private <T > void fire (Property <T > property , T value ) {
145
+ for (PropertyListener <?> listener : listeners .getOrDefault (property , Collections .emptyList ())) {
146
+ ((PropertyListener <T >)listener ).propertyChanged (property , value );
147
+ }
148
+ }
149
+
122
150
public static class Property <T > {
123
151
private final String key ;
124
152
public final T def ;
@@ -143,4 +171,5 @@ public static Property<Double> of(String key, double defaultValue) {
143
171
return new Property <>(key , defaultValue , Double ::valueOf );
144
172
}
145
173
}
174
+
146
175
}
0 commit comments