| 1 7 package javax.swing; 8 9 import java.text.Collator ; 10 import java.util.ArrayList ; 11 import java.util.Arrays ; 12 import java.util.Collections ; 13 import java.util.Comparator ; 14 import java.util.List ; 15 import javax.swing.SortOrder ; 16 17 95 public abstract class DefaultRowSorter<M, I> extends RowSorter <M> { 96 99 private boolean sortsOnUpdates; 100 101 104 private Row[] viewToModel; 105 106 109 private int[] modelToView; 110 111 114 private Comparator [] comparators; 115 116 119 private boolean[] isSortable; 120 121 124 private SortKey[] cachedSortKeys; 125 126 129 private Comparator [] sortComparators; 130 131 134 private RowFilter <? super M,? super I> filter; 135 136 140 private FilterEntry filterEntry; 141 142 145 private List <SortKey> sortKeys; 146 147 150 private boolean[] useToString; 151 152 156 private boolean sorted; 157 158 161 private int maxSortKeys; 162 163 166 private ModelWrapper<M,I> modelWrapper; 167 168 172 private int modelRowCount; 173 174 175 178 public DefaultRowSorter() { 179 sortKeys = Collections.emptyList(); 180 maxSortKeys = 3; 181 } 182 183 192 protected final void setModelWrapper(ModelWrapper<M,I> modelWrapper) { 193 if (modelWrapper == null) { 194 throw new IllegalArgumentException ( 195 "modelWrapper most be non-null"); 196 } 197 ModelWrapper<M,I> last = this.modelWrapper; 198 this.modelWrapper = modelWrapper; 199 if (last != null) { 200 modelStructureChanged(); 201 } else { 202 modelRowCount = getModelWrapper().getRowCount(); 205 } 206 } 207 208 215 protected final ModelWrapper<M,I> getModelWrapper() { 216 return modelWrapper; 217 } 218 219 224 public final M getModel() { 225 return getModelWrapper().getModel(); 226 } 227 228 243 public void setSortable(int column, boolean sortable) { 244 checkColumn(column); 245 if (isSortable == null) { 246 isSortable = new boolean[getModelWrapper().getColumnCount()]; 247 for (int i = isSortable.length - 1; i >= 0; i--) { 248 isSortable[i] = true; 249 } 250 } 251 isSortable[column] = sortable; 252 } 253 254 263 public boolean isSortable(int column) { 264 checkColumn(column); 265 return (isSortable == null) ? true : isSortable[column]; 266 } 267 268 281 public void setSortKeys(List <? extends SortKey> sortKeys) { 282 List <SortKey> old = this.sortKeys; 283 if (sortKeys != null && sortKeys.size() > 0) { 284 int max = getModelWrapper().getColumnCount(); 285 for (SortKey key : sortKeys) { 286 if (key == null || key.getColumn() < 0 || 287 key.getColumn() >= max) { 288 throw new IllegalArgumentException ("Invalid SortKey"); 289 } 290 } 291 this.sortKeys = Collections.unmodifiableList( 292 new ArrayList <SortKey>(sortKeys)); 293 } 294 else { 295 this.sortKeys = Collections.emptyList(); 296 } 297 if (!this.sortKeys.equals(old)) { 298 fireSortOrderChanged(); 299 if (viewToModel == null) { 300 sort(); 303 } else { 304 sortExistingData(); 305 } 306 } 307 } 308 309 317 public List <? extends SortKey> getSortKeys() { 318 return sortKeys; 319 } 320 321 349 public void setMaxSortKeys(int max) { 350 if (max < 1) { 351 throw new IllegalArgumentException ("Invalid max"); 352 } 353 maxSortKeys = max; 354 } 355 356 361 public int getMaxSortKeys() { 362 return maxSortKeys; 363 } 364 365 374 public void setSortsOnUpdates(boolean sortsOnUpdates) { 375 this.sortsOnUpdates = sortsOnUpdates; 376 } 377 378 384 public boolean getSortsOnUpdates() { 385 return sortsOnUpdates; 386 } 387 388 405 public void setRowFilter(RowFilter <? super M,? super I> filter) { 406 this.filter = filter; 407 sort(); 408 } 409 410 416 public RowFilter <? super M,? super I> getRowFilter() { 417 return filter; 418 } 419 420 434 public void toggleSortOrder(int column) { 435 checkColumn(column); 436 if (isSortable(column)) { 437 List <SortKey> keys = new ArrayList <SortKey>(getSortKeys()); 438 SortKey sortKey; 439 int sortIndex; 440 for (sortIndex = keys.size() - 1; sortIndex >= 0; sortIndex--) { 441 if (keys.get(sortIndex).getColumn() == column) { 442 break; 443 } 444 } 445 if (sortIndex == -1) { 446 sortKey = new SortKey(column, SortOrder.ASCENDING); 448 keys.add(0, sortKey); 449 } 450 else if (sortIndex == 0) { 451 keys.set(0, toggle(keys.get(0))); 453 } 454 else { 455 keys.remove(sortIndex); 458 keys.add(0, new SortKey(column, SortOrder.ASCENDING)); 459 } 460 if (keys.size() > getMaxSortKeys()) { 461 keys = keys.subList(0, getMaxSortKeys()); 462 } 463 setSortKeys(keys); 464 } 465 } 466 467 private SortKey toggle(SortKey key) { 468 if (key.getSortOrder() == SortOrder.ASCENDING) { 469 return new SortKey(key.getColumn(), SortOrder.DESCENDING); 470 } 471 return new SortKey(key.getColumn(), SortOrder.ASCENDING); 472 } 473 474 479 public int convertRowIndexToView(int index) { 480 if (modelToView == null) { 481 if (index < 0 || index >= getModelWrapper().getRowCount()) { 482 throw new IndexOutOfBoundsException ("Invalid index"); 483 } 484 return index; 485 } 486 return modelToView[index]; 487 } 488 489 494 public int convertRowIndexToModel(int index) { 495 if (viewToModel == null) { 496 if (index < 0 || index >= getModelWrapper().getRowCount()) { 497 throw new IndexOutOfBoundsException ("Invalid index"); 498 } 499 return index; 500 } 501 return viewToModel[index].modelIndex; 502 } 503 504 private boolean isUnsorted() { 505 List <? extends SortKey> keys = getSortKeys(); 506 int keySize = keys.size(); 507 return (keySize == 0 || keys.get(0).getSortOrder() == 508 SortOrder.UNSORTED); 509 } 510 511 515 private void sortExistingData() { 516 int[] lastViewToModel = getViewToModelAsInts(viewToModel); 517 518 updateUseToString(); 519 cacheSortKeys(getSortKeys()); 520 521 if (isUnsorted()) { 522 if (getRowFilter() == null) { 523 viewToModel = null; 524 modelToView = null; 525 } else { 526 int included = 0; 527 for (int i = 0; i < modelToView.length; i++) { 528 if (modelToView[i] != -1) { 529 viewToModel[included].modelIndex = i; 530 modelToView[i] = included++; 531 } 532 } 533 } 534 } else { 535 Arrays.sort(viewToModel); 537 538 setModelToViewFromViewToModel(false); 540 } 541 fireRowSorterChanged(lastViewToModel); 542 } 543 544 553 public void sort() { 554 sorted = true; 555 int[] lastViewToModel = getViewToModelAsInts(viewToModel); 556 updateUseToString(); 557 if (isUnsorted()) { 558 cachedSortKeys = new SortKey[0]; 560 if (getRowFilter() == null) { 561 if (viewToModel != null) { 563 viewToModel = null; 565 modelToView = null; 566 } 567 else { 568 return; 571 } 572 } 573 else { 574 initializeFilteredMapping(); 576 } 577 } 578 else { 579 cacheSortKeys(getSortKeys()); 580 581 if (getRowFilter() != null) { 582 initializeFilteredMapping(); 583 } 584 else { 585 createModelToView(getModelWrapper().getRowCount()); 586 createViewToModel(getModelWrapper().getRowCount()); 587 } 588 589 Arrays.sort(viewToModel); 591 592 setModelToViewFromViewToModel(false); 594 } 595 fireRowSorterChanged(lastViewToModel); 596 } 597 598 601 private void updateUseToString() { 602 int i = getModelWrapper().getColumnCount(); 603 if (useToString == null || useToString.length != i) { 604 useToString = new boolean[i]; 605 } 606 for (--i; i >= 0; i--) { 607 useToString[i] = useToString(i); 608 } 609 } 610 611 615 private void initializeFilteredMapping() { 616 int rowCount = getModelWrapper().getRowCount(); 617 int i, j; 618 int excludedCount = 0; 619 620 createModelToView(rowCount); 622 for (i = 0; i < rowCount; i++) { 623 if (include(i)) { 624 modelToView[i] = i - excludedCount; 625 } 626 else { 627 modelToView[i] = -1; 628 excludedCount++; 629 } 630 } 631 632 createViewToModel(rowCount - excludedCount); 634 for (i = 0, j = 0; i < rowCount; i++) { 635 if (modelToView[i] != -1) { 636 viewToModel[j++].modelIndex = i; 637 } 638 } 639 } 640 641 644 private void createModelToView(int rowCount) { 645 if (modelToView == null || modelToView.length != rowCount) { 646 modelToView = new int[rowCount]; 647 } 648 } 649 650 653 private void createViewToModel(int rowCount) { 654 int recreateFrom = 0; 655 if (viewToModel != null) { 656 recreateFrom = Math.min(rowCount, viewToModel.length); 657 if (viewToModel.length != rowCount) { 658 Row[] oldViewToModel = viewToModel; 659 viewToModel = new Row[rowCount]; 660 System.arraycopy(oldViewToModel, 0, viewToModel, 661 0, recreateFrom); 662 } 663 } 664 else { 665 viewToModel = new Row[rowCount]; 666 } 667 int i; 668 for (i = 0; i < recreateFrom; i++) { 669 viewToModel[i].modelIndex = i; 670 } 671 for (i = recreateFrom; i < rowCount; i++) { 672 viewToModel[i] = new Row(this, i); 673 } 674 } 675 676 679 private void cacheSortKeys(List <? extends SortKey> keys) { 680 int keySize = keys.size(); 681 sortComparators = new Comparator [keySize]; 682 for (int i = 0; i < keySize; i++) { 683 sortComparators[i] = getComparator0(keys.get(i).getColumn()); 684 } 685 cachedSortKeys = keys.toArray(new SortKey[keySize]); 686 } 687 688 700 protected boolean useToString(int column) { 701 return (getComparator(column) == null); 702 } 703 704 709 private void setModelToViewFromViewToModel(boolean unsetFirst) { 710 int i; 711 if (unsetFirst) { 712 for (i = modelToView.length - 1; i >= 0; i--) { 713 modelToView[i] = -1; 714 } 715 } 716 for (i = viewToModel.length - 1; i >= 0; i--) { 717 modelToView[viewToModel[i].modelIndex] = i; 718 } 719 } 720 721 private int[] getViewToModelAsInts(Row[] viewToModel) { 722 if (viewToModel != null) { 723 int[] viewToModelI = new int[viewToModel.length]; 724 for (int i = viewToModel.length - 1; i >= 0; i--) { 725 viewToModelI[i] = viewToModel[i].modelIndex; 726 } 727 return viewToModelI; 728 } 729 return new int[0]; 730 } 731 732 743 public void setComparator(int column, Comparator <?> comparator) { 744 checkColumn(column); 745 if (comparators == null) { 746 comparators = new Comparator [getModelWrapper().getColumnCount()]; 747 } 748 comparators[column] = comparator; 749 } 750 751 762 public Comparator <?> getComparator(int column) { 763 checkColumn(column); 764 if (comparators != null) { 765 return comparators[column]; 766 } 767 return null; 768 } 769 770 private Comparator getComparator0(int column) { 773 Comparator comparator = getComparator(column); 774 if (comparator != null) { 775 return comparator; 776 } 777 return Collator.getInstance(); 780 } 781 782 private RowFilter.Entry <M,I> getFilterEntry(int modelIndex) { 783 if (filterEntry == null) { 784 filterEntry = new FilterEntry(); 785 } 786 filterEntry.modelIndex = modelIndex; 787 return filterEntry; 788 } 789 790 793 public int getViewRowCount() { 794 if (viewToModel != null) { 795 return viewToModel.length; 797 } 798 return getModelWrapper().getRowCount(); 799 } 800 801 804 public int getModelRowCount() { 805 return getModelWrapper().getRowCount(); 806 } 807 808 private void allChanged() { 809 modelToView = null; 810 viewToModel = null; 811 comparators = null; 812 isSortable = null; 813 if (isUnsorted()) { 814 sort(); 817 } else { 818 setSortKeys(null); 819 } 820 } 821 822 825 public void modelStructureChanged() { 826 allChanged(); 827 modelRowCount = getModelWrapper().getRowCount(); 828 } 829 830 833 public void allRowsChanged() { 834 modelRowCount = getModelWrapper().getRowCount(); 835 sort(); 836 } 837 838 843 public void rowsInserted(int firstRow, int endRow) { 844 checkAgainstModel(firstRow, endRow); 845 int newModelRowCount = getModelWrapper().getRowCount(); 846 if (endRow >= newModelRowCount) { 847 throw new IndexOutOfBoundsException ("Invalid range"); 848 } 849 modelRowCount = newModelRowCount; 850 if (shouldOptimizeChange(firstRow, endRow)) { 851 rowsInserted0(firstRow, endRow); 852 } 853 } 854 855 860 public void rowsDeleted(int firstRow, int endRow) { 861 checkAgainstModel(firstRow, endRow); 862 if (firstRow >= modelRowCount || endRow >= modelRowCount) { 863 throw new IndexOutOfBoundsException ("Invalid range"); 864 } 865 modelRowCount = getModelWrapper().getRowCount(); 866 if (shouldOptimizeChange(firstRow, endRow)) { 867 rowsDeleted0(firstRow, endRow); 868 } 869 } 870 871 876 public void rowsUpdated(int firstRow, int endRow) { 877 checkAgainstModel(firstRow, endRow); 878 if (firstRow >= modelRowCount || endRow >= modelRowCount) { 879 throw new IndexOutOfBoundsException ("Invalid range"); 880 } 881 if (getSortsOnUpdates()) { 882 if (shouldOptimizeChange(firstRow, endRow)) { 883 rowsUpdated0(firstRow, endRow); 884 } 885 } 886 else { 887 sorted = false; 888 } 889 } 890 891 896 public void rowsUpdated(int firstRow, int endRow, int column) { 897 checkColumn(column); 898 rowsUpdated(firstRow, endRow); 899 } 900 901 private void checkAgainstModel(int firstRow, int endRow) { 902 if (firstRow > endRow || firstRow < 0 || endRow < 0 || 903 firstRow > modelRowCount) { 904 throw new IndexOutOfBoundsException ("Invalid range"); 905 } 906 } 907 908 911 private boolean include(int row) { 912 RowFilter <? super M, ? super I> filter = getRowFilter(); 913 if (filter != null) { 914 return filter.include(getFilterEntry(row)); 915 } 916 return true; 918 } 919 920 @SuppressWarnings ("unchecked") 921 private int compare(int model1, int model2) { 922 int column; 923 SortOrder sortOrder; 924 Object v1, v2; 925 int result; 926 927 for (int counter = 0; counter < cachedSortKeys.length; counter++) { 928 column = cachedSortKeys[counter].getColumn(); 929 sortOrder = cachedSortKeys[counter].getSortOrder(); 930 if (sortOrder == SortOrder.UNSORTED) { 931 result = model1 - model2; 932 } else { 933 if (useToString[column]) { 935 v1 = getModelWrapper().getStringValueAt(model1, column); 936 v2 = getModelWrapper().getStringValueAt(model2, column); 937 } else { 938 v1 = getModelWrapper().getValueAt(model1, column); 939 v2 = getModelWrapper().getValueAt(model2, column); 940 } 941 if (v1 == null) { 943 if (v2 == null) { 944 result = 0; 945 } else { 946 result = -1; 947 } 948 } else if (v2 == null) { 949 result = 1; 950 } else { 951 &nb
|