001 /* DefaultListSelectionModel.java -- 002 Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. 003 004 This file is part of GNU Classpath. 005 006 GNU Classpath is free software; you can redistribute it and/or modify 007 it under the terms of the GNU General Public License as published by 008 the Free Software Foundation; either version 2, or (at your option) 009 any later version. 010 011 GNU Classpath is distributed in the hope that it will be useful, but 012 WITHOUT ANY WARRANTY; without even the implied warranty of 013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 General Public License for more details. 015 016 You should have received a copy of the GNU General Public License 017 along with GNU Classpath; see the file COPYING. If not, write to the 018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 019 02110-1301 USA. 020 021 Linking this library statically or dynamically with other modules is 022 making a combined work based on this library. Thus, the terms and 023 conditions of the GNU General Public License cover the whole 024 combination. 025 026 As a special exception, the copyright holders of this library give you 027 permission to link this library with independent modules to produce an 028 executable, regardless of the license terms of these independent 029 modules, and to copy and distribute the resulting executable under 030 terms of your choice, provided that you also meet, for each linked 031 independent module, the terms and conditions of the license of that 032 module. An independent module is a module which is not derived from 033 or based on this library. If you modify this library, you may extend 034 this exception to your version of the library, but you are not 035 obligated to do so. If you do not wish to do so, delete this 036 exception statement from your version. */ 037 038 039 package javax.swing; 040 041 import java.io.Serializable; 042 import java.util.BitSet; 043 import java.util.EventListener; 044 045 import javax.swing.event.EventListenerList; 046 import javax.swing.event.ListSelectionEvent; 047 import javax.swing.event.ListSelectionListener; 048 049 /** 050 * The default implementation of {@link ListSelectionModel}, 051 * which is used by {@link javax.swing.JList} and 052 * similar classes to manage the selection status of a number of data 053 * elements. 054 * 055 * <p>The class is organized <em>abstractly</em> as a set of intervals of 056 * integers. Each interval indicates an inclusive range of indices in a 057 * list -- held by some other object and unknown to this class -- which is 058 * considered "selected". There are various accessors for querying and 059 * modifying the set of intervals, with simplified forms accepting a single 060 * index, representing an interval with only one element. </p> 061 */ 062 public class DefaultListSelectionModel implements Cloneable, 063 ListSelectionModel, 064 Serializable 065 { 066 private static final long serialVersionUID = -5718799865110415860L; 067 068 /** The list of ListSelectionListeners subscribed to this selection model. */ 069 protected EventListenerList listenerList = new EventListenerList(); 070 071 072 /** 073 * The current list selection mode. Must be one of the numeric constants 074 * <code>SINGLE_SELECTION</code>, <code>SINGLE_INTERVAL_SELECTION</code> 075 * or <code>MULTIPLE_INTERVAL_SELECTION</code> from {@link 076 * ListSelectionModel}. The default value is 077 * <code>MULTIPLE_INTERVAL_SELECTION</code>. 078 */ 079 int selectionMode = MULTIPLE_INTERVAL_SELECTION; 080 081 /** 082 * The index of the "lead" of the most recent selection. The lead is the 083 * second argument in any call to {@link #setSelectionInterval}, {@link 084 * #addSelectionInterval} or {@link #removeSelectionInterval}. Generally 085 * the lead refers to the most recent position a user dragged their mouse 086 * over. 087 */ 088 int leadSelectionIndex = -1; 089 090 /** 091 * The index of the "anchor" of the most recent selection. The anchor is 092 * the first argument in any call to {@link #setSelectionInterval}, 093 * {@link #addSelectionInterval} or {@link 094 * #removeSelectionInterval}. Generally the anchor refers to the first 095 * recent position a user clicks when they begin to drag their mouse over 096 * a list. 097 * 098 * @see #getAnchorSelectionIndex 099 * @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 }