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