KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jfree > data > time > TimePeriodValues


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 License
20  * along with this library; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
22  *
23  * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
24  * in the United States and other countries.]
25  *
26  * ---------------------
27  * TimePeriodValues.java
28  * ---------------------
29  * (C) Copyright 2003-2005, by Object Refinery Limited.
30  *
31  * Original Author: David Gilbert (for Object Refinery Limited);
32  * Contributor(s): -;
33  *
34  * $Id: TimePeriodValues.java,v 1.8 2005/05/19 10:35:27 mungady Exp $
35  *
36  * Changes
37  * -------
38  * 22-Apr-2003 : Version 1 (DG);
39  * 30-Jul-2003 : Added clone and equals methods while testing (DG);
40  * 11-Mar-2005 : Fixed bug in bounds recalculation - see bug report
41  * 1161329 (DG);
42  *
43  */

44
45 package org.jfree.data.time;
46
47 import java.io.Serializable JavaDoc;
48 import java.util.ArrayList JavaDoc;
49 import java.util.List JavaDoc;
50
51 import org.jfree.data.general.Series;
52 import org.jfree.data.general.SeriesException;
53
54 /**
55  * A structure containing zero, one or many {@link TimePeriodValue} instances.
56  * The time periods can overlap, and are maintained in the order that they are
57  * added to the collection.
58  * <p>
59  * This is similar to the {@link TimeSeries} class, except that the time
60  * periods can have irregular lengths.
61  */

