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