KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jfree > data > general > CombinedDataset


1 /* ===========================================================
2  * JFreeChart : a free chart library for the Java(tm) platform
3  * ===========================================================
4  *
5  * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
6  *
7  * Project Info: http://www.jfree.org/jfreechart/index.html
8  *
9  * This library is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 of the License, or
12  * (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
17  * License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
22  * USA.
23  *
24  * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
25  * in the United States and other countries.]
26  *
27  * --------------------
28  * CombinedDataset.java
29  * --------------------
30  * (C) Copyright 2001-2005, by Bill Kelemen and Contributors.
31  *
32  * Original Author: Bill Kelemen;
33  * Contributor(s): David Gilbert (for Object Refinery Limited);
34  *
35  * $Id: CombinedDataset.java,v 1.6.2.1 2005/10/25 21:32:29 mungady Exp $
36  *
37  * Changes
38  * -------
39  * 06-Dec-2001 : Version 1 (BK);
40  * 27-Dec-2001 : Fixed bug in getChildPosition method (BK);
41  * 29-Dec-2001 : Fixed bug in getChildPosition method with complex
42  * CombinePlot (BK);
43  * 05-Feb-2002 : Small addition to the interface HighLowDataset, as requested
44  * by Sylvain Vieujot (DG);
45  * 14-Feb-2002 : Added bug fix for IntervalXYDataset methods, submitted by
46  * Gyula Kun-Szabo (DG);
47  * 11-Jun-2002 : Updated for change in event constructor (DG);
48  * 04-Oct-2002 : Fixed errors reported by Checkstyle (DG);
49  * 06-May-2004 : Now extends AbstractIntervalXYDataset and added other methods
50  * that return double primitives (DG);
51  * 15-Jul-2004 : Switched getX() with getXValue() and getY() with
52  * getYValue() (DG);
53  *
54  */

55
56 package org.jfree.data.general;
57
58 import java.util.List JavaDoc;
59
60 import org.jfree.data.xy.AbstractIntervalXYDataset;
61 import org.jfree.data.xy.OHLCDataset;
62 import org.jfree.data.xy.IntervalXYDataset;
63 import org.jfree.data.xy.XYDataset;
64
65 /**
66  * This class can combine instances of {@link XYDataset}, {@link OHLCDataset}
67  * and {@link IntervalXYDataset} together exposing the union of all the series
68  * under one dataset.
69  *
70  * @author Bill Kelemen (bill@kelemen-usa.com)
71  */

