1 19 package org.openide.awt; 20 21 import java.awt.*; 22 import java.awt.event.*; 23 24 import java.beans.PropertyChangeEvent ; 25 import java.beans.PropertyChangeListener ; 26 27 import java.io.Serializable ; 28 29 import java.util.Vector ; 30 31 import javax.swing.*; 32 import javax.swing.event.*; 33 34 35 42 public class ListPane extends JList { 43 44 static final long serialVersionUID = 3828318151121500783L; 45 private int fixedCellWidth = 100; 46 private int fixedCellHeight = 100; 47 private int visibleRowCount = 6; 48 private int visibleColumnCount = 4; 49 private int realRowCount = 1; 50 private int realColumnCount = 1; 51 ListDataListener dataL; 52 PropertyChangeListener propertyL; 53 InputListener inputL; 54 ListSelectionListener selectionL; 55 boolean updateLayoutStateNeeded = true; 56 57 61 public ListPane(ListModel dataModel) { 62 super(dataModel); 63 64 addListListeners(); 65 } 66 67 72 public ListPane(final Object [] listData) { 73 this( 74 new AbstractListModel() { 75 public int getSize() { 76 return listData.length; 77 } 78 79 public Object getElementAt(int i) { 80 return listData[i]; 81 } 82 } 83 ); 84 } 85 86 91 public ListPane(final Vector listData) { 92 this( 93 new AbstractListModel() { 94 public int getSize() { 95 return listData.size(); 96 } 97 98 public Object getElementAt(int i) { 99 return listData.elementAt(i); 100 } 101 } 102 ); 103 } 104 105 108 public ListPane() { 109 this( 110 new AbstractListModel() { 111 public int getSize() { 112 return 0; 113 } 114 115 public Object getElementAt(int i) { 116 return null; 117 } 118 } 119 ); 120 } 121 122 126 public boolean isOpaque() { 127 return true; 128 } 129 130 134 public int getVisibleColumnCount() { 135 return visibleColumnCount; 136 } 137 138 150 public void setVisibleColumnCount(int visibleColumnCount) { 151 int oldValue = this.visibleColumnCount; 152 this.visibleColumnCount = Math.max(0, visibleColumnCount); 153 firePropertyChange("visibleColumnCount", oldValue, visibleColumnCount); } 155 156 164 public void ensureIndexIsVisible(int index) { 165 Point first = indexToLocation(index); 166 167 if (first != null) { 168 Rectangle cellBounds = new Rectangle(first.x, first.y, fixedCellWidth, fixedCellHeight); 169 scrollRectToVisible(cellBounds); 170 } 171 } 172 173 181 public int locationToIndex(Point location) { 182 int x = location.x / fixedCellWidth; 183 184 if (x >= realColumnCount) { 185 return -1; 186 } 187 188 int y = location.y / fixedCellHeight; 189 190 if (y >= realRowCount) { 191 return -1; 192 } 193 194 int ret = (y * realColumnCount) + x; 195 196 return (ret >= getModel().getSize()) ? (-1) : ret; 197 } 198 199 206 public Point indexToLocation(int index) { 207 if (index >= getModel().getSize()) { 208 return null; 209 } 210 211 int y = index / realColumnCount; 212 int x = index % realColumnCount; 213 214 return new Point(x * fixedCellWidth, y * fixedCellHeight); 215 } 216 217 225 public Rectangle getCellBounds(int index1, int index2) { 226 230 Point p1 = indexToLocation(index1); 231 Point p2 = indexToLocation(index2); 232 233 int x1 = p1.x; 234 int y1 = p1.y; 235 int x2 = p2.x + fixedCellWidth; 236 int y2 = p2.y + fixedCellHeight; 237 238 if (p1.y != p2.y) { 239 x1 = 0; 240 x2 = fixedCellWidth * realColumnCount; 241 } 242 243 return new Rectangle(x1, y1, x2 - x1, y2 - y1); 244 } 245 246 249 250 252 271 public Dimension getPreferredScrollableViewportSize() { 272 Insets insets = getInsets(); 273 int w = insets.left + insets.right + (visibleColumnCount * fixedCellWidth); 274 int h = insets.top + insets.bottom + (visibleRowCount * fixedCellHeight); 275 Dimension dim = new Dimension(w, h); 276 277 return dim; 278 } 279 280 292 public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) { 293 if (orientation == SwingConstants.HORIZONTAL) { 294 return 1; 295 } else { 296 int row = getFirstVisibleIndex(); 297 298 if (row == -1) { 299 return 0; 300 } else { 301 302 if (direction > 0) { 303 Rectangle r = getCellBounds(row, row); 304 305 return (r == null) ? 0 : (r.height - (visibleRect.y - r.y)); 306 } 307 308 else { 309 Rectangle r = getCellBounds(row, row); 310 311 314 if ((r.y == visibleRect.y) && (row == 0)) { 315 return 0; 316 } 317 320 else if (r.y == visibleRect.y) { 321 Rectangle prevR = getCellBounds(row - 1, row - 1); 322 323 return (prevR == null) ? 0 : prevR.height; 324 } 325 328 else { 329 return visibleRect.y - r.y; 330 } 331 } 332 } 333 } 334 } 335 336 340 public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) { 341 return (orientation == SwingConstants.VERTICAL) ? visibleRect.height : visibleRect.width; 342 } 343 344 352 public boolean getScrollableTracksViewportWidth() { 353 return true; 354 } 355 356 364 public boolean getScrollableTracksViewportHeight() { 365 return false; 366 } 367 368 374 protected void paintBackground(Graphics g) { 375 if (isOpaque()) { 376 Color backup = g.getColor(); 377 g.setColor(getBackground()); 378 g.fillRect(0, 0, getWidth(), getHeight()); 379 g.setColor(backup); 380 } 381 } 382 383 390 private void paintCell(Graphics g, int index) { 391 Object value = getModel().getElementAt(index); 392 393 boolean cellHasFocus = hasFocus() && (index == getSelectionModel().getLeadSelectionIndex()); 394 boolean isSelected = getSelectionModel().isSelectedIndex(index); 395 396 Component renderer = getCellRenderer().getListCellRendererComponent( 397 this, value, index, isSelected, cellHasFocus 398 ); 399 renderer.setSize(fixedCellWidth, fixedCellHeight); 400 renderer.paint(g); 401 } 402 403 410 protected void paintComponent(Graphics g) { 411 updateLayoutState(); 412 413 if (getCellRenderer() == null) { 414 return; 415 } 416 417 paintBackground(g); 418 419 int last = getModel().getSize(); 420 int dx; 421 int dy; 422 423 for (int i = 0; i < last; i++) { 424 paintCell(g, i); 426 427 if (((i + 1) % realColumnCount) == 0) { 428 dx = -fixedCellWidth * (realColumnCount - 1); 429 dy = fixedCellHeight; 430 } else { 431 dx = fixedCellWidth; 432 dy = 0; 433 } 434 435 g.translate(dx, dy); 436 } 437 } 438 439 443 private void updateLayoutState() { 444 Dimension d = getSize(); 445 int x = d.width / fixedCellWidth; 446 447 if (x < 1) { 448 x = 1; 449 } 450 451 if (x != realColumnCount) { 452 realColumnCount = x; 453 updateLayoutStateNeeded = true; 454 } 455 456 int y = d.height / fixedCellHeight; 457 458 if (y != realRowCount) { 459 realRowCount = y; 460 updateLayoutStateNeeded = true; 461 } 462 463 while ((realRowCount * realColumnCount) < getModel().getSize()) { 464 realRowCount++; 465 } 466 467 locationToIndex(getVisibleRect().getLocation()); 468 469 if (updateLayoutStateNeeded) { 470 updateLayoutStateNeeded = false; 471 revalidate(); 472 } 473 } 474 475 486 public Dimension getPreferredSize() { 487 Insets insets = getInsets(); 488 489 493 int max = getModel().getSize() - 1; 494 495 if (max <= 0) { 496 return new Dimension(fixedCellWidth, fixedCellHeight); 497 } 498 499 int y = (max / realColumnCount) + 1; 500 int x = ((max < realColumnCount) ? (max + 1) : realColumnCount); 501 502 int xParent = getParent().getSize().width; 503 int yParent = getParent().getSize().height; 504 505 int xRes = Math.max(xParent, x * fixedCellWidth); 506 int yRes = Math.max(yParent, y * fixedCellHeight); 507 508 Dimension d = new Dimension(xRes, yRes); 509 510 return d; 511 } 512 513 516 public Dimension getMinimumSize() { 517 return new Dimension(fixedCellWidth, fixedCellHeight); 518 } 519 520 524 private void addListListeners() { 525 inputL = createInputListener(); 526 addMouseListener(inputL); 527 addKeyListener(inputL); 528 addFocusListener(inputL); 529 530 535 propertyL = createPropertyListener(); 536 addPropertyChangeListener(propertyL); 537 538 dataL = createDataListener(); 539 540 ListModel model = getModel(); 541 542 if (model != null) { 543 model.addListDataListener(dataL); 544 } 545 546 if (selectionL == null) { 547 selectionL = new ListSelectionListener() { 548 public void valueChanged(ListSelectionEvent e) { 549 repaint(); 550 } 551 }; 552 553 ListSelectionModel selectionModel = getSelectionModel(); 554 555 if (selectionModel != null) { 556 selectionModel.addListSelectionListener(selectionL); 557 } 558 } 559 } 560 561 private InputListener createInputListener() { 565 return new InputListener(); 566 } 567 568 private ListDataListener createDataListener() { 569 return new DataListener(); 570 } 571 572 private PropertyChangeListener createPropertyListener() { 576 return new PropertyListener(); 577 } 578 579 581 private void mySetSelectionInterval(int anchor, int lead) { 582 super.setSelectionInterval(anchor, lead); 583 } 584 585 587 private void myAddSelectionInterval(int anchor, int lead) { 588 super.addSelectionInterval(anchor, lead); 589 } 590 591 593 private void myRemoveSelectionInterval(int index0, int index1) { 594 super.removeSelectionInterval(index0, index1); 595 } 596 597 public void setSelectionInterval(int anchor, int lead) { 598 } 600 601 public void addSelectionInterval(int anchor, int lead) { 602 } 604 605 public void removeSelectionInterval(int index0, int index1) { 606 } 608 609 613 620 private class InputListener extends MouseAdapter implements FocusListener, KeyListener, Serializable { 621 static final long serialVersionUID = -7907848327510962576L; 622 transient int dragFirstIndex = -1; 623 transient int dragLastIndex = -1; 624 625 InputListener() { 626 } 627 628 public void mousePressed(MouseEvent e) { 630 updateSelection(locationToIndex(e.getPoint()), e); 631 632 if (!hasFocus()) { 633 requestFocus(); 634 } 635 } 636 637 public void focusGained(FocusEvent e) { 639 repaintCellFocus(); 640 } 641 642 public void focusLost(FocusEvent e) { 643 repaintCellFocus(); 644 } 645 646 protected void repaintCellFocus() { 647 repaint(); 648 } 649 650 public void keyTyped(KeyEvent e) { 652 } 653 654 public void keyPressed(KeyEvent e) { 655 int s = getLeadSelectionIndex(); 656 657 if (s < 0) { 658 if (getModel().getSize() > 0) { 659 s = 0; 660 } else { 661 return; 662 } 663 } else { 664 switch (e.getKeyCode()) { 665 case KeyEvent.VK_LEFT: 666 s -= 1; 667 668 break; 669 670 case KeyEvent.VK_RIGHT: 671 s += 1; 672 673 break; 674 675 case KeyEvent.VK_UP: 676 s -= realColumnCount; 677 678 break; 679 680 case KeyEvent.VK_DOWN: 681 s += realColumnCount; 682 683 break; 684 685 case KeyEvent.VK_HOME: 686 s = 0; 687 688 break; 689 690 case KeyEvent.VK_END: 691 s = getModel().getSize() - 1; 692 693 break; 694 695 case KeyEvent.VK_PAGE_UP: 696 s -= (realColumnCount * realRowCount); 697 698 break; 699 700 case KeyEvent.VK_PAGE_DOWN: 701 s += (realColumnCount * realRowCount); 702 703 break; 704 705 default: 706 return; 707 } 708 } 709 710 if (s < 0) { 711 s = 0; 712 } 713 714 if (s > (getModel().getSize() - 1)) { 715 s = getModel().getSize() - 1; 716 } 717 718 if (s >= 0) { 719 updateSelection(s, e); 720 } 721 } 722 723 public void keyReleased(KeyEvent e) { 724 } 725 726 protected void updateSelection(int index, InputEvent e) { 728 ListSelectionModel sm = getSelectionModel(); 729 730 if (index != -1) { 731 setValueIsAdjusting(true); 732 733 if (e.isShiftDown()) { 734 if (e.isControlDown()) { 735 if (dragFirstIndex == -1) { 736 myAddSelectionInterval(index, index); 737 } else { 738 if (dragLastIndex == -1) { 739 myAddSelectionInterval(dragFirstIndex, index); 740 } else { 741 myRemoveSelectionInterval(dragFirstIndex, dragLastIndex); 742 myAddSelectionInterval(dragFirstIndex, index); 743 } 744 } 745 } else { 746 if (dragFirstIndex == -1) { 747 myAddSelectionInterval(index, index); 748 } else { 749 mySetSelectionInterval(dragFirstIndex, index); 750 } 751 } 752 753 if (dragFirstIndex == -1) { 754 dragFirstIndex = index; 755 dragLastIndex = -1; 756 } else { 757 dragLastIndex = index; 758 } 759 } else { 760 if (e.isControlDown()) { 761 if (isSelectedIndex(index)) { 762 myRemoveSelectionInterval(index, index); 763 } else { 764 myAddSelectionInterval(index, index); 765 } 766 } else { 767 mySetSelectionInterval(index, index); 768 } 769 770 dragFirstIndex = index; 771 dragLastIndex = -1; 772 } 773 774 setValueIsAdjusting(false); 775 } else { 776 sm.clearSelection(); 777 } 778 } 779 } 780 781 785 792 private class DataListener implements ListDataListener, Serializable { 793 static final long serialVersionUID = -2252515707418441L; 794 795 DataListener() { 796 } 797 798 public void intervalAdded(ListDataEvent e) { 799 updateLayoutStateNeeded = true; 800 801 int minIndex = Math.min(e.getIndex0(), e.getIndex1()); 802 int maxIndex = Math.max(e.getIndex0(), e.getIndex1()); 803 804 806 ListSelectionModel sm = getSelectionModel(); 807 808 if (sm != null) { 809 sm.insertIndexInterval(minIndex, maxIndex - minIndex, true); 810 } 811 } 812 813 public void intervalRemoved(ListDataEvent e) { 814 updateLayoutStateNeeded = true; 815 816 817 ListSelectionModel sm = getSelectionModel(); 818 819 if (sm != null) { 820 sm.removeIndexInterval(e.getIndex0(), e.getIndex1()); 821 } 822 } 823 824 public void contentsChanged(ListDataEvent e) { 825 updateLayoutStateNeeded = true; 826 } 827 } 828 829 833 841 private class PropertyListener implements PropertyChangeListener , Serializable { 842 static final long serialVersionUID = -6765578311995604737L; 843 844 PropertyListener() { 845 } 846 847 public void propertyChange(PropertyChangeEvent e) { 848 String propertyName = e.getPropertyName(); 849 850 if (propertyName.equals("model")) { 852 ListModel oldModel = (ListModel) e.getOldValue(); 853 ListModel newModel = (ListModel) e.getNewValue(); 854 855 if (oldModel != null) { 856 oldModel.removeListDataListener(dataL); 857 } 858 859 if (newModel != null) { 860 newModel.addListDataListener(dataL); 861 updateLayoutStateNeeded = true; 862 repaint(); 863 } 864 } else if (propertyName.equals("selectionModel")) { 866 ListSelectionModel oldModelS = (ListSelectionModel) e.getOldValue(); 867 ListSelectionModel newModelS = (ListSelectionModel) e.getNewValue(); 868 869 if (oldModelS != null) { 870 oldModelS.removeListSelectionListener(selectionL); 871 } 872 873 if (newModelS != null) { 874 newModelS.addListSelectionListener(selectionL); 875 } 876 877 updateLayoutStateNeeded = true; 878 repaint(); 879 } else if ( 880 propertyName.equals("cellRenderer") || propertyName.equals("font") || propertyName.equals("fixedCellHeight") || propertyName.equals("fixedCellWidth") 884 ) { updateLayoutStateNeeded = true; 886 repaint(); 887 } 888 } 889 } 890 } 891 | Popular Tags |