62 public class TimePeriodValues extends Series implements Serializable JavaDoc {
63
64     /** For serialization. */
65     static final long serialVersionUID = -2210593619794989709L;
66     
67     /** Default value for the domain description. */
68     protected static final String JavaDoc DEFAULT_DOMAIN_DESCRIPTION = "Time";
69
70     /** Default value for the range description. */
71     protected static final String JavaDoc DEFAULT_RANGE_DESCRIPTION = "Value";
72
73     /** A description of the domain. */
74     private String JavaDoc domain;
75
76     /** A description of the range. */
77     private String JavaDoc range;
78
79     /** The list of data pairs in the series. */
80     private List JavaDoc data;
81
82     /** Index of the time period with the minimum start milliseconds. */
83     private int minStartIndex = -1;
84     
85     /** Index of the time period with the maximum start milliseconds. */
86     private int maxStartIndex = -1;
87     
88     /** Index of the time period with the minimum middle milliseconds. */
89     private int minMiddleIndex = -1;
90     
91     /** Index of the time period with the maximum middle milliseconds. */
92     private int maxMiddleIndex = -1;
93     
94     /** Index of the time period with the minimum end milliseconds. */
95     private int minEndIndex = -1;
96     
97     /** Index of the time period with the maximum end milliseconds. */
98     private int maxEndIndex = -1;
99
100     /**
101      * Creates a new (empty) collection of time period values.
102      *
103      * @param name the name of the series.
104      */

105     public TimePeriodValues(String JavaDoc name) {
106         this(name, DEFAULT_DOMAIN_DESCRIPTION, DEFAULT_RANGE_DESCRIPTION);
107     }
108
109     /**
110      * Creates a new time series that contains no data.
111      * <P>
112      * Descriptions can be specified for the domain and range. One situation
113      * where this is helpful is when generating a chart for the time series -
114      * axis labels can be taken from the domain and range description.
115      *
116      * @param name the name of the series.
117      * @param domain the domain description.
118      * @param range the range description.
119      */

120     public TimePeriodValues(String JavaDoc name, String JavaDoc domain, String JavaDoc range) {
121         super(name);
122         this.domain = domain;
123         this.range = range;
124         this.data = new ArrayList JavaDoc();
125     }
126
127     /**
128      * Returns the domain description.
129      *
130      * @return The domain description.
131      */

132     public String JavaDoc getDomainDescription() {
133         return this.domain;
134     }
135
136     /**
137      * Sets the domain description and fires a property change event.
138      *
139      * @param description the new description.
140      */

141     public void setDomainDescription(String JavaDoc description) {
142         String JavaDoc old = this.domain;
143         this.domain = description;
144         firePropertyChange("Domain", old, description);
145     }
146
147     /**
148      * Returns the range description.
149      *
150      * @return The range description.
151      */

152     public String JavaDoc getRangeDescription() {
153         return this.range;
154     }
155
156     /**
157      * Sets the range description and fires a property change event.
158      *
159      * @param description the new description.
160      */

161     public void setRangeDescription(String JavaDoc description) {
162         String JavaDoc old = this.range;
163         this.range = description;
164         firePropertyChange("Range", old, description);
165     }
166
167     /**
168      * Returns the number of items in the series.
169      *
170      * @return The item count.
171      */

172     public int getItemCount() {
173         return this.data.size();
174     }
175
176     /**
177      * Returns one data item for the series.
178      *
179      * @param index the item index (zero-based).
180      *
181      * @return One data item for the series.
182      */

183     public TimePeriodValue getDataItem(int index) {
184         return (TimePeriodValue) this.data.get(index);
185     }
186
187     /**
188      * Returns the time period at the specified index.
189      *
190      * @param index the index of the data pair.
191      *
192      * @return The time period at the specified index.
193      */

194     public TimePeriod getTimePeriod(int index) {
195         return getDataItem(index).getPeriod();
196     }
197
198     /**
199      * Returns the value at the specified index.
200      *
201      * @param index index of a value.
202      *
203      * @return The value at the specified index.
204      */

205     public Number JavaDoc getValue(int index) {
206         return getDataItem(index).getValue();
207     }
208
209     /**
210      * Adds a data item to the series.
211      *
212      * @param item the (timeperiod, value) pair.
213      */

214     public void add(TimePeriodValue item) {
215
216         // check arguments...
217
if (item == null) {
218             throw new IllegalArgumentException JavaDoc("Null item not allowed.");
219         }
220
221         // make the change
222
this.data.add(item);
223         updateBounds(item.getPeriod(), this.data.size() - 1);
224
225     }
226     
227     /**
228      * Update the index values for the maximum and minimum bounds.
229      *
230      * @param period the time period.
231      * @param index the index of the time period.
232      */

233     private void updateBounds(TimePeriod period, int index) {
234         
235         long start = period.getStart().getTime();
236         long end = period.getEnd().getTime();
237         long middle = start + ((end - start) / 2);
238
239         if (this.minStartIndex >= 0) {
240             long minStart = getDataItem(this.minStartIndex).getPeriod()
241                 .getStart().getTime();
242             if (start < minStart) {
243                 this.minStartIndex = index;
244             }
245         }
246         else {
247             this.minStartIndex = index;
248         }
249         
250         if (this.maxStartIndex >= 0) {
251             long maxStart = getDataItem(this.maxStartIndex).getPeriod()
252                 .getStart().getTime();
253             if (start > maxStart) {
254                 this.maxStartIndex = index;
255             }
256         }
257         else {
258             this.maxStartIndex = index;
259         }
260         
261         if (this.minMiddleIndex >= 0) {
262             long s = getDataItem(this.minMiddleIndex).getPeriod().getStart()
263                 .getTime();
264             long e = getDataItem(this.minMiddleIndex).getPeriod().getEnd()
265                 .getTime();
266             long minMiddle = s + (e - s) / 2;
267             if (middle < minMiddle) {
268                 this.minMiddleIndex = index;
269             }
270         }
271         else {
272             this.minMiddleIndex = index;
273         }
274         
275         if (this.maxMiddleIndex >= 0) {
276             long s = getDataItem(this.minMiddleIndex).getPeriod().getStart()
277                 .getTime();
278             long e = getDataItem(this.minMiddleIndex).getPeriod().getEnd()
279                 .getTime();
280             long maxMiddle = s + (e - s) / 2;
281             if (middle > maxMiddle) {
282                 this.maxMiddleIndex = index;
283             }
284         }
285         else {
286             this.maxMiddleIndex = index;
287         }
288         
289         if (this.minEndIndex >= 0) {
290             long minEnd = getDataItem(this.minEndIndex).getPeriod().getEnd()
291                 .getTime();
292             if (end < minEnd) {
293                 this.minEndIndex = index;
294             }
295         }
296         else {
297             this.minEndIndex = index;
298         }
299        
300         if (this.maxEndIndex >= 0) {
301             long maxEnd = getDataItem(this.maxEndIndex).getPeriod().getEnd()
302                 .getTime();
303             if (end > maxEnd) {
304                 this.maxEndIndex = index;
305             }
306         }
307         else {
308             this.maxEndIndex = index;
309         }
310         
311     }
312     
313     /**
314      * Recalculates the bounds for the collection of items.
315      */

316     private void recalculateBounds() {
317         this.minStartIndex = -1;
318         this.minMiddleIndex = -1;
319         this.minEndIndex = -1;
320         this.maxStartIndex = -1;
321         this.maxMiddleIndex = -1;
322         this.maxEndIndex = -1;
323         for (int i = 0; i < this.data.size(); i++) {
324             TimePeriodValue tpv = (TimePeriodValue) this.data.get(i);
325             updateBounds(tpv.getPeriod(), i);
326         }
327     }
328
329     /**
330      * Adds a new data item to the series.
331      *
332      * @param period the time period.
333      * @param value the value.
334      */

335     public void add(TimePeriod period, double value) {
336         TimePeriodValue item = new TimePeriodValue(period, value);
337         add(item);
338     }
339
340     /**
341      * Adds a new data item to the series.
342      *
343      * @param period the time period.
344      * @param value the value.
345      */

346     public void add(TimePeriod period, Number JavaDoc value) {
347         TimePeriodValue item = new TimePeriodValue(period, value);
348         add(item);
349     }
350
351     /**
352      * Updates (changes) the value of a data item.
353      *
354      * @param index the index of the data item to update.
355      * @param value the new value.
356      */

357     public void update(int index, Number JavaDoc value) {
358         TimePeriodValue item = getDataItem(index);
359         item.setValue(value);
360         fireSeriesChanged();
361     }
362
363     /**
364      * Deletes data from start until end index (end inclusive).
365      *
366      * @param start the index of the first period to delete.
367      * @param end the index of the last period to delete.
368      */

369     public void delete(int start, int end) {
370         for (int i = 0; i <= (end - start); i++) {
371             this.data.remove(start);
372         }
373         recalculateBounds();
374         fireSeriesChanged();
375     }
376     
377     /**
378      * Tests the series for equality with another object.
379      *
380      * @param obj the object.
381      *
382      * @return <code>true</code> or <code>false</code>.
383      */

384     public boolean equals(Object JavaDoc obj) {
385         
386         if (obj == this) {
387             return true;
388         }
389
390         if (!(obj instanceof TimePeriodValues)) {
391             return false;
392         }
393
394         if (!super.equals(obj)) {
395             return false;
396         }
397
398         TimePeriodValues that = (TimePeriodValues) obj;
399         if (!getDomainDescription().equals(that.getDomainDescription())) {
400             return false;
401         }
402         if (!getRangeDescription().equals(that.getRangeDescription())) {
403             return false;
404         }
405
406         int count = getItemCount();
407         if (count != that.getItemCount()) {
408             return false;
409         }
410         for (int i = 0; i < count; i++) {
411             if (!getDataItem(i).equals(that.getDataItem(i))) {
412                 return false;
413             }
414         }
415         return true;
416
417     }
418
419     /**
420      * Returns a hash code value for the object.
421      *
422      * @return The hashcode
423      */

424     public int hashCode() {
425         int result;
426         result = (this.domain != null ? this.domain.hashCode() : 0);
427         result = 29 * result + (this.range != null ? this.range.hashCode() : 0);
428         result = 29 * result + this.data.hashCode();
429         result = 29 * result + this.minStartIndex;
430         result = 29 * result + this.maxStartIndex;
431         result = 29 * result + this.minMiddleIndex;
432         result = 29 * result + this.maxMiddleIndex;
433         result = 29 * result + this.minEndIndex;
434         result = 29 * result + this.maxEndIndex;
435         return result;
436     }
437
438     /**
439      * Returns a clone of the collection.
440      * <P>
441      * Notes:
442      * <ul>
443      * <li>no need to clone the domain and range descriptions, since String
444      * object is immutable;</li>
445      * <li>we pass over to the more general method createCopy(start, end).
446      * </li>
447      * </ul>
448      *
449      * @return A clone of the time series.
450      *
451      * @throws CloneNotSupportedException if there is a cloning problem.
452      */

453     public Object JavaDoc clone() throws CloneNotSupportedException JavaDoc {
454         Object JavaDoc clone = createCopy(0, getItemCount() - 1);
455         return clone;
456     }
457
458     /**
459      * Creates a new instance by copying a subset of the data in this
460      * collection.
461      *
462      * @param start the index of the first item to copy.
463      * @param end the index of the last item to copy.
464      *
465      * @return A copy of a subset of the items.
466      *
467      * @throws CloneNotSupportedException if there is a cloning problem.
468      */

469     public TimePeriodValues createCopy(int start, int end)
470         throws CloneNotSupportedException JavaDoc {
471
472         TimePeriodValues copy = (TimePeriodValues) super.clone();
473
474         copy.data = new ArrayList JavaDoc();
475         if (this.data.size() > 0) {
476             for (int index = start; index <= end; index++) {
477                 TimePeriodValue item = (TimePeriodValue) this.data.get(index);
478                 TimePeriodValue clone = (TimePeriodValue) item.clone();
479                 try {
480                     copy.add(clone);
481                 }
482                 catch (SeriesException e) {
483                     System.err.println("Failed to add cloned item.");
484                 }
485             }
486         }
487         return copy;
488
489     }
490     
491     /**
492      * Returns the index of the time period with the minimum start milliseconds.
493      *
494      * @return The index.
495      */

496     public int getMinStartIndex() {
497         return this.minStartIndex;
498     }
499     
500     /**
501      * Returns the index of the time period with the maximum start milliseconds.
502      *
503      * @return The index.
504      */

505     public int getMaxStartIndex() {
506         return this.maxStartIndex;
507     }
508
509     /**
510      * Returns the index of the time period with the minimum middle
511      * milliseconds.
512      *
513      * @return The index.
514      */

515     public int getMinMiddleIndex() {
516         return this.minMiddleIndex;
517     }
518     
519     /**
520      * Returns the index of the time period with the maximum middle
521      * milliseconds.
522      *
523      * @return The index.
524      */

525     public int getMaxMiddleIndex() {
526         return this.maxMiddleIndex;
527     }
528
529     /**
530      * Returns the index of the time period with the minimum end milliseconds.
531      *
532      * @return The index.
533      */

534     public int getMinEndIndex() {
535         return this.minEndIndex;
536     }
537     
538     /**
539      * Returns the index of the time period with the maximum end milliseconds.
540      *
541      * @return The index.
542      */

543     public int getMaxEndIndex() {
544         return this.maxEndIndex;
545     }
546
547 }
548
Popular Tags