mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			856 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			856 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			Java
		
	
	
	
| /* DefaultListSelectionModel.java --
 | |
|    Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
 | |
| 
 | |
| This file is part of GNU Classpath.
 | |
| 
 | |
| GNU Classpath is free software; you can redistribute it and/or modify
 | |
| it under the terms of the GNU General Public License as published by
 | |
| the Free Software Foundation; either version 2, or (at your option)
 | |
| any later version.
 | |
| 
 | |
| GNU Classpath is distributed in the hope that it will be useful, but
 | |
| WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
| General Public License for more details.
 | |
| 
 | |
| You should have received a copy of the GNU General Public License
 | |
| along with GNU Classpath; see the file COPYING.  If not, write to the
 | |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | |
| 02110-1301 USA.
 | |
| 
 | |
| Linking this library statically or dynamically with other modules is
 | |
| making a combined work based on this library.  Thus, the terms and
 | |
| conditions of the GNU General Public License cover the whole
 | |
| combination.
 | |
| 
 | |
| As a special exception, the copyright holders of this library give you
 | |
| permission to link this library with independent modules to produce an
 | |
| executable, regardless of the license terms of these independent
 | |
| modules, and to copy and distribute the resulting executable under
 | |
| terms of your choice, provided that you also meet, for each linked
 | |
| independent module, the terms and conditions of the license of that
 | |
| module.  An independent module is a module which is not derived from
 | |
| or based on this library.  If you modify this library, you may extend
 | |
| this exception to your version of the library, but you are not
 | |
| obligated to do so.  If you do not wish to do so, delete this
 | |
| exception statement from your version. */
 | |
| 
 | |
| 
 | |
| package javax.swing;
 | |
| 
 | |
| import java.io.Serializable;
 | |
| import java.util.BitSet;
 | |
| import java.util.EventListener;
 | |
| 
 | |
| import javax.swing.event.EventListenerList;
 | |
| import javax.swing.event.ListSelectionEvent;
 | |
| import javax.swing.event.ListSelectionListener;
 | |
| 
 | |
| /**
 | |
|  * The default implementation of {@link ListSelectionModel},
 | |
|  * which is used by {@link javax.swing.JList} and
 | |
|  * similar classes to manage the selection status of a number of data
 | |
|  * elements.
 | |
|  *
 | |
|  * <p>The class is organized <em>abstractly</em> as a set of intervals of
 | |
|  * integers. Each interval indicates an inclusive range of indices in a
 | |
|  * list -- held by some other object and unknown to this class -- which is
 | |
|  * considered "selected". There are various accessors for querying and
 | |
|  * modifying the set of intervals, with simplified forms accepting a single
 | |
|  * index, representing an interval with only one element. </p>
 | |
|  */
 | |
| public class DefaultListSelectionModel implements Cloneable,
 | |
|                                                   ListSelectionModel,
 | |
|                                                   Serializable
 | |
