| 1 7 8 package javax.swing.plaf.basic; 9 10 import sun.swing.DefaultLookup; 11 import sun.swing.UIAction; 12 13 import javax.swing.*; 14 import javax.swing.event.*; 15 import javax.swing.plaf.*; 16 import javax.swing.text.Position ; 17 18 import java.awt.*; 19 import java.awt.event.*; 20 import java.awt.datatransfer.Transferable ; 21 import java.awt.dnd.*; 22 23 import java.util.ArrayList ; 24 import java.util.TooManyListenersException ; 25 26 import java.beans.PropertyChangeListener ; 27 import java.beans.PropertyChangeEvent ; 28 29 import com.sun.java.swing.SwingUtilities2; 30 import static com.sun.java.swing.SwingUtilities2.DRAG_FIX; 31 import javax.swing.plaf.basic.DragRecognitionSupport.BeforeDrag ; 32 33 42 public class BasicListUI extends ListUI 43 { 44 protected JList list = null; 45 protected CellRendererPane rendererPane; 46 47 protected FocusListener focusListener; 49 protected MouseInputListener mouseInputListener; 50 protected ListSelectionListener listSelectionListener; 51 protected ListDataListener listDataListener; 52 protected PropertyChangeListener propertyChangeListener; 53 private Handler handler; 54 55 protected int[] cellHeights = null; 56 protected int cellHeight = -1; 57 protected int cellWidth = -1; 58 protected int updateLayoutStateNeeded = modelChanged; 59 63 private int listHeight; 64 65 69 private int listWidth; 70 71 74 private int layoutOrientation; 75 76 78 81 private int columnCount; 82 86 private int preferredHeight; 87 91 private int rowsPerColumn; 92 93 97 private long timeFactor = 1000L; 98 99 102 private boolean isFileList = false; 103 104 107 private boolean isLeftToRight = true; 108 109 115 116 protected final static int modelChanged = 1 << 0; 117 protected final static int selectionModelChanged = 1 << 1; 118 protected final static int fontChanged = 1 << 2; 119 protected final static int fixedCellWidthChanged = 1 << 3; 120 protected final static int fixedCellHeightChanged = 1 << 4; 121 protected final static int prototypeCellValueChanged = 1 << 5; 122 protected final static int cellRendererChanged = 1 << 6; 123 private final static int layoutOrientationChanged = 1 << 7; 124 private final static int heightChanged = 1 << 8; 125 private final static int widthChanged = 1 << 9; 126 private final static int componentOrientationChanged = 1 << 10; 127 128 129 static void loadActionMap(LazyActionMap map) { 130 map.put(new Actions(Actions.SELECT_PREVIOUS_COLUMN)); 131 map.put(new Actions(Actions.SELECT_PREVIOUS_COLUMN_EXTEND)); 132 map.put(new Actions(Actions.SELECT_PREVIOUS_COLUMN_CHANGE_LEAD)); 133 map.put(new Actions(Actions.SELECT_NEXT_COLUMN)); 134 map.put(new Actions(Actions.SELECT_NEXT_COLUMN_EXTEND)); 135 map.put(new Actions(Actions.SELECT_NEXT_COLUMN_CHANGE_LEAD)); 136 map.put(new Actions(Actions.SELECT_PREVIOUS_ROW)); 137 map.put(new Actions(Actions.SELECT_PREVIOUS_ROW_EXTEND)); 138 map.put(new Actions(Actions.SELECT_PREVIOUS_ROW_CHANGE_LEAD)); 139 map.put(new Actions(Actions.SELECT_NEXT_ROW)); 140 map.put(new Actions(Actions.SELECT_NEXT_ROW_EXTEND)); 141 map.put(new Actions(Actions.SELECT_NEXT_ROW_CHANGE_LEAD)); 142 map.put(new Actions(Actions.SELECT_FIRST_ROW)); 143 map.put(new Actions(Actions.SELECT_FIRST_ROW_EXTEND)); 144 map.put(new Actions(Actions.SELECT_FIRST_ROW_CHANGE_LEAD)); 145 map.put(new Actions(Actions.SELECT_LAST_ROW)); 146 map.put(new Actions(Actions.SELECT_LAST_ROW_EXTEND)); 147 map.put(new Actions(Actions.SELECT_LAST_ROW_CHANGE_LEAD)); 148 map.put(new Actions(Actions.SCROLL_UP)); 149 map.put(new Actions(Actions.SCROLL_UP_EXTEND)); 150 map.put(new Actions(Actions.SCROLL_UP_CHANGE_LEAD)); 151 map.put(new Actions(Actions.SCROLL_DOWN)); 152 map.put(new Actions(Actions.SCROLL_DOWN_EXTEND)); 153 map.put(new Actions(Actions.SCROLL_DOWN_CHANGE_LEAD)); 154 map.put(new Actions(Actions.SELECT_ALL)); 155 map.put(new Actions(Actions.CLEAR_SELECTION)); 156 map.put(new Actions(Actions.ADD_TO_SELECTION)); 157 map.put(new Actions(Actions.TOGGLE_AND_ANCHOR)); 158 map.put(new Actions(Actions.EXTEND_TO)); 159 map.put(new Actions(Actions.MOVE_SELECTION_TO)); 160 161 map.put(TransferHandler.getCutAction().getValue(Action.NAME), 162 TransferHandler.getCutAction()); 163 map.put(TransferHandler.getCopyAction().getValue(Action.NAME), 164 TransferHandler.getCopyAction()); 165 map.put(TransferHandler.getPasteAction().getValue(Action.NAME), 166 TransferHandler.getPasteAction()); 167 } 168 169 176 protected void paintCell( 177 Graphics g, 178 int row, 179 Rectangle rowBounds, 180 ListCellRenderer cellRenderer, 181 ListModel dataModel, 182 ListSelectionModel selModel, 183 int leadIndex) 184 { 185 Object value = dataModel.getElementAt(row); 186 boolean cellHasFocus = list.hasFocus() && (row == leadIndex); 187 boolean isSelected = selModel.isSelectedIndex(row); 188 189 Component rendererComponent = 190 cellRenderer.getListCellRendererComponent(list, value, row, isSelected, cellHasFocus); 191 192 int cx = rowBounds.x; 193 int cy = rowBounds.y; 194 int cw = rowBounds.width; 195 int ch = rowBounds.height; 196 197 if (isFileList) { 198 int w = Math.min(cw, rendererComponent.getPreferredSize().width + 4); 202 if (!isLeftToRight) { 203 cx += (cw - w); 204 } 205 cw = w; 206 } 207 208 rendererPane.paintComponent(g, rendererComponent, list, cx, cy, cw, ch, true); 209 } 210 211 212 219 public void paint(Graphics g, JComponent c) 220 { 221 switch (layoutOrientation) { 222 case JList.VERTICAL_WRAP: 223 if (list.getHeight() != listHeight) { 224 updateLayoutStateNeeded |= heightChanged; 225 redrawList(); 226 } 227 break; 228 case JList.HORIZONTAL_WRAP: 229 if (list.getWidth() != listWidth) { 230 updateLayoutStateNeeded |= widthChanged; 231 redrawList(); 232 } 233 break; 234 default: 235 break; 236 } 237 maybeUpdateLayoutState(); 238 239 ListCellRenderer renderer = list.getCellRenderer(); 240 ListModel dataModel = list.getModel(); 241 ListSelectionModel selModel = list.getSelectionModel(); 242 int size; 243 244 if ((renderer == null) || (size = dataModel.getSize()) == 0) { 245 return; 246 } 247 248 Rectangle paintBounds = g.getClipBounds(); 250 251 int startColumn, endColumn; 252 if (c.getComponentOrientation().isLeftToRight()) { 253 startColumn = convertLocationToColumn(paintBounds.x, 254 paintBounds.y); 255 endColumn = convertLocationToColumn(paintBounds.x + 256 paintBounds.width, 257 paintBounds.y); 258 } else { 259 startColumn = convertLocationToColumn(paintBounds.x + 260 paintBounds.width, 261 paintBounds.y); 262 endColumn = convertLocationToColumn(paintBounds.x, 263 paintBounds.y); 264 } 265 int maxY = paintBounds.y + paintBounds.height; 266 int leadIndex = list.getLeadSelectionIndex(); 267 int rowIncrement = (layoutOrientation == JList.HORIZONTAL_WRAP) ? 268 columnCount : 1; 269 270 271 for (int colCounter = startColumn; colCounter <= endColumn; 272 colCounter++) { 273 int row = convertLocationToRowInColumn(paintBounds.y, colCounter); 275 int rowCount = getRowCount(colCounter); 276 int index = getModelIndex(colCounter, row); 277 Rectangle rowBounds = getCellBounds(list, index, index); 278 279 if (rowBounds == null) { 280 return; 282 } 283 while (row < rowCount && rowBounds.y < maxY && 284 index < size) { 285 rowBounds.height = getHeight(colCounter, row); 286 g.setClip(rowBounds.x, rowBounds.y, rowBounds.width, 287 rowBounds.height); 288 g.clipRect(paintBounds.x, paintBounds.y, paintBounds.width, 289 paintBounds.height); 290 paintCell(g, index, rowBounds, renderer, dataModel, selModel, 291 leadIndex); 292 rowBounds.y += rowBounds.height; 293 index += rowIncrement; 294 row++; 295 } 296 } 297 } 298 299 300 355 public Dimension getPreferredSize(JComponent c) { 356 maybeUpdateLayoutState(); 357 358 int lastRow = list.getModel().getSize() - 1; 359 if (lastRow < 0) { 360 return new Dimension(0, 0); 361 } 362 363 Insets insets = list.getInsets(); 364 int width = cellWidth * columnCount + insets.left + insets.right; 365 int height; 366 367 if (layoutOrientation != JList.VERTICAL) { 368 height = preferredHeight; 369 } 370 else { 371 Rectangle bounds = getCellBounds(list, lastRow); 372 373 if (bounds != null) { 374 height = bounds.y + bounds.height + insets.bottom; 375 } 376 else { 377 height = 0; 378 } 379 } 380 return new Dimension(width, height); 381 } 382 383 384 389 protected void selectPreviousIndex() { 390 int s = list.getSelectedIndex(); 391 if(s > 0) { 392 s -= 1; 393 list.setSelectedIndex(s); 394 list.ensureIndexIsVisible(s); 395 } 396 } 397 398 399 404 protected void selectNextIndex() 405 { 406 int s = list.getSelectedIndex(); 407 if((s + 1) < list.getModel().getSize()) { 408 s += 1; 409 list.setSelectedIndex(s); 410 list.ensureIndexIsVisible(s); 411 } 412 } 413 414 415 422 protected void installKeyboardActions() { 423 InputMap inputMap = getInputMap(JComponent.WHEN_FOCUSED); 424 425 SwingUtilities.replaceUIInputMap(list, JComponent.WHEN_FOCUSED, 426 inputMap); 427 428 LazyActionMap.installLazyActionMap(list, BasicListUI .class, 429 "List.actionMap"); 430 } 431 432 InputMap getInputMap(int condition) { 433 if (condition == JComponent.WHEN_FOCUSED) { 434 InputMap keyMap = (InputMap)DefaultLookup.get( 435 list, this, "List.focusInputMap"); 436 InputMap rtlKeyMap; 437 438 if (isLeftToRight || 439 ((rtlKeyMap = (InputMap)DefaultLookup.get(list, this, 440 "List.focusInputMap.RightToLeft")) == null)) { 441 return keyMap; 442 } else { 443 rtlKeyMap.setParent(keyMap); 444 return rtlKeyMap; 445 } 446 } 447 return null; 448 } 449 450 459 protected void uninstallKeyboardActions() { 460 SwingUtilities.replaceUIActionMap(list, null); 461 SwingUtilities.replaceUIInputMap(list, JComponent.WHEN_FOCUSED, null); 462 } 463 464 465 472 protected void installListeners() 473 { 474 TransferHandler th = list.getTransferHandler(); 475 if (th == null || th instanceof UIResource) { 476 list.setTransferHandler(defaultTransferHandler); 477 } 478 DropTarget dropTarget = list.getDropTarget(); 479 if (dropTarget instanceof UIResource) { 480 try { 481 dropTarget.addDropTargetListener(new ListDropTargetListener()); 482 } catch (TooManyListenersException tmle) { 483 } 485 } 486 487 focusListener = createFocusListener(); 488 mouseInputListener = createMouseInputListener(); 489 propertyChangeListener = createPropertyChangeListener(); 490 listSelectionListener = createListSelectionListener(); 491 listDataListener = createListDataListener(); 492 493 list.addFocusListener(focusListener); 494 if (!DRAG_FIX) { 495 list.addMouseListener(defaultDragRecognizer); 496 list.addMouseMotionListener(defaultDragRecognizer); 497 } 498 list.addMouseListener(mouseInputListener); 499 list.addMouseMotionListener(mouseInputListener); 500 list.addPropertyChangeListener(propertyChangeListener); 501 list.addKeyListener(getHandler()); 502 503 ListModel model = list.getModel(); 504 if (model != null) { 505 model.addListDataListener(listDataListener); 506 } 507 508 ListSelectionModel selectionModel = list.getSelectionModel(); 509 if (selectionModel != null) { 510 selectionModel.addListSelectionListener(listSelectionListener); 511 } 512 } 513 514 515 524 protected void uninstallListeners() 525 { 526 list.removeFocusListener(focusListener); 527 if (!DRAG_FIX) { 528 list.removeMouseListener(defaultDragRecognizer); 529 list.removeMouseMotionListener(defaultDragRecognizer); 530 } 531 list.removeMouseListener(mouseInputListener); 532 list.removeMouseMotionListener(mouseInputListener); 533 list.removePropertyChangeListener(propertyChangeListener); 534 list.removeKeyListener(getHandler()); 535 536 ListModel model = list.getModel(); 537 if (model != null) { 538 model.removeListDataListener(listDataListener); 539 } 540 541 ListSelectionModel selectionModel = list.getSelectionModel(); 542 if (selectionModel != null) { 543 selectionModel.removeListSelectionListener(listSelectionListener); 544 } 545 546 focusListener = null; 547 mouseInputListener = null; 548 listSelectionListener = null; 549 listDataListener = null; 550 propertyChangeListener = null; 551 handler = null; 552 } 553 554 555 566 protected void installDefaults() 567 { 568 list.setLayout(null); 569 570 LookAndFeel.installBorder(list, "List.border"); 571 572 LookAndFeel.installColorsAndFont(list, "List.background", "List.foreground", "List.font"); 573 574 LookAndFeel.installProperty(list, "opaque", Boolean.TRUE); 575 576 if (list.getCellRenderer() == null) { 577 list.setCellRenderer((ListCellRenderer)(UIManager.get("List.cellRenderer"))); 578 } 579 580 Color sbg = list.getSelectionBackground(); 581 if (sbg == null || sbg instanceof UIResource) { 582 list.setSelectionBackground(UIManager.getColor("List.selectionBackground")); 583 } 584 585 Color sfg = list.getSelectionForeground(); 586 if (sfg == null || sfg instanceof UIResource) { 587 list.setSelectionForeground(UIManager.getColor("List.selectionForeground")); 588 } 589 590 Long l = (Long )UIManager.get("List.timeFactor"); 591 timeFactor = (l!=null) ? l.longValue() : 1000L; 592 593 updateIsFileList(); 594 isLeftToRight = list.getComponentOrientation().isLeftToRight(); 595 } 596 597 private void updateIsFileList() { 598 boolean b = Boolean.TRUE.equals(list.getClientProperty("List.isFileList")); 599 if (b != isFileList) { 600 isFileList = b; 601 Font oldFont = list.getFont(); 602 if (oldFont == null || oldFont instanceof UIResource) { 603 Font newFont = UIManager.getFont(b ? "FileChooser.listFont" : "List.font"); 604 if (newFont != null && newFont != oldFont) { 605 list.setFont(newFont); 606 } 607 } 608 } 609 } 610 611 612 621 protected void uninstallDefaults() 622 { 623 LookAndFeel.uninstallBorder(list); 624 if (list.getFont() instanceof UIResource) { 625 list.setFont(null); 626 } 627 if (list.getForeground() instanceof UIResource) { 628 list.setForeground(null); 629 } 630 if (list.getBackground() instanceof UIResource) { 631 list.setBackground(null); 632 } 633 if (list.getSelectionBackground() instanceof UIResource) { 634 list.setSelectionBackground(null); 635 } 636 if (list.getSelectionForeground() instanceof UIResource) { 637 list.setSelectionForeground(null); 638 } 639 if (list.getCellRenderer() instanceof UIResource) { 640 list.setCellRenderer(null); 641 } 642 if (list.getTransferHandler() instanceof UIResource) { 643 list.setTransferHandler(null); 644 } 645 } 646 647 648 657 public void installUI(JComponent c) 658 { 659 list = (JList)c; 660 661 layoutOrientation = list.getLayoutOrientation(); 662 663 rendererPane = new CellRendererPane(); 664 list.add(rendererPane); 665 666 columnCount = 1; 667 668 installDefaults(); 669 installListeners(); 670 installKeyboardActions(); 671 } 672 673 674 683 public void uninstallUI(JComponent c) 684 { 685 uninstallListeners(); 686 uninstallDefaults(); 687 uninstallKeyboardActions(); 688 689 cellWidth = cellHeight = -1; 690 cellHeights = null; 691 692 listWidth = listHeight = -1; 693 694 list.remove(rendererPane); 695 rendererPane = null; 696 list = null; 697 } 698 699 700 706 public static ComponentUI createUI(JComponent list) { 707 return new BasicListUI (); 708 } 709 710 711 720 public int locationToIndex(JList list, Point location) { 721 maybeUpdateLayoutState(); 722 return convertLocationToModel(location.x, location.y); 723 } 724 725 726 730 public Point indexToLocation(JList list, int index) { 731 maybeUpdateLayoutState(); 732 Rectangle rect = getCellBounds(list, index, index); 733 734 if (rect != null) { 735 return new Point(rect.x, rect.y); 736 } 737 return null; 738 } 739 740 741 745 public Rectangle getCellBounds(JList list, int index1, int index2) { 746 maybeUpdateLayoutState(); 747 748 int minIndex = Math.min(index1, index2); 749 int maxIndex = Math.max(index1, index2); 750 751 if (minIndex >= list.getModel().getSize()) { 752 return null; 753 } 754 755 Rectangle minBounds = getCellBounds(list, minIndex); 756 757 if (minBounds == null) { 758 return null; 759 } 760 if (minIndex == maxIndex) { 761 return minBounds; 762 } 763 Rectangle maxBounds = getCellBounds(list, maxIndex); 764 765 if (maxBounds != null) { 766 if (layoutOrientation == JList.HORIZONTAL_WRAP) { 767 int minRow = convertModelToRow(minIndex); 768 int maxRow = convertModelToRow(maxIndex); 769 770 if (minRow != maxRow) { 771 minBounds.x = 0; 772 minBounds.width = list.getWidth(); 773 } 774 } 775 else if (minBounds.x != maxBounds.x) { 776 minBounds.y = 0; 778 minBounds.height = list.getHeight(); 779 } 780 minBounds.add(maxBounds); 781 } 782 return minBounds; 783 } 784 785 789 private Rectangle getCellBounds(JList list, int index) { 790 maybeUpdateLayoutState(); 791 792 int row = convertModelToRow(index); 793 int column = convertModelToColumn(index); 794 795 if (row == -1 || column == -1) { 796 return null; 797 } 798 799 Insets insets = list.getInsets(); 800 int x; 801 int w = cellWidth; 802 int y = insets.top; 803 int h; 804 switch (layoutOrientation) { 805 case JList.VERTICAL_WRAP: 806 case JList.HORIZONTAL_WRAP: 807 if (isLeftToRight) { 808 x = insets.left + column * cellWidth; 809 } else { 810 x = list.getWidth() - insets.right - (column+1) * cellWidth; 811 } 812 y += cellHeight * row; 813 h = cellHeight; 814 break; 815 default: 816 x = insets.left; 817 if (cellHeights == null) { 818 y += (cellHeight * row); 819 } 820 else if (row >= cellHeights.length) { 821 y = 0; 822 } 823 else { 824 for(int i = 0; i < row; i++) { 825 y += cellHeights[i]; 826 } 827 } 828 w = list.getWidth() - (insets.left + insets.right); 829 h = getRowHeight(index); 830 break; 831 } 832 return new Rectangle(x, y, w, h); 833 } 834 835 843 protected int getRowHeight(int row) 844 { 845 return getHeight(0, row); 846 } 847 848 849 858 protected int convertYToRow(int y0) 859 { 860 return convertLocationToRow(0, y0, false); 861 } 862 863 864 872 protected int convertRowToY(int row) 873 { 874 if (row >= getRowCount(0) || row < 0) { 875 return -1; 876 } 877 Rectangle bounds = getCellBounds(list, row, row); 878 return bounds.y; 879 } 880 881 884 private int getHeight(int column, int row) { 885 if (column < 0 || column > columnCount || row < 0) { 886 return -1; 887 } 888 if (layoutOrientation != JList.VERTICAL) { 889 return cellHeight; 890 } 891 if (row >= list.getModel().getSize()) { 892 return -1; 893 } 894 return (cellHeights == null) ? cellHeight : 895 ((row < cellHeights.length) ? cellHeights[row] : -1); 896 } 897 898 904 private int convertLocationToRow(int x, int y0, boolean closest) { 905 int size = list.getModel().getSize(); 906 907 if (size <= 0) { 908 return -1; 909 } 910 Insets insets = list.getInsets(); 911 if (cellHeights == null) { 912 int row = (cellHeight == 0) ? 0 : 913 ((y0 - insets.top) / cellHeight); 914 if (closest) { 915 if (row < 0) { 916 row = 0; 917 } 918 else if (row >= size) { 919 row = size - 1; 920 } 921 } 922 return row; 923 } 924 else if (size > cellHeights.length) { 925 return -1; 926 } 927 else { 928 int y = insets.top; 929 int row = 0; 930 931 if (closest && y0 < y) { 932 return 0; 933 } 934 int i; 935 for (i = 0; i < size; i++) { 936 if ((y0 >= y) && (y0 < y + cellHeights[i])) { 937 return row; 938 } 939 y += cellHeights[i]; 940 row += 1; 941 } 942 return i - 1; 943 } 944 } 945 946 950 private int convertLocationToRowInColumn(int y, int column) { 951 int x = 0; 952 953 if (layoutOrientation != JList.VERTICAL) { 954 if (isLeftToRight) { 955 x = column * cellWidth; 956 } else { 957 x = list.getWidth() - (column+1)*cellWidth - list.getInsets().right; 958 } 959 } 960 return convertLocationToRow(x, y, true); 961 } 962 963 |