KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > info > monitorenter > gui > chart > traces > ATrace2D


1 /*
2  *
3  * ATrace2D.java jchart2d
4  * Copyright (C) Achim Westermann, created on 22.05.2005, 19:28:36
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19  *
20  * If you modify or optimize the code in a useful way please let me know.
21  * Achim.Westermann@gmx.de
22  *
23  */

24 package info.monitorenter.gui.chart.traces;
25
26 import info.monitorenter.gui.chart.Chart2D;
27 import info.monitorenter.gui.chart.ITrace2D;
28 import info.monitorenter.gui.chart.ITracePainter;
29 import info.monitorenter.gui.chart.TracePoint2D;
30 import info.monitorenter.gui.chart.traces.painters.TracePainterPolyline;
31 import info.monitorenter.util.StringUtil;
32
33 import java.awt.BasicStroke JavaDoc;
34 import java.awt.Color JavaDoc;
35 import java.awt.Stroke JavaDoc;
36 import java.beans.PropertyChangeListener JavaDoc;
37 import java.beans.PropertyChangeSupport JavaDoc;
38 import java.util.Iterator JavaDoc;
39 import java.util.LinkedList JavaDoc;
40 import java.util.List JavaDoc;
41 import java.util.Set JavaDoc;
42 import java.util.TreeSet JavaDoc;
43
44 import javax.swing.event.SwingPropertyChangeSupport JavaDoc;
45
46 /**
47  * <p>
48  * The abstract basic implementation of
49  * <code>{@link info.monitorenter.gui.chart.ITrace2D}</code> that provides the
50  * major amount of aspects needed in order to work correctly together with
51  * <code>{@link info.monitorenter.gui.chart.Chart2D}</code>.
52  * </p>
53  * <p>
54  * Caching of minimum and maximum bounds, property change support, the
55  * complexity of z-Index handling (incorporates calls to internals of
56  * <code>Chart2D</code>, default naming, bound management and event handling
57  * are covered here.
58  * </p>
59  * <h3>Property Change events</h3>
60  * <p>
61  * <table border="0">
62  * <tr>
63  * <th><code>getPropertyName()</code></th>
64  * <th><code>getSource()</code></th>
65  * <th><code>getOldValue()</code></th>
66  * <th><code>getNewValue()</code></th>
67  * </tr>
68  * <tr>
69  * <td><code>{@link info.monitorenter.gui.chart.ITrace2D#PROPERTY_ZINDEX}</code></td>
70  * <td><code>{@link ITrace2D}</code> that changed</td>
71  * <td><code>{@link java.lang.Number}</code>, the old value</td>
72  * <td><code>{@link java.lang.Number}</code>, the new value</td>
73  * </tr>
74  * <tr>
75  * <td><code>{@link info.monitorenter.gui.chart.ITrace2D#PROPERTY_MAX_X}</code></td>
76  * <td><code>{@link ITrace2D}</code> that changed</td>
77  * <td><code>{@link java.lang.Double}</code>, the old value</td>
78  * <td><code>{@link java.lang.Double}</code>, the new value</td>
79  * </tr>
80  * <tr>
81  * <td><code>{@link info.monitorenter.gui.chart.ITrace2D#PROPERTY_MIN_X}</code></td>
82  * <td><code>{@link ITrace2D}</code> that changed</td>
83  * <td><code>{@link java.lang.Double}</code>, the old value</td>
84  * <td><code>{@link java.lang.Double}</code>, the new value</td>
85  * </tr>
86  * <tr>
87  * <td><code>{@link info.monitorenter.gui.chart.ITrace2D#PROPERTY_MAX_Y}</code></td>
88  * <td><code>{@link ITrace2D}</code> that changed</td>
89  * <td><code>{@link java.lang.Double}</code>, the old value</td>
90  * <td><code>{@link java.lang.Double}</code>, the new value</td>
91  * </tr>
92  * <tr>
93  * <td><code>{@link info.monitorenter.gui.chart.ITrace2D#PROPERTY_MIN_Y}</code></td>
94  * <td><code>{@link ITrace2D}</code> that changed</td>
95  * <td><code>{@link java.lang.Double}</code>, the old value</td>
96  * <td><code>{@link java.lang.Double}</code>, the new value</td>
97  * </tr>
98  * <tr>
99  * <td><code>{@link info.monitorenter.gui.chart.ITrace2D#PROPERTY_TRACEPOINT}</code></td>
100  * <td><code>{@link ITrace2D}</code> that changed</td>
101  * <td><code>{@link info.monitorenter.gui.chart.TracePoint2D}</code>, the
102  * instance that was removed</td>
103  * <td><code>null</code>, indication that an instance was removed</td>
104  * </tr>
105  * <tr>
106  * <td><code>{@link info.monitorenter.gui.chart.ITrace2D#PROPERTY_TRACEPOINT}</code></td>
107  * <td><code>{@link ITrace2D}</code> that changed</td>
108  * <td><code>null</code>, indication that a value was added</td>
109  * <td><code>{@link info.monitorenter.gui.chart.TracePoint2D}</code>, the
110  * new instance that was added, identifying that an instance was removed</td>
111  * </tr>
112  * <tr>
113  * <td><code>{@link info.monitorenter.gui.chart.ITrace2D#PROPERTY_VISIBLE}</code></td>
114  * <td><code>{@link ITrace2D}</code> that changed</td>
115  * <td><code>{@link java.lang.Boolean}</code>, the old state.</td>
116  * <td><code>{@link java.lang.Boolean}</code>, the new state.</td>
117  * </tr>
118  * <tr>
119  * <td><code>{@link info.monitorenter.gui.chart.ITrace2D#PROPERTY_PAINTERS}</code></td>
120  * <td><code>{@link ITrace2D}</code> that changed</td>
121  * <td><code>null</code>, indicating that a painter was added.</td>
122  * <td><code>{@link info.monitorenter.gui.chart.ITracePainter}</code>, the new painter.</td>
123  * </tr>
124  * <tr>
125  * <td><code>{@link info.monitorenter.gui.chart.ITrace2D#PROPERTY_PAINTERS}</code></td>
126  * <td><code>{@link ITrace2D}</code> that changed</td>
127  * <td><code>{@link info.monitorenter.gui.chart.ITracePainter}</code>, the old painter.</td>
128  * <td><code>null</code>, indicating that a painter was removed.</td>
129  * </tr>
130  * <tr>
131  * <td><code>{@link info.monitorenter.gui.chart.ITrace2D#PROPERTY_STROKE}</code></td>
132  * <td><code>{@link ITrace2D}</code> that changed</td>
133  * <td><code>{@link java.awt.Stroke}</code>, the old stroke.</td>
134  * <td><code>{@link java.awt.Stroke}</code>, the new stroke.</td>
135  * </tr>
136  * <tr>
137  * <td><code>{@link info.monitorenter.gui.chart.ITrace2D#PROPERTY_COLOR}</code></td>
138  * <td><code>{@link ITrace2D}</code> that changed</td>
139  * <td><code>{@link java.awt.Color}</code>, the new color.</td>
140  * <td><code>{@link java.awt.Color}</code>, the new color.</td>
141  * </tr>
142  *
143  * </table>
144  * </p>
145  *
146  * @author <a HREF="mailto:Achim.Westermann@gmx.de">Achim Westermann </a>
147  *
148  * @version $Revision: 1.7 $
149  */

