1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package net.sf.magicproject.ui;
20
21 import java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.Collection;
24 import java.util.Collections;
25 import java.util.Iterator;
26 import java.util.List;
27 import java.util.Vector;
28
29 import javax.swing.AbstractListModel;
30 import javax.swing.JLabel;
31
32 import net.sf.magicproject.tools.MCardCompare;
33
34 /***
35 * @author <a href="mailto:fabdouglas@users.sourceforge.net">Fabrice Daugan </a>
36 * @param <T>
37 * the model type.
38 * @since 0.94
39 */
40 public class MListModel<T extends MCardCompare> extends AbstractListModel {
41
42 /***
43 * The content.
44 */
45 public final Vector<T> delegate = new Vector<T>();
46
47 /***
48 * The original content.
49 */
50 public final List<T> removedDelegate = new ArrayList<T>();
51
52 /***
53 * The label reflecting the amount of this list.
54 */
55 private final JLabel linkedAmount;
56
57 /***
58 * If <code>true</code> the amount lable is updated with the internal
59 * amount.
60 */
61 private final boolean deepSum;
62
63 /***
64 * Create a new instance of this class.
65 *
66 * @param linkedAmount
67 * the label reflecting the amount of this list.
68 * @param deepSum
69 * if <code>true</code> the amount lable is updated with the
70 * internal amount.
71 */
72 public MListModel(JLabel linkedAmount, boolean deepSum) {
73 super();
74 this.linkedAmount = linkedAmount;
75 this.deepSum = deepSum;
76 updateAmount();
77 }
78
79 /***
80 * Returns the number of components in this list.
81 * <p>
82 * This method is identical to <code>size</code>, which implements the
83 * <code>List</code> interface defined in the 1.2 Collections framework.
84 * This method exists in conjunction with <code>setSize</code> so that
85 * <code>size</code> is identifiable as a JavaBean property.
86 *
87 * @return the number of components in this list
88 * @see #size()
89 */
90 public int getSize() {
91 return delegate.size();
92 }
93
94 /***
95 * Returns the component at the specified index. <blockquote> <b>Note:</b>
96 * Although this method is not deprecated, the preferred method to use is
97 * <code>get(int)</code>, which implements the <code>List</code>
98 * interface defined in the 1.2 Collections framework. </blockquote>
99 *
100 * @param index
101 * an index into this list
102 * @return the component at the specified index
103 * @exception ArrayIndexOutOfBoundsException
104 * if the <code>index</code> is negative or greater than the
105 * current size of this list
106 * @see #get(int)
107 */
108 public T getElementAt(int index) {
109 return delegate.get(index);
110 }
111
112 /***
113 * Returns the number of components in this list.
114 *
115 * @return the number of components in this list
116 * @see List#size()
117 */
118 public int size() {
119 return delegate.size();
120 }
121
122 /***
123 * Tests whether this list has any components.
124 *
125 * @return <code>true</code> if and only if this list has no components,
126 * that is, its size is zero; <code>false</code> otherwise
127 * @see List#isEmpty()
128 */
129 public boolean isEmpty() {
130 return delegate.isEmpty();
131 }
132
133 /***
134 * Returns an enumeration of the components of this list.
135 *
136 * @return an enumeration of the components of this list
137 * @see List#iterator()
138 */
139 public Iterator<T> iterator() {
140 return delegate.iterator();
141 }
142
143 /***
144 * Tests whether the specified object is a component in this list.
145 *
146 * @param elem
147 * an object
148 * @return <code>true</code> if the specified object is the same as a
149 * component in this list
150 * @see List#contains(Object)
151 */
152 public boolean contains(T elem) {
153 return delegate.contains(elem);
154 }
155
156 /***
157 * Searches for the first occurrence of <code>elem</code>.
158 *
159 * @param elem
160 * an object
161 * @return the index of the first occurrence of the argument in this list;
162 * returns <code>-1</code> if the object is not found
163 * @see List#indexOf(Object)
164 */
165 public int indexOf(T elem) {
166 return delegate.indexOf(elem);
167 }
168
169 /***
170 * Searches for the first occurrence of <code>elem</code>.
171 *
172 * @param elem
173 * an object
174 * @return the index of the first occurrence of the argument in this list;
175 * returns <code>-1</code> if the object is not found
176 * @see List#indexOf(Object)
177 */
178 public int indexOf(String elem) {
179 for (int i = 0; i < delegate.size(); i++) {
180 if (delegate.get(i).equals(elem))
181 return i;
182 }
183 return -1;
184 }
185
186 /***
187 * Returns the index of the last occurrence of <code>elem</code>.
188 *
189 * @param elem
190 * the desired component
191 * @return the index of the last occurrence of <code>elem</code> in the
192 * list; returns <code>-1</code> if the object is not found
193 * @see List#lastIndexOf(Object)
194 */
195 public int lastIndexOf(T elem) {
196 return delegate.lastIndexOf(elem);
197 }
198
199 /***
200 * Returns the component at the specified index. Throws an
201 * <code>ArrayIndexOutOfBoundsException</code> if the index is negative or
202 * not less than the size of the list. <blockquote> <b>Note:</b> Although
203 * this method is not deprecated, the preferred method to use is
204 * <code>get(int)</code>, which implements the <code>List</code>
205 * interface defined in the 1.2 Collections framework. </blockquote>
206 *
207 * @param index
208 * an index into this list
209 * @return the component at the specified index
210 * @see #get(int)
211 * @see List#get(int)
212 */
213 public T elementAt(int index) {
214 return delegate.get(index);
215 }
216
217 /***
218 * Sets the component at the specified <code>index</code> of this list to be
219 * the specified object. The previous component at that position is discarded.
220 * <p>
221 * Throws an <code>ArrayIndexOutOfBoundsException</code> if the index is
222 * invalid. <blockquote> <b>Note:</b> Although this method is not deprecated,
223 * the preferred method to use is <code>set(int,Object)</code>, which
224 * implements the <code>List</code> interface defined in the 1.2 Collections
225 * framework. </blockquote>
226 *
227 * @param obj
228 * what the component is to be set to
229 * @param index
230 * the specified index
231 * @see List#set(int, Object)
232 */
233 public void setElementAt(T obj, int index) {
234 delegate.set(index, obj);
235 fireContentsChanged(this, index, index);
236 }
237
238 /***
239 * Adds the specified component to the end of this list.
240 *
241 * @param obj
242 * the component to be added
243 * @see List#add(Object)
244 */
245 public void add(T obj) {
246 int index = delegate.size();
247 delegate.add(obj);
248 fireIntervalAdded(this, index, index);
249 updateAmount();
250 }
251
252 /***
253 * Removes the first (lowest-indexed) occurrence of the argument from this
254 * list.
255 *
256 * @param obj
257 * the component to be removed
258 * @return <code>true</code> if the argument was a component of this list;
259 * <code>false</code> otherwise
260 * @see List#remove(Object)
261 */
262 public boolean remove(T obj) {
263 int index = indexOf(obj);
264 boolean rv = delegate.remove(obj);
265 if (index >= 0) {
266 fireIntervalRemoved(this, index, index);
267 }
268 updateAmount();
269 return rv;
270 }
271
272 /***
273 * Returns a string that displays and identifies this object's properties.
274 *
275 * @return a String representation of this object
276 */
277 @Override
278 public String toString() {
279 return delegate.toString();
280 }
281
282 /***
283 * Returns the element at the specified position in this list.
284 * <p>
285 * Throws an <code>ArrayIndexOutOfBoundsException</code> if the index is out
286 * of range (<code>index < 0 || index >= size()</code>).
287 *
288 * @param index
289 * index of element to return
290 * @return the object.
291 */
292 public T get(int index) {
293 return delegate.get(index);
294 }
295
296 /***
297 * Replaces the element at the specified position in this list with the
298 * specified element.
299 * <p>
300 * Throws an <code>ArrayIndexOutOfBoundsException</code> if the index is out
301 * of range (<code>index < 0 || index >= size()</code>).
302 *
303 * @param index
304 * index of element to replace
305 * @param element
306 * element to be stored at the specified position
307 * @return the element previously at the specified position
308 */
309 public T set(int index, T element) {
310 T rv = delegate.get(index);
311 delegate.set(index, element);
312 fireContentsChanged(this, index, index);
313 updateAmount();
314 return rv;
315 }
316
317 /***
318 * Inserts the specified object as a component in this list at the specified
319 * <code>index</code>.
320 * <p>
321 * Throws an <code>ArrayIndexOutOfBoundsException</code> if the index is
322 * invalid. <blockquote> <b>Note:</b> Although this method is not deprecated,
323 * the preferred method to use is <code>add(int,Object)</code>, which
324 * implements the <code>List</code> interface defined in the 1.2 Collections
325 * framework. </blockquote>
326 *
327 * @param obj
328 * the component to insert
329 * @param index
330 * where to insert the new component
331 * @exception ArrayIndexOutOfBoundsException
332 * if the index was invalid
333 */
334 public void insertElementAt(T obj, int index) {
335 delegate.insertElementAt(obj, index);
336 fireIntervalAdded(this, index, index);
337 updateAmount();
338 }
339
340 /***
341 * Removes the element at the specified position in this list. Returns the
342 * element that was removed from the list.
343 * <p>
344 * Throws an <code>ArrayIndexOutOfBoundsException</code> if the index is out
345 * of range (<code>index < 0 || index >= size()</code>).
346 *
347 * @param index
348 * the index of the element to removed
349 * @return the removed object.
350 */
351 public T remove(int index) {
352 T rv = delegate.get(index);
353 delegate.remove(index);
354 fireIntervalRemoved(this, index, index);
355 updateAmount();
356 return rv;
357 }
358
359 /***
360 * Removes all of the elements from this list. The list will be empty after
361 * this call returns (unless it throws an exception).
362 */
363 public void clear() {
364 int index1 = delegate.size() - 1;
365 delegate.clear();
366 if (index1 >= 0) {
367 fireIntervalRemoved(this, 0, index1);
368 }
369 updateAmount();
370 }
371
372 /***
373 * Returns an array containing all of the elements in this list in proper
374 * sequence (from first to last element).
375 * <p>
376 * The returned array will be "safe" in that no references to it are
377 * maintained by this list. (In other words, this method must allocate a new
378 * array even if this list is backed by an array). The caller is thus free to
379 * modify the returned array.
380 * <p>
381 * This method acts as bridge between array-based and collection-based APIs.
382 *
383 * @return an array containing all of the elements in this list in proper
384 * sequence
385 * @see Arrays#asList(Object[])
386 */
387 @SuppressWarnings("unchecked")
388 public T[] toArray() {
389 return (T[]) delegate.toArray();
390 }
391
392 /***
393 * Removes from this Vector all of its elements that are contained in the
394 * specified Collection.
395 *
396 * @param c
397 * a collection of elements to be removed from the Vector
398 * @return true if this Vector changed as a result of the call
399 * @throws ClassCastException
400 * if the types of one or more elements in this vector are
401 * incompatible with the specified collection (optional)
402 * @throws NullPointerException
403 * if this vector contains one or more null elements and the
404 * specified collection does not support null elements (optional),
405 * or if the specified collection is null
406 * @since 1.2
407 */
408 public boolean removeAll(Collection<T> c) {
409 removedDelegate.addAll(c);
410 delegate.removeAll(c);
411 updateAmount();
412 return true;
413 }
414
415 /***
416 * Appends all of the elements in the specified Collection to the end of this
417 * Vector, in the order that they are returned by the specified Collection's
418 * Iterator. The behavior of this operation is undefined if the specified
419 * Collection is modified while the operation is in progress. (This implies
420 * that the behavior of this call is undefined if the specified Collection is
421 * this Vector, and this Vector is nonempty.)
422 *
423 * @param c
424 * elements to be inserted into this Vector
425 * @return {@code true} if this Vector changed as a result of the call
426 * @throws NullPointerException
427 * if the specified collection is null
428 * @since 1.2
429 */
430 public boolean addAll(Collection<T> c) {
431 removedDelegate.removeAll(c);
432 delegate.addAll(c);
433 Collections.sort(delegate);
434 updateAmount();
435 return true;
436 }
437
438 /***
439 * Update the amount in the attached label.
440 */
441 private void updateAmount() {
442 int rightAmount;
443 if (deepSum) {
444 rightAmount = 0;
445 for (MCardCompare card : delegate) {
446 rightAmount += card.getAmount();
447 }
448 } else {
449 rightAmount = removedDelegate.size() + delegate.size();
450 }
451 linkedAmount.setText("<html>" + delegate.size() + "/" + rightAmount);
452 fireIntervalAdded(this, 0, 0);
453 }
454 }