1 /*
   2  * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javax.swing;
  27 
  28 import java.util.EventListener;
  29 import java.util.BitSet;
  30 import java.io.Serializable;
  31 import java.beans.Transient;
  32 
  33 import javax.swing.event.*;
  34 
  35 
  36 /**
  37  * Default data model for list selections.
  38  * <p>
  39  * <strong>Warning:</strong>
  40  * Serialized objects of this class will not be compatible with
  41  * future Swing releases. The current serialization support is
  42  * appropriate for short term storage or RMI between applications running
  43  * the same version of Swing.  As of 1.4, support for long term storage
  44  * of all JavaBeans&trade;
  45  * has been added to the <code>java.beans</code> package.
  46  * Please see {@link java.beans.XMLEncoder}.
  47  *
  48  * @author Philip Milne
  49  * @author Hans Muller
  50  * @see ListSelectionModel
  51  */
  52 @SuppressWarnings("serial") // Same-version serialization only
  53 public class DefaultListSelectionModel implements ListSelectionModel, Cloneable, Serializable
  54 {
  55     private static final int MIN = -1;
  56     private static final int MAX = Integer.MAX_VALUE;
  57     private int selectionMode = MULTIPLE_INTERVAL_SELECTION;
  58     private int minIndex = MAX;
  59     private int maxIndex = MIN;
  60     private int anchorIndex = -1;
  61     private int leadIndex = -1;
  62     private int firstAdjustedIndex = MAX;
  63     private int lastAdjustedIndex = MIN;
  64     private boolean isAdjusting = false;
  65 
  66     private int firstChangedIndex = MAX;
  67     private int lastChangedIndex = MIN;
  68 
  69     private BitSet value = new BitSet(32);
  70     protected EventListenerList listenerList = new EventListenerList();
  71 
  72     protected boolean leadAnchorNotificationEnabled = true;
  73 
  74     /** {@inheritDoc} */
  75     public int getMinSelectionIndex() { return isSelectionEmpty() ? -1 : minIndex; }
  76 
  77     /** {@inheritDoc} */
  78     public int getMaxSelectionIndex() { return maxIndex; }
  79 
  80     /** {@inheritDoc} */
  81     public boolean getValueIsAdjusting() { return isAdjusting; }
  82 
  83     /** {@inheritDoc} */
  84     public int getSelectionMode() { return selectionMode; }
  85 
  86     /**
  87      * {@inheritDoc}
  88      * @throws IllegalArgumentException {@inheritDoc}
  89      */
  90     public void setSelectionMode(int selectionMode) {
  91         switch (selectionMode) {
  92         case SINGLE_SELECTION:
  93         case SINGLE_INTERVAL_SELECTION:
  94         case MULTIPLE_INTERVAL_SELECTION:
  95             this.selectionMode = selectionMode;
  96             break;
  97         default:
  98             throw new IllegalArgumentException("invalid selectionMode");
  99         }
 100     }
 101 
 102     /** {@inheritDoc} */
 103     public boolean isSelectedIndex(int index) {
 104         return ((index < minIndex) || (index > maxIndex)) ? false : value.get(index);
 105     }
 106 
 107     /** {@inheritDoc} */
 108     public boolean isSelectionEmpty() {
 109         return (minIndex > maxIndex);
 110     }
 111 
 112     /** {@inheritDoc} */
 113     public void addListSelectionListener(ListSelectionListener l) {
 114         listenerList.add(ListSelectionListener.class, l);
 115     }
 116 
 117     /** {@inheritDoc} */
 118     public void removeListSelectionListener(ListSelectionListener l) {
 119         listenerList.remove(ListSelectionListener.class, l);
 120     }
 121 
 122     /**
 123      * Returns an array of all the list selection listeners
 124      * registered on this <code>DefaultListSelectionModel</code>.
 125      *
 126      * @return all of this model's <code>ListSelectionListener</code>s
 127      *         or an empty
 128      *         array if no list selection listeners are currently registered
 129      *
 130      * @see #addListSelectionListener
 131      * @see #removeListSelectionListener
 132      *
 133      * @since 1.4
 134      */
 135     public ListSelectionListener[] getListSelectionListeners() {
 136         return listenerList.getListeners(ListSelectionListener.class);
 137     }
 138 
 139     /**
 140      * Notifies listeners that we have ended a series of adjustments.
 141      */
 142     protected void fireValueChanged(boolean isAdjusting) {
 143         if (lastChangedIndex == MIN) {
 144             return;
 145         }
 146         /* Change the values before sending the event to the
 147          * listeners in case the event causes a listener to make
 148          * another change to the selection.
 149          */
 150         int oldFirstChangedIndex = firstChangedIndex;
 151         int oldLastChangedIndex = lastChangedIndex;
 152         firstChangedIndex = MAX;
 153         lastChangedIndex = MIN;
 154         fireValueChanged(oldFirstChangedIndex, oldLastChangedIndex, isAdjusting);
 155     }
 156 
 157 
 158     /**
 159      * Notifies <code>ListSelectionListeners</code> that the value
 160      * of the selection, in the closed interval <code>firstIndex</code>,
 161      * <code>lastIndex</code>, has changed.
 162      */
 163     protected void fireValueChanged(int firstIndex, int lastIndex) {
 164         fireValueChanged(firstIndex, lastIndex, getValueIsAdjusting());
 165     }
 166 
 167     /**
 168      * @param firstIndex the first index in the interval
 169      * @param lastIndex the last index in the interval
 170      * @param isAdjusting true if this is the final change in a series of
 171      *          adjustments
 172      * @see EventListenerList
 173      */
 174     protected void fireValueChanged(int firstIndex, int lastIndex, boolean isAdjusting)
 175     {
 176         Object[] listeners = listenerList.getListenerList();
 177         ListSelectionEvent e = null;
 178 
 179         for (int i = listeners.length - 2; i >= 0; i -= 2) {
 180             if (listeners[i] == ListSelectionListener.class) {
 181                 if (e == null) {
 182                     e = new ListSelectionEvent(this, firstIndex, lastIndex, isAdjusting);
 183                 }
 184                 ((ListSelectionListener)listeners[i+1]).valueChanged(e);
 185             }
 186         }
 187     }
 188 
 189     private void fireValueChanged() {
 190         if (lastAdjustedIndex == MIN) {
 191             return;
 192         }
 193         /* If getValueAdjusting() is true, (eg. during a drag opereration)
 194          * record the bounds of the changes so that, when the drag finishes (and
 195          * setValueAdjusting(false) is called) we can post a single event
 196          * with bounds covering all of these individual adjustments.
 197          */
 198         if (getValueIsAdjusting()) {
 199             firstChangedIndex = Math.min(firstChangedIndex, firstAdjustedIndex);
 200             lastChangedIndex = Math.max(lastChangedIndex, lastAdjustedIndex);
 201         }
 202         /* Change the values before sending the event to the
 203          * listeners in case the event causes a listener to make
 204          * another change to the selection.
 205          */
 206         int oldFirstAdjustedIndex = firstAdjustedIndex;
 207         int oldLastAdjustedIndex = lastAdjustedIndex;
 208         firstAdjustedIndex = MAX;
 209         lastAdjustedIndex = MIN;
 210 
 211         fireValueChanged(oldFirstAdjustedIndex, oldLastAdjustedIndex);
 212     }
 213 
 214     /**
 215      * Returns an array of all the objects currently registered as
 216      * <code><em>Foo</em>Listener</code>s
 217      * upon this model.
 218      * <code><em>Foo</em>Listener</code>s
 219      * are registered using the <code>add<em>Foo</em>Listener</code> method.
 220      * <p>
 221      * You can specify the <code>listenerType</code> argument
 222      * with a class literal, such as <code><em>Foo</em>Listener.class</code>.
 223      * For example, you can query a <code>DefaultListSelectionModel</code>
 224      * instance <code>m</code>
 225      * for its list selection listeners
 226      * with the following code:
 227      *
 228      * <pre>ListSelectionListener[] lsls = (ListSelectionListener[])(m.getListeners(ListSelectionListener.class));</pre>
 229      *
 230      * If no such listeners exist,
 231      * this method returns an empty array.
 232      *
 233      * @param listenerType  the type of listeners requested;
 234      *          this parameter should specify an interface
 235      *          that descends from <code>java.util.EventListener</code>
 236      * @return an array of all objects registered as
 237      *          <code><em>Foo</em>Listener</code>s
 238      *          on this model,
 239      *          or an empty array if no such
 240      *          listeners have been added
 241      * @exception ClassCastException if <code>listenerType</code> doesn't
 242      *          specify a class or interface that implements
 243      *          <code>java.util.EventListener</code>
 244      *
 245      * @see #getListSelectionListeners
 246      *
 247      * @since 1.3
 248      */
 249     public <T extends EventListener> T[] getListeners(Class<T> listenerType) {
 250         return listenerList.getListeners(listenerType);
 251     }
 252 
 253     // Updates first and last change indices
 254     private void markAsDirty(int r) {
 255         if (r == -1) {
 256             return;
 257         }
 258 
 259         firstAdjustedIndex = Math.min(firstAdjustedIndex, r);
 260         lastAdjustedIndex =  Math.max(lastAdjustedIndex, r);
 261     }
 262 
 263     // Sets the state at this index and update all relevant state.
 264     private void set(int r) {
 265         if (value.get(r)) {
 266             return;
 267         }
 268         value.set(r);
 269         markAsDirty(r);
 270 
 271         // Update minimum and maximum indices
 272         minIndex = Math.min(minIndex, r);
 273         maxIndex = Math.max(maxIndex, r);
 274     }
 275 
 276     // Clears the state at this index and update all relevant state.
 277     private void clear(int r) {
 278         if (!value.get(r)) {
 279             return;
 280         }
 281         value.clear(r);
 282         markAsDirty(r);
 283 
 284         // Update minimum and maximum indices
 285         /*
 286            If (r > minIndex) the minimum has not changed.
 287            The case (r < minIndex) is not possible because r'th value was set.
 288            We only need to check for the case when lowest entry has been cleared,
 289            and in this case we need to search for the first value set above it.
 290         */
 291         if (r == minIndex) {
 292             for(minIndex = minIndex + 1; minIndex <= maxIndex; minIndex++) {
 293                 if (value.get(minIndex)) {
 294                     break;
 295                 }
 296             }
 297         }
 298         /*
 299            If (r < maxIndex) the maximum has not changed.
 300            The case (r > maxIndex) is not possible because r'th value was set.
 301            We only need to check for the case when highest entry has been cleared,
 302            and in this case we need to search for the first value set below it.
 303         */
 304         if (r == maxIndex) {
 305             for(maxIndex = maxIndex - 1; minIndex <= maxIndex; maxIndex--) {
 306                 if (value.get(maxIndex)) {
 307                     break;
 308                 }
 309             }
 310         }
 311         /* Performance note: This method is called from inside a loop in
 312            changeSelection() but we will only iterate in the loops
 313            above on the basis of one iteration per deselected cell - in total.
 314            Ie. the next time this method is called the work of the previous
 315            deselection will not be repeated.
 316 
 317            We also don't need to worry about the case when the min and max
 318            values are in their unassigned states. This cannot happen because
 319            this method's initial check ensures that the selection was not empty
 320            and therefore that the minIndex and maxIndex had 'real' values.
 321 
 322            If we have cleared the whole selection, set the minIndex and maxIndex
 323            to their cannonical values so that the next set command always works
 324            just by using Math.min and Math.max.
 325         */
 326         if (isSelectionEmpty()) {
 327             minIndex = MAX;
 328             maxIndex = MIN;
 329         }
 330     }
 331 
 332     /**
 333      * Sets the value of the leadAnchorNotificationEnabled flag.
 334      * @see             #isLeadAnchorNotificationEnabled()
 335      */
 336     public void setLeadAnchorNotificationEnabled(boolean flag) {
 337         leadAnchorNotificationEnabled = flag;
 338     }
 339 
 340     /**
 341      * Returns the value of the <code>leadAnchorNotificationEnabled</code> flag.
 342      * When <code>leadAnchorNotificationEnabled</code> is true the model
 343      * generates notification events with bounds that cover all the changes to
 344      * the selection plus the changes to the lead and anchor indices.
 345      * Setting the flag to false causes a narrowing of the event's bounds to
 346      * include only the elements that have been selected or deselected since
 347      * the last change. Either way, the model continues to maintain the lead
 348      * and anchor variables internally. The default is true.
 349      * <p>
 350      * Note: It is possible for the lead or anchor to be changed without a
 351      * change to the selection. Notification of these changes is often
 352      * important, such as when the new lead or anchor needs to be updated in
 353      * the view. Therefore, caution is urged when changing the default value.
 354      *
 355      * @return  the value of the <code>leadAnchorNotificationEnabled</code> flag
 356      * @see             #setLeadAnchorNotificationEnabled(boolean)
 357      */
 358     public boolean isLeadAnchorNotificationEnabled() {
 359         return leadAnchorNotificationEnabled;
 360     }
 361 
 362     private void updateLeadAnchorIndices(int anchorIndex, int leadIndex) {
 363         if (leadAnchorNotificationEnabled) {
 364             if (this.anchorIndex != anchorIndex) {
 365                 markAsDirty(this.anchorIndex);
 366                 markAsDirty(anchorIndex);
 367             }
 368 
 369             if (this.leadIndex != leadIndex) {
 370                 markAsDirty(this.leadIndex);
 371                 markAsDirty(leadIndex);
 372             }
 373         }
 374         this.anchorIndex = anchorIndex;
 375         this.leadIndex = leadIndex;
 376     }
 377 
 378     private boolean contains(int a, int b, int i) {
 379         return (i >= a) && (i <= b);
 380     }
 381 
 382     private void changeSelection(int clearMin, int clearMax,
 383                                  int setMin, int setMax, boolean clearFirst) {
 384         for(int i = Math.min(setMin, clearMin); i <= Math.max(setMax, clearMax); i++) {
 385 
 386             boolean shouldClear = contains(clearMin, clearMax, i);
 387             boolean shouldSet = contains(setMin, setMax, i);
 388 
 389             if (shouldSet && shouldClear) {
 390                 if (clearFirst) {
 391                     shouldClear = false;
 392                 }
 393                 else {
 394                     shouldSet = false;
 395                 }
 396             }
 397 
 398             if (shouldSet) {
 399                 set(i);
 400             }
 401             if (shouldClear) {
 402                 clear(i);
 403             }
 404         }
 405         fireValueChanged();
 406     }
 407 
 408    /**
 409     * Change the selection with the effect of first clearing the values
 410     * in the inclusive range [clearMin, clearMax] then setting the values
 411     * in the inclusive range [setMin, setMax]. Do this in one pass so
 412     * that no values are cleared if they would later be set.
 413     */
 414     private void changeSelection(int clearMin, int clearMax, int setMin, int setMax) {
 415         changeSelection(clearMin, clearMax, setMin, setMax, true);
 416     }
 417 
 418     /** {@inheritDoc} */
 419     public void clearSelection() {
 420         removeSelectionIntervalImpl(minIndex, maxIndex, false);
 421     }
 422 
 423     /**
 424      * Changes the selection to be between {@code index0} and {@code index1}
 425      * inclusive. {@code index0} doesn't have to be less than or equal to
 426      * {@code index1}.
 427      * <p>
 428      * In {@code SINGLE_SELECTION} selection mode, only the second index
 429      * is used.
 430      * <p>
 431      * If this represents a change to the current selection, then each
 432      * {@code ListSelectionListener} is notified of the change.
 433      * <p>
 434      * If either index is {@code -1}, this method does nothing and returns
 435      * without exception. Otherwise, if either index is less than {@code -1},
 436      * an {@code IndexOutOfBoundsException} is thrown.
 437      *
 438      * @param index0 one end of the interval.
 439      * @param index1 other end of the interval
 440      * @throws IndexOutOfBoundsException if either index is less than {@code -1}
 441      *         (and neither index is {@code -1})
 442      * @see #addListSelectionListener
 443      */
 444     public void setSelectionInterval(int index0, int index1) {
 445         if (index0 == -1 || index1 == -1) {
 446             return;
 447         }
 448 
 449         if (getSelectionMode() == SINGLE_SELECTION) {
 450             index0 = index1;
 451         }
 452 
 453         updateLeadAnchorIndices(index0, index1);
 454 
 455         int clearMin = minIndex;
 456         int clearMax = maxIndex;
 457         int setMin = Math.min(index0, index1);
 458         int setMax = Math.max(index0, index1);
 459         changeSelection(clearMin, clearMax, setMin, setMax);
 460     }
 461 
 462     /**
 463      * Changes the selection to be the set union of the current selection
 464      * and the indices between {@code index0} and {@code index1} inclusive.
 465      * <p>
 466      * In {@code SINGLE_SELECTION} selection mode, this is equivalent
 467      * to calling {@code setSelectionInterval}, and only the second index
 468      * is used. In {@code SINGLE_INTERVAL_SELECTION} selection mode, this
 469      * method behaves like {@code setSelectionInterval}, unless the given
 470      * interval is immediately adjacent to or overlaps the existing selection,
 471      * and can therefore be used to grow it.
 472      * <p>
 473      * If this represents a change to the current selection, then each
 474      * {@code ListSelectionListener} is notified of the change. Note that
 475      * {@code index0} doesn't have to be less than or equal to {@code index1}.
 476      * <p>
 477      * If either index is {@code -1}, this method does nothing and returns
 478      * without exception. Otherwise, if either index is less than {@code -1},
 479      * an {@code IndexOutOfBoundsException} is thrown.
 480      *
 481      * @param index0 one end of the interval.
 482      * @param index1 other end of the interval
 483      * @throws IndexOutOfBoundsException if either index is less than {@code -1}
 484      *         (and neither index is {@code -1})
 485      * @see #addListSelectionListener
 486      * @see #setSelectionInterval
 487      */
 488     public void addSelectionInterval(int index0, int index1)
 489     {
 490         if (index0 == -1 || index1 == -1) {
 491             return;
 492         }
 493 
 494         // If we only allow a single selection, channel through
 495         // setSelectionInterval() to enforce the rule.
 496         if (getSelectionMode() == SINGLE_SELECTION) {
 497             setSelectionInterval(index0, index1);
 498             return;
 499         }
 500 
 501         updateLeadAnchorIndices(index0, index1);
 502 
 503         int clearMin = MAX;
 504         int clearMax = MIN;
 505         int setMin = Math.min(index0, index1);
 506         int setMax = Math.max(index0, index1);
 507 
 508         // If we only allow a single interval and this would result
 509         // in multiple intervals, then set the selection to be just
 510         // the new range.
 511         if (getSelectionMode() == SINGLE_INTERVAL_SELECTION &&
 512                 (setMax < minIndex - 1 || setMin > maxIndex + 1)) {
 513 
 514             setSelectionInterval(index0, index1);
 515             return;
 516         }
 517 
 518         changeSelection(clearMin, clearMax, setMin, setMax);
 519     }
 520 
 521 
 522     /**
 523      * Changes the selection to be the set difference of the current selection
 524      * and the indices between {@code index0} and {@code index1} inclusive.
 525      * {@code index0} doesn't have to be less than or equal to {@code index1}.
 526      * <p>
 527      * In {@code SINGLE_INTERVAL_SELECTION} selection mode, if the removal
 528      * would produce two disjoint selections, the removal is extended through
 529      * the greater end of the selection. For example, if the selection is
 530      * {@code 0-10} and you supply indices {@code 5,6} (in any order) the
 531      * resulting selection is {@code 0-4}.
 532      * <p>
 533      * If this represents a change to the current selection, then each
 534      * {@code ListSelectionListener} is notified of the change.
 535      * <p>
 536      * If either index is {@code -1}, this method does nothing and returns
 537      * without exception. Otherwise, if either index is less than {@code -1},
 538      * an {@code IndexOutOfBoundsException} is thrown.
 539      *
 540      * @param index0 one end of the interval
 541      * @param index1 other end of the interval
 542      * @throws IndexOutOfBoundsException if either index is less than {@code -1}
 543      *         (and neither index is {@code -1})
 544      * @see #addListSelectionListener
 545      */
 546     public void removeSelectionInterval(int index0, int index1)
 547     {
 548         removeSelectionIntervalImpl(index0, index1, true);
 549     }
 550 
 551     // private implementation allowing the selection interval
 552     // to be removed without affecting the lead and anchor
 553     private void removeSelectionIntervalImpl(int index0, int index1,
 554                                              boolean changeLeadAnchor) {
 555 
 556         if (index0 == -1 || index1 == -1) {
 557             return;
 558         }
 559 
 560         if (changeLeadAnchor) {
 561             updateLeadAnchorIndices(index0, index1);
 562         }
 563 
 564         int clearMin = Math.min(index0, index1);
 565         int clearMax = Math.max(index0, index1);
 566         int setMin = MAX;
 567         int setMax = MIN;
 568 
 569         // If the removal would produce to two disjoint selections in a mode
 570         // that only allows one, extend the removal to the end of the selection.
 571         if (getSelectionMode() != MULTIPLE_INTERVAL_SELECTION &&
 572                clearMin > minIndex && clearMax < maxIndex) {
 573             clearMax = maxIndex;
 574         }
 575 
 576         changeSelection(clearMin, clearMax, setMin, setMax);
 577     }
 578 
 579     private void setState(int index, boolean state) {
 580         if (state) {
 581             set(index);
 582         }
 583         else {
 584             clear(index);
 585         }
 586     }
 587 
 588     /**
 589      * Insert length indices beginning before/after index. If the value
 590      * at index is itself selected and the selection mode is not
 591      * SINGLE_SELECTION, set all of the newly inserted items as selected.
 592      * Otherwise leave them unselected. This method is typically
 593      * called to sync the selection model with a corresponding change
 594      * in the data model.
 595      */
 596     public void insertIndexInterval(int index, int length, boolean before)
 597     {
 598         /* The first new index will appear at insMinIndex and the last
 599          * one will appear at insMaxIndex
 600          */
 601         int insMinIndex = (before) ? index : index + 1;
 602         int insMaxIndex = (insMinIndex + length) - 1;
 603 
 604         /* Right shift the entire bitset by length, beginning with
 605          * index-1 if before is true, index+1 if it's false (i.e. with
 606          * insMinIndex).
 607          */
 608         for(int i = maxIndex; i >= insMinIndex; i--) {
 609             setState(i + length, value.get(i));
 610         }
 611 
 612         /* Initialize the newly inserted indices.
 613          */
 614         boolean setInsertedValues = ((getSelectionMode() == SINGLE_SELECTION) ?
 615                                         false : value.get(index));
 616         for(int i = insMinIndex; i <= insMaxIndex; i++) {
 617             setState(i, setInsertedValues);
 618         }
 619 
 620         int leadIndex = this.leadIndex;
 621         if (leadIndex > index || (before && leadIndex == index)) {
 622             leadIndex = this.leadIndex + length;
 623         }
 624         int anchorIndex = this.anchorIndex;
 625         if (anchorIndex > index || (before && anchorIndex == index)) {
 626             anchorIndex = this.anchorIndex + length;
 627         }
 628         if (leadIndex != this.leadIndex || anchorIndex != this.anchorIndex) {
 629             updateLeadAnchorIndices(anchorIndex, leadIndex);
 630         }
 631 
 632         fireValueChanged();
 633     }
 634 
 635 
 636     /**
 637      * Remove the indices in the interval index0,index1 (inclusive) from
 638      * the selection model.  This is typically called to sync the selection
 639      * model width a corresponding change in the data model.  Note
 640      * that (as always) index0 need not be &lt;= index1.
 641      */
 642     public void removeIndexInterval(int index0, int index1)
 643     {
 644         int rmMinIndex = Math.min(index0, index1);
 645         int rmMaxIndex = Math.max(index0, index1);
 646         int gapLength = (rmMaxIndex - rmMinIndex) + 1;
 647 
 648         /* Shift the entire bitset to the left to close the index0, index1
 649          * gap.
 650          */
 651         for(int i = rmMinIndex; i <= maxIndex; i++) {
 652             setState(i, value.get(i + gapLength));
 653         }
 654 
 655         int leadIndex = this.leadIndex;
 656         if (leadIndex == 0 && rmMinIndex == 0) {
 657             // do nothing
 658         } else if (leadIndex > rmMaxIndex) {
 659             leadIndex = this.leadIndex - gapLength;
 660         } else if (leadIndex >= rmMinIndex) {
 661             leadIndex = rmMinIndex - 1;
 662         }
 663 
 664         int anchorIndex = this.anchorIndex;
 665         if (anchorIndex == 0 && rmMinIndex == 0) {
 666             // do nothing
 667         } else if (anchorIndex > rmMaxIndex) {
 668             anchorIndex = this.anchorIndex - gapLength;
 669         } else if (anchorIndex >= rmMinIndex) {
 670             anchorIndex = rmMinIndex - 1;
 671         }
 672 
 673         if (leadIndex != this.leadIndex || anchorIndex != this.anchorIndex) {
 674             updateLeadAnchorIndices(anchorIndex, leadIndex);
 675         }
 676 
 677         fireValueChanged();
 678     }
 679 
 680 
 681     /** {@inheritDoc} */
 682     public void setValueIsAdjusting(boolean isAdjusting) {
 683         if (isAdjusting != this.isAdjusting) {
 684             this.isAdjusting = isAdjusting;
 685             this.fireValueChanged(isAdjusting);
 686         }
 687     }
 688 
 689 
 690     /**
 691      * Returns a string that displays and identifies this
 692      * object's properties.
 693      *
 694      * @return a <code>String</code> representation of this object
 695      */
 696     public String toString() {
 697         String s =  ((getValueIsAdjusting()) ? "~" : "=") + value.toString();
 698         return getClass().getName() + " " + Integer.toString(hashCode()) + " " + s;
 699     }
 700 
 701     /**
 702      * Returns a clone of this selection model with the same selection.
 703      * <code>listenerLists</code> are not duplicated.
 704      *
 705      * @exception CloneNotSupportedException if the selection model does not
 706      *    both (a) implement the Cloneable interface and (b) define a
 707      *    <code>clone</code> method.
 708      */
 709     public Object clone() throws CloneNotSupportedException {
 710         DefaultListSelectionModel clone = (DefaultListSelectionModel)super.clone();
 711         clone.value = (BitSet)value.clone();
 712         clone.listenerList = new EventListenerList();
 713         return clone;
 714     }
 715 
 716     /** {@inheritDoc} */
 717     @Transient
 718     public int getAnchorSelectionIndex() {
 719         return anchorIndex;
 720     }
 721 
 722     /** {@inheritDoc} */
 723     @Transient
 724     public int getLeadSelectionIndex() {
 725         return leadIndex;
 726     }
 727 
 728     /**
 729      * Set the anchor selection index, leaving all selection values unchanged.
 730      * If leadAnchorNotificationEnabled is true, send a notification covering
 731      * the old and new anchor cells.
 732      *
 733      * @see #getAnchorSelectionIndex
 734      * @see #setLeadSelectionIndex
 735      */
 736     public void setAnchorSelectionIndex(int anchorIndex) {
 737         updateLeadAnchorIndices(anchorIndex, this.leadIndex);
 738         fireValueChanged();
 739     }
 740 
 741     /**
 742      * Set the lead selection index, leaving all selection values unchanged.
 743      * If leadAnchorNotificationEnabled is true, send a notification covering
 744      * the old and new lead cells.
 745      *
 746      * @param leadIndex the new lead selection index
 747      *
 748      * @see #setAnchorSelectionIndex
 749      * @see #setLeadSelectionIndex
 750      * @see #getLeadSelectionIndex
 751      *
 752      * @since 1.5
 753      */
 754     public void moveLeadSelectionIndex(int leadIndex) {
 755         // disallow a -1 lead unless the anchor is already -1
 756         if (leadIndex == -1) {
 757             if (this.anchorIndex != -1) {
 758                 return;
 759             }
 760 
 761 /* PENDING(shannonh) - The following check is nice, to be consistent with
 762                        setLeadSelectionIndex. However, it is not absolutely
 763                        necessary: One could work around it by setting the anchor
 764                        to something valid, modifying the lead, and then moving
 765                        the anchor back to -1. For this reason, there's no sense
 766                        in adding it at this time, as that would require
 767                        updating the spec and officially committing to it.
 768 
 769         // otherwise, don't do anything if the anchor is -1
 770         } else if (this.anchorIndex == -1) {
 771             return;
 772 */
 773 
 774         }
 775 
 776         updateLeadAnchorIndices(this.anchorIndex, leadIndex);
 777         fireValueChanged();
 778     }
 779 
 780     /**
 781      * Sets the lead selection index, ensuring that values between the
 782      * anchor and the new lead are either all selected or all deselected.
 783      * If the value at the anchor index is selected, first clear all the
 784      * values in the range [anchor, oldLeadIndex], then select all the values
 785      * values in the range [anchor, newLeadIndex], where oldLeadIndex is the old
 786      * leadIndex and newLeadIndex is the new one.
 787      * <p>
 788      * If the value at the anchor index is not selected, do the same thing in
 789      * reverse selecting values in the old range and deselecting values in the
 790      * new one.
 791      * <p>
 792      * Generate a single event for this change and notify all listeners.
 793      * For the purposes of generating minimal bounds in this event, do the
 794      * operation in a single pass; that way the first and last index inside the
 795      * ListSelectionEvent that is broadcast will refer to cells that actually
 796      * changed value because of this method. If, instead, this operation were
 797      * done in two steps the effect on the selection state would be the same
 798      * but two events would be generated and the bounds around the changed
 799      * values would be wider, including cells that had been first cleared only
 800      * to later be set.
 801      * <p>
 802      * This method can be used in the <code>mouseDragged</code> method
 803      * of a UI class to extend a selection.
 804      *
 805      * @see #getLeadSelectionIndex
 806      * @see #setAnchorSelectionIndex
 807      */
 808     public void setLeadSelectionIndex(int leadIndex) {
 809         int anchorIndex = this.anchorIndex;
 810 
 811         // only allow a -1 lead if the anchor is already -1
 812         if (leadIndex == -1) {
 813             if (anchorIndex == -1) {
 814                 updateLeadAnchorIndices(anchorIndex, leadIndex);
 815                 fireValueChanged();
 816             }
 817 
 818             return;
 819         // otherwise, don't do anything if the anchor is -1
 820         } else if (anchorIndex == -1) {
 821             return;
 822         }
 823 
 824         if (this.leadIndex == -1) {
 825             this.leadIndex = leadIndex;
 826         }
 827 
 828         boolean shouldSelect = value.get(this.anchorIndex);
 829 
 830         if (getSelectionMode() == SINGLE_SELECTION) {
 831             anchorIndex = leadIndex;
 832             shouldSelect = true;
 833         }
 834 
 835         int oldMin = Math.min(this.anchorIndex, this.leadIndex);
 836         int oldMax = Math.max(this.anchorIndex, this.leadIndex);
 837         int newMin = Math.min(anchorIndex, leadIndex);
 838         int newMax = Math.max(anchorIndex, leadIndex);
 839 
 840         updateLeadAnchorIndices(anchorIndex, leadIndex);
 841 
 842         if (shouldSelect) {
 843             changeSelection(oldMin, oldMax, newMin, newMax);
 844         }
 845         else {
 846             changeSelection(newMin, newMax, oldMin, oldMax, false);
 847         }
 848     }
 849 }