KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jcckit > data > DataContainer


1 /*
2  * Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
3  *
4  * This library is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as published by
6  * the Free Software Foundation; either version 2.1 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU Lesser General Public License for more details
13  * (http://www.gnu.org/copyleft/lesser.html).
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  */

19 package jcckit.data;
20
21 import java.text.*;
22 import java.util.*;
23
24 /**
25  * Abstract superclass of all data containers. A data container holds an
26  * ordered list of {@link DataElement DataElements} of the same type.
27  * <p>
28  * Data elements can be added, inserted, removed, or replaced.
29  * Such an action leads to a {@link DataEvent} which will be delivered to
30  * all {@link DataListener DataListeners} observing this
31  * <code>DataContainer</code>. If this data container also implements
32  * {@link DataEvent} (as {@link DataCurve} does) also the listeners
33  * registrated at the data container containg this container will be notified.
34  * As a consequence a <tt>DataListener</tt> must only be registered at the
35  * {@link DataPlot} instance and it will automatically also received events
36  * caused by manipulating one of its <tt>DataCurves</tt>.
37  * <p>
38  * Concrete subclasses have to implement {@link #isValid} which
39  * checks whether the added or inserted <tt>DataElement</tt> is of the right
40  * type. This is an application of the Template Method Design Pattern.
41  *
42  * @author Franz-Josef Elmer
43  */

44 public abstract class DataContainer {
45   private final static String JavaDoc TEMPLATE
46       = "Invalid operation: {0}, Element: {1}, Container: {2}";
47   final static String JavaDoc ADD = "add",
48                       REPLACE = "replace",
49                       INSERT = "insert";
50
51   private final Vector _listeners = new Vector();
52   private final Vector _container = new Vector();
53
54   /** Adds a {@link DataListener}. Does nothing if already added. */
55   public void addDataListener(DataListener listener) {
56     if (!_listeners.contains(listener)) {
57       _listeners.addElement(listener);
58     }
59   }
60
61   /** Removes a {@link DataListener}. Does nothing if already removed. */
62   public void removeDataListener(DataListener listener) {
63     _listeners.removeElement(listener);
64   }
65
66   private void notifyListeners(DataEvent event) {
67     for (int i = 0, n = _listeners.size(); i < n; i++) {
68       ((DataListener) _listeners.elementAt(i)).dataChanged(event);
69     }
70     // Notifies also parent container
71
if (this instanceof DataElement) {
72       DataContainer container = ((DataElement) this).getContainer();
73       if (container != null) {
74         container.notifyListeners(event);
75       }
76     }
77   }
78
79   /** Returns the number of elements of this container. */
80   public int getNumberOfElements() {
81     return _container.size();
82   }
83
84   /** Returns the element for the specified index. */
85   public DataElement getElement(int index) {
86     return (DataElement) _container.elementAt(index);
87   }
88   
89   /**
90    * Returns the index of the specified element.
91    * @param element Element to be looked for.
92    * @return -1 if not found.
93    */

94   public int getIndexOf(DataElement element) {
95     return _container.indexOf(element);
96   }
97
98   /**
99    * Adds a {@link DataElement}. After the element has been successfully
100    * added all {@link DataListener DataListeners} will be informed.
101    * @param element DataElement to be added.
102    * @throws IllegalArgumentException if <tt>element</tt> is not of the correct
103    * type which will be checked by the method {@link #isValid}.
104    */

105   public void addElement(DataElement element) {
106     if (isValid(element)) {
107       _container.addElement(element);
108       element.setContainer(this);
109       notifyListeners(DataEvent.createAddEvent(this));
110     } else {
111       throwException(ADD, element);
112     }
113   }
114
115   /**
116    * Inserts a {@link DataElement} at the specified index.
117    * After the element has been successfully inserted
118    * all {@link DataListener DataListeners} will be informed.
119    * @param index Index at which <tt>element</tt> will be inserted.
120    * All elements with an index &gt;= <tt>index</tt> will be shifted.
121    * @param element DataElement to be added.
122    * @throws IllegalArgumentException if <tt>element</tt> is not of the correct
123    * type which will be checked by the method {@link #isValid}.
124    */

125   public void insertElementAt(int index, DataElement element) {
126     if (isValid(element)) {
127       _container.insertElementAt(element, index);
128       element.setContainer(this);
129       notifyListeners(DataEvent.createInsertEvent(this, index));
130     } else {
131       throwException(INSERT, element);
132     }
133   }
134
135   /**
136    * Removes a {@link DataElement} at the specified index.
137    * After the element has been successfully removed
138    * all {@link DataListener DataListeners} will be informed.
139    * @param index Index of the element which will be removed.
140    * All elements with an index &gt; <tt>index</tt> will be shifted.
141    */

142   public void removeElementAt(int index) {
143     DataElement element = (DataElement) _container.elementAt(index);
144     element.setContainer(null);
145     _container.removeElementAt(index);
146     notifyListeners(DataEvent.createRemoveEvent(this, index, element));
147   }
148
149   /**
150    * Replaces the {@link DataElement} at the specified index.
151    * After the element has been successfully replaced
152    * all {@link DataListener DataListeners} will be informed.
153    * @param index Index of the element which will be replaced by
154    * <tt>element</tt>.
155    * @param element The new <tt>DataElement</tt>.
156    * @throws IllegalArgumentException if <tt>element</tt> is not of the correct
157    * type which will be checked by the method {@link #isValid}.
158    */

159   public void replaceElementAt(int index, DataElement element) {
160     if (isValid(element)) {
161       DataElement oldElement = (DataElement) _container.elementAt(index);
162       oldElement.setContainer(null);
163       _container.setElementAt(element, index);
164       element.setContainer(this);
165       notifyListeners(DataEvent.createReplaceEvent(this, index, oldElement));
166     } else {
167       throwException(REPLACE, element);
168     }
169   }
170
171   private void throwException(String JavaDoc operation, DataElement element) {
172     throw new IllegalArgumentException JavaDoc(MessageFormat.format(TEMPLATE,
173                 new Object JavaDoc[] {operation, element, this.getClass().getName()}));
174   }
175
176   /**
177    * Returns <tt>true</tt> if the specified {@link DataElement} has the
178    * correct type. Concrete subclasses have to implement this method.
179    * @param element <tt>DataElement</tt> to be checked.
180    */

181   protected abstract boolean isValid(DataElement element);
182 }
183
Popular Tags