150 public abstract class ATrace2D implements ITrace2D {
151
152   /**
153    * Instance counter for read-access in subclasses.
154    */

155   private static int instanceCount = 0;
156
157   /**
158    * Returns the instanceCount for all <code>ATrace2D</code> subclasses.
159    *
160    * @return Returns the instanceCount for all <code>ATrace2D</code>
161    * subclasses.
162    */

163   public static int getInstanceCount() {
164     return ATrace2D.instanceCount;
165   }
166
167   /**
168    * {@link javax.swing.event.ChangeListener} instances (mainly
169    * <code>Char2D</code> instances that are interested in changes of internal
170    * <code>ITracePoint2D</code> instances.
171    */

172   private List JavaDoc m_changeListeners = new LinkedList JavaDoc();
173
174   /**
175    * The color property.
176    */

177   private Color JavaDoc m_color = Color.black;
178
179   /**
180    * Needed for special treatment of cached values in case of empty state (no
181    * points).
182    */

183   private boolean m_firsttime = true;
184
185   /**
186    * Cached maximum x value for performance improvement.
187    */

188   protected double m_maxX;
189
190   /**
191    * Cached maximum y value for performance improvement.
192    */

193   protected double m_maxY;
194
195   /**
196    * Cached minimum x value for performance improvement.
197    */

198   protected double m_minX;
199
200   /**
201    * Cached minimum y value for performance improvement.
202    */

203   protected double m_minY;
204
205   /**
206    * The name property.
207    */

208   protected String JavaDoc m_name = "";
209
210   /**
211    * The physical unit property.
212    */

213   protected String JavaDoc m_physicalUnits = "";
214
215   /**
216    * The instance that add support for firing <code>PropertyChangeEvents</code>
217    * and maintaining <code>PropertyChangeListeners</code>.
218    *
219    * {@link PropertyChangeListener} instances.
220    */

221
222   protected PropertyChangeSupport JavaDoc m_propertyChangeSupport = new SwingPropertyChangeSupport JavaDoc(this);
223
224   /**
225    * The <code>Chart2D</code> this trace is added to. Needed for
226    * synchronization.
227    */

228   protected Object JavaDoc m_renderer = new Object JavaDoc();
229
230   /**
231    * The stroke property.
232    */

233   private Stroke JavaDoc m_stroke = new BasicStroke JavaDoc(1f);
234
235   /**
236    * The visible property.
237    */

238   private boolean m_visible = true;
239
240   /**
241    * The zIndex property.
242    */

243   private Integer JavaDoc m_zIndex = new Integer JavaDoc(ITrace2D.ZINDEX_MAX);
244
245   /**
246    * Default contstructor.
247    * <p>
248    *
249    */

250   public ATrace2D() {
251     super();
252     ATrace2D.instanceCount++;
253     this.m_tracePainters = new TreeSet JavaDoc();
254     this.m_tracePainters.add(new TracePainterPolyline());
255   }
256
257   /**
258    * <p>
259    * Add a point to this trace.
260    * </p>
261    * <p>
262    * Prefer calling <code>{@link #addPoint(TracePoint2D)}</code> for better
263    * performance (avoid one invokevirtual for delegation).
264    * </p>
265    *
266    * @param x
267    * the x coordinate of the new point.
268    * @param y
269    * the y coordinate of the new point.
270    *
271    * @return true if the operation was successful, false else.
272    */

273   public final boolean addPoint(final double x, final double y) {
274     TracePoint2D p = new TracePoint2D(x, y);
275     return this.addPoint(p);
276   }
277
278   /**
279    * <p>
280    * Add the given point to this <code>ITrace2D</code>.
281    * </p>
282    * <p>
283    * This implementation performs caching of minimum and maximum values for x
284    * and y and the delegates to {@link #addPointInternal(TracePoint2D)} that has
285    * to perform the "real" add operation.
286    * </p>
287    * <p>
288    * Property change events are fired as described in method
289    * <code>{@link #firePointAdded(TracePoint2D)}</code>.
290    * </p>
291    *
292    * @see #firePointChanged(TracePoint2D, boolean)
293    * @param p
294    * the <code>TracePoint2D</code> to add.
295    * @return true if the operation was successful, false else.
296    *
297    */

298   public final boolean addPoint(final TracePoint2D p) {
299     if (Chart2D.DEBUG_THREADING) {
300       System.out.println("addPoint, 0 locks");
301     }
302     synchronized (this.m_renderer) {
303       if (Chart2D.DEBUG_THREADING) {
304         System.out.println("addPoint, 1 lock");
305       }
306       synchronized (this) {
307         if (Chart2D.DEBUG_THREADING) {
308           System.out.println("addPoint, 2 locks");
309         }
310         boolean accepted = this.addPointInternal(p);
311         if (this.m_firsttime) {
312           this.m_maxX = p.getX();
313           this.m_minX = this.m_maxX;
314           this.m_maxY = p.getY();
315           this.m_minY = this.m_maxY;
316           this.firePropertyChange(PROPERTY_MAX_X, this, new Double JavaDoc(this.m_maxX));
317           this.firePropertyChange(PROPERTY_MIN_X, this, new Double JavaDoc(this.m_minX));
318           this.firePropertyChange(PROPERTY_MAX_Y, this, new Double JavaDoc(this.m_maxY));
319           this.firePropertyChange(PROPERTY_MIN_Y, this, new Double JavaDoc(this.m_minY));
320
321           this.m_firsttime = false;
322         }
323         if (accepted) {
324           this.firePointAdded(p);
325           p.setListener(this);
326         }
327         // else{
328
// System.err.println("Not accepted!");
329
// }
330
return accepted;
331       }
332     }
333   }
334
335   /**
336    * <p>
337    * Override this template method for the custom add operation that depends on
338    * the policies of the implementation.
339    * </p>
340    * <p>
341    * No property change events have to be fired by default. If this method
342    * returns <code>true</code> the outer logic of the calling method
343    * <code>{@link #addPoint(TracePoint2D)}</code> will perform bound checks
344    * for the new point and fire property changes as described in method
345    * <code>{@link #firePointChanged(TracePoint2D, boolean)}</code>.
346    * </p>
347    * <p>
348    * In special cases - when additional modifications to the internal set of
349    * points take place (e.g. a further point gets removed) this method should
350    * return false (regardless wether the new point was accepted or not) and
351    * perform bound checks and fire the property changes as mentioned above
352    * "manually".
353    * </p>
354    *
355    * @param p
356    * the point to add.
357    * @return true if the given point was accepted or false if not.
358    *
359    */

360   protected abstract boolean addPointInternal(TracePoint2D p);
361
362   /**
363    * @see info.monitorenter.gui.chart.ITrace2D#addPropertyChangeListener(java.lang.String,
364    * java.beans.PropertyChangeListener)
365    */

366   public final void addPropertyChangeListener(final String JavaDoc propertyName,
367       final PropertyChangeListener JavaDoc listener) {
368     this.m_propertyChangeSupport.addPropertyChangeListener(propertyName, listener);
369   }
370
371   /**
372    * @see info.monitorenter.gui.chart.ITrace2D#addTracePainter(info.monitorenter.gui.chart.ITracePainter)
373    */

374   public boolean addTracePainter(final ITracePainter painter) {
375     boolean result = this.m_tracePainters.add(painter);
376     if (result) {
377       this.firePropertyChange(PROPERTY_PAINTERS, null, painter);
378     }
379     return result;
380   }
381
382   /**
383    * Decreases internal instance count by one.
384    * <p>
385    *
386    * @throws Throwable
387    * if sth. goes wrong.
388    */

389   public void finalize() throws Throwable JavaDoc {
390     super.finalize();
391     ATrace2D.instanceCount--;
392   }
393
394   /**
395    * <p>
396    * Fire property change events related to an added point.
397    * </p>
398    * <p>
399    * A property change event for property
400    * <code>{@link ITrace2D#PROPERTY_TRACEPOINT}</code> with null as the old
401    * value and the new point as the new value is fired. This allows e.g.
402    * rescaling of those instances (instead of having to rescale a whole trace).
403    * </p>
404    * <p>
405    * Additionally before this property change, property change events for bounds
406    * are fired as described in method
407    * <code>{@link #firePointChanged(TracePoint2D, boolean)}</code>.
408    * </p>
409    *
410    * @param added
411    * the point that was added.
412    */

413   protected void firePointAdded(final TracePoint2D added) {
414     this.firePointChanged(added, true);
415     this.firePropertyChange(PROPERTY_TRACEPOINT, null, added);
416   }
417
418   /**
419    * <p>
420    * Method triggered by
421    * <code>{@link TracePoint2D#setLocation(double, double)}</code>,
422    * <code>{@link #addPoint(TracePoint2D)}</code> or
423    * <code>{@link #removePoint(TracePoint2D)}</code>.
424    * </p>
425    * <p>
426    * Bound checks are performed and property change events for the properties
427    * <code>{@link ITrace2D#PROPERTY_MAX_X}</code>,
428    * <code>{@link ITrace2D#PROPERTY_MIN_X}</code>,
429    * <code>{@link ITrace2D#PROPERTY_MAX_Y}</code> and
430    * <code>{@link ITrace2D#PROPERTY_MIN_Y}</code> are fired if the add bounds
431    * have changed due to the modification of the point.
432    * </p>
433    *
434    * @param changed
435    * the point that has been changed which may be a newly added point
436    * (from <code>{@link #addPoint(TracePoint2D)}</code>, a removed
437    * one or a modified one.
438    * @param added
439    * if true the points values dominate old bounds, if false the bounds
440    * are rechecked against the removed points values.
441    */

442   public void firePointChanged(final TracePoint2D changed, final boolean added) {
443     double tmpx = changed.getX();
444     double tmpy = changed.getY();
445     if (added) {
446       if (tmpx > this.m_maxX) {
447         this.m_maxX = tmpx;
448         this.firePropertyChange(PROPERTY_MAX_X, null, new Double JavaDoc(this.m_maxX));
449       } else if (tmpx < this.m_minX) {
450         this.m_minX = tmpx;
451         this.firePropertyChange(PROPERTY_MIN_X, null, new Double JavaDoc(this.m_minX));
452       }
453       if (tmpy > this.m_maxY) {
454         this.m_maxY = tmpy;
455         this.firePropertyChange(PROPERTY_MAX_Y, null, new Double JavaDoc(this.m_maxY));
456       } else if (tmpy < this.m_minY) {
457         this.m_minY = tmpy;
458         this.firePropertyChange(PROPERTY_MIN_Y, null, new Double JavaDoc(this.m_minY));
459       }
460     } else {
461       if (tmpx > this.m_maxX) {
462         tmpx = this.m_maxX;
463         this.maxXSearch();
464         this.firePropertyChange(PROPERTY_MAX_X, new Double JavaDoc(tmpx), new Double JavaDoc(this.m_maxX));
465
466       } else if (tmpx < this.m_minX) {
467         tmpx = this.m_minX;
468         this.minXSearch();
469         this.firePropertyChange(PROPERTY_MIN_X, new Double JavaDoc(tmpx), new Double JavaDoc(this.m_minX));
470       }
471       if (tmpy > this.m_maxY) {
472         tmpy = this.m_maxY;
473         this.maxYSearch();
474         this.firePropertyChange(PROPERTY_MAX_Y, new Double JavaDoc(tmpy), new Double JavaDoc(this.m_maxY));
475       } else if (tmpy < this.m_minY) {
476         tmpy = this.m_minY;
477         this.minYSearch();
478         this.firePropertyChange(PROPERTY_MIN_Y, new Double JavaDoc(tmpy), new Double JavaDoc(this.m_minY));
479       }
480       if (this.getSize() == 0) {
481         this.m_firsttime = true;
482       }
483     }
484   }
485
486   /**
487    * <p>
488    * Fire property change events related to a removed point.
489    * </p>
490    * <p>
491    * A property change event for property
492    * <code>{@link ITrace2D#PROPERTY_TRACEPOINT}</code> with a point as the old
493    * value and null as the new value is fired. This allows e.g. rescaling of
494    * those instances (instead of having to rescale a whole trace).
495    * </p>
496    * <p>
497    * Additionally before this property change, property change events for bounds
498    * are fired as described in method
499    * <code>{@link #firePointChanged(TracePoint2D, boolean)}</code>.
500    * </p>
501    *
502    * @param removed
503    * the point that was removed.
504    */

505   protected void firePointRemoved(final TracePoint2D removed) {
506     this.firePointChanged(removed, false);
507     this.firePropertyChange(PROPERTY_TRACEPOINT, removed, null);
508   }
509
510   /**
511    * <p>
512    * Fires a property change event to the registered listeners.
513    * </p>
514    *
515    * @param property
516    * one of the <code>PROPERTY_XXX</code> constants defined in
517    * <code>{@link ITrace2D}</code>.
518    * @param oldvalue
519    * the old value of the property.
520    * @param newvalue
521    * the new value of the property.
522    *
523    */

524   protected final void firePropertyChange(final String JavaDoc property, final Object JavaDoc oldvalue,
525       final Object JavaDoc newvalue) {
526     if (Chart2D.DEBUG_THREADING) {
527       System.out.println("trace.firePropertyChange (" + property + "), 0 locks");
528     }
529     if (property.equals(PROPERTY_MAX_X) || property.equals(PROPERTY_MAX_Y)
530         || property.equals(PROPERTY_MIN_X) || property.equals(PROPERTY_MIN_Y)
531         || property.equals(PROPERTY_TRACEPOINT)) {
532       if (!Thread.holdsLock(this.m_renderer)) {
533         throw new RuntimeException JavaDoc("Acquire a look on the corresponding chart first!");
534       }
535     }
536
537     this.m_propertyChangeSupport.firePropertyChange(property, oldvalue, newvalue);
538   }
539
540   /**
541    * Returns the change listeners of this instance.
542    * <p>
543    *
544    * @return the change listeners of this instance.
545    */

546   public List JavaDoc getChangeListeners() {
547     return new LinkedList JavaDoc(this.m_changeListeners);
548   }
549
550   /**
551    * <p>
552    * Get the <code>Color</code> this trace will be painted with.
553    * </p>
554    *
555    * @return the <code>Color</code> of this instance
556    */

557   public final Color JavaDoc getColor() {
558     return this.m_color;
559   }
560
561   /**
562    * @see info.monitorenter.util.collections.IComparableProperty#getComparableProperty()
563    */

564   public Number JavaDoc getComparableProperty() {
565     return this.m_zIndex;
566   }
567
568   /**
569    * Returns a label for this trace.
570    * <p>
571    *
572    * The label is constructed of
573    * <ul>
574    * <li>The name of this trace ({@link #getName()}).</li>
575    * <li>The phyical unit of this trace ({@link #getPhysicalUnits()}). </li>
576    * </ul>
577    * <p>
578    *
579    * @return a label for this trace.
580    *
581    * @see ITrace2D#getLable()
582    *
583    * @see #getName()
584    *
585    * @see #getPhysicalUnits()
586    */

587   public final String JavaDoc getLable() {
588     String JavaDoc name = this.getName();
589     String JavaDoc physunit = this.getPhysicalUnits();
590     if ((name != "") && (physunit != "")) {
591       name = new StringBuffer JavaDoc(name).append(" ").append(physunit).toString();
592     } else if (physunit != "") {
593       name = new StringBuffer JavaDoc("unnamed").append(" ").append(physunit).toString();
594     }
595     return name.toString();
596   }
597
598   /**
599    * Returns the original maximum x- value ignoring the offsetX.
600    * <p>
601    *
602    * @return the original maximum x- value ignoring the offsetX.
603    */

604   public final double getMaxX() {
605     return this.m_maxX;
606   }
607
608   /**
609    * Returns the original maximum y- value ignoring the offsetY.
610    * <p>
611    *
612    * @return the original maximum y- value ignoring the offsetY.
613    */

614
615   public final double getMaxY() {
616     return this.m_maxY;
617   }
618
619   /**
620    * Returns the original minimum x- value ignoring the offsetX.
621    * <p>
622    *
623    * @return the original minimum x- value ignoring the offsetX.
624    */

625   public final double getMinX() {
626     return this.m_minX;
627   }
628
629   /**
630    * Returns the original minimum y- value ignoring the offsetY.
631    * <p>
632    *
633    * @return the original minimum y- value ignoring the offsetY.
634    */

635   public final double getMinY() {
636     return this.m_minY;
637   }
638
639   /**
640    * Returns the name of this trace.
641    * <p>
642    *
643    * @return the name of this trace.
644    *
645    * @see ITrace2D#getName()
646    *
647    * @see #setName(String s)
648    */

649   public final String JavaDoc getName() {
650     return this.m_name;
651   }
652
653   /**
654    * @see #setPhysicalUnits(String x,String y)
655    */

656   public final String JavaDoc getPhysicalUnits() {
657     return this.m_physicalUnits;
658   }
659
660   /**
661    * @see info.monitorenter.gui.chart.ITrace2D#getPropertyChangeListeners(String)
662    */

663   public PropertyChangeListener JavaDoc[] getPropertyChangeListeners(final String JavaDoc property) {
664     return this.m_propertyChangeSupport.getPropertyChangeListeners(property);
665   }
666
667   /**
668    * Returns the chart that renders this instance or null, if this trace is not
669    * added to a chart.
670    * <p>
671    *
672    * The chart that renders this trace registers itself with this trace in
673    * {@link Chart2D#addTrace(ITrace2D)}.
674    * <p>
675    *
676    * @return Returns the renderer.
677    *
678    * @see Chart2D#addTrace(ITrace2D)
679    */

680   public final Chart2D getRenderer() {
681     if (this.m_renderer instanceof Chart2D) {
682       return (Chart2D) this.m_renderer;
683     } else {
684       return null;
685     }
686   }
687
688   /**
689    * <p>
690    * Get the <code>Stroke</code> object this instance will be painted with.
691    * </p>
692    *
693    * @return the <code>Stroke</code> object this <code>ITrace2D</code> will
694    * be painted with.
695    *
696    * @see info.monitorenter.gui.chart.ITrace2D#getStroke()
697    */

698   public final Stroke JavaDoc getStroke() {
699     return this.m_stroke;
700   }
701
702   /**
703    * @see info.monitorenter.gui.chart.ITrace2D#isVisible()
704    */

705   public final boolean isVisible() {
706     return this.m_visible;
707   }
708
709   /**
710    * @see info.monitorenter.gui.chart.ITrace2D#getZIndex()
711    */

712   public final Integer JavaDoc getZIndex() {
713     // More expensive but the contract of the order of values described in the
714
// interfaceis inverted to the contract of TreeSetGreedy.
715
// This is done here instead of get/set ComparableProperty
716
// as those are invoked several times for each iteration
717
// (and paint contains several iterations).
718
if (Chart2D.DEBUG_THREADING) {
719       System.out.println("trace.getZindex, 0 locks");
720     }
721
722     synchronized (this.m_renderer) {
723       if (Chart2D.DEBUG_THREADING) {
724         System.out.println("trace.getZindex, 1 locks");
725       }
726
727       synchronized (this) {
728         if (Chart2D.DEBUG_THREADING) {
729           System.out.println("trace.getZindex, 2 locks");
730         }
731
732         return new Integer JavaDoc(ZINDEX_MAX - this.m_zIndex.intValue());
733       }
734     }
735   }
736
737   /**
738    * Internal search for the maximum x value that is only invoked if no cached
739    * value is at hand or bounds have changed by adding new points.
740    * <p>
741    *
742    * The result is assigned to the property maxX.
743    * <p>
744    *
745    * @see #getMaxX()
746    */

747   protected void maxXSearch() {
748     if (Chart2D.DEBUG_THREADING) {
749       System.out.println("trace.maxXSearch, 0 locks");
750     }
751
752     synchronized (this) {
753       if (Chart2D.DEBUG_THREADING) {
754         System.out.println("trace.maxXSearch, 1 locks");
755       }
756       double ret = -Double.MAX_VALUE;
757       TracePoint2D tmpoint = null;
758       double tmp;
759       Iterator JavaDoc it = this.iterator();
760       while (it.hasNext()) {
761         tmpoint = (TracePoint2D) it.next();
762         tmp = tmpoint.getX();
763         if (tmp > ret) {
764           ret = tmp;
765         }
766       }
767       this.m_maxX = ret;
768     }
769   }
770
771   /**
772    * Internal search for the maximum y value that is only invoked if no cached
773    * value is at hand or bounds have changed by adding new points.
774    * <p>
775    *
776    * The result is assigned to the property maxY.
777    * <p>
778    *
779    * @see #getMaxY()
780    */

781   protected void maxYSearch() {
782     if (Chart2D.DEBUG_THREADING) {
783       System.out.println("trace.maxYSearch, 0 locks");
784     }
785
786     synchronized (this) {
787       if (Chart2D.DEBUG_THREADING) {
788         System.out.println("trace.maxYSearch, 1 lock");
789       }
790
791       double ret = -Double.MAX_VALUE;
792       TracePoint2D tmpoint = null;
793       double tmp;
794       Iterator JavaDoc it = this.iterator();
795       while (it.hasNext()) {
796         tmpoint = (TracePoint2D) it.next();
797         tmp = tmpoint.getY();
798         if (tmp > ret) {
799           ret = tmp;
800         }
801       }
802       this.m_maxY = ret;
803     }
804   }
805
806   /**
807    * Internal search for the minimum x value that is only invoked if no cached
808    * value is at hand or bounds have changed by adding new points.
809    * <p>
810    *
811    * The result is assigned to the property minX.
812    * <p>
813    *
814    * @see #getMinX()
815    */

816   protected void minXSearch() {
817     if (Chart2D.DEBUG_THREADING) {
818       System.out.println("trace.minXSearch, 0 locks");
819     }
820
821     synchronized (this) {
822       if (Chart2D.DEBUG_THREADING) {
823         System.out.println("trace.minXSearch, 1 locks");
824       }
825
826       double ret = Double.MAX_VALUE;
827       TracePoint2D tmpoint = null;
828       double tmp;
829       Iterator JavaDoc it = this.iterator();
830       while (it.hasNext()) {
831         tmpoint = (TracePoint2D) it.next();
832         tmp = tmpoint.getX();
833         if (tmp < ret) {
834           ret = tmp;
835         }
836       }
837       this.m_minX = ret;
838     }
839   }
840
841   /**
842    * Internal search for the minimum y value that is only invoked if no cached
843    * value is at hand or bounds have changed by adding new points.
844    * <p>
845    *
846    * The result is assigned to the property minY.
847    * <p>
848    *
849    * @see #getMinY()
850    */

851   protected void minYSearch() {
852     if (Chart2D.DEBUG_THREADING) {
853       System.out.println("trace.minYSearch, 0 locks");
854     }
855
856     synchronized (this) {
857       if (Chart2D.DEBUG_THREADING) {
858         System.out.println("trace.minYSearch, 1 locks");
859       }
860
861       double ret = Double.MAX_VALUE;
862       TracePoint2D tmpoint = null;
863       double tmp;
864       Iterator JavaDoc it = this.iterator();
865       while (it.hasNext()) {
866         tmpoint = (TracePoint2D) it.next();
867         tmp = tmpoint.getY();
868         if (tmp < ret) {
869           ret = tmp;
870         }
871       }
872       this.m_minY = ret;
873     }
874
875   }
876
877   /**
878    * Changes the internal state to empty to allow that the caching of bounds is
879    * cleared and delegates the call to {@link #removeAllPointsInternal()}.
880    * <p>
881    *
882    * @see info.monitorenter.gui.chart.ITrace2D#removeAllPoints()
883    */

884   public final void removeAllPoints() {
885     synchronized (this.m_renderer) {
886       synchronized (this) {
887
888         this.m_firsttime = true;
889         this.removeAllPointsInternal();
890         this.m_minX = 0;
891         this.m_maxX = 0;
892         this.m_maxY = 0;
893         this.m_minY = 0;
894         this.firePropertyChange(PROPERTY_MAX_X, null, new Double JavaDoc(this.m_maxX));
895         this.firePropertyChange(PROPERTY_MIN_X, null, new Double JavaDoc(this.m_minX));
896         this.firePropertyChange(PROPERTY_MAX_Y, null, new Double JavaDoc(this.m_maxY));
897         this.firePropertyChange(PROPERTY_MIN_Y, null, new Double JavaDoc(this.m_minY));
898       }
899     }
900   }
901
902   /**
903    * <p>
904    * Override this template method for the custom remove operation that depends
905    * on the <code>Collection</code> used in the implementation.
906    * </p>
907    * <p>
908    * No change events have to be fired, this is done by {@link ATrace2D}.
909    * </p>
910    *
911    */

912   protected abstract void removeAllPointsInternal();
913
914   /**
915    * <p>
916    * Remove the given point from this <code>ITrace2D</code>.
917    * </p>
918    * <p>
919    * This implementation performs caching of minimum and maximum values for x
920    * and y and the delegates to
921    * <code>{@link #removePointInternal(TracePoint2D)}</code> that has to
922    * perform the "real" add remove operation.
923    * </p>
924    * <p>
925    * Property change events are fired as described in method
926    * <code>{@link #firePointRemoved(TracePoint2D)}</code>.
927    * </p>
928    *
929    * @param point
930    * the <code>TracePoint2D</code> to remove.
931    *
932    * @return true if the removal suceeded, false else: this could be that the
933    * given point was not contained.
934    *
935    * @see #firePointChanged(TracePoint2D, boolean)
936    */

937   public boolean removePoint(final TracePoint2D point) {
938     synchronized (this.m_renderer) {
939       if (Chart2D.DEBUG_THREADING) {
940
941         System.out.println("removePoint, 0 locks");
942       }
943       synchronized (this) {
944         if (Chart2D.DEBUG_THREADING) {
945           System.out.println("removePoint, 1 lock");
946         }
947         boolean success = this.removePointInternal(point);
948         if (success) {
949           this.firePointRemoved(point);
950         }
951         return success;
952
953       }
954     }
955   }
956
957   /**
958    * <p>
959    * Override this template method for the custom remove operation that depends
960    * on the internal storage the implementation.
961    * </p>
962    * <p>
963    * No property change events have to be fired by default. If this method
964    * returns <code>true</code> the outer logic of the calling method
965    * <code>{@link #removePoint(TracePoint2D)}</code> will perform bound checks
966    * for the new point and fire property changes for the properties
967    * <code>{@link ITrace2D#PROPERTY_MAX_X}</code>,
968    * <code>{@link ITrace2D#PROPERTY_MIN_X}</code>,
969    * <code>{@link ITrace2D#PROPERTY_MAX_Y}</code> and
970    * <code>{@link ITrace2D#PROPERTY_MIN_Y}</code>.
971    * </p>
972    * <p>
973    * In special cases - when additional modifications to the internal set of
974    * points take place (e.g. a further point get added) this method should
975    * return false (regardless wether the old point was really removed or not)
976    * and perform bound checks and fire the property changes as mentioned above
977    * "manually".
978    * </p>
979    *
980    * @param point
981    * the point to remove.
982    *
983    * @return true if the given point was removed or false if not.
984    */

985   protected abstract boolean removePointInternal(final TracePoint2D point);
986
987   /**
988    * @see info.monitorenter.gui.chart.ITrace2D#removePropertyChangeListener(java.beans.PropertyChangeListener)
989    */

990   public void removePropertyChangeListener(final PropertyChangeListener JavaDoc listener) {
991     this.m_propertyChangeSupport.removePropertyChangeListener(listener);
992   }
993
994   /**
995    * @see info.monitorenter.gui.chart.ITrace2D#removePropertyChangeListener(java.lang.String,
996    * java.beans.PropertyChangeListener)
997    */

998   public void removePropertyChangeListener(final String JavaDoc property,
999       final PropertyChangeListener JavaDoc listener) {
1000    this.m_propertyChangeSupport.removePropertyChangeListener(property, listener);
1001  }
1002
1003  /**
1004   * Removes the given trace painter if an instance of the same class is
1005   * contained and more painters are remaining.
1006   * <p>
1007   *
1008   * @param painter
1009   * the painter to remove.
1010   *
1011   * @return true if a painter of the same class as the given painter was
1012   * removed.
1013   */

1014  public boolean removeTracePainter(final ITracePainter painter) {
1015    boolean result = false;
1016    if (this.m_tracePainters.size() > 1) {
1017      result = this.m_tracePainters.remove(painter);
1018      if (result) {
1019        this.firePropertyChange(PROPERTY_PAINTERS, painter, null);
1020      }
1021
1022    } else {
1023      // nop: if not contained operation will not be successful, if contained
1024
// not allowed.
1025
}
1026    return result;
1027  }
1028
1029  /**
1030   * <p>
1031   * Set the <code>Color</code> this trace will be painted with.
1032   * </p>
1033   *
1034   * @param color
1035   * the <code>Color</code> this trace will be painted with.
1036   */

1037  public final void setColor(final Color JavaDoc color) {
1038    Color JavaDoc oldValue = this.m_color;
1039    this.m_color = color;
1040    if (!this.m_color.equals(oldValue)) {
1041      this.firePropertyChange(PROPERTY_COLOR, oldValue, this.m_color);
1042    }
1043  }
1044
1045  /**
1046   * @see info.monitorenter.util.collections.IComparableProperty#setComparableProperty(java.lang.Number)
1047   */

1048  public void setComparableProperty(final Number JavaDoc n) {
1049    this.m_zIndex = ((Integer JavaDoc) n);
1050  }
1051
1052  /**
1053   * Sets the descriptive name for this trace.
1054   * <p>
1055   *
1056   * If the given argument is null or consists of whitespaces only nothing will
1057   * be changed.
1058   * <p>
1059   *
1060   * @param name
1061   * the descriptive name for this trace.
1062   *
1063   * @see info.monitorenter.gui.chart.ITrace2D#setName(java.lang.String)
1064   */

1065  public final void setName(final String JavaDoc name) {
1066    if (!StringUtil.isEmpty(name)) {
1067      String JavaDoc oldValue = this.m_name;
1068      this.m_name = name;
1069      if (!this.m_name.equals(oldValue)) {
1070        this.firePropertyChange(PROPERTY_NAME, oldValue, this.m_name);
1071      }
1072    }
1073  }
1074
1075  /**
1076   * @see ITrace2D#setPhysicalUnits(String, String)
1077   */

1078  public final void setPhysicalUnits(final String JavaDoc xunit, final String JavaDoc yunit) {
1079    String JavaDoc oldValue = this.m_physicalUnits;
1080    if ((xunit == null) && (yunit == null)) {
1081      return;
1082    }
1083    if ((xunit == null) && (yunit != null)) {
1084      this.m_physicalUnits = new StringBuffer JavaDoc("[x: , y: ").append(yunit).append("]").toString();
1085      return;
1086    }
1087    if ((xunit != null) && (yunit == null)) {
1088      this.m_physicalUnits = new StringBuffer JavaDoc("[x: ").append(xunit).append(", y: ]").toString();
1089      return;
1090    }
1091    this.m_physicalUnits = new StringBuffer JavaDoc("[x: ").append(xunit).append(", y: ").append(yunit)
1092        .append("]").toString();
1093    if (!this.m_physicalUnits.equals(oldValue)) {
1094      this.firePropertyChange(PROPERTY_PHYSICALUNITS, oldValue, this.m_physicalUnits);
1095    }
1096  }
1097
1098  /**
1099   * <p>
1100   * Allows the chart this instance is painted by to register itself.
1101   * </p>
1102   * <p>
1103   * This is internally required for synchronization and re-ordering due to
1104   * z-Index changes.
1105   * </p>
1106   *
1107   * @param renderer
1108   * the chart that paints this instance.
1109   */

1110  public final void setRenderer(final Chart2D renderer) {
1111    this.m_renderer = renderer;
1112  }
1113
1114  /**
1115   * @see info.monitorenter.gui.chart.ITrace2D#setStroke(java.awt.Stroke)
1116   */

1117  public final void setStroke(final Stroke JavaDoc stroke) {
1118    if (stroke == null) {
1119      throw new IllegalArgumentException JavaDoc("Argument must not be null.");
1120    }
1121    Stroke JavaDoc oldValue = this.m_stroke;
1122    this.m_stroke = stroke;
1123    if (!this.m_stroke.equals(oldValue)) {
1124      this.firePropertyChange(PROPERTY_STROKE, oldValue, this.m_stroke);
1125    }
1126  }
1127
1128  /** The internal lists of the painters to use. */
1129  private Set JavaDoc m_tracePainters = new TreeSet JavaDoc();
1130
1131  /**
1132   * @see info.monitorenter.gui.chart.ITrace2D#containsTracePainter(info.monitorenter.gui.chart.ITracePainter)
1133   */

1134  public boolean containsTracePainter(final ITracePainter painter) {
1135    return this.m_tracePainters.contains(painter);
1136  }
1137
1138  /**
1139   * <p>
1140   * Set the visible property of this instance.
1141   * </p>
1142   * <p>
1143   * Invisible <code>ITrace2D</code> instances (visible == false) will not be
1144   * painted.
1145   * </p>
1146   *
1147   * @param visible
1148   * the visible property of this instance to set.
1149   *
1150   * @see info.monitorenter.gui.chart.ITrace2D#setVisible(boolean)
1151   */

1152  public final void setVisible(final boolean visible) {
1153    boolean oldValue = this.m_visible;
1154    this.m_visible = visible;
1155    if (oldValue != this.m_visible) {
1156      this.firePropertyChange(PROPERTY_VISIBLE, new Boolean JavaDoc(oldValue), new Boolean JavaDoc(this.m_visible));
1157    }
1158  }
1159
1160  /**
1161   * Replaces all internal trace painters by the new one.
1162   * <p>
1163   *
1164   * @param painter
1165   * the new sole painter to use.
1166   *
1167   * @return the <code>Set&lt;{@link ITracePainter}&gt;</code> that was used
1168   * before.
1169   */

1170  public Set JavaDoc setTracePainter(final ITracePainter painter) {
1171    Set JavaDoc result = this.m_tracePainters;
1172    this.m_tracePainters = new TreeSet JavaDoc();
1173    boolean added = this.m_tracePainters.add(painter);
1174    if (added) {
1175      this.firePropertyChange(PROPERTY_PAINTERS, null, painter);
1176    }
1177    return result;
1178  }
1179
1180  /**
1181   * @see info.monitorenter.gui.chart.ITrace2D#setZIndex(java.lang.Integer)
1182   */

1183  public final void setZIndex(final Integer JavaDoc zIndex) {
1184    if (Chart2D.DEBUG_THREADING) {
1185      System.out.println("trace.setZIndex, 0 locks");
1186    }
1187
1188    if (!zIndex.equals(this.m_zIndex)) {
1189
1190      synchronized (this.m_renderer) {
1191        if (Chart2D.DEBUG_THREADING) {
1192          System.out.println("trace.setZIndex, 1 lock");
1193        }
1194
1195        Integer JavaDoc oldValue = this.m_zIndex;
1196        synchronized (this) {
1197          if (Chart2D.DEBUG_THREADING) {
1198            System.out.println("trace.setZIndex, 2 locks");
1199          }
1200          /*
1201           * see javadoc of TreeSetGreedy: we have to remove before outside
1202           * modification of the IComparableProperty, then modify and finally
1203           * add again.
1204           */

1205          boolean rendered = this.m_renderer instanceof Chart2D;
1206          if (rendered) {
1207            ((Chart2D) this.m_renderer).removeTrace(this);
1208          }
1209          this.m_zIndex = new Integer JavaDoc(ZINDEX_MAX - zIndex.intValue());
1210          if (rendered) {
1211            ((Chart2D) this.m_renderer).addTrace(this);
1212          }
1213          this.firePropertyChange(PROPERTY_ZINDEX, oldValue, this.m_zIndex);
1214
1215        }
1216
1217      }
1218    }
1219  }
1220
1221  /**
1222   * @see info.monitorenter.gui.chart.ITrace2D#getTracePainters()
1223   */

1224  public final Set JavaDoc getTracePainters() {
1225
1226    return this.m_tracePainters;
1227  }
1228
1229  /**
1230   * <p>
1231   * Returns <code>{@link #getName()}.</code>
1232   * </p>
1233   *
1234   * @return <code>{@link #getName()}</code>.
1235   */

1236  public String JavaDoc toString() {
1237    return this.getName();
1238  }
1239}
1240
Popular Tags