       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         updateLeadAnchorIndices(-1, -1);
     459         removeSelectionIntervalImpl(minIndex, maxIndex, false);
     460     }
     461
     462     /**
     463      * Changes the selection to be between {@code index0} and {@code index1}
     464      * inclusive. {@code index0} doesn't have to be less than or equal to
     465      * {@code index1}.
     466      * <p>
     467      * In {@code SINGLE_SELECTION} selection mode, only the second index
     468      * is used.
     469      * <p>
     470      * If this represents a change to the current selection, then each
     471      * {@code ListSelectionListener} is notified of the change.
     472      * <p>
     473      * If either index is {@code -1}, this method does nothing and returns
     474      * without exception. Otherwise, if either index is less than {@code -1},
     475      * an {@code IndexOutOfBoundsException} is thrown.
     476      *
     477      * @param index0 one end of the interval.
     478      * @param index1 other end of the interval
     479      * @throws IndexOutOfBoundsException if either index is less than {@code -1}
     480      *         (and neither index is {@code -1})
     481      * @see #addListSelectionListener
     482      */
     483     public void setSelectionInterval(int index0, int index1) {
     484         if (index0 == -1 || index1 == -1) {
     485             return;
     486         }
     487
     488         if (getSelectionMode() == SINGLE_SELECTION) {
     489             index0 = index1;
     490         }
     491
     492         updateLeadAnchorIndices(index0, index1);
     493
     494         int clearMin = minIndex;
     495         int clearMax = maxIndex;
     496         int setMin = Math.min(index0, index1);
     497         int setMax = Math.max(index0, index1);
     498         changeSelection(clearMin, clearMax, setMin, setMax);
     499     }
     500
     501     /**
     502      * Changes the selection to be the set union of the current selection
     503      * and the indices between {@code index0} and {@code index1} inclusive.
     504      * <p>
     505      * In {@code SINGLE_SELECTION} selection mode, this is equivalent
     506      * to calling {@code setSelectionInterval}, and only the second index
     507      * is used. In {@code SINGLE_INTERVAL_SELECTION} selection mode, this
     508      * method behaves like {@code setSelectionInterval}, unless the given
     509      * interval is immediately adjacent to or overlaps the existing selection,
     510      * and can therefore be used to grow it.
     511      * <p>
     512      * If this represents a change to the current selection, then each
     513      * {@code ListSelectionListener} is notified of the change. Note that
     514      * {@code index0} doesn't have to be less than or equal to {@code index1}.
     515      * <p>
     516      * If either index is {@code -1}, this method does nothing and returns
     517      * without exception. Otherwise, if either index is less than {@code -1},
     518      * an {@code IndexOutOfBoundsException} is thrown.
     519      *
     520      * @param index0 one end of the interval.
     521      * @param index1 other end of the interval
     522      * @throws IndexOutOfBoundsException if either index is less than {@code -1}
     523      *         (and neither index is {@code -1})
     524      * @see #addListSelectionListener
     525      * @see #setSelectionInterval
     526      */
     527     public void addSelectionInterval(int index0, int index1)
     528     {
     529         if (index0 == -1 || index1 == -1) {
     530             return;
     531         }
     532
     533         // If we only allow a single selection, channel through
     534         // setSelectionInterval() to enforce the rule.
     535         if (getSelectionMode() == SINGLE_SELECTION) {
     536             setSelectionInterval(index0, index1);
     537             return;
     538         }
     539
     540         updateLeadAnchorIndices(index0, index1);
     541
     542         int clearMin = MAX;
     543         int clearMax = MIN;
     544         int setMin = Math.min(index0, index1);
     545         int setMax = Math.max(index0, index1);
     546
     547         // If we only allow a single interval and this would result
     548         // in multiple intervals, then set the selection to be just
     549         // the new range.
     550         if (getSelectionMode() == SINGLE_INTERVAL_SELECTION &&
     551                 (setMax < minIndex - 1 || setMin > maxIndex + 1)) {
     552
     553             setSelectionInterval(index0, index1);
     554             return;
     555         }
     556
     557         changeSelection(clearMin, clearMax, setMin, setMax);
     558     }
     559
     560
     561     /**
     562      * Changes the selection to be the set difference of the current selection
     563      * and the indices between {@code index0} and {@code index1} inclusive.
     564      * {@code index0} doesn't have to be less than or equal to {@code index1}.
     565      * <p>
     566      * In {@code SINGLE_INTERVAL_SELECTION} selection mode, if the removal
     567      * would produce two disjoint selections, the removal is extended through
     568      * the greater end of the selection. For example, if the selection is
     569      * {@code 0-10} and you supply indices {@code 5,6} (in any order) the
     570      * resulting selection is {@code 0-4}.
     571      * <p>
     572      * If this represents a change to the current selection, then each
     573      * {@code ListSelectionListener} is notified of the change.
     574      * <p>
     575      * If either index is {@code -1}, this method does nothing and returns
     576      * without exception. Otherwise, if either index is less than {@code -1},
     577      * an {@code IndexOutOfBoundsException} is thrown.
     578      *
     579      * @param index0 one end of the interval
     580      * @param index1 other end of the interval
     581      * @throws IndexOutOfBoundsException if either index is less than {@code -1}
     582      *         (and neither index is {@code -1})
     583      * @see #addListSelectionListener
     584      */
     585     public void removeSelectionInterval(int index0, int index1)
     586     {
     587         removeSelectionIntervalImpl(index0, index1, true);
     588     }
     589
     590     // private implementation allowing the selection interval
     591     // to be removed without affecting the lead and anchor
     592     private void removeSelectionIntervalImpl(int index0, int index1,
     593                                              boolean changeLeadAnchor) {
     594
     595         if (index0 == -1 || index1 == -1) {
     596             return;
     597         }
     598
     599         if (changeLeadAnchor) {
     600             updateLeadAnchorIndices(index0, index1);
     601         }
     602
     603         int clearMin = Math.min(index0, index1);
     604         int clearMax = Math.max(index0, index1);
     605         int setMin = MAX;
     606         int setMax = MIN;
     607
     608         // If the removal would produce to two disjoint selections in a mode
     609         // that only allows one, extend the removal to the end of the selection.
     610         if (getSelectionMode() != MULTIPLE_INTERVAL_SELECTION &&
     611                clearMin > minIndex && clearMax < maxIndex) {
     612             clearMax = maxIndex;
     613         }
     614
     615         changeSelection(clearMin, clearMax, setMin, setMax);
     616     }
     617
     618     private void setState(int index, boolean state) {
     619         if (state) {
     620             set(index);
     621         }
     622         else {
     623             clear(index);
     624         }
     625     }
     626
     627     /**
     628      * Insert length indices beginning before/after index. If the value
     629      * at index is itself selected and the selection mode is not
     630      * SINGLE_SELECTION, set all of the newly inserted items as selected.
     631      * Otherwise leave them unselected. This method is typically
     632      * called to sync the selection model with a corresponding change
     633      * in the data model.
     634      */
     635     public void insertIndexInterval(int index, int length, boolean before)
     636     {
     637         /* The first new index will appear at insMinIndex and the last
     638          * one will appear at insMaxIndex
     639          */
     640         int insMinIndex = (before) ? index : index + 1;
     641         int insMaxIndex = (insMinIndex + length) - 1;
     642
     643         /* Right shift the entire bitset by length, beginning with
     644          * index-1 if before is true, index+1 if it's false (i.e. with
     645          * insMinIndex).
     646          */
     647         for(int i = maxIndex; i >= insMinIndex; i--) {
     648             setState(i + length, value.get(i));
     649         }
     650
     651         /* Initialize the newly inserted indices.
     652          */
     653         boolean setInsertedValues = ((getSelectionMode() == SINGLE_SELECTION) ?
     654                                         false : value.get(index));
     655         for(int i = insMinIndex; i <= insMaxIndex; i++) {
     656             setState(i, setInsertedValues);
     657         }
     658
     659         int leadIndex = this.leadIndex;
     660         if (leadIndex > index || (before && leadIndex == index)) {
     661             leadIndex = this.leadIndex + length;
     662         }
     663         int anchorIndex = this.anchorIndex;
     664         if (anchorIndex > index || (before && anchorIndex == index)) {
     665             anchorIndex = this.anchorIndex + length;
     666         }
     667         if (leadIndex != this.leadIndex || anchorIndex != this.anchorIndex) {
     668             updateLeadAnchorIndices(anchorIndex, leadIndex);
     669         }
     670
     671         fireValueChanged();
     672     }
     673
     674
     675     /**
     676      * Remove the indices in the interval index0,index1 (inclusive) from
     677      * the selection model.  This is typically called to sync the selection
     678      * model width a corresponding change in the data model.  Note
     679      * that (as always) index0 need not be &lt;= index1.
     680      */
     681     public void removeIndexInterval(int index0, int index1)
     682     {
     683         int rmMinIndex = Math.min(index0, index1);
     684         int rmMaxIndex = Math.max(index0, index1);
     685         int gapLength = (rmMaxIndex - rmMinIndex) + 1;
     686
     687         /* Shift the entire bitset to the left to close the index0, index1
     688          * gap.
     689          */
     690         for(int i = rmMinIndex; i <= maxIndex; i++) {
     691             setState(i, value.get(i + gapLength));
     692         }
     693
     694         int leadIndex = this.leadIndex;
     695         if (leadIndex > rmMaxIndex) {
     696             leadIndex = this.leadIndex - gapLength;
     697         } else if (leadIndex >= rmMinIndex) {
     698             leadIndex = rmMinIndex - 1;
     699         }
     700
     701         int anchorIndex = this.anchorIndex;
     702         if (anchorIndex > rmMaxIndex) {
     703             anchorIndex = this.anchorIndex - gapLength;
     704         } else if (anchorIndex >= rmMinIndex) {
     705             anchorIndex = rmMinIndex - 1;
     706         }
     707
     708         if (leadIndex != this.leadIndex || anchorIndex != this.anchorIndex) {
     709             updateLeadAnchorIndices(anchorIndex, leadIndex);
     710         }
     711
     712         fireValueChanged();
     713     }
     714
     715
     716     /** {@inheritDoc} */
     717     public void setValueIsAdjusting(boolean isAdjusting) {
     718         if (isAdjusting != this.isAdjusting) {
     719             this.isAdjusting = isAdjusting;
     720             this.fireValueChanged(isAdjusting);
     721         }
     722     }
     723
     724
     725     /**
     726      * Returns a string that displays and identifies this
     727      * object's properties.
     728      *
     729      * @return a <code>String</code> representation of this object
     730      */
     731     public String toString() {
     732         String s =  ((getValueIsAdjusting()) ? "~" : "=") + value.toString();
     733         return getClass().getName() + " " + Integer.toString(hashCode()) + " " + s;
     734     }
     735
     736     /**
     737      * Returns a clone of this selection model with the same selection.
     738      * <code>listenerLists</code> are not duplicated.
     739      *
     740      * @exception CloneNotSupportedException if the selection model does not
     741      *    both (a) implement the Cloneable interface and (b) define a
     742      *    <code>clone</code> method.
     743      */
     744     public Object clone() throws CloneNotSupportedException {
     745         DefaultListSelectionModel clone = (DefaultListSelectionModel)super.clone();
     746         clone.value = (BitSet)value.clone();
     747         clone.listenerList = new EventListenerList();
     748         return clone;
     749     }
     750
     751     /** {@inheritDoc} */
     752     @Transient
     753     public int getAnchorSelectionIndex() {
     754         return anchorIndex;
     755     }
     756
     757     /** {@inheritDoc} */
     758     @Transient
     759     public int getLeadSelectionIndex() {
     760         return leadIndex;
     761     }
     762
     763     /**
     764      * Set the anchor selection index, leaving all selection values unchanged.
     765      * If leadAnchorNotificationEnabled is true, send a notification covering
     766      * the old and new anchor cells.
     767      *
     768      * @see #getAnchorSelectionIndex
     769      * @see #setLeadSelectionIndex
     770      */
     771     public void setAnchorSelectionIndex(int anchorIndex) {
     772         updateLeadAnchorIndices(anchorIndex, this.leadIndex);
     773         fireValueChanged();
     774     }
     775
     776     /**
     777      * Set the lead selection index, leaving all selection values unchanged.
     778      * If leadAnchorNotificationEnabled is true, send a notification covering
     779      * the old and new lead cells.
     780      *
     781      * @param leadIndex the new lead selection index
     782      *
     783      * @see #setAnchorSelectionIndex
     784      * @see #setLeadSelectionIndex
     785      * @see #getLeadSelectionIndex
     786      *
     787      * @since 1.5
     788      */
     789     public void moveLeadSelectionIndex(int leadIndex) {
     790         // disallow a -1 lead unless the anchor is already -1
     791         if (leadIndex == -1) {
     792             if (this.anchorIndex != -1) {
     793                 return;
     794             }
     795
     796 /* PENDING(shannonh) - The following check is nice, to be consistent with
     797                        setLeadSelectionIndex. However, it is not absolutely
     798                        necessary: One could work around it by setting the anchor
     799                        to something valid, modifying the lead, and then moving
     800                        the anchor back to -1. For this reason, there's no sense
     801                        in adding it at this time, as that would require
     802                        updating the spec and officially committing to it.
     803
     804         // otherwise, don't do anything if the anchor is -1
     805         } else if (this.anchorIndex == -1) {
     806             return;
     807 */
     808
     809         }
     810
     811         updateLeadAnchorIndices(this.anchorIndex, leadIndex);
     812         fireValueChanged();
     813     }
     814
     815     /**
     816      * Sets the lead selection index, ensuring that values between the
     817      * anchor and the new lead are either all selected or all deselected.
     818      * If the value at the anchor index is selected, first clear all the
     819      * values in the range [anchor, oldLeadIndex], then select all the values
     820      * values in the range [anchor, newLeadIndex], where oldLeadIndex is the old
     821      * leadIndex and newLeadIndex is the new one.
     822      * <p>
     823      * If the value at the anchor index is not selected, do the same thing in
     824      * reverse selecting values in the old range and deselecting values in the
     825      * new one.
     826      * <p>
     827      * Generate a single event for this change and notify all listeners.
     828      * For the purposes of generating minimal bounds in this event, do the
     829      * operation in a single pass; that way the first and last index inside the
     830      * ListSelectionEvent that is broadcast will refer to cells that actually
     831      * changed value because of this method. If, instead, this operation were
     832      * done in two steps the effect on the selection state would be the same
     833      * but two events would be generated and the bounds around the changed
     834      * values would be wider, including cells that had been first cleared only
     835      * to later be set.
     836      * <p>
     837      * This method can be used in the <code>mouseDragged</code> method
     838      * of a UI class to extend a selection.
     839      *
     840      * @see #getLeadSelectionIndex
     841      * @see #setAnchorSelectionIndex
     842      */
     843     public void setLeadSelectionIndex(int leadIndex) {
     844         int anchorIndex = this.anchorIndex;
     845
     846         // only allow a -1 lead if the anchor is already -1
     847         if (leadIndex == -1) {
     848             if (anchorIndex == -1) {
     849                 updateLeadAnchorIndices(anchorIndex, leadIndex);
     850                 fireValueChanged();
     851             }
     852
     853             return;
     854         // otherwise, don't do anything if the anchor is -1
     855         } else if (anchorIndex == -1) {
     856             return;
     857         }
     858
     859         if (this.leadIndex == -1) {
     860             this.leadIndex = leadIndex;
     861         }
     862
     863         boolean shouldSelect = value.get(this.anchorIndex);
     864
     865         if (getSelectionMode() == SINGLE_SELECTION) {
     866             anchorIndex = leadIndex;
     867             shouldSelect = true;
     868         }
     869
     870         int oldMin = Math.min(this.anchorIndex, this.leadIndex);
     871         int oldMax = Math.max(this.anchorIndex, this.leadIndex);
     872         int newMin = Math.min(anchorIndex, leadIndex);
     873         int newMax = Math.max(anchorIndex, leadIndex);
     874
     875         updateLeadAnchorIndices(anchorIndex, leadIndex);
     876
     877         if (shouldSelect) {
     878             changeSelection(oldMin, oldMax, newMin, newMax);
     879         }
     880         else {
     881             changeSelection(newMin, newMax, oldMin, oldMax, false);
     882         }
     883     }
     884 }