1 /*
2
3 dsh-piccolo-venn Piccolo2D venn diagram nodes and supporting classes.
4 Copyright (c) 2009-2013 held jointly by the individual authors.
5
6 This library is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation; either version 3 of the License, or (at
9 your option) any later version.
10
11 This library is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; with out even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with this library; if not, write to the Free Software Foundation,
18 Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
19
20 > http://www.fsf.org/licensing/licenses/lgpl.html
21 > http://www.opensource.org/licenses/lgpl-license.php
22
23 */
24 package org.dishevelled.piccolo.venn;
25
26 import java.util.Arrays;
27 import java.util.List;
28 import java.util.Set;
29
30 import org.piccolo2d.nodes.PText;
31 import org.dishevelled.observable.event.SetChangeEvent;
32 import org.dishevelled.observable.event.SetChangeListener;
33 import org.dishevelled.venn.BinaryVennModel;
34 import org.dishevelled.venn.model.BinaryVennModelImpl;
35
36 /**
37 * Abstract binary venn diagram node.
38 *
39 * @param <E> value type
40 * @author Michael Heuer
41 * @version $Revision$ $Date$
42 */
43 public abstract class AbstractBinaryVennNode<E>
44 extends AbstractVennNode<E>
45 {
46 /** Binary venn model. */
47 private BinaryVennModel<E> model;
48
49 /** Label text for the first set. */
50 private String firstLabelText = DEFAULT_FIRST_LABEL_TEXT;
51
52 /** Label text for the second set. */
53 private String secondLabelText = DEFAULT_SECOND_LABEL_TEXT;
54
55 /** Label text for the first only view. */
56 private String firstOnlyLabelText = DEFAULT_FIRST_ONLY_LABEL_TEXT;
57
58 /** Label text for the second only view. */
59 private String secondOnlyLabelText = DEFAULT_SECOND_ONLY_LABEL_TEXT;
60
61 /** Label text for the intersection view. */
62 private String intersectionLabelText = DEFAULT_INTERSECTION_LABEL_TEXT;
63
64 /** Label text for the union view. */
65 private String unionLabelText = DEFAULT_UNION_LABEL_TEXT;
66
67 /** Label for the first set. */
68 private final PText firstLabel = new PText();
69
70 /** Label for the second set. */
71 private final PText secondLabel = new PText();
72
73 /** Label for the first only view. */
74 private final PText firstOnlyLabel = new PText();
75
76 /** Label for the second only view. */
77 private final PText secondOnlyLabel = new PText();
78
79 /** Label for the intersection view. */
80 private final PText intersectionLabel = new PText();
81
82 /** Label for the union view. */
83 private final PText unionLabel = new PText();
84
85 /** List of labels. */
86 private final List<PText> labels = Arrays.asList(new PText[] { firstLabel, secondLabel, firstOnlyLabel,
87 secondOnlyLabel, intersectionLabel, unionLabel });
88
89 /** Update labels and contents. */
90 private final SetChangeListener<E> update = new SetChangeListener<E>()
91 {
92 @Override
93 public void setChanged(final SetChangeEvent<E> event)
94 {
95 updateLabels();
96 updateContents();
97 }
98 };
99
100 /** Default label text for the first set, <code>"First set"</code>. */
101 public static final String DEFAULT_FIRST_LABEL_TEXT = "First set";
102
103 /** Default label text for the second set, <code>"Second set"</code>. */
104 public static final String DEFAULT_SECOND_LABEL_TEXT = "Second set";
105
106 /** Default label text for the first only view, <code>"First only"</code>. */
107 public static final String DEFAULT_FIRST_ONLY_LABEL_TEXT = "First only";
108
109 /** Default label text for the second only view, <code>"Second only"</code>. */
110 public static final String DEFAULT_SECOND_ONLY_LABEL_TEXT = "Second only";
111
112 /** Default label text for the intersection view, <code>"Intersection"</code>. */
113 public static final String DEFAULT_INTERSECTION_LABEL_TEXT = "Intersection";
114
115 /** Default label text for the union view, <code>"Union"</code>. */
116 public static final String DEFAULT_UNION_LABEL_TEXT = "Union";
117
118
119 /**
120 * Create a new empty abstract binary venn diagram node.
121 */
122 protected AbstractBinaryVennNode()
123 {
124 super();
125 model = new BinaryVennModelImpl<E>();
126
127 installListeners();
128 updateLabels();
129 }
130
131 /**
132 * Create a new abstract binary venn diagram node with the specified sets.
133 *
134 * @param firstLabelText label text for the first set
135 * @param first first set, must not be null
136 * @param secondLabelText label text for the second set
137 * @param second second set, must not be null
138 */
139 protected AbstractBinaryVennNode(final String firstLabelText, final Set<? extends E> first,
140 final String secondLabelText, final Set<? extends E> second)
141 {
142 super();
143 model = new BinaryVennModelImpl<E>(first, second);
144 this.firstLabelText = firstLabelText;
145 this.secondLabelText = secondLabelText;
146 this.firstOnlyLabelText = firstLabelText + " only";
147 this.secondOnlyLabelText = secondLabelText + " only";
148
149 installListeners();
150 updateLabels();
151 }
152
153 /**
154 * Create a new abstract binary venn diagram node with the specified model.
155 *
156 * @param model model for this abstract binary venn diagram node, must not be null
157 */
158 protected AbstractBinaryVennNode(final BinaryVennModel<E> model)
159 {
160 super();
161 if (model == null)
162 {
163 throw new IllegalArgumentException("model must not be null");
164 }
165 this.model = model;
166
167 installListeners();
168 updateLabels();
169 }
170
171
172 /**
173 * Install listeners.
174 */
175 private void installListeners()
176 {
177 model.first().addSetChangeListener(update);
178 model.second().addSetChangeListener(update);
179 }
180
181 /**
182 * Uninstall listeners.
183 */
184 private void uninstallListeners()
185 {
186 model.first().removeSetChangeListener(update);
187 model.second().removeSetChangeListener(update);
188 }
189
190 @Override
191 protected void updateLabels()
192 {
193 firstLabel.setText(buildLabel(firstLabelText, model.first().size()));
194 secondLabel.setText(buildLabel(secondLabelText, model.second().size()));
195 firstOnlyLabel.setText(buildLabel(firstOnlyLabelText, model.firstOnly().size()));
196 secondOnlyLabel.setText(buildLabel(secondOnlyLabelText, model.secondOnly().size()));
197 intersectionLabel.setText(buildLabel(intersectionLabelText, model.intersection().size()));
198 unionLabel.setText(buildLabel(unionLabelText, model.union().size()));
199
200 firstLabel.setVisible(getDisplayLabels());
201 secondLabel.setVisible(getDisplayLabels());
202 firstOnlyLabel.setVisible(getDisplayLabels());
203 secondOnlyLabel.setVisible(getDisplayLabels());
204 intersectionLabel.setVisible(getDisplayLabels());
205 unionLabel.setVisible(getDisplayLabels());
206 }
207
208 /**
209 * Update contents.
210 */
211 protected abstract void updateContents();
212
213
214 @Override
215 public final Iterable<PText> labels()
216 {
217 return labels;
218 }
219
220 /**
221 * Return the model for this binary venn label. The model will not be null.
222 *
223 * @return the model for this binary venn label
224 */
225 public final BinaryVennModel<E> getModel()
226 {
227 return model;
228 }
229
230 /**
231 * Set the model for this binary venn label to <code>model</code>.
232 *
233 * <p>This is a bound property.</p>
234 *
235 * @param model model for this binary venn label, must not be null
236 */
237 public final void setModel(final BinaryVennModel<E> model)
238 {
239 if (model == null)
240 {
241 throw new IllegalArgumentException("model must not be null");
242 }
243 BinaryVennModel<E> oldModel = this.model;
244 uninstallListeners();
245 this.model = model;
246 installListeners();
247 updateLabels();
248 firePropertyChange(-1, "model", oldModel, this.model);
249 }
250
251 /**
252 * Return the label text for the first set. Defaults to {@link #DEFAULT_FIRST_LABEL_TEXT}.
253 *
254 * @return the label text for the first set
255 */
256 public final String getFirstLabelText()
257 {
258 return firstLabelText;
259 }
260
261 /**
262 * Set the label text for the first set to <code>firstLabelText</code>.
263 *
264 * <p>This is a bound property.</p>
265 *
266 * @param firstLabelText label text for the first set
267 */
268 public final void setFirstLabelText(final String firstLabelText)
269 {
270 String oldFirstLabelText = this.firstLabelText;
271 this.firstLabelText = firstLabelText;
272 firstLabel.setText(buildLabel(this.firstLabelText, model.first().size()));
273 firePropertyChange(-1, "firstLabelText", this.firstLabelText, oldFirstLabelText);
274 }
275
276 /**
277 * Return the label text for the second set. Defaults to {@link #DEFAULT_SECOND_LABEL_TEXT}.
278 *
279 * @return the label text for the second set
280 */
281 public final String getSecondLabelText()
282 {
283 return secondLabelText;
284 }
285
286 /**
287 * Set the label text for the second set to <code>secondLabelText</code>.
288 *
289 * <p>This is a bound property.</p>
290 *
291 * @param secondLabelText label text for the second set
292 */
293 public final void setSecondLabelText(final String secondLabelText)
294 {
295 String oldSecondLabelText = this.secondLabelText;
296 this.secondLabelText = secondLabelText;
297 secondLabel.setText(buildLabel(this.secondLabelText, model.second().size()));
298 firePropertyChange(-1, "secondLabelText", this.secondLabelText, oldSecondLabelText);
299 }
300
301 /**
302 * Return the label text for the first only view. Defaults to {@link #DEFAULT_FIRST_ONLY_LABEL_TEXT}.
303 *
304 * @return the label text for the first only view
305 */
306 public final String getFirstOnlyLabelText()
307 {
308 return firstOnlyLabelText;
309 }
310
311 /**
312 * Set the label text for the first only view to <code>firstOnlyLabelText</code>.
313 *
314 * <p>This is a bound property.</p>
315 *
316 * @param firstOnlyLabelText label text for the first only view
317 */
318 public final void setFirstOnlyLabelText(final String firstOnlyLabelText)
319 {
320 String oldFirstOnlyLabelText = this.firstOnlyLabelText;
321 this.firstOnlyLabelText = firstOnlyLabelText;
322 firstOnlyLabel.setText(buildLabel(this.firstOnlyLabelText, model.firstOnly().size()));
323 firePropertyChange(-1, "firstOnlyLabelText", this.firstOnlyLabelText, oldFirstOnlyLabelText);
324 }
325
326 /**
327 * Return the label text for the second only view. Defaults to {@link #DEFAULT_SECOND_ONLY_LABEL_TEXT}.
328 *
329 * @return the label text for the second only view
330 */
331 public final String getSecondOnlyLabelText()
332 {
333 return secondOnlyLabelText;
334 }
335
336 /**
337 * Set the label text for the second only view to <code>secondOnlyLabelText</code>.
338 *
339 * <p>This is a bound property.</p>
340 *
341 * @param secondOnlyLabelText label text for the second only view
342 */
343 public final void setSecondOnlyLabelText(final String secondOnlyLabelText)
344 {
345 String oldSecondOnlyLabelText = this.secondOnlyLabelText;
346 this.secondOnlyLabelText = secondOnlyLabelText;
347 secondOnlyLabel.setText(buildLabel(this.secondOnlyLabelText, model.secondOnly().size()));
348 firePropertyChange(-1, "secondOnlyLabelText", this.secondOnlyLabelText, oldSecondOnlyLabelText);
349 }
350
351 /**
352 * Return the label text for the intersection view. Defaults to {@link #DEFAULT_INTERSECTION_LABEL_TEXT}.
353 *
354 * @return the label text for the intersection view
355 */
356 public final String getIntersectionLabelText()
357 {
358 return intersectionLabelText;
359 }
360
361 /**
362 * Set the label text for the intersection view to <code>intersectionLabelText</code>.
363 *
364 * <p>This is a bound property.</p>
365 *
366 * @param intersectionLabelText label text for the intersection view
367 */
368 public final void setIntersectionLabelText(final String intersectionLabelText)
369 {
370 String oldIntersectionLabelText = this.intersectionLabelText;
371 this.intersectionLabelText = intersectionLabelText;
372 intersectionLabel.setText(buildLabel(this.intersectionLabelText, model.intersection().size()));
373 firePropertyChange(-1, "intersectionLabelText", this.intersectionLabelText, oldIntersectionLabelText);
374 }
375
376 /**
377 * Return the label text for the union view. Defaults to {@link #DEFAULT_UNION_LABEL_TEXT}.
378 *
379 * @return the label text for the union view
380 */
381 public final String getUnionLabelText()
382 {
383 return unionLabelText;
384 }
385
386 /**
387 * Set the label text for the union view to <code>unionLabelText</code>.
388 *
389 * <p>This is a bound property.</p>
390 *
391 * @param unionLabelText label text for the union view
392 */
393 public final void setUnionLabelText(final String unionLabelText)
394 {
395 String oldUnionLabelText = this.unionLabelText;
396 this.unionLabelText = unionLabelText;
397 unionLabel.setText(buildLabel(this.unionLabelText, model.union().size()));
398 firePropertyChange(-1, "unionLabelText", this.unionLabelText, oldUnionLabelText);
399 }
400
401 /**
402 * Return the label for the first set. The text for the returned PText
403 * should not be changed, as the text is synchronized to the binary
404 * venn model backing this venn diagram. Use methods
405 * {@link #setFirstLabelText(String)} and {@link #setDisplaySizes(boolean)}
406 * to set the label text and whether to display sizes respectively.
407 *
408 * @return the label for the first set
409 */
410 public final PText getFirstLabel()
411 {
412 return firstLabel;
413 }
414
415 /**
416 * Return the label for the second set. The text for the returned PText
417 * should not be changed, as the text is synchronized to the binary
418 * venn model backing this venn diagram. Use methods
419 * {@link #setSecondLabelText(String)} and {@link #setDisplaySizes(boolean)}
420 * to set the label text and whether to display sizes respectively.
421 *
422 * @return the label for the second set
423 */
424 public final PText getSecondLabel()
425 {
426 return secondLabel;
427 }
428
429 /**
430 * Return the label for the first only view. The text for the returned PText
431 * should not be changed, as the text is synchronized to the binary
432 * venn model backing this venn diagram. Use methods
433 * {@link #setFirstOnlyLabelText(String)} and {@link #setDisplaySizes(boolean)}
434 * to set the label text and whether to display sizes respectively.
435 *
436 * @return the label for the first only view
437 */
438 public final PText getFirstOnlyLabel()
439 {
440 return firstOnlyLabel;
441 }
442
443 /**
444 * Return the label for the second only view. The text for the returned PText
445 * should not be changed, as the text is synchronized to the binary
446 * venn model backing this venn diagram. Use methods
447 * {@link #setSecondOnlyLabelText(String)} and {@link #setDisplaySizes(boolean)}
448 * to set the label text and whether to display sizes respectively.
449 *
450 * @return the label for the second only view
451 */
452 public final PText getSecondOnlyLabel()
453 {
454 return secondOnlyLabel;
455 }
456
457 /**
458 * Return the label for the intersection view. The text for the returned PText
459 * should not be changed, as the text is synchronized to the binary
460 * venn model backing this venn diagram. Use methods
461 * {@link #setIntersectionLabelText(String)} and {@link #setDisplaySizes(boolean)}
462 * to set the label text and whether to display sizes respectively.
463 *
464 * @return the label for the intersection view
465 */
466 public final PText getIntersectionLabel()
467 {
468 return intersectionLabel;
469 }
470
471 /**
472 * Return the label for the union view. The text for the returned PText
473 * should not be changed, as the text is synchronized to the binary
474 * venn model backing this venn diagram. Use methods
475 * {@link #setUnionLabelText(String)} and {@link #setDisplaySizes(boolean)}
476 * to set the label text and whether to display sizes respectively.
477 *
478 * @return the label for the union view
479 */
480 public final PText getUnionLabel()
481 {
482 return unionLabel;
483 }
484 }