View Javadoc

1   /*
2    * Copyright (c) 2007 Creative Sphere Limited.
3    * All rights reserved. This program and the accompanying materials
4    * are made available under the terms of the Eclipse Public License v1.0
5    * which accompanies this distribution, and is available at
6    * http://www.eclipse.org/legal/epl-v10.html
7    *
8    * Contributors:
9    *
10   *   Creative Sphere - initial API and implementation
11   *
12   */
13  package org.abstracthorizon.aequo;
14  
15  import java.util.ArrayList;
16  import java.util.Collection;
17  import java.util.List;
18  
19  import javax.swing.DefaultListSelectionModel;
20  import javax.swing.ListSelectionModel;
21  import javax.swing.event.ListDataEvent;
22  import javax.swing.event.ListDataListener;
23  
24  /**
25   * Implementation of {@link CompareModel}.
26   * 
27   * @param <T> type
28   * @param <CompareEntryType> compare entry type of T.
29   *
30   * @author Daniel Sendula
31   *
32   */
33  public class DefaultCompareModel<T, CompareEntryType extends CompareEntry<T>> implements CompareModel<T, CompareEntryType> {
34  
35      /** List of entries */
36      protected List<CompareEntryType> entries;
37      
38      /** List of data listeners */
39      protected ArrayList<ListDataListener> listeners = new ArrayList<ListDataListener>();
40  
41      /** Default list selection model */
42      protected DefaultListSelectionModel selectionModel = new DefaultListSelectionModel();
43      
44      /** Model's width - number of columns to compare */
45      protected int width;
46      
47      /**
48       * Constructor
49       * 
50       * @param width model's width - number of columns to compare
51       */
52      public DefaultCompareModel(int width) {
53          this.width = width;
54          entries = new ArrayList<CompareEntryType>();
55      }
56      
57      /**
58       * Constructor
59       * 
60       * @param entries initial list of entries
61       */
62      public DefaultCompareModel(List<CompareEntryType> entries) {
63          this.entries = entries;
64          if (entries.size() == 0) {
65              throw new IllegalArgumentException("Supplied list must not be empty");
66          }
67          width = entries.get(0).getData().length;
68          ensureWidth(entries);
69      }
70      
71      /**
72       * Returns width - number of columns
73       * @return width of the model
74       */
75      public int getWidth() {
76          return width;
77      }
78      
79      /**
80       * Method that ensures that each entry has same length of data
81       * @param entry entry
82       * @throws IllegalArgumentException if length is not the same as model's
83       */
84      protected void ensureWidth(CompareEntryType entry) throws IllegalArgumentException {
85          if (entry.getData().length != width) {
86              throw new IllegalArgumentException("Not all elements are of the required width; width=" + width);
87          }
88      }
89      
90      /**
91       * Method that ensures that each entry from the given collection has same length of data
92       * @param entries collection of entries
93       * @throws IllegalArgumentException if length is not the same as model's
94       */
95      protected void ensureWidth(Collection<? extends CompareEntryType> entries) throws IllegalArgumentException {
96          for (CompareEntryType entry : entries) {
97              if (entry.getData().length != width) {
98                  throw new IllegalArgumentException("Not all elements are of the required width; width=" + width);
99              }
100         }
101     }
102     
103     /**
104      * Returns default selection model
105      * @return selection model
106      */
107     public ListSelectionModel getSelectionModel() {
108         return selectionModel;
109     }
110     
111     /**
112      * This method exposes internal entries list to clients. Be careful as changes to this
113      * list won't be propagated to listeners
114      * @return internal list of entries
115      */
116     public List<CompareEntryType> getAllEntries() {
117         return entries;
118     }
119     
120     /**
121      * Notifies data listeners of change
122      * @param listeners listeners to be notified
123      * @param event change
124      */
125     protected static void notifyListeners(Collection<ListDataListener> listeners, ListDataEvent event) {
126         if (event.getType() == ListDataEvent.CONTENTS_CHANGED) {
127             for (ListDataListener listener : listeners) {
128                 listener.contentsChanged(event);
129             }
130         } else if (event.getType() == ListDataEvent.INTERVAL_ADDED) {
131             for (ListDataListener listener : listeners) {
132                 listener.intervalAdded(event);
133             }
134         } else {
135             for (ListDataListener listener : listeners) {
136                 listener.intervalRemoved(event);
137             }
138         }
139     }
140     
141     /**
142      * Fires change event
143      * @param from starting index of change
144      * @param to ending index of change
145      */
146     protected void fireConentChangedEvent(int from, int to) {
147         ListDataEvent event = new ListDataEvent(DefaultCompareModel.this, ListDataEvent.CONTENTS_CHANGED, from, to);
148         notifyListeners(listeners, event);
149     }
150 
151     /**
152      * Notifies listeners of entries added
153      * @param from starting index of change
154      * @param to ending index of change
155      */
156     protected void fireIntervalAddedEvent(int from, int to) {
157         ListDataEvent event = new ListDataEvent(DefaultCompareModel.this, ListDataEvent.INTERVAL_ADDED, from, to);
158         notifyListeners(listeners, event);
159     }
160 
161     /**
162      * Notifies listeners of entries removed
163      * @param from starting index of change
164      * @param to ending index of change
165      */
166     protected void fireIntervalRemovedEvent(int from, int to) {
167         ListDataEvent event = new ListDataEvent(DefaultCompareModel.this, ListDataEvent.INTERVAL_REMOVED, from, to);
168         notifyListeners(listeners, event);
169     }
170 
171     /**
172      * Callback method where clients notify listeners of updated entries of the model
173      * @param from starting index of change
174      * @param to ending index of change
175      */
176     public void notifyUpdate(int from, int to) {
177         ListDataEvent event = new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, from, to);
178         notifyListeners(listeners, event);
179     }
180     
181     /**
182      * Adds data listener
183      * @param l listener
184      */
185     public void addListDataListener(ListDataListener l) {
186         listeners.add(l);
187     }
188 
189     /**
190      * Removes data listener
191      * @param l listener
192      */
193     public void removeListDataListener(ListDataListener l) {
194         listeners.remove(l);
195     }
196 
197     /**
198      * Returns model's column as list of data
199      * @param column column
200      * @return list of data from given column
201      */
202     public List<T> getAsList(int column) {
203         ArrayList<T> res = new ArrayList<T>();
204         for (CompareEntryType entry : entries) {
205             T o = entry.getData()[column];
206             if (o != null) {
207                 res.add(o);
208             }
209         }
210         return res;
211     }
212     
213 
214     /**
215      * Returns model's column as list of data
216      * @param column column
217      * @param start start index
218      * @param end end index
219      * @return list of data from given column
220      */
221     public List<T> getAsSubList(int column, int start, int end) {
222         ArrayList<T> res = new ArrayList<T>();
223         for (int i = start; i <= end; i++) {
224             CompareEntryType entry = get(i);
225             T o = entry.getData()[column];
226             if (o != null) {
227                 res.add(o);
228             }
229         }
230         return res;
231     }
232     
233     /**
234      * Adds new entry to the internal list
235      * @param index index to be added to
236      * @param entry entry
237      */
238     public void addImpl(int index, CompareEntryType entry) {
239         entries.add(index, entry);
240     }
241     
242     /**
243      * Adds new entry to the internal list
244      * @param entry entry
245      * @return <code>true</code> if entry is really added
246      */
247     public boolean addImpl(CompareEntryType entry) {
248         return entries.add(entry);
249     }
250     
251     /**
252      * Removes entry from the internal list
253      * @param index index
254      * @return old entry
255      */
256     public CompareEntryType removeImpl(int index) {
257         return entries.remove(index);
258     }
259     
260     /* List implementations */
261 
262     /**
263      * Adds new entry to the model
264      * @param entry entry 
265      * @return <code>true</code> model changed
266      */
267     public boolean add(CompareEntryType entry) {
268         ensureWidth(entry);
269         int i = entries.size();
270         boolean res = addImpl(entry);
271         if (res) {
272             fireIntervalAddedEvent(i, i);
273         }
274         return res;
275     }
276 
277     /**
278      * Returns entry at given index
279      * @return entry at given index
280      */
281     public CompareEntryType get(int index) {
282         return entries.get(index);
283     }
284 
285     /**
286      * Removes entry at given index
287      * @param index index
288      * @return entry at given index
289      */
290     public CompareEntryType remove(int index) {
291         CompareEntryType res = removeImpl(index);
292         fireIntervalRemovedEvent(index, index);
293         return res;
294     }
295 
296     /* ListModel implementations */
297     
298     /**
299      * Returns entry at given index
300      * @param index index
301      * @return entry at given index
302      */
303     public Object getElementAt(int index) {
304         return get(index);
305     }
306     
307     /**
308      * Returns number of entries
309      * @return number of entries
310      */
311     public int getSize() {
312         return entries.size();
313     }
314 
315 }