001/* ----------------------------------------------------------------------------
002   The Kiwi Toolkit - A Java Class Library
003   Copyright (C) 1998-2004 Mark A. Lindner
004
005   This library is free software; you can redistribute it and/or
006   modify it under the terms of the GNU General Public License as
007   published by the Free Software Foundation; either version 2 of the
008   License, or (at your option) any later version.
009
010   This library is distributed in the hope that it will be useful,
011   but WITHOUT ANY WARRANTY; without even the implied warranty of
012   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013   General Public License for more details.
014
015   You should have received a copy of the GNU General Public License
016   along with this library; if not, write to the Free Software
017   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
018   02111-1307, USA.
019 
020   The author may be contacted at: mark_a_lindner@yahoo.com
021   ----------------------------------------------------------------------------
022   $Log: OrderedListModel.java,v $
023   Revision 1.3  2004/05/13 21:40:59  markl
024   javadoc updates
025
026   Revision 1.2  2004/05/05 22:40:38  markl
027   comment block updates
028
029   Revision 1.1  2004/03/16 06:15:15  markl
030   new class
031   ----------------------------------------------------------------------------
032*/
033
034package kiwi.ui.model;
035
036import kiwi.util.*;
037
038import java.text.*;
039import java.util.*;
040import javax.swing.*;
041import javax.swing.event.*;
042
043/** An implementation of <i>ListModel</i> that keeps its elements ordered.
044 *
045 * @author Mark Lindner
046 * @since Kiwi 2.0
047 */
048
049public class OrderedListModel implements ListModel
050  {
051  private Vector data = new Vector();
052  private Vector listeners = new Vector();
053  private Collator collator;
054
055  /** Construct a new, empty <code>OrderedListModel</code>.
056   */
057  
058  public OrderedListModel()
059    {
060    collator = Collator.getInstance();
061    collator.setStrength(Collator.SECONDARY); // ignore case
062    }
063
064  /** Construct a new <code>OrderedListModel</code> with the given data.
065   *
066   * @param data A collection of elements to insert into the model. The
067   * elements are inserted in sorted order.
068   */
069
070  public OrderedListModel(Vector data)
071    {
072    this();
073
074    this.data.addAll(data);
075
076    Collections.sort(this.data);
077    }
078
079  /** Set the collator to be used by this model.
080   *
081   * @param collator The collator.
082   */
083
084  public void setCollator(Collator collator)
085    {
086    this.collator = collator;
087    }
088
089  /** Add a list data listener to this model's list of listeners.
090   *
091   * @param listener The listener to add.
092   */
093  
094  public void addListDataListener(ListDataListener listener)
095    {
096    listeners.addElement(listener);
097    }
098
099  /** Remove a list data listener from this model's list of listeners.
100   *
101   * @param listener The listener to remove.
102   */
103  
104  public void removeListDataListener(ListDataListener listener)
105    {
106    listeners.removeElement(listener);
107    }
108
109  /** Get the size of the model.
110   *
111   * @return The number of items in the model.
112   */
113  
114  public int getSize()
115    {
116    return(data.size());
117    }
118
119  /** Get the object at the given index in the model.
120   *
121   * @param index The index of the object to retrieve.
122   * @return The object at the given index, or <code>null</code> if the index
123   * is out of range.
124   */
125  
126  public Object getElementAt(int index)
127    {
128    return(data.elementAt(index));
129    }
130
131  /** Add an object to the model. The object is inserted at the proper index
132   * to maintain a sorted model.
133   *
134   * @param elem The new object to add.
135   */
136  
137  public void addElement(Object elem)
138    {
139    int index = Collections.binarySearch(data, elem, collator);
140    if(index < 0)
141      {
142      index = -index - 1;
143      
144      data.insertElementAt(elem, index);
145      fireIntervalAdded(index, index);
146      }
147    }
148
149  /** Remove all elements from the model. */
150  
151  public void clear()
152    {
153    if(! data.isEmpty())
154      {
155      int sz = data.size();
156      data.clear();
157      fireIntervalRemoved(0, sz - 1);
158      }
159    }
160
161  /** Determine if the model contains an object.
162   *
163   * @param elem The object to search for.
164   * @return <code>true</code> if the object is in the model,
165   * <code>false</code> otherwise.
166   */
167
168  public boolean contains(Object elem)
169    {
170    return(data.contains(elem));
171    }
172
173  /** Get an enumeration of the elements in the model. */
174  
175  public Enumeration elements()
176    {
177    return(data.elements());
178    }
179
180  /** Get the index of an element in the model. */
181  
182  public int indexOf(Object elem)
183    {
184    return(data.indexOf(elem));
185    }
186
187  /** Determine if the model is empty.
188   *
189   * @return <code>true</code> if there are no elements in the model,
190   * <code>false</code> otherwise.
191   */
192  
193  public boolean isEmpty()
194    {
195    return(data.isEmpty());
196    }
197
198  /** Remove an element at the given index in the model.
199   *
200   * @param index The index of the element to remove.
201   */
202  
203  public void removeElementAt(int index)
204    {
205    if((index >= 0) && (index < data.size()))
206      {
207      data.removeElementAt(index);
208      fireIntervalRemoved(index, index);
209      }
210    }
211
212  /** Remove a range of elements form the model.
213   *
214   * @param fromIndex The starting index of the range.
215   * @param toIndex The ending index of the range.
216   */
217  
218  public void removeRange(int fromIndex, int toIndex)
219    {
220    if((fromIndex >= 0) && (toIndex < data.size()) && (fromIndex <= toIndex))
221      {
222      int ct = toIndex - fromIndex;
223
224      for(int i = 0; i < ct; i++)
225        data.removeElementAt(fromIndex);
226
227      fireIntervalRemoved(fromIndex, toIndex);
228      }
229    }
230  
231  /** Fire an <i>interval added</i> event.
232   *
233   * @param start The starting index of the interval.
234   * @param end The ending index of the interval.
235   */
236
237  protected void fireIntervalAdded(int start, int end)
238    {
239    ListDataEvent evt = null;
240
241    Enumeration e = listeners.elements();
242    while(e.hasMoreElements())
243      {
244      ListDataListener l = (ListDataListener)e.nextElement();
245      if(evt == null)
246        evt = new ListDataEvent(this, ListDataEvent.INTERVAL_ADDED, start,
247                                end);
248
249      l.intervalAdded(evt);
250      }
251    }
252
253  /** Fire an <i>interval removed</i> event.
254   *
255   * @param start The starting index of the interval.
256   * @param end The ending index of the interval.
257   */
258  
259  protected void fireIntervalRemoved(int start, int end)
260    {
261    ListDataEvent evt = null;
262
263    Enumeration e = listeners.elements();
264    while(e.hasMoreElements())
265      {
266      ListDataListener l = (ListDataListener)e.nextElement();
267      if(evt == null)
268        evt = new ListDataEvent(this, ListDataEvent.INTERVAL_REMOVED, start,
269                                end);
270
271      l.intervalRemoved(evt);
272      }
273    }
274
275  /** Fire a <i>contents changed</i> event. */
276
277  protected void fireContentsChanged()
278    {
279    ListDataEvent evt = null;
280
281    Enumeration e = listeners.elements();
282    while(e.hasMoreElements())
283      {
284      ListDataListener l = (ListDataListener)e.nextElement();
285      if(evt == null)
286        evt = new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, 0,
287                                data.size() - 1);
288
289      l.contentsChanged(evt);
290      }
291    }  
292  
293  }
294
295/* end of source file */