| /* 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 EventListener[] getListeners(Class 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; |
| } |
| } |