72 public class CombinedDataset extends AbstractIntervalXYDataset
73                              implements XYDataset,
74                                         OHLCDataset,
75                                         IntervalXYDataset,
76                                         CombinationDataset {
77
78     /** Storage for the datasets we combine. */
79     private List JavaDoc datasetInfo = new java.util.ArrayList JavaDoc();
80
81     /**
82      * Default constructor for an empty combination.
83      */

84     public CombinedDataset() {
85         super();
86     }
87
88     /**
89      * Creates a CombinedDataset initialized with an array of SeriesDatasets.
90      *
91      * @param data array of SeriesDataset that contains the SeriesDatasets to
92      * combine.
93      */

94     public CombinedDataset(SeriesDataset[] data) {
95         add(data);
96     }
97
98     /**
99      * Adds one SeriesDataset to the combination. Listeners are notified of the
100      * change.
101      *
102      * @param data the SeriesDataset to add.
103      */

104     public void add(SeriesDataset data) {
105         fastAdd(data);
106         DatasetChangeEvent event = new DatasetChangeEvent(this, this);
107         notifyListeners(event);
108     }
109
110     /**
111      * Adds an array of SeriesDataset's to the combination. Listeners are
112      * notified of the change.
113      *
114      * @param data array of SeriesDataset to add
115      */

116     public void add(SeriesDataset[] data) {
117
118         for (int i = 0; i < data.length; i++) {
119             fastAdd(data[i]);
120         }
121         DatasetChangeEvent event = new DatasetChangeEvent(this, this);
122         notifyListeners(event);
123
124     }
125
126     /**
127      * Adds one series from a SeriesDataset to the combination. Listeners are
128      * notified of the change.
129      *
130      * @param data the SeriesDataset where series is contained
131      * @param series series to add
132      */

133     public void add(SeriesDataset data, int series) {
134         add(new SubSeriesDataset(data, series));
135     }
136
137     /**
138      * Fast add of a SeriesDataset. Does not notify listeners of the change.
139      *
140      * @param data SeriesDataset to add
141      */

142     private void fastAdd(SeriesDataset data) {
143         for (int i = 0; i < data.getSeriesCount(); i++) {
144             this.datasetInfo.add(new DatasetInfo(data, i));
145         }
146     }
147
148     ///////////////////////////////////////////////////////////////////////////
149
// From SeriesDataset
150
///////////////////////////////////////////////////////////////////////////
151

152     /**
153      * Returns the number of series in the dataset.
154      *
155      * @return The number of series in the dataset.
156      */

157     public int getSeriesCount() {
158         return this.datasetInfo.size();
159     }
160
161     /**
162      * Returns the key for a series.
163      *
164      * @param series the series (zero-based index).
165      *
166      * @return The key for a series.
167      */

168     public Comparable JavaDoc getSeriesKey(int series) {
169         DatasetInfo di = getDatasetInfo(series);
170         return di.data.getSeriesKey(di.series);
171     }
172
173     ///////////////////////////////////////////////////////////////////////////
174
// From XYDataset
175
///////////////////////////////////////////////////////////////////////////
176

177     /**
178      * Returns the X-value for the specified series and item.
179      * <P>
180      * Note: throws <code>ClassCastException</code> if the series is not from
181      * a {@link XYDataset}.
182      *
183      * @param series the index of the series of interest (zero-based).
184      * @param item the index of the item of interest (zero-based).
185      *
186      * @return The X-value for the specified series and item.
187      */

188     public Number JavaDoc getX(int series, int item) {
189         DatasetInfo di = getDatasetInfo(series);
190         return ((XYDataset) di.data).getX(di.series, item);
191     }
192
193     /**
194      * Returns the Y-value for the specified series and item.
195      * <P>
196      * Note: throws <code>ClassCastException</code> if the series is not from
197      * a {@link XYDataset}.
198      *
199      * @param series the index of the series of interest (zero-based).
200      * @param item the index of the item of interest (zero-based).
201      *
202      * @return The Y-value for the specified series and item.
203      */

204     public Number JavaDoc getY(int series, int item) {
205         DatasetInfo di = getDatasetInfo(series);
206         return ((XYDataset) di.data).getY(di.series, item);
207     }
208
209     /**
210      * Returns the number of items in a series.
211      * <P>
212      * Note: throws <code>ClassCastException</code> if the series is not from
213      * a {@link XYDataset}.
214      *
215      * @param series the index of the series of interest (zero-based).
216      *
217      * @return The number of items in a series.
218      */

219     public int getItemCount(int series) {
220         DatasetInfo di = getDatasetInfo(series);
221         return ((XYDataset) di.data).getItemCount(di.series);
222     }
223
224     ///////////////////////////////////////////////////////////////////////////
225
// From HighLowDataset
226
///////////////////////////////////////////////////////////////////////////
227

228     /**
229      * Returns the high-value for the specified series and item.
230      * <P>
231      * Note: throws <code>ClassCastException</code> if the series is not from a
232      * {@link OHLCDataset}.
233      *
234      * @param series the index of the series of interest (zero-based).
235      * @param item the index of the item of interest (zero-based).
236      *
237      * @return The high-value for the specified series and item.
238      */

239     public Number JavaDoc getHigh(int series, int item) {
240         DatasetInfo di = getDatasetInfo(series);
241         return ((OHLCDataset) di.data).getHigh(di.series, item);
242     }
243
244     /**
245      * Returns the high-value (as a double primitive) for an item within a
246      * series.
247      *
248      * @param series the series (zero-based index).
249      * @param item the item (zero-based index).
250      *
251      * @return The high-value.
252      */

253     public double getHighValue(int series, int item) {
254         double result = Double.NaN;
255         Number JavaDoc high = getHigh(series, item);
256         if (high != null) {
257             result = high.doubleValue();
258         }
259         return result;
260     }
261
262     /**
263      * Returns the low-value for the specified series and item.
264      * <P>
265      * Note: throws <code>ClassCastException</code> if the series is not from a
266      * {@link OHLCDataset}.
267      *
268      * @param series the index of the series of interest (zero-based).
269      * @param item the index of the item of interest (zero-based).
270      *
271      * @return The low-value for the specified series and item.
272      */

273     public Number JavaDoc getLow(int series, int item) {
274         DatasetInfo di = getDatasetInfo(series);
275         return ((OHLCDataset) di.data).getLow(di.series, item);
276     }
277
278     /**
279      * Returns the low-value (as a double primitive) for an item within a
280      * series.
281      *
282      * @param series the series (zero-based index).
283      * @param item the item (zero-based index).
284      *
285      * @return The low-value.
286      */

287     public double getLowValue(int series, int item) {
288         double result = Double.NaN;
289         Number JavaDoc low = getLow(series, item);
290         if (low != null) {
291             result = low.doubleValue();
292         }
293         return result;
294     }
295
296     /**
297      * Returns the open-value for the specified series and item.
298      * <P>
299      * Note: throws <code>ClassCastException</code> if the series is not from a
300      * {@link OHLCDataset}.
301      *
302      * @param series the index of the series of interest (zero-based).
303      * @param item the index of the item of interest (zero-based).
304      *
305      * @return The open-value for the specified series and item.
306      */

307     public Number JavaDoc getOpen(int series, int item) {
308         DatasetInfo di = getDatasetInfo(series);
309         return ((OHLCDataset) di.data).getOpen(di.series, item);
310     }
311
312     /**
313      * Returns the open-value (as a double primitive) for an item within a
314      * series.
315      *
316      * @param series the series (zero-based index).
317      * @param item the item (zero-based index).
318      *
319      * @return The open-value.
320      */

321     public double getOpenValue(int series, int item) {
322         double result = Double.NaN;
323         Number JavaDoc open = getOpen(series, item);
324         if (open != null) {
325             result = open.doubleValue();
326         }
327         return result;
328     }
329
330     /**
331      * Returns the close-value for the specified series and item.
332      * <P>
333      * Note: throws <code>ClassCastException</code> if the series is not from a
334      * {@link OHLCDataset}.
335      *
336      * @param series the index of the series of interest (zero-based).
337      * @param item the index of the item of interest (zero-based).
338      *
339      * @return The close-value for the specified series and item.
340      */

341     public Number JavaDoc getClose(int series, int item) {
342         DatasetInfo di = getDatasetInfo(series);
343         return ((OHLCDataset) di.data).getClose(di.series, item);
344     }
345
346     /**
347      * Returns the close-value (as a double primitive) for an item within a
348      * series.
349      *
350      * @param series the series (zero-based index).
351      * @param item the item (zero-based index).
352      *
353      * @return The close-value.
354      */

355     public double getCloseValue(int series, int item) {
356         double result = Double.NaN;
357         Number JavaDoc close = getClose(series, item);
358         if (close != null) {
359             result = close.doubleValue();
360         }
361         return result;
362     }
363
364     /**
365      * Returns the volume value for the specified series and item.
366      * <P>
367      * Note: throws <code>ClassCastException</code> if the series is not from a
368      * {@link OHLCDataset}.
369      *
370      * @param series the index of the series of interest (zero-based).
371      * @param item the index of the item of interest (zero-based).
372      *
373      * @return The volume value for the specified series and item.
374      */

375     public Number JavaDoc getVolume(int series, int item) {
376         DatasetInfo di = getDatasetInfo(series);
377         return ((OHLCDataset) di.data).getVolume(di.series, item);
378     }
379
380     /**
381      * Returns the volume-value (as a double primitive) for an item within a
382      * series.
383      *
384      * @param series the series (zero-based index).
385      * @param item the item (zero-based index).
386      *
387      * @return The volume-value.
388      */

389     public double getVolumeValue(int series, int item) {
390         double result = Double.NaN;
391         Number JavaDoc volume = getVolume(series, item);
392         if (volume != null) {
393             result = volume.doubleValue();
394         }
395         return result;
396     }
397
398     ///////////////////////////////////////////////////////////////////////////
399
// From IntervalXYDataset
400
///////////////////////////////////////////////////////////////////////////
401

402     /**
403      * Returns the starting X value for the specified series and item.
404      *
405      * @param series the index of the series of interest (zero-based).
406      * @param item the index of the item of interest (zero-based).
407      *
408      * @return The value.
409      */

410     public Number JavaDoc getStartX(int series, int item) {
411         DatasetInfo di = getDatasetInfo(series);
412         if (di.data instanceof IntervalXYDataset) {
413             return ((IntervalXYDataset) di.data).getStartX(di.series, item);
414         }
415         else {
416             return getX(series, item);
417         }
418     }
419
420     /**
421      * Returns the ending X value for the specified series and item.
422      *
423      * @param series the index of the series of interest (zero-based).
424      * @param item the index of the item of interest (zero-based).
425      *
426      * @return The value.
427      */

428     public Number JavaDoc getEndX(int series, int item) {
429         DatasetInfo di = getDatasetInfo(series);
430         if (di.data instanceof IntervalXYDataset) {
431             return ((IntervalXYDataset) di.data).getEndX(di.series, item);
432         }
433         else {
434             return getX(series, item);
435         }
436     }
437
438     /**
439      * Returns the starting Y value for the specified series and item.
440      *
441      * @param series the index of the series of interest (zero-based).
442      * @param item the index of the item of interest (zero-based).
443      *
444      * @return The starting Y value for the specified series and item.
445      */

446     public Number JavaDoc getStartY(int series, int item) {
447         DatasetInfo di = getDatasetInfo(series);
448         if (di.data instanceof IntervalXYDataset) {
449             return ((IntervalXYDataset) di.data).getStartY(di.series, item);
450         }
451         else {
452             return getY(series, item);
453         }
454     }
455
456     /**
457      * Returns the ending Y value for the specified series and item.
458      *
459      * @param series the index of the series of interest (zero-based).
460      * @param item the index of the item of interest (zero-based).
461      *
462      * @return The ending Y value for the specified series and item.
463      */

464     public Number JavaDoc getEndY(int series, int item) {
465         DatasetInfo di = getDatasetInfo(series);
466         if (di.data instanceof IntervalXYDataset) {
467             return ((IntervalXYDataset) di.data).getEndY(di.series, item);
468         }
469         else {
470             return getY(series, item);
471         }
472     }
473
474     ///////////////////////////////////////////////////////////////////////////
475
// New methods from CombinationDataset
476
///////////////////////////////////////////////////////////////////////////
477

478     /**
479      * Returns the parent Dataset of this combination. If there is more than
480      * one parent, or a child is found that is not a CombinationDataset, then
481      * returns <code>null</code>.
482      *
483      * @return The parent Dataset of this combination or <code>null</code>.
484      */

485     public SeriesDataset getParent() {
486
487         SeriesDataset parent = null;
488         for (int i = 0; i < this.datasetInfo.size(); i++) {
489             SeriesDataset child = getDatasetInfo(i).data;
490             if (child instanceof CombinationDataset) {
491                 SeriesDataset childParent
492                     = ((CombinationDataset) child).getParent();
493                 if (parent == null) {
494                     parent = childParent;
495                 }
496                 else if (parent != childParent) {
497                     return null;
498                 }
499             }
500             else {
501                 return null;
502             }
503         }
504         return parent;
505
506     }
507
508     /**
509      * Returns a map or indirect indexing form our series into parent's series.
510      * Prior to calling this method, the client should check getParent() to make
511      * sure the CombinationDataset uses the same parent. If not, the map
512      * returned by this method will be invalid or null.
513      *
514      * @return A map or indirect indexing form our series into parent's series.
515      *
516      * @see #getParent()
517      */

518     public int[] getMap() {
519
520         int[] map = null;
521         for (int i = 0; i < this.datasetInfo.size(); i++) {
522             SeriesDataset child = getDatasetInfo(i).data;
523             if (child instanceof CombinationDataset) {
524                 int[] childMap = ((CombinationDataset) child).getMap();
525                 if (childMap == null) {
526                     return null;
527                 }
528                 map = joinMap(map, childMap);
529             }
530             else {
531                 return null;
532             }
533         }
534         return map;
535     }
536
537     ///////////////////////////////////////////////////////////////////////////
538
// New Methods
539
///////////////////////////////////////////////////////////////////////////
540

541     /**
542      * Returns the child position.
543      *
544      * @param child the child dataset.
545      *
546      * @return The position.
547      */

548     public int getChildPosition(Dataset child) {
549
550         int n = 0;
551         for (int i = 0; i < this.datasetInfo.size(); i++) {
552             SeriesDataset childDataset = getDatasetInfo(i).data;
553             if (childDataset instanceof CombinedDataset) {
554                 int m = ((CombinedDataset) childDataset)
555                     .getChildPosition(child);
556                 if (m >= 0) {
557                     return n + m;
558                 }
559                 n++;
560             }
561             else {
562                 if (child == childDataset) {
563                     return n;
564                 }
565                 n++;
566             }
567         }
568         return -1;
569     }
570
571     ///////////////////////////////////////////////////////////////////////////
572
// Private
573
///////////////////////////////////////////////////////////////////////////
574

575     /**
576      * Returns the DatasetInfo object associated with the series.
577      *
578      * @param series the index of the series.
579      *
580      * @return The DatasetInfo object associated with the series.
581      */

582     private DatasetInfo getDatasetInfo(int series) {
583         return (DatasetInfo) this.datasetInfo.get(series);
584     }
585
586     /**
587      * Joins two map arrays (int[]) together.
588      *
589      * @param a the first array.
590      * @param b the second array.
591      *
592      * @return A copy of { a[], b[] }.
593      */

594     private int[] joinMap(int[] a, int[] b) {
595         if (a == null) {
596             return b;
597         }
598         if (b == null) {
599             return a;
600         }
601         int[] result = new int[a.length + b.length];
602         System.arraycopy(a, 0, result, 0, a.length);
603         System.arraycopy(b, 0, result, a.length, b.length);
604         return result;
605     }
606
607     /**
608      * Private class to store as pairs (SeriesDataset, series) for all combined
609      * series.
610      */

611     private class DatasetInfo {
612
613         /** The dataset. */
614         private SeriesDataset data;
615
616         /** The series. */
617         private int series;
618
619         /**
620          * Creates a new dataset info record.
621          *
622          * @param data the dataset.
623          * @param series the series.
624          */

625         DatasetInfo(SeriesDataset data, int series) {
626             this.data = data;
627             this.series = series;
628         }
629     }
630
631 }
632
Popular Tags