001/* DefaultListSelectionModel.java --
002   Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
003
004This file is part of GNU Classpath.
005
006GNU Classpath is free software; you can redistribute it and/or modify
007it under the terms of the GNU General Public License as published by
008the Free Software Foundation; either version 2, or (at your option)
009any later version.
010
011GNU Classpath is distributed in the hope that it will be useful, but
012WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014General Public License for more details.
015
016You should have received a copy of the GNU General Public License
017along with GNU Classpath; see the file COPYING.  If not, write to the
018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
01902110-1301 USA.
020
021Linking this library statically or dynamically with other modules is
022making a combined work based on this library.  Thus, the terms and
023conditions of the GNU General Public License cover the whole
024combination.
025
026As a special exception, the copyright holders of this library give you
027permission to link this library with independent modules to produce an
028executable, regardless of the license terms of these independent
029modules, and to copy and distribute the resulting executable under
030terms of your choice, provided that you also meet, for each linked
031independent module, the terms and conditions of the license of that
032module.  An independent module is a module which is not derived from
033or based on this library.  If you modify this library, you may extend
034this exception to your version of the library, but you are not
035obligated to do so.  If you do not wish to do so, delete this
036exception statement from your version. */
037
038
039package javax.swing;
040
041import java.io.Serializable;
042import java.util.BitSet;
043import java.util.EventListener;
044
045import javax.swing.event.EventListenerList;
046import javax.swing.event.ListSelectionEvent;
047import javax.swing.event.ListSelectionListener;
048
049/**
050 * The default implementation of {@link ListSelectionModel},
051 * which is used by {@link javax.swing.JList} and
052 * similar classes to manage the selection status of a number of data
053 * elements.
054 *
055 * <p>The class is organized <em>abstractly</em> as a set of intervals of
056 * integers. Each interval indicates an inclusive range of indices in a
057 * list -- held by some other object and unknown to this class -- which is
058 * considered "selected". There are various accessors for querying and
059 * modifying the set of intervals, with simplified forms accepting a single
060 * index, representing an interval with only one element. </p>
061 */
062public class DefaultListSelectionModel implements Cloneable,
063                                                  ListSelectionModel,
064                                                  Serializable
065{
066  private static final long serialVersionUID = -5718799865110415860L;
067
068  /** The list of ListSelectionListeners subscribed to this selection model. */
069  protected EventListenerList listenerList = new EventListenerList();
070
071
072  /** 
073   * The current list selection mode. Must be one of the numeric constants
074   * <code>SINGLE_SELECTION</code>, <code>SINGLE_INTERVAL_SELECTION</code>
075   * or <code>MULTIPLE_INTERVAL_SELECTION</code> from {@link
076   * ListSelectionModel}. The default value is
077   * <code>MULTIPLE_INTERVAL_SELECTION</code>.
078   */
079  int selectionMode = MULTIPLE_INTERVAL_SELECTION;
080
081  /**
082   * The index of the "lead" of the most recent selection. The lead is the
083   * second argument in any call to {@link #setSelectionInterval}, {@link
084   * #addSelectionInterval} or {@link #removeSelectionInterval}. Generally
085   * the lead refers to the most recent position a user dragged their mouse
086   * over.
087   */
088  int leadSelectionIndex = -1;
089
090  /**
091   * The index of the "anchor" of the most recent selection. The anchor is
092   * the first argument in any call to {@link #setSelectionInterval},
093   * {@link #addSelectionInterval} or {@link
094   * #removeSelectionInterval}. Generally the anchor refers to the first
095   * recent position a user clicks when they begin to drag their mouse over
096   * a list.
097   *
098   * @see #getAnchorSelectionIndex
099   * @see #setAnchorSelectionIndex
100   */
101  int anchorSelectionIndex = -1;
102
103  /**
104   * controls the range of indices provided in any {@link
105   * ListSelectionEvent} fired by the selectionModel. Let
106   * <code>[A,L]</code> be the range of indices between {@link
107   * #anchorSelectionIndex} and {@link #leadSelectionIndex} inclusive, and
108   * let <code>[i0,i1]</code> be the range of indices changed in a given
109   * call which generates a {@link ListSelectionEvent}. Then when this
110   * property is <code>true</code>, the {@link ListSelectionEvent} contains
111   * the range <code>[A,L] union [i0,i1]</code>; when <code>false</code> it
112   * will contain only <code>[i0,i1]</code>. The default is
113   * <code>true</code>.
114   *
115   * @see #isLeadAnchorNotificationEnabled
116   * @see #setLeadAnchorNotificationEnabled
117   */
118  protected boolean leadAnchorNotificationEnabled = true;
119
120  /**
121   * Whether the selection is currently "adjusting". Any {@link
122   * ListSelectionEvent} events constructed in response to changes in this
123   * list selection model will have their {@link
124   * ListSelectionEvent#isAdjusting} field set to this value.
125   *
126   * @see #getValueIsAdjusting
127   * @see #setValueIsAdjusting
128   */
129  boolean valueIsAdjusting = false;
130
131
132  /** 
133   * The current set of "intervals", represented simply by a {@link
134   * java.util.BitSet}. A set bit indicates a selected index, whereas a
135   * cleared bit indicates a non-selected index.
136   */
137  BitSet sel = new BitSet();
138
139  /**
140   * A variable to store the previous value of sel.
141   * Used to make sure we only fireValueChanged when the BitSet
142   * actually does change.
143   */
144  Object oldSel;
145
146  /**
147   * Whether this call of setLeadSelectionInterval was called locally
148   * from addSelectionInterval
149   */
150  boolean setLeadCalledFromAdd = false;
151
152  /**
153   * Returns the selection mode, which is one of {@link #SINGLE_SELECTION}, 
154   * {@link #SINGLE_INTERVAL_SELECTION} and 
155   * {@link #MULTIPLE_INTERVAL_SELECTION}.  The default value is
156   * {@link #MULTIPLE_INTERVAL_SELECTION}.
157   * 
158   * @return The selection mode.
159   * 
160   * @see #setSelectionMode(int)
161   */
162  public int getSelectionMode()
163  {
164    return selectionMode;
165  }
166
167  /**
168   * Sets the value of the {@link #selectionMode} property.
169   *
170   * @param mode The new value of the property
171   */
172  public void setSelectionMode(int mode)
173  {
174    if (mode < ListSelectionModel.SINGLE_SELECTION 
175        || mode > ListSelectionModel.MULTIPLE_INTERVAL_SELECTION)
176      throw new IllegalArgumentException("Unrecognised mode: " + mode);
177    selectionMode = mode;
178  }
179
180  /**
181   * Gets the value of the {@link #anchorSelectionIndex} property.
182   * 
183   * @return The current property value
184   *
185   * @see #setAnchorSelectionIndex
186   */
187  public int getAnchorSelectionIndex()
188  {
189    return anchorSelectionIndex;
190  }
191
192  /**
193   * Sets the value of the {@link #anchorSelectionIndex} property.
194   * 
195   * @param index The new property value
196   *
197   * @see #getAnchorSelectionIndex
198   */
199  public void setAnchorSelectionIndex(int index)
200  {
201    if (anchorSelectionIndex != index)
202      {
203        int old = anchorSelectionIndex;
204        anchorSelectionIndex = index;
205        if (leadAnchorNotificationEnabled)
206          fireValueChanged(index, old);
207      }
208  }
209  
210  /**
211   * Gets the value of the {@link #leadSelectionIndex} property.
212   * 
213   * @return The current property value
214   *
215   * @see #setLeadSelectionIndex
216   */
217  public int getLeadSelectionIndex()
218  {
219    return leadSelectionIndex;
220  }
221
222  /**
223   * <p>Sets the value of the {@link #anchorSelectionIndex} property. As a
224   * side effect, alters the selection status of two ranges of indices. Let
225   * <code>OL</code> be the old lead selection index, <code>NL</code> be
226   * the new lead selection index, and <code>A</code> be the anchor
227   * selection index. Then if <code>A</code> is a valid selection index,
228   * one of two things happens depending on the seleciton status of
229   * <code>A</code>:</p>
230   *
231   * <ul>
232   *
233   * <li><code>isSelectedIndex(A) == true</code>: set <code>[A,OL]</code>
234   * to <em>deselected</em>, then set <code>[A,NL]</code> to
235   * <em>selected</em>.</li>
236   *
237   * <li><code>isSelectedIndex(A) == false</code>: set <code>[A,OL]</code>
238   * to <em>selected</em>, then set <code>[A,NL]</code> to
239   * <em>deselected</em>.</li>
240   *
241   * </ul>
242   *
243   * <p>This method generates at most a single {@link ListSelectionEvent}
244   * despite changing multiple ranges. The range of values provided to the
245   * {@link ListSelectionEvent} includes only the minimum range of values
246   * which changed selection status between the beginning and end of the
247   * method.</p>
248   * 
249   * @param leadIndex The new property value
250   *
251   * @see #getAnchorSelectionIndex
252   */
253  public void setLeadSelectionIndex(int leadIndex)
254  {
255    // Only set the lead selection index to < 0 if anchorSelectionIndex < 0.
256    if (leadIndex < 0)
257      {
258        if (anchorSelectionIndex < 0)
259          leadSelectionIndex = -1;
260        else
261          return;
262      }
263
264    // Only touch the lead selection index if the anchor is >= 0.
265    if (anchorSelectionIndex < 0)
266      return;
267
268    if (selectionMode == SINGLE_SELECTION)
269      setSelectionInterval (leadIndex, leadIndex);
270    
271    int oldLeadIndex = leadSelectionIndex;
272    if (oldLeadIndex == -1)
273      oldLeadIndex = leadIndex;
274    if (setLeadCalledFromAdd == false)
275      oldSel = sel.clone();
276    leadSelectionIndex = leadIndex;
277
278    if (anchorSelectionIndex == -1)
279      return;    
280    
281    int R1 = Math.min(anchorSelectionIndex, oldLeadIndex);
282    int R2 = Math.max(anchorSelectionIndex, oldLeadIndex);
283    int S1 = Math.min(anchorSelectionIndex, leadIndex);
284    int S2 = Math.max(anchorSelectionIndex, leadIndex);
285
286    int lo = Math.min(R1, S1);
287    int hi = Math.max(R2, S2);
288
289    if (isSelectedIndex(anchorSelectionIndex))
290      {
291        sel.clear(R1, R2+1);
292        sel.set(S1, S2+1);
293      }
294    else
295      {
296        sel.set(R1, R2+1);
297        sel.clear(S1, S2+1);
298      }    
299
300    int beg = sel.nextSetBit(0), end = -1;
301    for(int i=beg; i >= 0; i=sel.nextSetBit(i+1)) 
302      end = i;
303    
304    BitSet old = (BitSet) oldSel;
305    
306    // The new and previous lead location requires repainting.
307    old.set(oldLeadIndex, !sel.get(oldLeadIndex));
308    old.set(leadSelectionIndex, !sel.get(leadSelectionIndex));
309    
310    fireDifference(sel, old);
311  }
312
313  /**
314   * Moves the lead selection index to <code>leadIndex</code> without 
315   * changing the selection values.
316   * 
317   * If leadAnchorNotificationEnabled is true, send a notification covering the
318   * old and new lead cells.
319   * 
320   * @param leadIndex the new lead selection index
321   * @since 1.5
322   */
323  public void moveLeadSelectionIndex (int leadIndex)
324  {
325    if (leadSelectionIndex == leadIndex)
326      return;
327    
328    leadSelectionIndex = leadIndex;
329    if (isLeadAnchorNotificationEnabled())
330      fireValueChanged(Math.min(leadSelectionIndex, leadIndex),
331                       Math.max(leadSelectionIndex, leadIndex));
332  }
333  
334  /**
335   * Gets the value of the {@link #leadAnchorNotificationEnabled} property.
336   * 
337   * @return The current property value
338   *
339   * @see #setLeadAnchorNotificationEnabled
340   */
341  public boolean isLeadAnchorNotificationEnabled()
342  {
343    return leadAnchorNotificationEnabled;
344  }
345
346  /**
347   * Sets the value of the {@link #leadAnchorNotificationEnabled} property.
348   * 
349   * @param l The new property value
350   *
351   * @see #isLeadAnchorNotificationEnabled
352   */
353  public void setLeadAnchorNotificationEnabled(boolean l)
354  {
355    leadAnchorNotificationEnabled = l;
356  }
357
358  /**
359   * Gets the value of the {@link #valueIsAdjusting} property.
360   *
361   * @return The current property value
362   *
363   * @see #setValueIsAdjusting
364   */
365  public boolean getValueIsAdjusting()
366  {
367    return valueIsAdjusting;
368  }
369
370  /**
371   * Sets the value of the {@link #valueIsAdjusting} property.
372   *
373   * @param v The new property value
374   *
375   * @see #getValueIsAdjusting
376   */
377  public void setValueIsAdjusting(boolean v)
378  {
379    valueIsAdjusting = v;
380  }
381
382  /**
383   * Determines whether the selection is empty.
384   *
385   * @return <code>true</code> if the selection is empty, otherwise
386   * <code>false</code>
387   */
388  public boolean isSelectionEmpty()
389  {
390    return sel.isEmpty();
391  }
392
393  /**
394   * Gets the smallest index which is currently a member of a selection
395   * interval.
396   *
397   * @return The least integer <code>i</code> such that <code>i >=
398   *     0</code> and <code>i</code> is a member of a selected interval, or
399   *     <code>-1</code> if there are no selected intervals
400   *
401   * @see #getMaxSelectionIndex
402   */
403  public int getMinSelectionIndex()
404  {
405    if (isSelectionEmpty())
406      return -1;
407    
408    return sel.nextSetBit(0);
409  }
410
411  /**
412   * Gets the largest index which is currently a member of a selection
413   * interval.
414   *
415   * @return The greatest integer <code>i</code> such that <code>i >=
416   *     0</code> and <code>i</code> is a member of a selected interval, or
417   *     <code>-1</code> if there are no selected intervals
418   *
419   * @see #getMinSelectionIndex
420   */
421  public int getMaxSelectionIndex()
422  {
423    if (isSelectionEmpty())
424      return -1;
425
426    int mx = -1;
427    for(int i=sel.nextSetBit(0); i >= 0; i=sel.nextSetBit(i+1)) 
428      { 
429        mx = i;
430      }
431    return mx;
432  }
433
434  /**
435   * Determines whether a particular index is a member of a selection
436   * interval.
437   *
438   * @param a The index to search for
439   *
440   * @return <code>true</code> if the index is a member of a selection interval,
441   *     otherwise <code>false</code>
442   */
443  public boolean isSelectedIndex(int a)
444  {
445    // TODO: Probably throw an exception here?
446    if (a >= sel.length() || a < 0)
447      return false;
448    return sel.get(a);
449  }
450
451  /**
452   * If the {@link #selectionMode} property is equal to
453   * <code>SINGLE_SELECTION</code> equivalent to calling
454   * <code>setSelectionInterval(index1, index2)</code>; 
455   * If the {@link #selectionMode} property is equal to 
456   * <code>SINGLE_INTERVAL_SELECTION</code> and the interval being
457   * added is not adjacent to an already selected interval,
458   * equivalent to <code>setSelectionInterval(index1, index2)</code>.
459   * Otherwise adds the range <code>[index0, index1]</code> 
460   * to the selection interval set.
461   *
462   * @param index0 The beginning of the range of indices to select
463   * @param index1 The end of the range of indices to select
464   *
465   * @see #setSelectionInterval
466   * @see #removeSelectionInterval
467   */
468  public void addSelectionInterval(int index0, int index1) 
469  {
470    if (index0 == -1 || index1 == -1)
471      return;
472    
473    if (selectionMode == SINGLE_SELECTION)
474      setSelectionInterval(index0, index1);
475    else
476    {
477    int lo = Math.min(index0, index1);
478    int hi = Math.max(index0, index1);
479    oldSel = sel.clone();
480
481
482    // COMPAT: Like Sun (but not like IBM), we allow calls to 
483    // addSelectionInterval when selectionMode is
484    // SINGLE_SELECTION_INTERVAL iff the interval being added
485    // is adjacent to an already selected interval
486    if (selectionMode == SINGLE_INTERVAL_SELECTION)
487      if (!(isSelectedIndex(index0) || 
488            isSelectedIndex(index1) || 
489            isSelectedIndex(Math.max(lo-1,0)) || 
490            isSelectedIndex(Math.min(hi+1,sel.size()))))
491        sel.clear();    
492
493    // We have to update the anchorSelectionIndex and leadSelectionIndex
494    // variables
495    
496    // The next if statements breaks down to "if this selection is adjacent
497    // to the previous selection and going in the same direction"
498    if ((isSelectedIndex(leadSelectionIndex)) 
499        && ((index0 - 1 == leadSelectionIndex 
500             && (index1 >= index0) 
501             && (leadSelectionIndex >= anchorSelectionIndex))
502            || (index0 + 1 == leadSelectionIndex && (index1 <= index0) 
503                && (leadSelectionIndex <= anchorSelectionIndex)))
504        && (anchorSelectionIndex != -1 || leadSelectionIndex != -1))
505      {
506        // setting setLeadCalledFromAdd to true tells setLeadSelectionIndex
507        //   not to update oldSel
508        setLeadCalledFromAdd = true;
509        setLeadSelectionIndex(index1);
510        setLeadCalledFromAdd = false;
511      }
512    else
513      {
514        leadSelectionIndex = index1;
515        anchorSelectionIndex = index0;
516        sel.set(lo, hi+1);
517        fireDifference(sel, (BitSet) oldSel);
518      }
519    }
520  }
521
522
523  /**
524   * Deselects all indices in the inclusive range
525   * <code>[index0,index1]</code>.
526   *
527   * @param index0 The beginning of the range of indices to deselect
528   * @param index1 The end of the range of indices to deselect
529   *
530   * @see #addSelectionInterval
531   * @see #setSelectionInterval
532   */
533  public void removeSelectionInterval(int index0,
534                                      int index1)
535  {
536    if (index0 == -1 || index1 == -1)
537      return;
538    
539    oldSel = sel.clone();
540    int lo = Math.min(index0, index1);
541    int hi = Math.max(index0, index1);
542    
543    // if selectionMode is SINGLE_INTERVAL_SELECTION and removing the interval
544    //   (index0,index1) would leave two disjoint selection intervals, remove all
545    //   selected indices from lo to the last selected index
546    if (getMinSelectionIndex() > 0 && getMinSelectionIndex() < lo && 
547        selectionMode == SINGLE_INTERVAL_SELECTION)
548      hi = sel.size() - 1;
549
550    sel.clear(lo, hi+1); 
551    //update anchorSelectionIndex and leadSelectionIndex variables
552    //TODO: will probably need MouseDragged to test properly and know if this works
553    setAnchorSelectionIndex(index0);
554    leadSelectionIndex = index1;
555    
556    fireDifference(sel, (BitSet) oldSel);
557  }
558
559  /**
560   * Removes all intervals in the selection set.
561   */
562  public void clearSelection()
563  {
564    // Find the selected interval.
565    int from = sel.nextSetBit(0);
566    if (from < 0)
567      return; // Empty selection - nothing to do.
568    int to = from;
569    
570    int i;
571
572    for (i = from; i>=0; i=sel.nextSetBit(i+1))
573      to = i;
574    
575    sel.clear();
576    fireValueChanged(from, to, valueIsAdjusting);
577  }
578  
579  /**
580   * Fire the change event, covering the difference between the two sets.
581   * 
582   * @param current the current set
583   * @param x the previous set, the object will be reused.
584   */
585  private void fireDifference(BitSet current, BitSet x)
586  {
587    x.xor(current);
588    int from = x.nextSetBit(0);
589    if (from < 0)
590      return; // No difference.
591    int to = from;
592    int i;
593
594    for (i = from; i >= 0; i = x.nextSetBit(i+1))
595      to = i;
596
597    fireValueChanged(from, to, valueIsAdjusting);
598  }
599  
600  /**
601   * Clears the current selection and marks a given interval as "selected". If
602   * the current selection mode is <code>SINGLE_SELECTION</code> only the
603   * index <code>index2</code> is selected.
604   * 
605   * @param anchor  the anchor selection index.
606   * @param lead  the lead selection index.
607   */
608  public void setSelectionInterval(int anchor, int lead)
609  {
610    if (anchor == -1 || lead == -1)
611      return;
612    if (selectionMode == SINGLE_SELECTION)
613      {
614        int lo = lead;
615        int hi = lead;
616        int selected = sel.nextSetBit(0);
617        if (selected == lead)
618          return;  // the selection is not changing
619        if (selected >= 0)
620          {
621            lo = Math.min(lo, selected);
622            hi = Math.max(hi, selected);
623          }
624        if (anchorSelectionIndex >= 0)
625          {
626            lo = Math.min(lo, anchorSelectionIndex);
627            hi = Math.max(hi, anchorSelectionIndex);
628          }
629        sel.clear();
630        sel.set(lead);
631        leadSelectionIndex = lead;
632        anchorSelectionIndex = lead;
633        fireValueChanged(lo, hi);
634      }
635    else if (selectionMode == SINGLE_INTERVAL_SELECTION)
636      {
637        // determine the current interval
638        int first = sel.nextSetBit(0);
639        int last = first;
640        if (first >= 0)
641          last += (sel.cardinality() - 1);
642        
643        // update the selection
644        int lo = Math.min(anchor, lead);
645        int hi = Math.max(anchor, lead);
646        if (lo == first && hi == last)
647          return;  // selected interval is not being changed
648        sel.clear();
649        sel.set(lo, hi + 1);
650        
651        // include the old selection in the event range
652        if (first >= 0)
653          lo = Math.min(lo, first);
654        if (last >= 0)
655          hi = Math.max(hi, last);
656        if (anchorSelectionIndex >= 0)
657          {
658            lo = Math.min(lo, anchorSelectionIndex);
659            hi = Math.max(hi, anchorSelectionIndex);
660          }
661        anchorSelectionIndex = anchor;
662        leadSelectionIndex = lead;
663        fireValueChanged(lo, hi);
664      }    
665    else
666    {
667      BitSet oldSel = (BitSet) sel.clone();
668      sel.clear();
669      if (selectionMode == SINGLE_SELECTION)
670        anchor = lead;
671
672      int lo = Math.min(anchor, lead);
673      int hi = Math.max(anchor, lead);
674      sel.set(lo, hi+1);
675      // update the anchorSelectionIndex and leadSelectionIndex variables
676      setAnchorSelectionIndex(anchor);
677      leadSelectionIndex = lead;
678    
679      fireDifference(sel, oldSel);
680    }
681  }
682
683  /**
684   * Inserts a number of indices either before or after a particular
685   * position in the set of indices. Renumbers all indices after the
686   * inserted range. The new indices in the inserted range are not
687   * selected. This method is typically called to synchronize the selection
688   * model with an inserted range of elements in a {@link ListModel}.
689   *
690   * @param index The position to insert indices at
691   * @param length The number of indices to insert
692   * @param before Indicates whether to insert the indices before the index
693   *     or after it
694   */
695  public void insertIndexInterval(int index,
696                                  int length,
697                                  boolean before)
698  {
699    if (!before)
700      {        
701        index++;
702        length--;
703      }
704    BitSet tmp = sel.get(index, sel.size());
705    sel.clear(index, sel.size());
706    int n = tmp.size();
707    for (int i = 0; i < n; ++i)
708      sel.set(index + length + i, tmp.get(i));
709  }
710
711  /**
712   * Removes a range from the set of indices. Renumbers all indices after
713   * the removed range. This method is typically called to synchronize the
714   * selection model with a deleted range of elements in a {@link
715   * ListModel}.
716   *
717   * @param index0 The first index to remove (inclusive)
718   * @param index1 The last index to remove (inclusive)
719   */
720  public void removeIndexInterval(int index0,
721                                  int index1)
722  {
723    int lo = Math.min(index0, index1);
724    int hi = Math.max(index0, index1);
725
726    BitSet tmp = sel.get(hi, sel.size());
727    sel.clear(lo, sel.size());
728    int n = tmp.size();
729    for (int i = 0; i < n; ++i)
730      sel.set(lo + i, tmp.get(i));
731  }
732
733  /**
734   * Fires a {@link ListSelectionEvent} to all the listeners of type {@link
735   * ListSelectionListener} registered with this selection model to
736   * indicate that a series of adjustment has just ended.
737   *
738   * The values of {@link #getMinSelectionIndex} and
739   * {@link #getMaxSelectionIndex} are used in the {@link ListSelectionEvent}
740   * that gets fired.
741   *
742   * @param isAdjusting <code>true</code> if this is the final change
743   *     in a series of adjustments, <code>false/code> otherwise
744   */
745  protected void fireValueChanged(boolean isAdjusting)
746  {
747    fireValueChanged(getMinSelectionIndex(), getMaxSelectionIndex(),
748                     isAdjusting);
749  }
750
751  /**
752   * Fires a {@link ListSelectionEvent} to all the listeners of type {@link
753   * ListSelectionListener} registered with this selection model.
754   *
755   * @param firstIndex The low index of the changed range
756   * @param lastIndex The high index of the changed range
757   */
758  protected void fireValueChanged(int firstIndex, int lastIndex)
759  {
760    fireValueChanged(firstIndex, lastIndex, getValueIsAdjusting());
761  }
762  
763  /**
764   * Fires a {@link ListSelectionEvent} to all the listeners of type {@link
765   * ListSelectionListener} registered with this selection model.
766   *
767   * @param firstIndex The low index of the changed range
768   * @param lastIndex The high index of the changed range
769   * @param isAdjusting Whether this change is part of a seqence of adjustments
770   *     made to the selection, such as during interactive scrolling
771   */
772  protected void fireValueChanged(int firstIndex, int lastIndex,
773                                  boolean isAdjusting)
774  {
775    ListSelectionEvent evt = new ListSelectionEvent(this, firstIndex,
776                                                    lastIndex, isAdjusting);
777    ListSelectionListener[] listeners = getListSelectionListeners();
778    for (int i = 0; i < listeners.length; ++i)
779      listeners[i].valueChanged(evt);
780  }
781
782  /**
783   * Adds a listener.
784   *
785   * @param listener The listener to add
786   *
787   * @see #removeListSelectionListener
788   * @see #getListSelectionListeners
789   */
790  public void addListSelectionListener(ListSelectionListener listener)
791  {
792    listenerList.add(ListSelectionListener.class, listener);
793  }
794
795  /**
796   * Removes a registered listener.
797   *
798   * @param listener The listener to remove
799   *
800   * @see #addListSelectionListener
801   * @see #getListSelectionListeners
802   */
803  public void removeListSelectionListener(ListSelectionListener listener)
804  {
805    listenerList.remove(ListSelectionListener.class, listener);
806  }
807
808  /**
809   * Returns an array of all registerers listeners.
810   *
811   * @param listenerType The type of listener to retrieve
812   *
813   * @return The array
814   *
815   * @see #getListSelectionListeners
816   * @since 1.3
817   */
818  public <T extends EventListener> T[] getListeners(Class<T> listenerType)
819  {
820    return listenerList.getListeners(listenerType);
821  }
822
823  /**
824   * Returns an array of all registerd list selection listeners.
825   *
826   * @return the array
827   *
828   * @see #addListSelectionListener
829   * @see #removeListSelectionListener
830   * @see #getListeners
831   * @since 1.4
832   */
833  public ListSelectionListener[] getListSelectionListeners()
834  {
835    return (ListSelectionListener[]) getListeners(ListSelectionListener.class);
836  }
837
838  /**
839   * Returns a clone of this object.
840   * <code>listenerList</code> don't gets duplicated.
841   *
842   * @return the cloned object
843   *
844   * @throws CloneNotSupportedException if an error occurs
845   */
846  public Object clone()
847    throws CloneNotSupportedException
848  {
849    DefaultListSelectionModel model =
850      (DefaultListSelectionModel) super.clone();
851    model.sel = (BitSet) sel.clone();
852    model.listenerList = new EventListenerList();
853    return model;
854  }
855}