Source for javax.swing.DefaultListSelectionModel

   1: /* DefaultListSelectionModel.java --
   2:    Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package javax.swing;
  40: 
  41: import java.io.Serializable;
  42: import java.util.BitSet;
  43: import java.util.EventListener;
  44: 
  45: import javax.swing.event.EventListenerList;
  46: import javax.swing.event.ListSelectionEvent;
  47: import javax.swing.event.ListSelectionListener;
  48: 
  49: /**
  50:  * The default implementation of {@link ListSelectionModel},
  51:  * which is used by {@link javax.swing.JList} and
  52:  * similar classes to manage the selection status of a number of data
  53:  * elements.
  54:  *
  55:  * <p>The class is organized <em>abstractly</em> as a set of intervals of
  56:  * integers. Each interval indicates an inclusive range of indices in a
  57:  * list -- held by some other object and unknown to this class -- which is
  58:  * considered "selected". There are various accessors for querying and
  59:  * modifying the set of intervals, with simplified forms accepting a single
  60:  * index, representing an interval with only one element. </p>
  61:  */
  62: public class DefaultListSelectionModel implements Cloneable,
  63:                                                   ListSelectionModel,
  64:                                                   Serializable
  65: {
  66:   private static final long serialVersionUID = -5718799865110415860L;
  67: 
  68:   /** The list of ListSelectionListeners subscribed to this selection model. */
  69:   protected EventListenerList listenerList = new EventListenerList();
  70: 
  71: 
  72:   /** 
  73:    * The current list selection mode. Must be one of the numeric constants
  74:    * <code>SINGLE_SELECTION</code>, <code>SINGLE_INTERVAL_SELECTION</code>
  75:    * or <code>MULTIPLE_INTERVAL_SELECTION</code> from {@link
  76:    * ListSelectionModel}. The default value is
  77:    * <code>MULTIPLE_INTERVAL_SELECTION</code>.
  78:    */
  79:   int selectionMode = MULTIPLE_INTERVAL_SELECTION;
  80: 
  81:   /**
  82:    * The index of the "lead" of the most recent selection. The lead is the
  83:    * second argument in any call to {@link #setSelectionInterval}, {@link
  84:    * #addSelectionInterval} or {@link #removeSelectionInterval}. Generally
  85:    * the lead refers to the most recent position a user dragged their mouse
  86:    * over.
  87:    */
  88:   int leadSelectionIndex = -1;
  89: 
  90:   /**
  91:    * The index of the "anchor" of the most recent selection. The anchor is
  92:    * the first argument in any call to {@link #setSelectionInterval},
  93:    * {@link #addSelectionInterval} or {@link
  94:    * #removeSelectionInterval}. Generally the anchor refers to the first
  95:    * recent position a user clicks when they begin to drag their mouse over
  96:    * a list.
  97:    *
  98:    * @see #getAnchorSelectionIndex
  99:    * @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:    * Gets the value of the {@link #selectionMode} property.
 154:    *
 155:    * @return The current value of the property
 156:    */
 157:   public int getSelectionMode()
 158:   {
 159:     return selectionMode;
 160:   }
 161: 
 162:   /**
 163:    * Sets the value of the {@link #selectionMode} property.
 164:    *
 165:    * @param a The new value of the property
 166:    */
 167:   public void setSelectionMode(int a)
 168:   {
 169:     selectionMode = a;
 170:   }
 171: 
 172:   /**
 173:    * Gets the value of the {@link #anchorSelectionIndex} property.
 174:    * 
 175:    * @return The current property value
 176:    *
 177:    * @see #setAnchorSelectionIndex
 178:    */
 179:   public int getAnchorSelectionIndex()
 180:   {
 181:     return anchorSelectionIndex;
 182:   }
 183: 
 184:   /**
 185:    * Sets the value of the {@link #anchorSelectionIndex} property.
 186:    * 
 187:    * @param anchorIndex The new property value
 188:    *
 189:    * @see #getAnchorSelectionIndex
 190:    */
 191:   public void setAnchorSelectionIndex(int anchorIndex)
 192:   {
 193:     anchorSelectionIndex = anchorIndex;
 194:   }
 195:   
 196:   /**
 197:    * Gets the value of the {@link #leadSelectionIndex} property.
 198:    * 
 199:    * @return The current property value
 200:    *
 201:    * @see #setLeadSelectionIndex
 202:    */
 203:   public int getLeadSelectionIndex()
 204:   {
 205:     return leadSelectionIndex;
 206:   }
 207: 
 208:   /**
 209:    * <p>Sets the value of the {@link #anchorSelectionIndex} property. As a
 210:    * side effect, alters the selection status of two ranges of indices. Let
 211:    * <code>OL</code> be the old lead selection index, <code>NL</code> be
 212:    * the new lead selection index, and <code>A</code> be the anchor
 213:    * selection index. Then if <code>A</code> is a valid selection index,
 214:    * one of two things happens depending on the seleciton status of
 215:    * <code>A</code>:</p>
 216:    *
 217:    * <ul>
 218:    *
 219:    * <li><code>isSelectedIndex(A) == true</code>: set <code>[A,OL]</code>
 220:    * to <em>deselected</em>, then set <code>[A,NL]</code> to
 221:    * <em>selected</em>.</li>
 222:    *
 223:    * <li><code>isSelectedIndex(A) == false</code>: set <code>[A,OL]</code>
 224:    * to <em>selected</em>, then set <code>[A,NL]</code> to
 225:    * <em>deselected</em>.</li>
 226:    *
 227:    * </ul>
 228:    *
 229:    * <p>This method generates at most a single {@link ListSelectionEvent}
 230:    * despite changing multiple ranges. The range of values provided to the
 231:    * {@link ListSelectionEvent} includes only the minimum range of values
 232:    * which changed selection status between the beginning and end of the
 233:    * method.</p>
 234:    * 
 235:    * @param leadIndex The new property value
 236:    *
 237:    * @see #getAnchorSelectionIndex
 238:    */
 239:   public void setLeadSelectionIndex(int leadIndex)
 240:   {
 241:     int oldLeadIndex = leadSelectionIndex;
 242:     if (setLeadCalledFromAdd == false)
 243:       oldSel = sel.clone();
 244:     leadSelectionIndex = leadIndex;
 245: 
 246:     if (anchorSelectionIndex == -1)
 247:       return;
 248: 
 249:     int R1 = Math.min(anchorSelectionIndex, oldLeadIndex);
 250:     int R2 = Math.max(anchorSelectionIndex, oldLeadIndex);
 251:     int S1 = Math.min(anchorSelectionIndex, leadIndex);
 252:     int S2 = Math.max(anchorSelectionIndex, leadIndex);
 253: 
 254:     int lo = Math.min(R1, S1);
 255:     int hi = Math.max(R2, S2);
 256: 
 257:     BitSet oldRange = sel.get(lo, hi+1);
 258: 
 259:     if (isSelectedIndex(anchorSelectionIndex))
 260:       {
 261:         sel.clear(R1, R2+1);
 262:         sel.set(S1, S2+1);
 263:       }
 264:     else
 265:       {
 266:         sel.set(R1, R2+1);
 267:         sel.clear(S1, S2+1);
 268:       }
 269:     
 270:     BitSet newRange = sel.get(lo, hi+1);
 271:     newRange.xor(oldRange);
 272: 
 273:     int beg = sel.nextSetBit(0), end = -1;
 274:     for(int i=beg; i >= 0; i=sel.nextSetBit(i+1)) 
 275:       end = i;
 276:     if (sel.equals(oldSel) == false)
 277:       fireValueChanged(beg, end, valueIsAdjusting);    
 278:   }
 279: 
 280:   /**
 281:    * Gets the value of the {@link #leadAnchorNotificationEnabled} property.
 282:    * 
 283:    * @return The current property value
 284:    *
 285:    * @see #setLeadAnchorNotificationEnabled
 286:    */
 287:   public boolean isLeadAnchorNotificationEnabled()
 288:   {
 289:     return leadAnchorNotificationEnabled;
 290:   }
 291: 
 292:   /**
 293:    * Sets the value of the {@link #leadAnchorNotificationEnabled} property.
 294:    * 
 295:    * @param l The new property value
 296:    *
 297:    * @see #isLeadAnchorNotificationEnabled
 298:    */
 299:   public void setLeadAnchorNotificationEnabled(boolean l)
 300:   {
 301:     leadAnchorNotificationEnabled = l;
 302:   }
 303: 
 304:   /**
 305:    * Gets the value of the {@link #valueIsAdjusting} property.
 306:    *
 307:    * @return The current property value
 308:    *
 309:    * @see #setValueIsAdjusting
 310:    */
 311:   public boolean getValueIsAdjusting()
 312:   {
 313:     return valueIsAdjusting;
 314:   }
 315: 
 316:   /**
 317:    * Sets the value of the {@link #valueIsAdjusting} property.
 318:    *
 319:    * @param v The new property value
 320:    *
 321:    * @see #getValueIsAdjusting
 322:    */
 323:   public void setValueIsAdjusting(boolean v)
 324:   {
 325:     valueIsAdjusting = v;
 326:   }
 327: 
 328:   /**
 329:    * Determines whether the selection is empty.
 330:    *
 331:    * @return <code>true</code> if the selection is empty, otherwise
 332:    * <code>false</code>
 333:    */
 334:   public boolean isSelectionEmpty()
 335:   {
 336:     return sel.isEmpty();
 337:   }
 338: 
 339:   /**
 340:    * Gets the smallest index which is currently a member of a selection
 341:    * interval.
 342:    *
 343:    * @return The least integer <code>i</code> such that <code>i >=
 344:    *     0</code> and <code>i</code> is a member of a selected interval, or
 345:    *     <code>-1</code> if there are no selected intervals
 346:    *
 347:    * @see #getMaxSelectionIndex
 348:    */
 349:   public int getMinSelectionIndex()
 350:   {
 351:     if (isSelectionEmpty())
 352:       return -1;
 353:     
 354:     return sel.nextSetBit(0);
 355:   }
 356: 
 357:   /**
 358:    * Gets the largest index which is currently a member of a selection
 359:    * interval.
 360:    *
 361:    * @return The greatest integer <code>i</code> such that <code>i >=
 362:    *     0</code> and <code>i</code> is a member of a selected interval, or
 363:    *     <code>-1</code> if there are no selected intervals
 364:    *
 365:    * @see #getMinSelectionIndex
 366:    */
 367:   public int getMaxSelectionIndex()
 368:   {
 369:     if (isSelectionEmpty())
 370:       return -1;
 371: 
 372:     int mx = -1;
 373:     for(int i=sel.nextSetBit(0); i >= 0; i=sel.nextSetBit(i+1)) 
 374:       { 
 375:         mx = i;
 376:       }
 377:     return mx;
 378:   }
 379: 
 380:   /**
 381:    * Determines whether a particular index is a member of a selection
 382:    * interval.
 383:    *
 384:    * @param a The index to search for
 385:    *
 386:    * @return <code>true</code> if the index is a member of a selection interval,
 387:    *     otherwise <code>false</code>
 388:    */
 389:   public boolean isSelectedIndex(int a)
 390:   {
 391:     return sel.get(a);
 392:   }
 393: 
 394:   /**
 395:    * If the {@link #selectionMode} property is equal to
 396:    * <code>SINGLE_SELECTION</code> equivalent to calling
 397:    * <code>setSelectionInterval(index1, index2)</code>; 
 398:    * If the {@link #selectionMode} property is equal to 
 399:    * <code>SINGLE_INTERVAL_SELECTION</code> and the interval being
 400:    * added is not adjacent to an already selected interval,
 401:    * equivalent to <code>setSelectionInterval(index1, index2)</code>.
 402:    * Otherwise adds the range <code>[index0, index1]</code> 
 403:    * to the selection interval set.
 404:    *
 405:    * @param index0 The beginning of the range of indices to select
 406:    * @param index1 The end of the range of indices to select
 407:    *
 408:    * @see #setSelectionInterval
 409:    * @see #removeSelectionInterval
 410:    */
 411:   public void addSelectionInterval(int index0, int index1) 
 412:   {
 413:     int lo = Math.min(index0, index1);
 414:     int hi = Math.max(index0, index1);
 415:     oldSel = sel.clone();
 416: 
 417:     if (selectionMode == SINGLE_SELECTION)
 418:       sel.clear();
 419: 
 420:     // COMPAT: Like Sun (but not like IBM), we allow calls to 
 421:     // addSelectionInterval when selectionMode is
 422:     // SINGLE_SELECTION_INTERVAL iff the interval being added
 423:     // is adjacent to an already selected interval
 424:     if (selectionMode == SINGLE_INTERVAL_SELECTION)
 425:       if (!(isSelectedIndex(index0) || 
 426:             isSelectedIndex(index1) || 
 427:             isSelectedIndex(Math.max(lo-1,0)) || 
 428:             isSelectedIndex(Math.min(hi+1,sel.size()))))
 429:         sel.clear();
 430:     
 431:     if (selectionMode == SINGLE_SELECTION)
 432:       index0 = index1;
 433: 
 434:     // We have to update the anchorSelectionIndex and leadSelectionIndex
 435:     // variables
 436:     
 437:     // The next if statements breaks down to "if this selection is adjacent
 438:     // to the previous selection and going in the same direction"
 439:     if ((isSelectedIndex(leadSelectionIndex)) 
 440:         && ((index0 - 1 == leadSelectionIndex 
 441:              && (index1 >= index0) 
 442:              && (leadSelectionIndex >= anchorSelectionIndex))
 443:             || (index0 + 1 == leadSelectionIndex && (index1 <= index0) 
 444:                 && (leadSelectionIndex <= anchorSelectionIndex)))
 445:         && (anchorSelectionIndex != -1 || leadSelectionIndex != -1))
 446:       {
 447:         // setting setLeadCalledFromAdd to true tells setLeadSelectionIndex
 448:         //   not to update oldSel
 449:         setLeadCalledFromAdd = true;
 450:         setLeadSelectionIndex(index1);
 451:         setLeadCalledFromAdd = false;
 452:       }
 453:     else
 454:       {
 455:         leadSelectionIndex = index1;
 456:         anchorSelectionIndex = index0;
 457:         sel.set(lo, hi+1);
 458:         if (sel.equals(oldSel) == false)
 459:           fireValueChanged(lo, hi, valueIsAdjusting);
 460:       }
 461:   }
 462: 
 463: 
 464:   /**
 465:    * Deselects all indices in the inclusive range
 466:    * <code>[index0,index1]</code>.
 467:    *
 468:    * @param index0 The beginning of the range of indices to deselect
 469:    * @param index1 The end of the range of indices to deselect
 470:    *
 471:    * @see #addSelectionInterval
 472:    * @see #setSelectionInterval
 473:    */
 474:   public void removeSelectionInterval(int index0,
 475:                                       int index1)
 476:   {
 477:     oldSel = sel.clone();
 478:     int lo = Math.min(index0, index1);
 479:     int hi = Math.max(index0, index1);
 480:     
 481:     // if selectionMode is SINGLE_INTERVAL_SELECTION and removing the interval
 482:     //   (index0,index1) would leave two disjoint selection intervals, remove all
 483:     //   selected indices from lo to the last selected index
 484:     if (getMinSelectionIndex() > 0 && getMinSelectionIndex() < lo && 
 485:         selectionMode == SINGLE_INTERVAL_SELECTION)
 486:       hi = sel.size() - 1;
 487: 
 488:     sel.clear(lo, hi+1); 
 489:     //update anchorSelectionIndex and leadSelectionIndex variables
 490:     //TODO: will probably need MouseDragged to test properly and know if this works
 491:     setAnchorSelectionIndex(index0);
 492:     leadSelectionIndex = index1;
 493:     if (sel.equals(oldSel) == false)
 494:       fireValueChanged(lo, hi, valueIsAdjusting);
 495:   }
 496: 
 497:   /**
 498:    * Removes all intervals in the selection set.
 499:    */
 500:   public void clearSelection()
 501:   {
 502:     oldSel = sel.clone();
 503:     int sz = sel.size();
 504:     sel.clear();
 505:     if (sel.equals(oldSel) == false)
 506:       fireValueChanged(0, sz, valueIsAdjusting);
 507:   }
 508:   
 509:   /**
 510:    * Clears the current selection and marks a given interval as
 511:    * "selected". If the current selection mode is
 512:    * <code>SINGLE_SELECTION</code> only the index <code>index2</code> is
 513:    * selected.
 514:    *
 515:    * @param index0 The low end of the new selection 
 516:    * @param index1 The high end of the new selection
 517:    */
 518:   public void setSelectionInterval(int index0, int index1)
 519:   {
 520:     oldSel = sel.clone();
 521:     sel.clear();
 522:     if (selectionMode == SINGLE_SELECTION)
 523:       index0 = index1;
 524: 
 525:     int lo = Math.min(index0, index1);
 526:     int hi = Math.max(index0, index1);
 527:     sel.set(lo, hi+1);
 528:     // update the anchorSelectionIndex and leadSelectionIndex variables
 529:     setAnchorSelectionIndex(index0);
 530:     leadSelectionIndex=index1;
 531:     if (sel.equals(oldSel) == false)
 532:       fireValueChanged(lo, hi, valueIsAdjusting);
 533:   }
 534: 
 535:   /**
 536:    * Inserts a number of indices either before or after a particular
 537:    * position in the set of indices. Renumbers all indices after the
 538:    * inserted range. The new indices in the inserted range are not
 539:    * selected. This method is typically called to synchronize the selection
 540:    * model with an inserted range of elements in a {@link ListModel}.
 541:    *
 542:    * @param index The position to insert indices at
 543:    * @param length The number of indices to insert
 544:    * @param before Indicates whether to insert the indices before the index
 545:    *     or after it
 546:    */
 547:   public void insertIndexInterval(int index,
 548:                                   int length,
 549:                                   boolean before)
 550:   {
 551:     if (!before)
 552:       {        
 553:         index++;
 554:         length--;
 555:       }
 556:     BitSet tmp = sel.get(index, sel.size());
 557:     sel.clear(index, sel.size());
 558:     int n = tmp.size();
 559:     for (int i = 0; i < n; ++i)
 560:       sel.set(index + length + i, tmp.get(i));
 561:   }
 562: 
 563:   /**
 564:    * Removes a range from the set of indices. Renumbers all indices after
 565:    * the removed range. This method is typically called to synchronize the
 566:    * selection model with a deleted range of elements in a {@link
 567:    * ListModel}.
 568:    *
 569:    * @param index0 The first index to remove (inclusive)
 570:    * @param index1 The last index to remove (inclusive)
 571:    */
 572:   public void removeIndexInterval(int index0,
 573:                                   int index1)
 574:   {
 575:     int lo = Math.min(index0, index1);
 576:     int hi = Math.max(index0, index1);
 577: 
 578:     BitSet tmp = sel.get(hi, sel.size());
 579:     sel.clear(lo, sel.size());
 580:     int n = tmp.size();
 581:     for (int i = 0; i < n; ++i)
 582:       sel.set(lo + i, tmp.get(i));
 583:   }
 584: 
 585:   /**
 586:    * Fires a {@link ListSelectionEvent} to all the listeners of type {@link
 587:    * ListSelectionListener} registered with this selection model to
 588:    * indicate that a series of adjustment has just ended.
 589:    *
 590:    * The values of {@link #getMinSelectionIndex} and
 591:    * {@link #getMaxSelectionIndex} are used in the {@link ListSelectionEvent}
 592:    * that gets fired.
 593:    *
 594:    * @param isAdjusting <code>true</code> if this is the final change
 595:    *     in a series of adjustments, <code>false/code> otherwise
 596:    */
 597:   protected void fireValueChanged(boolean isAdjusting)
 598:   {
 599:     fireValueChanged(getMinSelectionIndex(), getMaxSelectionIndex(),
 600:                      isAdjusting);
 601:   }
 602: 
 603:   /**
 604:    * Fires a {@link ListSelectionEvent} to all the listeners of type {@link
 605:    * ListSelectionListener} registered with this selection model.
 606:    *
 607:    * @param firstIndex The low index of the changed range
 608:    * @param lastIndex The high index of the changed range
 609:    */
 610:   protected void fireValueChanged(int firstIndex, int lastIndex)
 611:   {
 612:     fireValueChanged(firstIndex, lastIndex, getValueIsAdjusting());
 613:   }
 614:   
 615:   /**
 616:    * Fires a {@link ListSelectionEvent} to all the listeners of type {@link
 617:    * ListSelectionListener} registered with this selection model.
 618:    *
 619:    * @param firstIndex The low index of the changed range
 620:    * @param lastIndex The high index of the changed range
 621:    * @param isAdjusting Whether this change is part of a seqence of adjustments
 622:    *     made to the selection, such as during interactive scrolling
 623:    */
 624:   protected void fireValueChanged(int firstIndex, int lastIndex,
 625:                   boolean isAdjusting)
 626:   {
 627:     ListSelectionEvent evt = new ListSelectionEvent(this, firstIndex,
 628:                                                     lastIndex, isAdjusting);
 629:     ListSelectionListener[] listeners = getListSelectionListeners();
 630:     for (int i = 0; i < listeners.length; ++i)
 631:       listeners[i].valueChanged(evt);
 632:   }
 633: 
 634:   /**
 635:    * Adds a listener.
 636:    *
 637:    * @param listener The listener to add
 638:    *
 639:    * @see #removeListSelectionListener
 640:    * @see #getListSelectionListeners
 641:    */
 642:   public void addListSelectionListener(ListSelectionListener listener)
 643:   {
 644:     listenerList.add(ListSelectionListener.class, listener);
 645:   }
 646: 
 647:   /**
 648:    * Removes a registered listener.
 649:    *
 650:    * @param listener The listener to remove
 651:    *
 652:    * @see #addListSelectionListener
 653:    * @see #getListSelectionListeners
 654:    */
 655:   public void removeListSelectionListener(ListSelectionListener listener)
 656:   {
 657:     listenerList.remove(ListSelectionListener.class, listener);
 658:   }
 659: 
 660:   /**
 661:    * Returns an array of all registerers listeners.
 662:    *
 663:    * @param listenerType The type of listener to retrieve
 664:    *
 665:    * @return The array
 666:    *
 667:    * @see #getListSelectionListeners
 668:    * @since 1.3
 669:    */
 670:   public EventListener[] getListeners(Class listenerType)
 671:   {
 672:     return listenerList.getListeners(listenerType);
 673:   }
 674: 
 675:   /**
 676:    * Returns an array of all registerd list selection listeners.
 677:    *
 678:    * @return the array
 679:    *
 680:    * @see #addListSelectionListener
 681:    * @see #removeListSelectionListener
 682:    * @see #getListeners
 683:    * @since 1.4
 684:    */
 685:   public ListSelectionListener[] getListSelectionListeners()
 686:   {
 687:     return (ListSelectionListener[]) getListeners(ListSelectionListener.class);
 688:   }
 689: 
 690:   /**
 691:    * Returns a clone of this object.
 692:    * <code>listenerList</code> don't gets duplicated.
 693:    *
 694:    * @return the cloned object
 695:    *
 696:    * @throws CloneNotSupportedException if an error occurs
 697:    */
 698:   public Object clone()
 699:     throws CloneNotSupportedException
 700:   {
 701:     DefaultListSelectionModel model =
 702:       (DefaultListSelectionModel) super.clone();
 703:     model.sel = (BitSet) sel.clone();
 704:     return model;
 705:   }
 706: }