Frames | No Frames |
1: /* DefaultListSelectionModel.java -- 2: Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package javax.swing; 40: 41: import java.io.Serializable; 42: import java.util.BitSet; 43: import java.util.EventListener; 44: 45: import javax.swing.event.EventListenerList; 46: import javax.swing.event.ListSelectionEvent; 47: import javax.swing.event.ListSelectionListener; 48: 49: /** 50: * The default implementation of {@link ListSelectionModel}, 51: * which is used by {@link javax.swing.JList} and 52: * similar classes to manage the selection status of a number of data 53: * elements. 54: * 55: * <p>The class is organized <em>abstractly</em> as a set of intervals of 56: * integers. Each interval indicates an inclusive range of indices in a 57: * list -- held by some other object and unknown to this class -- which is 58: * considered "selected". There are various accessors for querying and 59: * modifying the set of intervals, with simplified forms accepting a single 60: * index, representing an interval with only one element. </p> 61: */ 62: public class DefaultListSelectionModel implements Cloneable, 63: ListSelectionModel, 64: Serializable 65: { 66: private static final long serialVersionUID = -5718799865110415860L; 67: 68: /** The list of ListSelectionListeners subscribed to this selection model. */ 69: protected EventListenerList listenerList = new EventListenerList(); 70: 71: 72: /** 73: * The current list selection mode. Must be one of the numeric constants 74: * <code>SINGLE_SELECTION</code>, <code>SINGLE_INTERVAL_SELECTION</code> 75: * or <code>MULTIPLE_INTERVAL_SELECTION</code> from {@link 76: * ListSelectionModel}. The default value is 77: * <code>MULTIPLE_INTERVAL_SELECTION</code>. 78: */ 79: int selectionMode = MULTIPLE_INTERVAL_SELECTION; 80: 81: /** 82: * The index of the "lead" of the most recent selection. The lead is the 83: * second argument in any call to {@link #setSelectionInterval}, {@link 84: * #addSelectionInterval} or {@link #removeSelectionInterval}. Generally 85: * the lead refers to the most recent position a user dragged their mouse 86: * over. 87: */ 88: int leadSelectionIndex = -1; 89: 90: /** 91: * The index of the "anchor" of the most recent selection. The anchor is 92: * the first argument in any call to {@link #setSelectionInterval}, 93: * {@link #addSelectionInterval} or {@link 94: * #removeSelectionInterval}. Generally the anchor refers to the first 95: * recent position a user clicks when they begin to drag their mouse over 96: * a list. 97: * 98: * @see #getAnchorSelectionIndex 99: * @see #setAnchorSelectionIndex 100: */ 101: int anchorSelectionIndex = -1; 102: 103: /** 104: * controls the range of indices provided in any {@link 105: * ListSelectionEvent} fired by the selectionModel. Let 106: * <code>[A,L]</code> be the range of indices between {@link 107: * #anchorSelectionIndex} and {@link #leadSelectionIndex} inclusive, and 108: * let <code>[i0,i1]</code> be the range of indices changed in a given 109: * call which generates a {@link ListSelectionEvent}. Then when this 110: * property is <code>true</code>, the {@link ListSelectionEvent} contains 111: * the range <code>[A,L] union [i0,i1]</code>; when <code>false</code> it 112: * will contain only <code>[i0,i1]</code>. The default is 113: * <code>true</code>. 114: * 115: * @see #isLeadAnchorNotificationEnabled 116: * @see #setLeadAnchorNotificationEnabled 117: */ 118: protected boolean leadAnchorNotificationEnabled = true; 119: 120: /** 121: * Whether the selection is currently "adjusting". Any {@link 122: * ListSelectionEvent} events constructed in response to changes in this 123: * list selection model will have their {@link 124: * ListSelectionEvent#isAdjusting} field set to this value. 125: * 126: * @see #getValueIsAdjusting 127: * @see #setValueIsAdjusting 128: */ 129: boolean valueIsAdjusting = false; 130: 131: 132: /** 133: * The current set of "intervals", represented simply by a {@link 134: * java.util.BitSet}. A set bit indicates a selected index, whereas a 135: * cleared bit indicates a non-selected index. 136: */ 137: BitSet sel = new BitSet(); 138: 139: /** 140: * A variable to store the previous value of sel. 141: * Used to make sure we only fireValueChanged when the BitSet 142: * actually does change. 143: */ 144: Object oldSel; 145: 146: /** 147: * Whether this call of setLeadSelectionInterval was called locally 148: * from addSelectionInterval 149: */ 150: boolean setLeadCalledFromAdd = false; 151: 152: /** 153: * Returns the selection mode, which is one of {@link #SINGLE_SELECTION}, 154: * {@link #SINGLE_INTERVAL_SELECTION} and 155: * {@link #MULTIPLE_INTERVAL_SELECTION}. The default value is 156: * {@link #MULTIPLE_INTERVAL_SELECTION}. 157: * 158: * @return The selection mode. 159: * 160: * @see #setSelectionMode(int) 161: */ 162: public int getSelectionMode() 163: { 164: return selectionMode; 165: } 166: 167: /** 168: * Sets the value of the {@link #selectionMode} property. 169: * 170: * @param mode The new value of the property 171: */ 172: public void setSelectionMode(int mode) 173: { 174: if (mode < ListSelectionModel.SINGLE_SELECTION 175: || mode > ListSelectionModel.MULTIPLE_INTERVAL_SELECTION) 176: throw new IllegalArgumentException("Unrecognised mode: " + mode); 177: selectionMode = mode; 178: } 179: 180: /** 181: * Gets the value of the {@link #anchorSelectionIndex} property. 182: * 183: * @return The current property value 184: * 185: * @see #setAnchorSelectionIndex 186: */ 187: public int getAnchorSelectionIndex() 188: { 189: return anchorSelectionIndex; 190: } 191: 192: /** 193: * Sets the value of the {@link #anchorSelectionIndex} property. 194: * 195: * @param index The new property value 196: * 197: * @see #getAnchorSelectionIndex 198: */ 199: public void setAnchorSelectionIndex(int index) 200: { 201: if (anchorSelectionIndex != index) 202: { 203: int old = anchorSelectionIndex; 204: anchorSelectionIndex = index; 205: if (leadAnchorNotificationEnabled) 206: fireValueChanged(index, old); 207: } 208: } 209: 210: /** 211: * Gets the value of the {@link #leadSelectionIndex} property. 212: * 213: * @return The current property value 214: * 215: * @see #setLeadSelectionIndex 216: */ 217: public int getLeadSelectionIndex() 218: { 219: return leadSelectionIndex; 220: } 221: 222: /** 223: * <p>Sets the value of the {@link #anchorSelectionIndex} property. As a 224: * side effect, alters the selection status of two ranges of indices. Let 225: * <code>OL</code> be the old lead selection index, <code>NL</code> be 226: * the new lead selection index, and <code>A</code> be the anchor 227: * selection index. Then if <code>A</code> is a valid selection index, 228: * one of two things happens depending on the seleciton status of 229: * <code>A</code>:</p> 230: * 231: * <ul> 232: * 233: * <li><code>isSelectedIndex(A) == true</code>: set <code>[A,OL]</code> 234: * to <em>deselected</em>, then set <code>[A,NL]</code> to 235: * <em>selected</em>.</li> 236: * 237: * <li><code>isSelectedIndex(A) == false</code>: set <code>[A,OL]</code> 238: * to <em>selected</em>, then set <code>[A,NL]</code> to 239: * <em>deselected</em>.</li> 240: * 241: * </ul> 242: * 243: * <p>This method generates at most a single {@link ListSelectionEvent} 244: * despite changing multiple ranges. The range of values provided to the 245: * {@link ListSelectionEvent} includes only the minimum range of values 246: * which changed selection status between the beginning and end of the 247: * method.</p> 248: * 249: * @param leadIndex The new property value 250: * 251: * @see #getAnchorSelectionIndex 252: */ 253: public void setLeadSelectionIndex(int leadIndex) 254: { 255: // Only set the lead selection index to < 0 if anchorSelectionIndex < 0. 256: if (leadIndex < 0) 257: { 258: if (anchorSelectionIndex < 0) 259: leadSelectionIndex = -1; 260: else 261: return; 262: } 263: 264: // Only touch the lead selection index if the anchor is >= 0. 265: if (anchorSelectionIndex < 0) 266: return; 267: 268: if (selectionMode == SINGLE_SELECTION) 269: setSelectionInterval (leadIndex, leadIndex); 270: 271: int oldLeadIndex = leadSelectionIndex; 272: if (oldLeadIndex == -1) 273: oldLeadIndex = leadIndex; 274: if (setLeadCalledFromAdd == false) 275: oldSel = sel.clone(); 276: leadSelectionIndex = leadIndex; 277: 278: if (anchorSelectionIndex == -1) 279: return; 280: 281: int R1 = Math.min(anchorSelectionIndex, oldLeadIndex); 282: int R2 = Math.max(anchorSelectionIndex, oldLeadIndex); 283: int S1 = Math.min(anchorSelectionIndex, leadIndex); 284: int S2 = Math.max(anchorSelectionIndex, leadIndex); 285: 286: int lo = Math.min(R1, S1); 287: int hi = Math.max(R2, S2); 288: 289: if (isSelectedIndex(anchorSelectionIndex)) 290: { 291: sel.clear(R1, R2+1); 292: sel.set(S1, S2+1); 293: } 294: else 295: { 296: sel.set(R1, R2+1); 297: sel.clear(S1, S2+1); 298: } 299: 300: int beg = sel.nextSetBit(0), end = -1; 301: for(int i=beg; i >= 0; i=sel.nextSetBit(i+1)) 302: end = i; 303: 304: BitSet old = (BitSet) oldSel; 305: 306: // The new and previous lead location requires repainting. 307: old.set(oldLeadIndex, !sel.get(oldLeadIndex)); 308: old.set(leadSelectionIndex, !sel.get(leadSelectionIndex)); 309: 310: fireDifference(sel, old); 311: } 312: 313: /** 314: * Moves the lead selection index to <code>leadIndex</code> without 315: * changing the selection values. 316: * 317: * If leadAnchorNotificationEnabled is true, send a notification covering the 318: * old and new lead cells. 319: * 320: * @param leadIndex the new lead selection index 321: * @since 1.5 322: */ 323: public void moveLeadSelectionIndex (int leadIndex) 324: { 325: if (leadSelectionIndex == leadIndex) 326: return; 327: 328: leadSelectionIndex = leadIndex; 329: if (isLeadAnchorNotificationEnabled()) 330: fireValueChanged(Math.min(leadSelectionIndex, leadIndex), 331: Math.max(leadSelectionIndex, leadIndex)); 332: } 333: 334: /** 335: * Gets the value of the {@link #leadAnchorNotificationEnabled} property. 336: * 337: * @return The current property value 338: * 339: * @see #setLeadAnchorNotificationEnabled 340: */ 341: public boolean isLeadAnchorNotificationEnabled() 342: { 343: return leadAnchorNotificationEnabled; 344: } 345: 346: /** 347: * Sets the value of the {@link #leadAnchorNotificationEnabled} property. 348: * 349: * @param l The new property value 350: * 351: * @see #isLeadAnchorNotificationEnabled 352: */ 353: public void setLeadAnchorNotificationEnabled(boolean l) 354: { 355: leadAnchorNotificationEnabled = l; 356: } 357: 358: /** 359: * Gets the value of the {@link #valueIsAdjusting} property. 360: * 361: * @return The current property value 362: * 363: * @see #setValueIsAdjusting 364: */ 365: public boolean getValueIsAdjusting() 366: { 367: return valueIsAdjusting; 368: } 369: 370: /** 371: * Sets the value of the {@link #valueIsAdjusting} property. 372: * 373: * @param v The new property value 374: * 375: * @see #getValueIsAdjusting 376: */ 377: public void setValueIsAdjusting(boolean v) 378: { 379: valueIsAdjusting = v; 380: } 381: 382: /** 383: * Determines whether the selection is empty. 384: * 385: * @return <code>true</code> if the selection is empty, otherwise 386: * <code>false</code> 387: */ 388: public boolean isSelectionEmpty() 389: { 390: return sel.isEmpty(); 391: } 392: 393: /** 394: * Gets the smallest index which is currently a member of a selection 395: * interval. 396: * 397: * @return The least integer <code>i</code> such that <code>i >= 398: * 0</code> and <code>i</code> is a member of a selected interval, or 399: * <code>-1</code> if there are no selected intervals 400: * 401: * @see #getMaxSelectionIndex 402: */ 403: public int getMinSelectionIndex() 404: { 405: if (isSelectionEmpty()) 406: return -1; 407: 408: return sel.nextSetBit(0); 409: } 410: 411: /** 412: * Gets the largest index which is currently a member of a selection 413: * interval. 414: * 415: * @return The greatest integer <code>i</code> such that <code>i >= 416: * 0</code> and <code>i</code> is a member of a selected interval, or 417: * <code>-1</code> if there are no selected intervals 418: * 419: * @see #getMinSelectionIndex 420: */ 421: public int getMaxSelectionIndex() 422: { 423: if (isSelectionEmpty()) 424: return -1; 425: 426: int mx = -1; 427: for(int i=sel.nextSetBit(0); i >= 0; i=sel.nextSetBit(i+1)) 428: { 429: mx = i; 430: } 431: return mx; 432: } 433: 434: /** 435: * Determines whether a particular index is a member of a selection 436: * interval. 437: * 438: * @param a The index to search for 439: * 440: * @return <code>true</code> if the index is a member of a selection interval, 441: * otherwise <code>false</code> 442: */ 443: public boolean isSelectedIndex(int a) 444: { 445: // TODO: Probably throw an exception here? 446: if (a >= sel.length() || a < 0) 447: return false; 448: return sel.get(a); 449: } 450: 451: /** 452: * If the {@link #selectionMode} property is equal to 453: * <code>SINGLE_SELECTION</code> equivalent to calling 454: * <code>setSelectionInterval(index1, index2)</code>; 455: * If the {@link #selectionMode} property is equal to 456: * <code>SINGLE_INTERVAL_SELECTION</code> and the interval being 457: * added is not adjacent to an already selected interval, 458: * equivalent to <code>setSelectionInterval(index1, index2)</code>. 459: * Otherwise adds the range <code>[index0, index1]</code> 460: * to the selection interval set. 461: * 462: * @param index0 The beginning of the range of indices to select 463: * @param index1 The end of the range of indices to select 464: * 465: * @see #setSelectionInterval 466: * @see #removeSelectionInterval 467: */ 468: public void addSelectionInterval(int index0, int index1) 469: { 470: if (index0 == -1 || index1 == -1) 471: return; 472: 473: if (selectionMode == SINGLE_SELECTION) 474: setSelectionInterval(index0, index1); 475: else 476: { 477: int lo = Math.min(index0, index1); 478: int hi = Math.max(index0, index1); 479: oldSel = sel.clone(); 480: 481: 482: // COMPAT: Like Sun (but not like IBM), we allow calls to 483: // addSelectionInterval when selectionMode is 484: // SINGLE_SELECTION_INTERVAL iff the interval being added 485: // is adjacent to an already selected interval 486: if (selectionMode == SINGLE_INTERVAL_SELECTION) 487: if (!(isSelectedIndex(index0) || 488: isSelectedIndex(index1) || 489: isSelectedIndex(Math.max(lo-1,0)) || 490: isSelectedIndex(Math.min(hi+1,sel.size())))) 491: sel.clear(); 492: 493: // We have to update the anchorSelectionIndex and leadSelectionIndex 494: // variables 495: 496: // The next if statements breaks down to "if this selection is adjacent 497: // to the previous selection and going in the same direction" 498: if ((isSelectedIndex(leadSelectionIndex)) 499: && ((index0 - 1 == leadSelectionIndex 500: && (index1 >= index0) 501: && (leadSelectionIndex >= anchorSelectionIndex)) 502: || (index0 + 1 == leadSelectionIndex && (index1 <= index0) 503: && (leadSelectionIndex <= anchorSelectionIndex))) 504: && (anchorSelectionIndex != -1 || leadSelectionIndex != -1)) 505: { 506: // setting setLeadCalledFromAdd to true tells setLeadSelectionIndex 507: // not to update oldSel 508: setLeadCalledFromAdd = true; 509: setLeadSelectionIndex(index1); 510: setLeadCalledFromAdd = false; 511: } 512: else 513: { 514: leadSelectionIndex = index1; 515: anchorSelectionIndex = index0; 516: sel.set(lo, hi+1); 517: fireDifference(sel, (BitSet) oldSel); 518: } 519: } 520: } 521: 522: 523: /** 524: * Deselects all indices in the inclusive range 525: * <code>[index0,index1]</code>. 526: * 527: * @param index0 The beginning of the range of indices to deselect 528: * @param index1 The end of the range of indices to deselect 529: * 530: * @see #addSelectionInterval 531: * @see #setSelectionInterval 532: */ 533: public void removeSelectionInterval(int index0, 534: int index1) 535: { 536: if (index0 == -1 || index1 == -1) 537: return; 538: 539: oldSel = sel.clone(); 540: int lo = Math.min(index0, index1); 541: int hi = Math.max(index0, index1); 542: 543: // if selectionMode is SINGLE_INTERVAL_SELECTION and removing the interval 544: // (index0,index1) would leave two disjoint selection intervals, remove all 545: // selected indices from lo to the last selected index 546: if (getMinSelectionIndex() > 0 && getMinSelectionIndex() < lo && 547: selectionMode == SINGLE_INTERVAL_SELECTION) 548: hi = sel.size() - 1; 549: 550: sel.clear(lo, hi+1); 551: //update anchorSelectionIndex and leadSelectionIndex variables 552: //TODO: will probably need MouseDragged to test properly and know if this works 553: setAnchorSelectionIndex(index0); 554: leadSelectionIndex = index1; 555: 556: fireDifference(sel, (BitSet) oldSel); 557: } 558: 559: /** 560: * Removes all intervals in the selection set. 561: */ 562: public void clearSelection() 563: { 564: // Find the selected interval. 565: int from = sel.nextSetBit(0); 566: if (from < 0) 567: return; // Empty selection - nothing to do. 568: int to = from; 569: 570: int i; 571: 572: for (i = from; i>=0; i=sel.nextSetBit(i+1)) 573: to = i; 574: 575: sel.clear(); 576: fireValueChanged(from, to, valueIsAdjusting); 577: } 578: 579: /** 580: * Fire the change event, covering the difference between the two sets. 581: * 582: * @param current the current set 583: * @param x the previous set, the object will be reused. 584: */ 585: private void fireDifference(BitSet current, BitSet x) 586: { 587: x.xor(current); 588: int from = x.nextSetBit(0); 589: if (from < 0) 590: return; // No difference. 591: int to = from; 592: int i; 593: 594: for (i = from; i >= 0; i = x.nextSetBit(i+1)) 595: to = i; 596: 597: fireValueChanged(from, to, valueIsAdjusting); 598: } 599: 600: /** 601: * Clears the current selection and marks a given interval as "selected". If 602: * the current selection mode is <code>SINGLE_SELECTION</code> only the 603: * index <code>index2</code> is selected. 604: * 605: * @param anchor the anchor selection index. 606: * @param lead the lead selection index. 607: */ 608: public void setSelectionInterval(int anchor, int lead) 609: { 610: if (anchor == -1 || lead == -1) 611: return; 612: if (selectionMode == SINGLE_SELECTION) 613: { 614: int lo = lead; 615: int hi = lead; 616: int selected = sel.nextSetBit(0); 617: if (selected == lead) 618: return; // the selection is not changing 619: if (selected >= 0) 620: { 621: lo = Math.min(lo, selected); 622: hi = Math.max(hi, selected); 623: } 624: if (anchorSelectionIndex >= 0) 625: { 626: lo = Math.min(lo, anchorSelectionIndex); 627: hi = Math.max(hi, anchorSelectionIndex); 628: } 629: sel.clear(); 630: sel.set(lead); 631: leadSelectionIndex = lead; 632: anchorSelectionIndex = lead; 633: fireValueChanged(lo, hi); 634: } 635: else if (selectionMode == SINGLE_INTERVAL_SELECTION) 636: { 637: // determine the current interval 638: int first = sel.nextSetBit(0); 639: int last = first; 640: if (first >= 0) 641: last += (sel.cardinality() - 1); 642: 643: // update the selection 644: int lo = Math.min(anchor, lead); 645: int hi = Math.max(anchor, lead); 646: if (lo == first && hi == last) 647: return; // selected interval is not being changed 648: sel.clear(); 649: sel.set(lo, hi + 1); 650: 651: // include the old selection in the event range 652: if (first >= 0) 653: lo = Math.min(lo, first); 654: if (last >= 0) 655: hi = Math.max(hi, last); 656: if (anchorSelectionIndex >= 0) 657: { 658: lo = Math.min(lo, anchorSelectionIndex); 659: hi = Math.max(hi, anchorSelectionIndex); 660: } 661: anchorSelectionIndex = anchor; 662: leadSelectionIndex = lead; 663: fireValueChanged(lo, hi); 664: } 665: else 666: { 667: BitSet oldSel = (BitSet) sel.clone(); 668: sel.clear(); 669: if (selectionMode == SINGLE_SELECTION) 670: anchor = lead; 671: 672: int lo = Math.min(anchor, lead); 673: int hi = Math.max(anchor, lead); 674: sel.set(lo, hi+1); 675: // update the anchorSelectionIndex and leadSelectionIndex variables 676: setAnchorSelectionIndex(anchor); 677: leadSelectionIndex = lead; 678: 679: fireDifference(sel, oldSel); 680: } 681: } 682: 683: /** 684: * Inserts a number of indices either before or after a particular 685: * position in the set of indices. Renumbers all indices after the 686: * inserted range. The new indices in the inserted range are not 687: * selected. This method is typically called to synchronize the selection 688: * model with an inserted range of elements in a {@link ListModel}. 689: * 690: * @param index The position to insert indices at 691: * @param length The number of indices to insert 692: * @param before Indicates whether to insert the indices before the index 693: * or after it 694: */ 695: public void insertIndexInterval(int index, 696: int length, 697: boolean before) 698: { 699: if (!before) 700: { 701: index++; 702: length--; 703: } 704: BitSet tmp = sel.get(index, sel.size()); 705: sel.clear(index, sel.size()); 706: int n = tmp.size(); 707: for (int i = 0; i < n; ++i) 708: sel.set(index + length + i, tmp.get(i)); 709: } 710: 711: /** 712: * Removes a range from the set of indices. Renumbers all indices after 713: * the removed range. This method is typically called to synchronize the 714: * selection model with a deleted range of elements in a {@link 715: * ListModel}. 716: * 717: * @param index0 The first index to remove (inclusive) 718: * @param index1 The last index to remove (inclusive) 719: */ 720: public void removeIndexInterval(int index0, 721: int index1) 722: { 723: int lo = Math.min(index0, index1); 724: int hi = Math.max(index0, index1); 725: 726: BitSet tmp = sel.get(hi, sel.size()); 727: sel.clear(lo, sel.size()); 728: int n = tmp.size(); 729: for (int i = 0; i < n; ++i) 730: sel.set(lo + i, tmp.get(i)); 731: } 732: 733: /** 734: * Fires a {@link ListSelectionEvent} to all the listeners of type {@link 735: * ListSelectionListener} registered with this selection model to 736: * indicate that a series of adjustment has just ended. 737: * 738: * The values of {@link #getMinSelectionIndex} and 739: * {@link #getMaxSelectionIndex} are used in the {@link ListSelectionEvent} 740: * that gets fired. 741: * 742: * @param isAdjusting <code>true</code> if this is the final change 743: * in a series of adjustments, <code>false/code> otherwise 744: */ 745: protected void fireValueChanged(boolean isAdjusting) 746: { 747: fireValueChanged(getMinSelectionIndex(), getMaxSelectionIndex(), 748: isAdjusting); 749: } 750: 751: /** 752: * Fires a {@link ListSelectionEvent} to all the listeners of type {@link 753: * ListSelectionListener} registered with this selection model. 754: * 755: * @param firstIndex The low index of the changed range 756: * @param lastIndex The high index of the changed range 757: */ 758: protected void fireValueChanged(int firstIndex, int lastIndex) 759: { 760: fireValueChanged(firstIndex, lastIndex, getValueIsAdjusting()); 761: } 762: 763: /** 764: * Fires a {@link ListSelectionEvent} to all the listeners of type {@link 765: * ListSelectionListener} registered with this selection model. 766: * 767: * @param firstIndex The low index of the changed range 768: * @param lastIndex The high index of the changed range 769: * @param isAdjusting Whether this change is part of a seqence of adjustments 770: * made to the selection, such as during interactive scrolling 771: */ 772: protected void fireValueChanged(int firstIndex, int lastIndex, 773: boolean isAdjusting) 774: { 775: ListSelectionEvent evt = new ListSelectionEvent(this, firstIndex, 776: lastIndex, isAdjusting); 777: ListSelectionListener[] listeners = getListSelectionListeners(); 778: for (int i = 0; i < listeners.length; ++i) 779: listeners[i].valueChanged(evt); 780: } 781: 782: /** 783: * Adds a listener. 784: * 785: * @param listener The listener to add 786: * 787: * @see #removeListSelectionListener 788: * @see #getListSelectionListeners 789: */ 790: public void addListSelectionListener(ListSelectionListener listener) 791: { 792: listenerList.add(ListSelectionListener.class, listener); 793: } 794: 795: /** 796: * Removes a registered listener. 797: * 798: * @param listener The listener to remove 799: * 800: * @see #addListSelectionListener 801: * @see #getListSelectionListeners 802: */ 803: public void removeListSelectionListener(ListSelectionListener listener) 804: { 805: listenerList.remove(ListSelectionListener.class, listener); 806: } 807: 808: /** 809: * Returns an array of all registerers listeners. 810: * 811: * @param listenerType The type of listener to retrieve 812: * 813: * @return The array 814: * 815: * @see #getListSelectionListeners 816: * @since 1.3 817: */ 818: public <T extends EventListener> T[] getListeners(Class<T> listenerType) 819: { 820: return listenerList.getListeners(listenerType); 821: } 822: 823: /** 824: * Returns an array of all registerd list selection listeners. 825: * 826: * @return the array 827: * 828: * @see #addListSelectionListener 829: * @see #removeListSelectionListener 830: * @see #getListeners 831: * @since 1.4 832: */ 833: public ListSelectionListener[] getListSelectionListeners() 834: { 835: return (ListSelectionListener[]) getListeners(ListSelectionListener.class); 836: } 837: 838: /** 839: * Returns a clone of this object. 840: * <code>listenerList</code> don't gets duplicated. 841: * 842: * @return the cloned object 843: * 844: * @throws CloneNotSupportedException if an error occurs 845: */ 846: public Object clone() 847: throws CloneNotSupportedException 848: { 849: DefaultListSelectionModel model = 850: (DefaultListSelectionModel) super.clone(); 851: model.sel = (BitSet) sel.clone(); 852: model.listenerList = new EventListenerList(); 853: return model; 854: } 855: }