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:     // Only set the lead selection index to < 0 if anchorSelectionIndex < 0.
 242:     if (leadIndex < 0)
 243:       {
 244:         if (anchorSelectionIndex < 0)
 245:           leadSelectionIndex = -1;
 246:         else
 247:           return;
 248:       }
 249: 
 250:     // Only touch the lead selection index if the anchor is >= 0.
 251:     if (anchorSelectionIndex < 0)
 252:       return;
 253: 
 254:     if (selectionMode == SINGLE_SELECTION)
 255:       setSelectionInterval (leadIndex, leadIndex);
 256:     
 257:     int oldLeadIndex = leadSelectionIndex;
 258:     if (oldLeadIndex == -1)
 259:       oldLeadIndex = leadIndex;
 260:     if (setLeadCalledFromAdd == false)
 261:       oldSel = sel.clone();
 262:     leadSelectionIndex = leadIndex;
 263: 
 264:     if (anchorSelectionIndex == -1)
 265:       return;    
 266:     
 267:     int R1 = Math.min(anchorSelectionIndex, oldLeadIndex);
 268:     int R2 = Math.max(anchorSelectionIndex, oldLeadIndex);
 269:     int S1 = Math.min(anchorSelectionIndex, leadIndex);
 270:     int S2 = Math.max(anchorSelectionIndex, leadIndex);
 271: 
 272:     int lo = Math.min(R1, S1);
 273:     int hi = Math.max(R2, S2);
 274: 
 275:     if (isSelectedIndex(anchorSelectionIndex))
 276:       {
 277:         sel.clear(R1, R2+1);
 278:         sel.set(S1, S2+1);
 279:       }
 280:     else
 281:       {
 282:         sel.set(R1, R2+1);
 283:         sel.clear(S1, S2+1);
 284:       }    
 285: 
 286:     int beg = sel.nextSetBit(0), end = -1;
 287:     for(int i=beg; i >= 0; i=sel.nextSetBit(i+1)) 
 288:       end = i;
 289:     if (sel.equals(oldSel) == false)
 290:       fireValueChanged(beg, end, valueIsAdjusting);    
 291:   }
 292: 
 293:   /**
 294:    * Moves the lead selection index to <code>leadIndex</code> without 
 295:    * changing the selection values.
 296:    * 
 297:    * If leadAnchorNotificationEnabled is true, send a notification covering the
 298:    * old and new lead cells.
 299:    * 
 300:    * @param leadIndex the new lead selection index
 301:    * @since 1.5
 302:    */
 303:   public void moveLeadSelectionIndex (int leadIndex)
 304:   {
 305:     if (leadSelectionIndex == leadIndex)
 306:       return;
 307:     
 308:     leadSelectionIndex = leadIndex;
 309:     if (isLeadAnchorNotificationEnabled())
 310:       fireValueChanged(Math.min(leadSelectionIndex, leadIndex),
 311:                        Math.max(leadSelectionIndex, leadIndex));
 312:   }
 313:   
 314:   /**
 315:    * Gets the value of the {@link #leadAnchorNotificationEnabled} property.
 316:    * 
 317:    * @return The current property value
 318:    *
 319:    * @see #setLeadAnchorNotificationEnabled
 320:    */
 321:   public boolean isLeadAnchorNotificationEnabled()
 322:   {
 323:     return leadAnchorNotificationEnabled;
 324:   }
 325: 
 326:   /**
 327:    * Sets the value of the {@link #leadAnchorNotificationEnabled} property.
 328:    * 
 329:    * @param l The new property value
 330:    *
 331:    * @see #isLeadAnchorNotificationEnabled
 332:    */
 333:   public void setLeadAnchorNotificationEnabled(boolean l)
 334:   {
 335:     leadAnchorNotificationEnabled = l;
 336:   }
 337: 
 338:   /**
 339:    * Gets the value of the {@link #valueIsAdjusting} property.
 340:    *
 341:    * @return The current property value
 342:    *
 343:    * @see #setValueIsAdjusting
 344:    */
 345:   public boolean getValueIsAdjusting()
 346:   {
 347:     return valueIsAdjusting;
 348:   }
 349: 
 350:   /**
 351:    * Sets the value of the {@link #valueIsAdjusting} property.
 352:    *
 353:    * @param v The new property value
 354:    *
 355:    * @see #getValueIsAdjusting
 356:    */
 357:   public void setValueIsAdjusting(boolean v)
 358:   {
 359:     valueIsAdjusting = v;
 360:   }
 361: 
 362:   /**
 363:    * Determines whether the selection is empty.
 364:    *
 365:    * @return <code>true</code> if the selection is empty, otherwise
 366:    * <code>false</code>
 367:    */
 368:   public boolean isSelectionEmpty()
 369:   {
 370:     return sel.isEmpty();
 371:   }
 372: 
 373:   /**
 374:    * Gets the smallest index which is currently a member of a selection
 375:    * interval.
 376:    *
 377:    * @return The least integer <code>i</code> such that <code>i >=
 378:    *     0</code> and <code>i</code> is a member of a selected interval, or
 379:    *     <code>-1</code> if there are no selected intervals
 380:    *
 381:    * @see #getMaxSelectionIndex
 382:    */
 383:   public int getMinSelectionIndex()
 384:   {
 385:     if (isSelectionEmpty())
 386:       return -1;
 387:     
 388:     return sel.nextSetBit(0);
 389:   }
 390: 
 391:   /**
 392:    * Gets the largest index which is currently a member of a selection
 393:    * interval.
 394:    *
 395:    * @return The greatest integer <code>i</code> such that <code>i >=
 396:    *     0</code> and <code>i</code> is a member of a selected interval, or
 397:    *     <code>-1</code> if there are no selected intervals
 398:    *
 399:    * @see #getMinSelectionIndex
 400:    */
 401:   public int getMaxSelectionIndex()
 402:   {
 403:     if (isSelectionEmpty())
 404:       return -1;
 405: 
 406:     int mx = -1;
 407:     for(int i=sel.nextSetBit(0); i >= 0; i=sel.nextSetBit(i+1)) 
 408:       { 
 409:         mx = i;
 410:       }
 411:     return mx;
 412:   }
 413: 
 414:   /**
 415:    * Determines whether a particular index is a member of a selection
 416:    * interval.
 417:    *
 418:    * @param a The index to search for
 419:    *
 420:    * @return <code>true</code> if the index is a member of a selection interval,
 421:    *     otherwise <code>false</code>
 422:    */
 423:   public boolean isSelectedIndex(int a)
 424:   {
 425:     // TODO: Probably throw an exception here?
 426:     if (a >= sel.length() || a < 0)
 427:       return false;
 428:     return sel.get(a);
 429:   }
 430: 
 431:   /**
 432:    * If the {@link #selectionMode} property is equal to
 433:    * <code>SINGLE_SELECTION</code> equivalent to calling
 434:    * <code>setSelectionInterval(index1, index2)</code>; 
 435:    * If the {@link #selectionMode} property is equal to 
 436:    * <code>SINGLE_INTERVAL_SELECTION</code> and the interval being
 437:    * added is not adjacent to an already selected interval,
 438:    * equivalent to <code>setSelectionInterval(index1, index2)</code>.
 439:    * Otherwise adds the range <code>[index0, index1]</code> 
 440:    * to the selection interval set.
 441:    *
 442:    * @param index0 The beginning of the range of indices to select
 443:    * @param index1 The end of the range of indices to select
 444:    *
 445:    * @see #setSelectionInterval
 446:    * @see #removeSelectionInterval
 447:    */
 448:   public void addSelectionInterval(int index0, int index1) 
 449:   {
 450:     int lo = Math.min(index0, index1);
 451:     int hi = Math.max(index0, index1);
 452:     oldSel = sel.clone();
 453: 
 454:     if (selectionMode == SINGLE_SELECTION)
 455:       setSelectionInterval(index0, index1);
 456: 
 457:     // COMPAT: Like Sun (but not like IBM), we allow calls to 
 458:     // addSelectionInterval when selectionMode is
 459:     // SINGLE_SELECTION_INTERVAL iff the interval being added
 460:     // is adjacent to an already selected interval
 461:     if (selectionMode == SINGLE_INTERVAL_SELECTION)
 462:       if (!(isSelectedIndex(index0) || 
 463:             isSelectedIndex(index1) || 
 464:             isSelectedIndex(Math.max(lo-1,0)) || 
 465:             isSelectedIndex(Math.min(hi+1,sel.size()))))
 466:         sel.clear();    
 467: 
 468:     // We have to update the anchorSelectionIndex and leadSelectionIndex
 469:     // variables
 470:     
 471:     // The next if statements breaks down to "if this selection is adjacent
 472:     // to the previous selection and going in the same direction"
 473:     if ((isSelectedIndex(leadSelectionIndex)) 
 474:         && ((index0 - 1 == leadSelectionIndex 
 475:              && (index1 >= index0) 
 476:              && (leadSelectionIndex >= anchorSelectionIndex))
 477:             || (index0 + 1 == leadSelectionIndex && (index1 <= index0) 
 478:                 && (leadSelectionIndex <= anchorSelectionIndex)))
 479:         && (anchorSelectionIndex != -1 || leadSelectionIndex != -1))
 480:       {
 481:         // setting setLeadCalledFromAdd to true tells setLeadSelectionIndex
 482:         //   not to update oldSel
 483:         setLeadCalledFromAdd = true;
 484:         setLeadSelectionIndex(index1);
 485:         setLeadCalledFromAdd = false;
 486:       }
 487:     else
 488:       {
 489:         leadSelectionIndex = index1;
 490:         anchorSelectionIndex = index0;
 491:         sel.set(lo, hi+1);
 492:         if (sel.equals(oldSel) == false)
 493:           fireValueChanged(lo, hi, valueIsAdjusting);
 494:       }
 495:   }
 496: 
 497: 
 498:   /**
 499:    * Deselects all indices in the inclusive range
 500:    * <code>[index0,index1]</code>.
 501:    *
 502:    * @param index0 The beginning of the range of indices to deselect
 503:    * @param index1 The end of the range of indices to deselect
 504:    *
 505:    * @see #addSelectionInterval
 506:    * @see #setSelectionInterval
 507:    */
 508:   public void removeSelectionInterval(int index0,
 509:                                       int index1)
 510:   {
 511:     oldSel = sel.clone();
 512:     int lo = Math.min(index0, index1);
 513:     int hi = Math.max(index0, index1);
 514:     
 515:     // if selectionMode is SINGLE_INTERVAL_SELECTION and removing the interval
 516:     //   (index0,index1) would leave two disjoint selection intervals, remove all
 517:     //   selected indices from lo to the last selected index
 518:     if (getMinSelectionIndex() > 0 && getMinSelectionIndex() < lo && 
 519:         selectionMode == SINGLE_INTERVAL_SELECTION)
 520:       hi = sel.size() - 1;
 521: 
 522:     sel.clear(lo, hi+1); 
 523:     //update anchorSelectionIndex and leadSelectionIndex variables
 524:     //TODO: will probably need MouseDragged to test properly and know if this works
 525:     setAnchorSelectionIndex(index0);
 526:     leadSelectionIndex = index1;
 527:     if (sel.equals(oldSel) == false)
 528:       fireValueChanged(lo, hi, valueIsAdjusting);
 529:   }
 530: 
 531:   /**
 532:    * Removes all intervals in the selection set.
 533:    */
 534:   public void clearSelection()
 535:   {
 536:     oldSel = sel.clone();
 537:     int sz = sel.size();
 538:     sel.clear();
 539:     if (sel.equals(oldSel) == false)
 540:       fireValueChanged(0, sz, valueIsAdjusting);
 541:   }
 542:   
 543:   /**
 544:    * Clears the current selection and marks a given interval as
 545:    * "selected". If the current selection mode is
 546:    * <code>SINGLE_SELECTION</code> only the index <code>index2</code> is
 547:    * selected.
 548:    *
 549:    * @param index0 The low end of the new selection 
 550:    * @param index1 The high end of the new selection
 551:    */
 552:   public void setSelectionInterval(int index0, int index1)
 553:   {
 554:     oldSel = sel.clone();
 555:     sel.clear();
 556:     if (selectionMode == SINGLE_SELECTION)
 557:       index0 = index1;
 558: 
 559:     int lo = Math.min(index0, index1);
 560:     int hi = Math.max(index0, index1);
 561:     sel.set(lo, hi+1);
 562:     // update the anchorSelectionIndex and leadSelectionIndex variables
 563:     setAnchorSelectionIndex(index0);
 564:     leadSelectionIndex=index1;
 565:     if (sel.equals(oldSel) == false)
 566:       fireValueChanged(lo, hi, valueIsAdjusting);
 567:   }
 568: 
 569:   /**
 570:    * Inserts a number of indices either before or after a particular
 571:    * position in the set of indices. Renumbers all indices after the
 572:    * inserted range. The new indices in the inserted range are not
 573:    * selected. This method is typically called to synchronize the selection
 574:    * model with an inserted range of elements in a {@link ListModel}.
 575:    *
 576:    * @param index The position to insert indices at
 577:    * @param length The number of indices to insert
 578:    * @param before Indicates whether to insert the indices before the index
 579:    *     or after it
 580:    */
 581:   public void insertIndexInterval(int index,
 582:                                   int length,
 583:                                   boolean before)
 584:   {
 585:     if (!before)
 586:       {        
 587:         index++;
 588:         length--;
 589:       }
 590:     BitSet tmp = sel.get(index, sel.size());
 591:     sel.clear(index, sel.size());
 592:     int n = tmp.size();
 593:     for (int i = 0; i < n; ++i)
 594:       sel.set(index + length + i, tmp.get(i));
 595:   }
 596: 
 597:   /**
 598:    * Removes a range from the set of indices. Renumbers all indices after
 599:    * the removed range. This method is typically called to synchronize the
 600:    * selection model with a deleted range of elements in a {@link
 601:    * ListModel}.
 602:    *
 603:    * @param index0 The first index to remove (inclusive)
 604:    * @param index1 The last index to remove (inclusive)
 605:    */
 606:   public void removeIndexInterval(int index0,
 607:                                   int index1)
 608:   {
 609:     int lo = Math.min(index0, index1);
 610:     int hi = Math.max(index0, index1);
 611: 
 612:     BitSet tmp = sel.get(hi, sel.size());
 613:     sel.clear(lo, sel.size());
 614:     int n = tmp.size();
 615:     for (int i = 0; i < n; ++i)
 616:       sel.set(lo + i, tmp.get(i));
 617:   }
 618: 
 619:   /**
 620:    * Fires a {@link ListSelectionEvent} to all the listeners of type {@link
 621:    * ListSelectionListener} registered with this selection model to
 622:    * indicate that a series of adjustment has just ended.
 623:    *
 624:    * The values of {@link #getMinSelectionIndex} and
 625:    * {@link #getMaxSelectionIndex} are used in the {@link ListSelectionEvent}
 626:    * that gets fired.
 627:    *
 628:    * @param isAdjusting <code>true</code> if this is the final change
 629:    *     in a series of adjustments, <code>false/code> otherwise
 630:    */
 631:   protected void fireValueChanged(boolean isAdjusting)
 632:   {
 633:     fireValueChanged(getMinSelectionIndex(), getMaxSelectionIndex(),
 634:                      isAdjusting);
 635:   }
 636: 
 637:   /**
 638:    * Fires a {@link ListSelectionEvent} to all the listeners of type {@link
 639:    * ListSelectionListener} registered with this selection model.
 640:    *
 641:    * @param firstIndex The low index of the changed range
 642:    * @param lastIndex The high index of the changed range
 643:    */
 644:   protected void fireValueChanged(int firstIndex, int lastIndex)
 645:   {
 646:     fireValueChanged(firstIndex, lastIndex, getValueIsAdjusting());
 647:   }
 648:   
 649:   /**
 650:    * Fires a {@link ListSelectionEvent} to all the listeners of type {@link
 651:    * ListSelectionListener} registered with this selection model.
 652:    *
 653:    * @param firstIndex The low index of the changed range
 654:    * @param lastIndex The high index of the changed range
 655:    * @param isAdjusting Whether this change is part of a seqence of adjustments
 656:    *     made to the selection, such as during interactive scrolling
 657:    */
 658:   protected void fireValueChanged(int firstIndex, int lastIndex,
 659:                   boolean isAdjusting)
 660:   {
 661:     ListSelectionEvent evt = new ListSelectionEvent(this, firstIndex,
 662:                                                     lastIndex, isAdjusting);
 663:     ListSelectionListener[] listeners = getListSelectionListeners();
 664:     for (int i = 0; i < listeners.length; ++i)
 665:       listeners[i].valueChanged(evt);
 666:   }
 667: 
 668:   /**
 669:    * Adds a listener.
 670:    *
 671:    * @param listener The listener to add
 672:    *
 673:    * @see #removeListSelectionListener
 674:    * @see #getListSelectionListeners
 675:    */
 676:   public void addListSelectionListener(ListSelectionListener listener)
 677:   {
 678:     listenerList.add(ListSelectionListener.class, listener);
 679:   }
 680: 
 681:   /**
 682:    * Removes a registered listener.
 683:    *
 684:    * @param listener The listener to remove
 685:    *
 686:    * @see #addListSelectionListener
 687:    * @see #getListSelectionListeners
 688:    */
 689:   public void removeListSelectionListener(ListSelectionListener listener)
 690:   {
 691:     listenerList.remove(ListSelectionListener.class, listener);
 692:   }
 693: 
 694:   /**
 695:    * Returns an array of all registerers listeners.
 696:    *
 697:    * @param listenerType The type of listener to retrieve
 698:    *
 699:    * @return The array
 700:    *
 701:    * @see #getListSelectionListeners
 702:    * @since 1.3
 703:    */
 704:   public EventListener[] getListeners(Class listenerType)
 705:   {
 706:     return listenerList.getListeners(listenerType);
 707:   }
 708: 
 709:   /**
 710:    * Returns an array of all registerd list selection listeners.
 711:    *
 712:    * @return the array
 713:    *
 714:    * @see #addListSelectionListener
 715:    * @see #removeListSelectionListener
 716:    * @see #getListeners
 717:    * @since 1.4
 718:    */
 719:   public ListSelectionListener[] getListSelectionListeners()
 720:   {
 721:     return (ListSelectionListener[]) getListeners(ListSelectionListener.class);
 722:   }
 723: 
 724:   /**
 725:    * Returns a clone of this object.
 726:    * <code>listenerList</code> don't gets duplicated.
 727:    *
 728:    * @return the cloned object
 729:    *
 730:    * @throws CloneNotSupportedException if an error occurs
 731:    */
 732:   public Object clone()
 733:     throws CloneNotSupportedException
 734:   {
 735:     DefaultListSelectionModel model =
 736:       (DefaultListSelectionModel) super.clone();
 737:     model.sel = (BitSet) sel.clone();
 738:     return model;
 739:   }
 740: }