View Javadoc

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 }