| {
 | |
|   private static final long serialVersionUID = -5718799865110415860L;
 | |
| 
 | |
|   /** The list of ListSelectionListeners subscribed to this selection model. */
 | |
|   protected EventListenerList listenerList = new EventListenerList();
 | |
| 
 | |
| 
 | |
|   /**
 | |
|    * The current list selection mode. Must be one of the numeric constants
 | |
|    * <code>SINGLE_SELECTION</code>, <code>SINGLE_INTERVAL_SELECTION</code>
 | |
|    * or <code>MULTIPLE_INTERVAL_SELECTION</code> from {@link
 | |
|    * ListSelectionModel}. The default value is
 | |
|    * <code>MULTIPLE_INTERVAL_SELECTION</code>.
 | |
|    */
 | |
|   int selectionMode = MULTIPLE_INTERVAL_SELECTION;
 | |
| 
 | |
|   /**
 | |
|    * The index of the "lead" of the most recent selection. The lead is the
 | |
|    * second argument in any call to {@link #setSelectionInterval}, {@link
 | |
|    * #addSelectionInterval} or {@link #removeSelectionInterval}. Generally
 | |
|    * the lead refers to the most recent position a user dragged their mouse
 | |
|    * over.
 | |
|    */
 | |
|   int leadSelectionIndex = -1;
 | |
| 
 | |
|   /**
 | |
|    * The index of the "anchor" of the most recent selection. The anchor is
 | |
|    * the first argument in any call to {@link #setSelectionInterval},
 | |
|    * {@link #addSelectionInterval} or {@link
 | |
|    * #removeSelectionInterval}. Generally the anchor refers to the first
 | |
|    * recent position a user clicks when they begin to drag their mouse over
 | |
|    * a list.
 | |
|    *
 | |
|    * @see #getAnchorSelectionIndex
 | |
|    * @see #setAnchorSelectionIndex
 | |
|    */
 | |
|   int anchorSelectionIndex = -1;
 | |
| 
 | |
|   /**
 | |
|    * controls the range of indices provided in any {@link
 | |
|    * ListSelectionEvent} fired by the selectionModel. Let
 | |
|    * <code>[A,L]</code> be the range of indices between {@link
 | |
|    * #anchorSelectionIndex} and {@link #leadSelectionIndex} inclusive, and
 | |
|    * let <code>[i0,i1]</code> be the range of indices changed in a given
 | |
|    * call which generates a {@link ListSelectionEvent}. Then when this
 | |
|    * property is <code>true</code>, the {@link ListSelectionEvent} contains
 | |
|    * the range <code>[A,L] union [i0,i1]</code>; when <code>false</code> it
 | |
|    * will contain only <code>[i0,i1]</code>. The default is
 | |
|    * <code>true</code>.
 | |
|    *
 | |
|    * @see #isLeadAnchorNotificationEnabled
 | |
|    * @see #setLeadAnchorNotificationEnabled
 | |
|    */
 | |
|   protected boolean leadAnchorNotificationEnabled = true;
 | |
| 
 | |
|   /**
 | |
|    * Whether the selection is currently "adjusting". Any {@link
 | |
|    * ListSelectionEvent} events constructed in response to changes in this
 | |
|    * list selection model will have their {@link
 | |
|    * ListSelectionEvent#isAdjusting} field set to this value.
 | |
|    *
 | |
|    * @see #getValueIsAdjusting
 | |
|    * @see #setValueIsAdjusting
 | |
|    */
 | |
|   boolean valueIsAdjusting = false;
 | |
| 
 | |
| 
 | |
|   /**
 | |
|    * The current set of "intervals", represented simply by a {@link
 | |
|    * java.util.BitSet}. A set bit indicates a selected index, whereas a
 | |
|    * cleared bit indicates a non-selected index.
 | |
|    */
 | |
|   BitSet sel = new BitSet();
 | |
| 
 | |
|   /**
 | |
|    * A variable to store the previous value of sel.
 | |
|    * Used to make sure we only fireValueChanged when the BitSet
 | |
|    * actually does change.
 | |
|    */
 | |
|   Object oldSel;
 | |
| 
 | |
|   /**
 | |
|    * Whether this call of setLeadSelectionInterval was called locally
 | |
|    * from addSelectionInterval
 | |
|    */
 | |
|   boolean setLeadCalledFromAdd = false;
 | |
| 
 | |
|   /**
 | |
|    * Returns the selection mode, which is one of {@link #SINGLE_SELECTION},
 | |
|    * {@link #SINGLE_INTERVAL_SELECTION} and
 | |
|    * {@link #MULTIPLE_INTERVAL_SELECTION}.  The default value is
 | |
|    * {@link #MULTIPLE_INTERVAL_SELECTION}.
 | |
|    *
 | |
|    * @return The selection mode.
 | |
|    *
 | |
|    * @see #setSelectionMode(int)
 | |
|    */
 | |
|   public int getSelectionMode()
 | |
|   {
 | |
|     return selectionMode;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Sets the value of the {@link #selectionMode} property.
 | |
|    *
 | |
|    * @param mode The new value of the property
 | |
|    */
 | |
|   public void setSelectionMode(int mode)
 | |
|   {
 | |
|     if (mode < ListSelectionModel.SINGLE_SELECTION
 | |
|         || mode > ListSelectionModel.MULTIPLE_INTERVAL_SELECTION)
 | |
|       throw new IllegalArgumentException("Unrecognised mode: " + mode);
 | |
|     selectionMode = mode;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Gets the value of the {@link #anchorSelectionIndex} property.
 | |
|    *
 | |
|    * @return The current property value
 | |
|    *
 | |
|    * @see #setAnchorSelectionIndex
 | |
|    */
 | |
|   public int getAnchorSelectionIndex()
 | |
|   {
 | |
|     return anchorSelectionIndex;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Sets the value of the {@link #anchorSelectionIndex} property.
 | |
|    *
 | |
|    * @param index The new property value
 | |
|    *
 | |
|    * @see #getAnchorSelectionIndex
 | |
|    */
 | |
|   public void setAnchorSelectionIndex(int index)
 | |
|   {
 | |
|     if (anchorSelectionIndex != index)
 | |
|       {
 | |
|         int old = anchorSelectionIndex;
 | |
|         anchorSelectionIndex = index;
 | |
|         if (leadAnchorNotificationEnabled)
 | |
|           fireValueChanged(index, old);
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Gets the value of the {@link #leadSelectionIndex} property.
 | |
|    *
 | |
|    * @return The current property value
 | |
|    *
 | |
|    * @see #setLeadSelectionIndex
 | |
|    */
 | |
|   public int getLeadSelectionIndex()
 | |
|   {
 | |
|     return leadSelectionIndex;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * <p>Sets the value of the {@link #anchorSelectionIndex} property. As a
 | |
|    * side effect, alters the selection status of two ranges of indices. Let
 | |
|    * <code>OL</code> be the old lead selection index, <code>NL</code> be
 | |
|    * the new lead selection index, and <code>A</code> be the anchor
 | |
|    * selection index. Then if <code>A</code> is a valid selection index,
 | |
|    * one of two things happens depending on the seleciton status of
 | |
|    * <code>A</code>:</p>
 | |
|    *
 | |
|    * <ul>
 | |
|    *
 | |
|    * <li><code>isSelectedIndex(A) == true</code>: set <code>[A,OL]</code>
 | |
|    * to <em>deselected</em>, then set <code>[A,NL]</code> to
 | |
|    * <em>selected</em>.</li>
 | |
|    *
 | |
|    * <li><code>isSelectedIndex(A) == false</code>: set <code>[A,OL]</code>
 | |
|    * to <em>selected</em>, then set <code>[A,NL]</code> to
 | |
|    * <em>deselected</em>.</li>
 | |
|    *
 | |
|    * </ul>
 | |
|    *
 | |
|    * <p>This method generates at most a single {@link ListSelectionEvent}
 | |
|    * despite changing multiple ranges. The range of values provided to the
 | |
|    * {@link ListSelectionEvent} includes only the minimum range of values
 | |
|    * which changed selection status between the beginning and end of the
 | |
|    * method.</p>
 | |
|    *
 | |
|    * @param leadIndex The new property value
 | |
|    *
 | |
|    * @see #getAnchorSelectionIndex
 | |
|    */
 | |
|   public void setLeadSelectionIndex(int leadIndex)
 | |
|   {
 | |
|     // Only set the lead selection index to < 0 if anchorSelectionIndex < 0.
 | |
|     if (leadIndex < 0)
 | |
|       {
 | |
|         if (anchorSelectionIndex < 0)
 | |
|           leadSelectionIndex = -1;
 | |
|         else
 | |
|           return;
 | |
|       }
 | |
| 
 | |
|     // Only touch the lead selection index if the anchor is >= 0.
 | |
|     if (anchorSelectionIndex < 0)
 | |
|       return;
 | |
| 
 | |
|     if (selectionMode == SINGLE_SELECTION)
 | |
|       setSelectionInterval (leadIndex, leadIndex);
 | |
| 
 | |
|     int oldLeadIndex = leadSelectionIndex;
 | |
|     if (oldLeadIndex == -1)
 | |
|       oldLeadIndex = leadIndex;
 | |
|     if (setLeadCalledFromAdd == false)
 | |
|       oldSel = sel.clone();
 | |
|     leadSelectionIndex = leadIndex;
 | |
| 
 | |
|     if (anchorSelectionIndex == -1)
 | |
|       return;
 | |
| 
 | |
|     int R1 = Math.min(anchorSelectionIndex, oldLeadIndex);
 | |
|     int R2 = Math.max(anchorSelectionIndex, oldLeadIndex);
 | |
|     int S1 = Math.min(anchorSelectionIndex, leadIndex);
 | |
|     int S2 = Math.max(anchorSelectionIndex, leadIndex);
 | |
| 
 | |
|     int lo = Math.min(R1, S1);
 | |
|     int hi = Math.max(R2, S2);
 | |
| 
 | |
|     if (isSelectedIndex(anchorSelectionIndex))
 | |
|       {
 | |
|         sel.clear(R1, R2+1);
 | |
|         sel.set(S1, S2+1);
 | |
|       }
 | |
|     else
 | |
|       {
 | |
|         sel.set(R1, R2+1);
 | |
|         sel.clear(S1, S2+1);
 | |
|       }
 | |
| 
 | |
|     int beg = sel.nextSetBit(0), end = -1;
 | |
|     for(int i=beg; i >= 0; i=sel.nextSetBit(i+1))
 | |
|       end = i;
 | |
| 
 | |
|     BitSet old = (BitSet) oldSel;
 | |
| 
 | |
|     // The new and previous lead location requires repainting.
 | |
|     old.set(oldLeadIndex, !sel.get(oldLeadIndex));
 | |
|     old.set(leadSelectionIndex, !sel.get(leadSelectionIndex));
 | |
| 
 | |
|     fireDifference(sel, old);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Moves the lead selection index to <code>leadIndex</code> without
 | |
|    * changing the selection values.
 | |
|    *
 | |
|    * If leadAnchorNotificationEnabled is true, send a notification covering the
 | |
|    * old and new lead cells.
 | |
|    *
 | |
|    * @param leadIndex the new lead selection index
 | |
|    * @since 1.5
 | |
|    */
 | |
|   public void moveLeadSelectionIndex (int leadIndex)
 | |
|   {
 | |
|     if (leadSelectionIndex == leadIndex)
 | |
|       return;
 | |
| 
 | |
|     leadSelectionIndex = leadIndex;
 | |
|     if (isLeadAnchorNotificationEnabled())
 | |
|       fireValueChanged(Math.min(leadSelectionIndex, leadIndex),
 | |
|                        Math.max(leadSelectionIndex, leadIndex));
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Gets the value of the {@link #leadAnchorNotificationEnabled} property.
 | |
|    *
 | |
|    * @return The current property value
 | |
|    *
 | |
|    * @see #setLeadAnchorNotificationEnabled
 | |
|    */
 | |
|   public boolean isLeadAnchorNotificationEnabled()
 | |
|   {
 | |
|     return leadAnchorNotificationEnabled;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Sets the value of the {@link #leadAnchorNotificationEnabled} property.
 | |
|    *
 | |
|    * @param l The new property value
 | |
|    *
 | |
|    * @see #isLeadAnchorNotificationEnabled
 | |
|    */
 | |
|   public void setLeadAnchorNotificationEnabled(boolean l)
 | |
|   {
 | |
|     leadAnchorNotificationEnabled = l;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Gets the value of the {@link #valueIsAdjusting} property.
 | |
|    *
 | |
|    * @return The current property value
 | |
|    *
 | |
|    * @see #setValueIsAdjusting
 | |
|    */
 | |
|   public boolean getValueIsAdjusting()
 | |
|   {
 | |
|     return valueIsAdjusting;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Sets the value of the {@link #valueIsAdjusting} property.
 | |
|    *
 | |
|    * @param v The new property value
 | |
|    *
 | |
|    * @see #getValueIsAdjusting
 | |
|    */
 | |
|   public void setValueIsAdjusting(boolean v)
 | |
|   {
 | |
|     valueIsAdjusting = v;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Determines whether the selection is empty.
 | |
|    *
 | |
|    * @return <code>true</code> if the selection is empty, otherwise
 | |
|    * <code>false</code>
 | |
|    */
 | |
|   public boolean isSelectionEmpty()
 | |
|   {
 | |
|     return sel.isEmpty();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Gets the smallest index which is currently a member of a selection
 | |
|    * interval.
 | |
|    *
 | |
|    * @return The least integer <code>i</code> such that <code>i >=
 | |
|    *     0</code> and <code>i</code> is a member of a selected interval, or
 | |
|    *     <code>-1</code> if there are no selected intervals
 | |
|    *
 | |
|    * @see #getMaxSelectionIndex
 | |
|    */
 | |
|   public int getMinSelectionIndex()
 | |
|   {
 | |
|     if (isSelectionEmpty())
 | |
|       return -1;
 | |
| 
 | |
|     return sel.nextSetBit(0);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Gets the largest index which is currently a member of a selection
 | |
|    * interval.
 | |
|    *
 | |
|    * @return The greatest integer <code>i</code> such that <code>i >=
 | |
|    *     0</code> and <code>i</code> is a member of a selected interval, or
 | |
|    *     <code>-1</code> if there are no selected intervals
 | |
|    *
 | |
|    * @see #getMinSelectionIndex
 | |
|    */
 | |
|   public int getMaxSelectionIndex()
 | |
|   {
 | |
|     if (isSelectionEmpty())
 | |
|       return -1;
 | |
| 
 | |
|     int mx = -1;
 | |
|     for(int i=sel.nextSetBit(0); i >= 0; i=sel.nextSetBit(i+1))
 | |
|       {
 | |
|         mx = i;
 | |
|       }
 | |
|     return mx;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Determines whether a particular index is a member of a selection
 | |
|    * interval.
 | |
|    *
 | |
|    * @param a The index to search for
 | |
|    *
 | |
|    * @return <code>true</code> if the index is a member of a selection interval,
 | |
|    *     otherwise <code>false</code>
 | |
|    */
 | |
|   public boolean isSelectedIndex(int a)
 | |
|   {
 | |
|     // TODO: Probably throw an exception here?
 | |
|     if (a >= sel.length() || a < 0)
 | |
|       return false;
 | |
|     return sel.get(a);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * If the {@link #selectionMode} property is equal to
 | |
|    * <code>SINGLE_SELECTION</code> equivalent to calling
 | |
|    * <code>setSelectionInterval(index1, index2)</code>;
 | |
|    * If the {@link #selectionMode} property is equal to
 | |
|    * <code>SINGLE_INTERVAL_SELECTION</code> and the interval being
 | |
|    * added is not adjacent to an already selected interval,
 | |
|    * equivalent to <code>setSelectionInterval(index1, index2)</code>.
 | |
|    * Otherwise adds the range <code>[index0, index1]</code>
 | |
|    * to the selection interval set.
 | |
|    *
 | |
|    * @param index0 The beginning of the range of indices to select
 | |
|    * @param index1 The end of the range of indices to select
 | |
|    *
 | |
|    * @see #setSelectionInterval
 | |
|    * @see #removeSelectionInterval
 | |
|    */
 | |
|   public void addSelectionInterval(int index0, int index1)
 | |
|   {
 | |
|     if (index0 == -1 || index1 == -1)
 | |
|       return;
 | |
| 
 | |
|     if (selectionMode == SINGLE_SELECTION)
 | |
|       setSelectionInterval(index0, index1);
 | |
|     else
 | |
|     {
 | |
|     int lo = Math.min(index0, index1);
 | |
|     int hi = Math.max(index0, index1);
 | |
|     oldSel = sel.clone();
 | |
| 
 | |
| 
 | |
|     // COMPAT: Like Sun (but not like IBM), we allow calls to
 | |
|     // addSelectionInterval when selectionMode is
 | |
|     // SINGLE_SELECTION_INTERVAL iff the interval being added
 | |
|     // is adjacent to an already selected interval
 | |
|     if (selectionMode == SINGLE_INTERVAL_SELECTION)
 | |
|       if (!(isSelectedIndex(index0) ||
 | |
|             isSelectedIndex(index1) ||
 | |
|             isSelectedIndex(Math.max(lo-1,0)) ||
 | |
|             isSelectedIndex(Math.min(hi+1,sel.size()))))
 | |
|         sel.clear();
 | |
| 
 | |
|     // We have to update the anchorSelectionIndex and leadSelectionIndex
 | |
|     // variables
 | |
| 
 | |
|     // The next if statements breaks down to "if this selection is adjacent
 | |
|     // to the previous selection and going in the same direction"
 | |
|     if ((isSelectedIndex(leadSelectionIndex))
 | |
|         && ((index0 - 1 == leadSelectionIndex
 | |
|              && (index1 >= index0)
 | |
|              && (leadSelectionIndex >= anchorSelectionIndex))
 | |
|             || (index0 + 1 == leadSelectionIndex && (index1 <= index0)
 | |
|                 && (leadSelectionIndex <= anchorSelectionIndex)))
 | |
|         && (anchorSelectionIndex != -1 || leadSelectionIndex != -1))
 | |
|       {
 | |
|         // setting setLeadCalledFromAdd to true tells setLeadSelectionIndex
 | |
|         //   not to update oldSel
 | |
|         setLeadCalledFromAdd = true;
 | |
|         setLeadSelectionIndex(index1);
 | |
|         setLeadCalledFromAdd = false;
 | |
|       }
 | |
|     else
 | |
|       {
 | |
|         leadSelectionIndex = index1;
 | |
|         anchorSelectionIndex = index0;
 | |
|         sel.set(lo, hi+1);
 | |
|         fireDifference(sel, (BitSet) oldSel);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
| 
 | |
|   /**
 | |
|    * Deselects all indices in the inclusive range
 | |
|    * <code>[index0,index1]</code>.
 | |
|    *
 | |
|    * @param index0 The beginning of the range of indices to deselect
 | |
|    * @param index1 The end of the range of indices to deselect
 | |
|    *
 | |
|    * @see #addSelectionInterval
 | |
|    * @see #setSelectionInterval
 | |
|    */
 | |
|   public void removeSelectionInterval(int index0,
 | |
|                                       int index1)
 | |
|   {
 | |
|     if (index0 == -1 || index1 == -1)
 | |
|       return;
 | |
| 
 | |
|     oldSel = sel.clone();
 | |
|     int lo = Math.min(index0, index1);
 | |
|     int hi = Math.max(index0, index1);
 | |
| 
 | |
|     // if selectionMode is SINGLE_INTERVAL_SELECTION and removing the interval
 | |
|     //   (index0,index1) would leave two disjoint selection intervals, remove all
 | |
|     //   selected indices from lo to the last selected index
 | |
|     if (getMinSelectionIndex() > 0 && getMinSelectionIndex() < lo &&
 | |
|         selectionMode == SINGLE_INTERVAL_SELECTION)
 | |
|       hi = sel.size() - 1;
 | |
| 
 | |
|     sel.clear(lo, hi+1);
 | |
|     //update anchorSelectionIndex and leadSelectionIndex variables
 | |
|     //TODO: will probably need MouseDragged to test properly and know if this works
 | |
|     setAnchorSelectionIndex(index0);
 | |
|     leadSelectionIndex = index1;
 | |
| 
 | |
|     fireDifference(sel, (BitSet) oldSel);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Removes all intervals in the selection set.
 | |
|    */
 | |
|   public void clearSelection()
 | |
|   {
 | |
|     // Find the selected interval.
 | |
|     int from = sel.nextSetBit(0);
 | |
|     if (from < 0)
 | |
|       return; // Empty selection - nothing to do.
 | |
|     int to = from;
 | |
| 
 | |
|     int i;
 | |
| 
 | |
|     for (i = from; i>=0; i=sel.nextSetBit(i+1))
 | |
|       to = i;
 | |
| 
 | |
|     sel.clear();
 | |
|     fireValueChanged(from, to, valueIsAdjusting);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Fire the change event, covering the difference between the two sets.
 | |
|    *
 | |
|    * @param current the current set
 | |
|    * @param x the previous set, the object will be reused.
 | |
|    */
 | |
|   private void fireDifference(BitSet current, BitSet x)
 | |
|   {
 | |
|     x.xor(current);
 | |
|     int from = x.nextSetBit(0);
 | |
|     if (from < 0)
 | |
|       return; // No difference.
 | |
|     int to = from;
 | |
|     int i;
 | |
| 
 | |
|     for (i = from; i >= 0; i = x.nextSetBit(i+1))
 | |
|       to = i;
 | |
| 
 | |
|     fireValueChanged(from, to, valueIsAdjusting);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Clears the current selection and marks a given interval as "selected". If
 | |
|    * the current selection mode is <code>SINGLE_SELECTION</code> only the
 | |
|    * index <code>index2</code> is selected.
 | |
|    *
 | |
|    * @param anchor  the anchor selection index.
 | |
|    * @param lead  the lead selection index.
 | |
|    */
 | |
|   public void setSelectionInterval(int anchor, int lead)
 | |
|   {
 | |
|     if (anchor == -1 || lead == -1)
 | |
|       return;
 | |
|     if (selectionMode == SINGLE_SELECTION)
 | |
|       {
 | |
|         int lo = lead;
 | |
|         int hi = lead;
 | |
|         int selected = sel.nextSetBit(0);
 | |
|         if (selected == lead)
 | |
|           return;  // the selection is not changing
 | |
|         if (selected >= 0)
 | |
|           {
 | |
|             lo = Math.min(lo, selected);
 | |
|             hi = Math.max(hi, selected);
 | |
|           }
 | |
|         if (anchorSelectionIndex >= 0)
 | |
|           {
 | |
|             lo = Math.min(lo, anchorSelectionIndex);
 | |
|             hi = Math.max(hi, anchorSelectionIndex);
 | |
|           }
 | |
|         sel.clear();
 | |
|         sel.set(lead);
 | |
|         leadSelectionIndex = lead;
 | |
|         anchorSelectionIndex = lead;
 | |
|         fireValueChanged(lo, hi);
 | |
|       }
 | |
|     else if (selectionMode == SINGLE_INTERVAL_SELECTION)
 | |
|       {
 | |
|         // determine the current interval
 | |
|         int first = sel.nextSetBit(0);
 | |
|         int last = first;
 | |
|         if (first >= 0)
 | |
|           last += (sel.cardinality() - 1);
 | |
| 
 | |
|         // update the selection
 | |
|         int lo = Math.min(anchor, lead);
 | |
|         int hi = Math.max(anchor, lead);
 | |
|         if (lo == first && hi == last)
 | |
|           return;  // selected interval is not being changed
 | |
|         sel.clear();
 | |
|         sel.set(lo, hi + 1);
 | |
| 
 | |
|         // include the old selection in the event range
 | |
|         if (first >= 0)
 | |
|           lo = Math.min(lo, first);
 | |
|         if (last >= 0)
 | |
|           hi = Math.max(hi, last);
 | |
|         if (anchorSelectionIndex >= 0)
 | |
|           {
 | |
|             lo = Math.min(lo, anchorSelectionIndex);
 | |
|             hi = Math.max(hi, anchorSelectionIndex);
 | |
|           }
 | |
|         anchorSelectionIndex = anchor;
 | |
|         leadSelectionIndex = lead;
 | |
|         fireValueChanged(lo, hi);
 | |
|       }
 | |
|     else
 | |
|     {
 | |
|       BitSet oldSel = (BitSet) sel.clone();
 | |
|       sel.clear();
 | |
|       if (selectionMode == SINGLE_SELECTION)
 | |
|         anchor = lead;
 | |
| 
 | |
|       int lo = Math.min(anchor, lead);
 | |
|       int hi = Math.max(anchor, lead);
 | |
|       sel.set(lo, hi+1);
 | |
|       // update the anchorSelectionIndex and leadSelectionIndex variables
 | |
|       setAnchorSelectionIndex(anchor);
 | |
|       leadSelectionIndex = lead;
 | |
| 
 | |
|       fireDifference(sel, oldSel);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Inserts a number of indices either before or after a particular
 | |
|    * position in the set of indices. Renumbers all indices after the
 | |
|    * inserted range. The new indices in the inserted range are not
 | |
|    * selected. This method is typically called to synchronize the selection
 | |
|    * model with an inserted range of elements in a {@link ListModel}.
 | |
|    *
 | |
|    * @param index The position to insert indices at
 | |
|    * @param length The number of indices to insert
 | |
|    * @param before Indicates whether to insert the indices before the index
 | |
|    *     or after it
 | |
|    */
 | |
|   public void insertIndexInterval(int index,
 | |
|                                   int length,
 | |
|                                   boolean before)
 | |
|   {
 | |
|     if (!before)
 | |
|       {
 | |
|         index++;
 | |
|         length--;
 | |
|       }
 | |
|     BitSet tmp = sel.get(index, sel.size());
 | |
|     sel.clear(index, sel.size());
 | |
|     int n = tmp.size();
 | |
|     for (int i = 0; i < n; ++i)
 | |
|       sel.set(index + length + i, tmp.get(i));
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Removes a range from the set of indices. Renumbers all indices after
 | |
|    * the removed range. This method is typically called to synchronize the
 | |
|    * selection model with a deleted range of elements in a {@link
 | |
|    * ListModel}.
 | |
|    *
 | |
|    * @param index0 The first index to remove (inclusive)
 | |
|    * @param index1 The last index to remove (inclusive)
 | |
|    */
 | |
|   public void removeIndexInterval(int index0,
 | |
|                                   int index1)
 | |
|   {
 | |
|     int lo = Math.min(index0, index1);
 | |
|     int hi = Math.max(index0, index1);
 | |
| 
 | |
|     BitSet tmp = sel.get(hi, sel.size());
 | |
|     sel.clear(lo, sel.size());
 | |
|     int n = tmp.size();
 | |
|     for (int i = 0; i < n; ++i)
 | |
|       sel.set(lo + i, tmp.get(i));
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Fires a {@link ListSelectionEvent} to all the listeners of type {@link
 | |
|    * ListSelectionListener} registered with this selection model to
 | |
|    * indicate that a series of adjustment has just ended.
 | |
|    *
 | |
|    * The values of {@link #getMinSelectionIndex} and
 | |
|    * {@link #getMaxSelectionIndex} are used in the {@link ListSelectionEvent}
 | |
|    * that gets fired.
 | |
|    *
 | |
|    * @param isAdjusting <code>true</code> if this is the final change
 | |
|    *     in a series of adjustments, <code>false/code> otherwise
 | |
|    */
 | |
|   protected void fireValueChanged(boolean isAdjusting)
 | |
|   {
 | |
|     fireValueChanged(getMinSelectionIndex(), getMaxSelectionIndex(),
 | |
|                      isAdjusting);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Fires a {@link ListSelectionEvent} to all the listeners of type {@link
 | |
|    * ListSelectionListener} registered with this selection model.
 | |
|    *
 | |
|    * @param firstIndex The low index of the changed range
 | |
|    * @param lastIndex The high index of the changed range
 | |
|    */
 | |
|   protected void fireValueChanged(int firstIndex, int lastIndex)
 | |
|   {
 | |
|     fireValueChanged(firstIndex, lastIndex, getValueIsAdjusting());
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Fires a {@link ListSelectionEvent} to all the listeners of type {@link
 | |
|    * ListSelectionListener} registered with this selection model.
 | |
|    *
 | |
|    * @param firstIndex The low index of the changed range
 | |
|    * @param lastIndex The high index of the changed range
 | |
|    * @param isAdjusting Whether this change is part of a seqence of adjustments
 | |
|    *     made to the selection, such as during interactive scrolling
 | |
|    */
 | |
|   protected void fireValueChanged(int firstIndex, int lastIndex,
 | |
|                                   boolean isAdjusting)
 | |
|   {
 | |
|     ListSelectionEvent evt = new ListSelectionEvent(this, firstIndex,
 | |
|                                                     lastIndex, isAdjusting);
 | |
|     ListSelectionListener[] listeners = getListSelectionListeners();
 | |
|     for (int i = 0; i < listeners.length; ++i)
 | |
|       listeners[i].valueChanged(evt);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Adds a listener.
 | |
|    *
 | |
|    * @param listener The listener to add
 | |
|    *
 | |
|    * @see #removeListSelectionListener
 | |
|    * @see #getListSelectionListeners
 | |
|    */
 | |
|   public void addListSelectionListener(ListSelectionListener listener)
 | |
|   {
 | |
|     listenerList.add(ListSelectionListener.class, listener);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Removes a registered listener.
 | |
|    *
 | |
|    * @param listener The listener to remove
 | |
|    *
 | |
|    * @see #addListSelectionListener
 | |
|    * @see #getListSelectionListeners
 | |
|    */
 | |
|   public void removeListSelectionListener(ListSelectionListener listener)
 | |
|   {
 | |
|     listenerList.remove(ListSelectionListener.class, listener);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns an array of all registerers listeners.
 | |
|    *
 | |
|    * @param listenerType The type of listener to retrieve
 | |
|    *
 | |
|    * @return The array
 | |
|    *
 | |
|    * @see #getListSelectionListeners
 | |
|    * @since 1.3
 | |
|    */
 | |
|   public <T extends EventListener> T[] getListeners(Class<T> listenerType)
 | |
|   {
 | |
|     return listenerList.getListeners(listenerType);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns an array of all registerd list selection listeners.
 | |
|    *
 | |
|    * @return the array
 | |
|    *
 | |
|    * @see #addListSelectionListener
 | |
|    * @see #removeListSelectionListener
 | |
|    * @see #getListeners
 | |
|    * @since 1.4
 | |
|    */
 | |
|   public ListSelectionListener[] getListSelectionListeners()
 | |
|   {
 | |
|     return (ListSelectionListener[]) getListeners(ListSelectionListener.class);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns a clone of this object.
 | |
|    * <code>listenerList</code> don't gets duplicated.
 | |
|    *
 | |
|    * @return the cloned object
 | |
|    *
 | |
|    * @throws CloneNotSupportedException if an error occurs
 | |
|    */
 | |
|   public Object clone()
 | |
|     throws CloneNotSupportedException
 | |
|   {
 | |
|     DefaultListSelectionModel model =
 | |
|       (DefaultListSelectionModel) super.clone();
 | |
|     model.sel = (BitSet) sel.clone();
 | |
|     model.listenerList = new EventListenerList();
 | |
|     return model;
 | |
|   }
 | |
| }
 |