< prev index next >

src/java.desktop/share/classes/javax/swing/plaf/basic/BasicListUI.java

Print this page




 603      *       of the list, or the maximum cell height, whichever is
 604      *       bigger. The preferred width is than the maximum cell width *
 605      *       number of columns needed. Where the number of columns needs is
 606      *       list.height / max cell height. Max cell height is either the fixed
 607      *       cell height, or is determined by iterating through all the cells
 608      *       to find the maximum height from the ListCellRenderer.
 609      * <tr>
 610      *   <td>JList.HORIZONTAL_WRAP
 611      *   <td>If the visible row count is greater than zero, the preferredHeight
 612      *       is the maximum cell height * adjustedRowCount.  Where
 613      *       visibleRowCount is used to determine the number of columns.
 614      *       Because this lays out horizontally the number of rows is
 615      *       then determined from the column count.  For example, lets say
 616      *       you have a model with 10 items and the visible row count is 8.
 617      *       The number of columns needed to display this is 2, but you no
 618      *       longer need 8 rows to display this, you only need 5, thus
 619      *       the adjustedRowCount is 5.
 620      *       <p>If the visible row
 621      *       count is &lt;= 0, the preferred height is dictated by the
 622      *       number of columns, which will be as many as can fit in the width
 623      *       of the <code>JList</code> (width / max cell width), with at
 624      *       least one column.  The preferred height then becomes the
 625      *       model size / number of columns * maximum cell height.
 626      *       Max cell height is either the fixed
 627      *       cell height, or is determined by iterating through all the cells
 628      *       to find the maximum height from the ListCellRenderer.
 629      * </table>
 630      * The above specifies the raw preferred width and height. The resulting
 631      * preferred width is the above width + insets.left + insets.right and
 632      * the resulting preferred height is the above height + insets.top +
 633      * insets.bottom. Where the <code>Insets</code> are determined from
 634      * <code>list.getInsets()</code>.
 635      *
 636      * @param c The JList component.
 637      * @return The total size of the list.
 638      */
 639     public Dimension getPreferredSize(JComponent c) {
 640         maybeUpdateLayoutState();
 641 
 642         int lastRow = list.getModel().getSize() - 1;
 643         if (lastRow < 0) {
 644             return new Dimension(0, 0);
 645         }
 646 
 647         Insets insets = list.getInsets();
 648         int width = cellWidth * columnCount + insets.left + insets.right;
 649         int height;
 650 
 651         if (layoutOrientation != JList.VERTICAL) {
 652             height = preferredHeight;
 653         }
 654         else {


 680     }
 681 
 682 
 683     /**
 684      * Selected the previous row and force it to be visible.
 685      *
 686      * @see JList#ensureIndexIsVisible
 687      */
 688     protected void selectNextIndex()
 689     {
 690         int s = list.getSelectedIndex();
 691         if((s + 1) < list.getModel().getSize()) {
 692             s += 1;
 693             list.setSelectedIndex(s);
 694             list.ensureIndexIsVisible(s);
 695         }
 696     }
 697 
 698 
 699     /**
 700      * Registers the keyboard bindings on the <code>JList</code> that the
 701      * <code>BasicListUI</code> is associated with. This method is called at
 702      * installUI() time.
 703      *
 704      * @see #installUI
 705      */
 706     protected void installKeyboardActions() {
 707         InputMap inputMap = getInputMap(JComponent.WHEN_FOCUSED);
 708 
 709         SwingUtilities.replaceUIInputMap(list, JComponent.WHEN_FOCUSED,
 710                                            inputMap);
 711 
 712         LazyActionMap.installLazyActionMap(list, BasicListUI.class,
 713                                            "List.actionMap");
 714     }
 715 
 716     InputMap getInputMap(int condition) {
 717         if (condition == JComponent.WHEN_FOCUSED) {
 718             InputMap keyMap = (InputMap)DefaultLookup.get(
 719                              list, this, "List.focusInputMap");
 720             InputMap rtlKeyMap;
 721 
 722             if (isLeftToRight ||
 723                 ((rtlKeyMap = (InputMap)DefaultLookup.get(list, this,
 724                               "List.focusInputMap.RightToLeft")) == null)) {
 725                     return keyMap;
 726             } else {
 727                 rtlKeyMap.setParent(keyMap);
 728                 return rtlKeyMap;
 729             }
 730         }
 731         return null;
 732     }
 733 
 734     /**
 735      * Unregisters keyboard actions installed from
 736      * <code>installKeyboardActions</code>.
 737      * This method is called at uninstallUI() time - subclassess should
 738      * ensure that all of the keyboard actions registered at installUI
 739      * time are removed here.
 740      *
 741      * @see #installUI
 742      */
 743     protected void uninstallKeyboardActions() {
 744         SwingUtilities.replaceUIActionMap(list, null);
 745         SwingUtilities.replaceUIInputMap(list, JComponent.WHEN_FOCUSED, null);
 746     }
 747 
 748 
 749     /**
 750      * Creates and installs the listeners for the JList, its model, and its
 751      * selectionModel.  This method is called at installUI() time.
 752      *
 753      * @see #installUI
 754      * @see #uninstallListeners
 755      */
 756     protected void installListeners()


 903         }
 904         if (list.getBackground() instanceof UIResource) {
 905             list.setBackground(null);
 906         }
 907         if (list.getSelectionBackground() instanceof UIResource) {
 908             list.setSelectionBackground(null);
 909         }
 910         if (list.getSelectionForeground() instanceof UIResource) {
 911             list.setSelectionForeground(null);
 912         }
 913         if (list.getCellRenderer() instanceof UIResource) {
 914             list.setCellRenderer(null);
 915         }
 916         if (list.getTransferHandler() instanceof UIResource) {
 917             list.setTransferHandler(null);
 918         }
 919     }
 920 
 921 
 922     /**
 923      * Initializes <code>this.list</code> by calling <code>installDefaults()</code>,
 924      * <code>installListeners()</code>, and <code>installKeyboardActions()</code>
 925      * in order.
 926      *
 927      * @see #installDefaults
 928      * @see #installListeners
 929      * @see #installKeyboardActions
 930      */
 931     public void installUI(JComponent c)
 932     {
 933         @SuppressWarnings("unchecked")
 934         JList<Object> tmp = (JList)c;
 935         list = tmp;
 936 
 937         layoutOrientation = list.getLayoutOrientation();
 938 
 939         rendererPane = new CellRendererPane();
 940         list.add(rendererPane);
 941 
 942         columnCount = 1;
 943 
 944         updateLayoutStateNeeded = modelChanged;
 945         isLeftToRight = list.getComponentOrientation().isLeftToRight();
 946 
 947         installDefaults();
 948         installListeners();
 949         installKeyboardActions();
 950     }
 951 
 952 
 953     /**
 954      * Uninitializes <code>this.list</code> by calling <code>uninstallListeners()</code>,
 955      * <code>uninstallKeyboardActions()</code>, and <code>uninstallDefaults()</code>
 956      * in order.  Sets this.list to null.
 957      *
 958      * @see #uninstallListeners
 959      * @see #uninstallKeyboardActions
 960      * @see #uninstallDefaults
 961      */
 962     public void uninstallUI(JComponent c)
 963     {
 964         uninstallListeners();
 965         uninstallDefaults();
 966         uninstallKeyboardActions();
 967 
 968         cellWidth = cellHeight = -1;
 969         cellHeights = null;
 970 
 971         listWidth = listHeight = -1;
 972 
 973         list.remove(rendererPane);
 974         rendererPane = null;
 975         list = null;


1040                 int minRow = convertModelToRow(minIndex);
1041                 int maxRow = convertModelToRow(maxIndex);
1042 
1043                 if (minRow != maxRow) {
1044                     minBounds.x = 0;
1045                     minBounds.width = list.getWidth();
1046                 }
1047             }
1048             else if (minBounds.x != maxBounds.x) {
1049                 // Different columns
1050                 minBounds.y = 0;
1051                 minBounds.height = list.getHeight();
1052             }
1053             minBounds.add(maxBounds);
1054         }
1055         return minBounds;
1056     }
1057 
1058     /**
1059      * Gets the bounds of the specified model index, returning the resulting
1060      * bounds, or null if <code>index</code> is not valid.
1061      */
1062     private Rectangle getCellBounds(JList<?> list, int index) {
1063         maybeUpdateLayoutState();
1064 
1065         int row = convertModelToRow(index);
1066         int column = convertModelToColumn(index);
1067 
1068         if (row == -1 || column == -1) {
1069             return null;
1070         }
1071 
1072         Insets insets = list.getInsets();
1073         int x;
1074         int w = cellWidth;
1075         int y = insets.top;
1076         int h;
1077         switch (layoutOrientation) {
1078         case JList.VERTICAL_WRAP:
1079         case JList.HORIZONTAL_WRAP:
1080             if (isLeftToRight) {


1266         }
1267         if (layoutOrientation == JList.VERTICAL_WRAP) {
1268             if (column < (columnCount - 1)) {
1269                 return rowsPerColumn;
1270             }
1271             return list.getModel().getSize() - (columnCount - 1) *
1272                         rowsPerColumn;
1273         }
1274         // JList.HORIZONTAL_WRAP
1275         int diff = columnCount - (columnCount * rowsPerColumn -
1276                                   list.getModel().getSize());
1277 
1278         if (column >= diff) {
1279             return Math.max(0, rowsPerColumn - 1);
1280         }
1281         return rowsPerColumn;
1282     }
1283 
1284     /**
1285      * Returns the model index for the specified display location.
1286      * If <code>column</code>x<code>row</code> is beyond the length of the
1287      * model, this will return the model size - 1.
1288      */
1289     private int getModelIndex(int column, int row) {
1290         switch (layoutOrientation) {
1291         case JList.VERTICAL_WRAP:
1292             return Math.min(list.getModel().getSize() - 1, rowsPerColumn *
1293                             column + Math.min(row, rowsPerColumn-1));
1294         case JList.HORIZONTAL_WRAP:
1295             return Math.min(list.getModel().getSize() - 1, row * columnCount +
1296                             column);
1297         default:
1298             return row;
1299         }
1300     }
1301 
1302     /**
1303      * Returns the closest column to the passed in location.
1304      */
1305     private int convertLocationToColumn(int x, int y) {
1306         if (cellWidth > 0) {


1309             }
1310             Insets insets = list.getInsets();
1311             int col;
1312             if (isLeftToRight) {
1313                 col = (x - insets.left) / cellWidth;
1314             } else {
1315                 col = (list.getWidth() - x - insets.right - 1) / cellWidth;
1316             }
1317             if (col < 0) {
1318                 return 0;
1319             }
1320             else if (col >= columnCount) {
1321                 return columnCount - 1;
1322             }
1323             return col;
1324         }
1325         return 0;
1326     }
1327 
1328     /**
1329      * Returns the row that the model index <code>index</code> will be
1330      * displayed in..
1331      */
1332     private int convertModelToRow(int index) {
1333         int size = list.getModel().getSize();
1334 
1335         if ((index < 0) || (index >= size)) {
1336             return -1;
1337         }
1338 
1339         if (layoutOrientation != JList.VERTICAL && columnCount > 1 &&
1340                                                    rowsPerColumn > 0) {
1341             if (layoutOrientation == JList.VERTICAL_WRAP) {
1342                 return index % rowsPerColumn;
1343             }
1344             return index / columnCount;
1345         }
1346         return index;
1347     }
1348 
1349     /**
1350      * Returns the column that the model index <code>index</code> will be
1351      * displayed in.
1352      */
1353     private int convertModelToColumn(int index) {
1354         int size = list.getModel().getSize();
1355 
1356         if ((index < 0) || (index >= size)) {
1357             return -1;
1358         }
1359 
1360         if (layoutOrientation != JList.VERTICAL && rowsPerColumn > 0 &&
1361                                                    columnCount > 1) {
1362             if (layoutOrientation == JList.VERTICAL_WRAP) {
1363                 return index / rowsPerColumn;
1364             }
1365             return index % columnCount;
1366         }
1367         return 0;
1368     }
1369 
1370     /**


1445                 }
1446                 if (cellHeights == null) {
1447                     cellHeights = new int[dataModelSize];
1448                 }
1449                 for(int index = 0; index < dataModelSize; index++) {
1450                     cellHeights[index] = 0;
1451                 }
1452             }
1453         }
1454 
1455         columnCount = 1;
1456         if (layoutOrientation != JList.VERTICAL) {
1457             updateHorizontalLayoutState(fixedCellWidth, fixedCellHeight);
1458         }
1459     }
1460 
1461     /**
1462      * Invoked when the list is layed out horizontally to determine how
1463      * many columns to create.
1464      * <p>
1465      * This updates the <code>rowsPerColumn, </code><code>columnCount</code>,
1466      * <code>preferredHeight</code> and potentially <code>cellHeight</code>
1467      * instance variables.
1468      */
1469     private void updateHorizontalLayoutState(int fixedCellWidth,
1470                                              int fixedCellHeight) {
1471         int visRows = list.getVisibleRowCount();
1472         int dataModelSize = list.getModel().getSize();
1473         Insets insets = list.getInsets();
1474 
1475         listHeight = list.getHeight();
1476         listWidth = list.getWidth();
1477 
1478         if (dataModelSize == 0) {
1479             rowsPerColumn = columnCount = 0;
1480             preferredHeight = insets.top + insets.bottom;
1481             return;
1482         }
1483 
1484         int height;
1485 
1486         if (fixedCellHeight != -1) {


1542 
1543     private Handler getHandler() {
1544         if (handler == null) {
1545             handler = new Handler();
1546         }
1547         return handler;
1548     }
1549 
1550     /**
1551      * Mouse input, and focus handling for JList.  An instance of this
1552      * class is added to the appropriate java.awt.Component lists
1553      * at installUI() time.  Note keyboard input is handled with JComponent
1554      * KeyboardActions, see installKeyboardActions().
1555      * <p>
1556      * <strong>Warning:</strong>
1557      * Serialized objects of this class will not be compatible with
1558      * future Swing releases. The current serialization support is
1559      * appropriate for short term storage or RMI between applications running
1560      * the same version of Swing.  As of 1.4, support for long term storage
1561      * of all JavaBeans&trade;
1562      * has been added to the <code>java.beans</code> package.
1563      * Please see {@link java.beans.XMLEncoder}.
1564      *
1565      * @see #createMouseInputListener
1566      * @see #installKeyboardActions
1567      * @see #installUI
1568      */
1569     @SuppressWarnings("serial") // Same-version serialization only
1570     public class MouseInputHandler implements MouseInputListener
1571     {
1572         public void mouseClicked(MouseEvent e) {
1573             getHandler().mouseClicked(e);
1574         }
1575 
1576         public void mouseEntered(MouseEvent e) {
1577             getHandler().mouseEntered(e);
1578         }
1579 
1580         public void mouseExited(MouseEvent e) {
1581             getHandler().mouseExited(e);
1582         }


1656     /**
1657      * Returns an instance of {@code FocusListener}.
1658      *
1659      * @return an instance of {@code FocusListener}
1660      */
1661     protected FocusListener createFocusListener() {
1662         return getHandler();
1663     }
1664 
1665     /**
1666      * The ListSelectionListener that's added to the JLists selection
1667      * model at installUI time, and whenever the JList.selectionModel property
1668      * changes.  When the selection changes we repaint the affected rows.
1669      * <p>
1670      * <strong>Warning:</strong>
1671      * Serialized objects of this class will not be compatible with
1672      * future Swing releases. The current serialization support is
1673      * appropriate for short term storage or RMI between applications running
1674      * the same version of Swing.  As of 1.4, support for long term storage
1675      * of all JavaBeans&trade;
1676      * has been added to the <code>java.beans</code> package.
1677      * Please see {@link java.beans.XMLEncoder}.
1678      *
1679      * @see #createListSelectionListener
1680      * @see #getCellBounds
1681      * @see #installUI
1682      */
1683     @SuppressWarnings("serial") // Same-version serialization only
1684     public class ListSelectionHandler implements ListSelectionListener
1685     {
1686         public void valueChanged(ListSelectionEvent e)
1687         {
1688             getHandler().valueChanged(e);
1689         }
1690     }
1691 
1692 
1693     /**
1694      * Creates an instance of {@code ListSelectionHandler} that's added to
1695      * the {@code JLists} by selectionModel as needed.  Subclasses can override
1696      * this method to return a custom {@code ListSelectionListener}, e.g.


1716         return getHandler();
1717     }
1718 
1719 
1720     private void redrawList() {
1721         list.revalidate();
1722         list.repaint();
1723     }
1724 
1725 
1726     /**
1727      * The {@code ListDataListener} that's added to the {@code JLists} model at
1728      * {@code installUI time}, and whenever the JList.model property changes.
1729      * <p>
1730      * <strong>Warning:</strong>
1731      * Serialized objects of this class will not be compatible with
1732      * future Swing releases. The current serialization support is
1733      * appropriate for short term storage or RMI between applications running
1734      * the same version of Swing.  As of 1.4, support for long term storage
1735      * of all JavaBeans&trade;
1736      * has been added to the <code>java.beans</code> package.
1737      * Please see {@link java.beans.XMLEncoder}.
1738      *
1739      * @see JList#getModel
1740      * @see #maybeUpdateLayoutState
1741      * @see #createListDataListener
1742      * @see #installUI
1743      */
1744     @SuppressWarnings("serial") // Same-version serialization only
1745     public class ListDataHandler implements ListDataListener
1746     {
1747         public void intervalAdded(ListDataEvent e) {
1748             getHandler().intervalAdded(e);
1749         }
1750 
1751 
1752         public void intervalRemoved(ListDataEvent e)
1753         {
1754             getHandler().intervalRemoved(e);
1755         }
1756 


1785      * @see #installUI
1786      */
1787     protected ListDataListener createListDataListener() {
1788         return getHandler();
1789     }
1790 
1791 
1792     /**
1793      * The PropertyChangeListener that's added to the JList at
1794      * installUI time.  When the value of a JList property that
1795      * affects layout changes, we set a bit in updateLayoutStateNeeded.
1796      * If the JLists model changes we additionally remove our listeners
1797      * from the old model.  Likewise for the JList selectionModel.
1798      * <p>
1799      * <strong>Warning:</strong>
1800      * Serialized objects of this class will not be compatible with
1801      * future Swing releases. The current serialization support is
1802      * appropriate for short term storage or RMI between applications running
1803      * the same version of Swing.  As of 1.4, support for long term storage
1804      * of all JavaBeans&trade;
1805      * has been added to the <code>java.beans</code> package.
1806      * Please see {@link java.beans.XMLEncoder}.
1807      *
1808      * @see #maybeUpdateLayoutState
1809      * @see #createPropertyChangeListener
1810      * @see #installUI
1811      */
1812     @SuppressWarnings("serial") // Same-version serialization only
1813     public class PropertyChangeHandler implements PropertyChangeListener
1814     {
1815         public void propertyChange(PropertyChangeEvent e)
1816         {
1817             getHandler().propertyChange(e);
1818         }
1819     }
1820 
1821 
1822     /**
1823      * Creates an instance of {@code PropertyChangeHandler} that's added to
1824      * the {@code JList} by {@code installUI()}. Subclasses can override this method
1825      * to return a custom {@code PropertyChangeListener}, e.g.


2430         }
2431     }
2432 
2433 
2434     private class Handler implements FocusListener, KeyListener,
2435                           ListDataListener, ListSelectionListener,
2436                           MouseInputListener, PropertyChangeListener,
2437                           BeforeDrag {
2438         //
2439         // KeyListener
2440         //
2441         private String prefix = "";
2442         private String typedString = "";
2443         private long lastTime = 0L;
2444 
2445         /**
2446          * Invoked when a key has been typed.
2447          *
2448          * Moves the keyboard focus to the first element whose prefix matches the
2449          * sequence of alphanumeric keys pressed by the user with delay less
2450          * than value of <code>timeFactor</code> property (or 1000 milliseconds
2451          * if it is not defined). Subsequent same key presses move the keyboard
2452          * focus to the next object that starts with the same letter until another
2453          * key is pressed, then it is treated as the prefix with appropriate number
2454          * of the same letters followed by first typed another letter.
2455          */
2456         public void keyTyped(KeyEvent e) {
2457             JList<?> src = (JList)e.getSource();
2458             ListModel<?> model = src.getModel();
2459 
2460             if (model.getSize() == 0 || e.isAltDown() ||
2461                     BasicGraphicsUtils.isMenuShortcutKeyDown(e) ||
2462                     isNavigationKey(e)) {
2463                 // Nothing to select
2464                 return;
2465             }
2466             boolean startingFromSelection = true;
2467 
2468             char c = e.getKeyChar();
2469 
2470             long time = e.getWhen();




 603      *       of the list, or the maximum cell height, whichever is
 604      *       bigger. The preferred width is than the maximum cell width *
 605      *       number of columns needed. Where the number of columns needs is
 606      *       list.height / max cell height. Max cell height is either the fixed
 607      *       cell height, or is determined by iterating through all the cells
 608      *       to find the maximum height from the ListCellRenderer.
 609      * <tr>
 610      *   <td>JList.HORIZONTAL_WRAP
 611      *   <td>If the visible row count is greater than zero, the preferredHeight
 612      *       is the maximum cell height * adjustedRowCount.  Where
 613      *       visibleRowCount is used to determine the number of columns.
 614      *       Because this lays out horizontally the number of rows is
 615      *       then determined from the column count.  For example, lets say
 616      *       you have a model with 10 items and the visible row count is 8.
 617      *       The number of columns needed to display this is 2, but you no
 618      *       longer need 8 rows to display this, you only need 5, thus
 619      *       the adjustedRowCount is 5.
 620      *       <p>If the visible row
 621      *       count is &lt;= 0, the preferred height is dictated by the
 622      *       number of columns, which will be as many as can fit in the width
 623      *       of the {@code JList} (width / max cell width), with at
 624      *       least one column.  The preferred height then becomes the
 625      *       model size / number of columns * maximum cell height.
 626      *       Max cell height is either the fixed
 627      *       cell height, or is determined by iterating through all the cells
 628      *       to find the maximum height from the ListCellRenderer.
 629      * </table>
 630      * The above specifies the raw preferred width and height. The resulting
 631      * preferred width is the above width + insets.left + insets.right and
 632      * the resulting preferred height is the above height + insets.top +
 633      * insets.bottom. Where the {@code Insets} are determined from
 634      * {@code list.getInsets()}.
 635      *
 636      * @param c The JList component.
 637      * @return The total size of the list.
 638      */
 639     public Dimension getPreferredSize(JComponent c) {
 640         maybeUpdateLayoutState();
 641 
 642         int lastRow = list.getModel().getSize() - 1;
 643         if (lastRow < 0) {
 644             return new Dimension(0, 0);
 645         }
 646 
 647         Insets insets = list.getInsets();
 648         int width = cellWidth * columnCount + insets.left + insets.right;
 649         int height;
 650 
 651         if (layoutOrientation != JList.VERTICAL) {
 652             height = preferredHeight;
 653         }
 654         else {


 680     }
 681 
 682 
 683     /**
 684      * Selected the previous row and force it to be visible.
 685      *
 686      * @see JList#ensureIndexIsVisible
 687      */
 688     protected void selectNextIndex()
 689     {
 690         int s = list.getSelectedIndex();
 691         if((s + 1) < list.getModel().getSize()) {
 692             s += 1;
 693             list.setSelectedIndex(s);
 694             list.ensureIndexIsVisible(s);
 695         }
 696     }
 697 
 698 
 699     /**
 700      * Registers the keyboard bindings on the {@code JList} that the
 701      * {@code BasicListUI} is associated with. This method is called at
 702      * installUI() time.
 703      *
 704      * @see #installUI
 705      */
 706     protected void installKeyboardActions() {
 707         InputMap inputMap = getInputMap(JComponent.WHEN_FOCUSED);
 708 
 709         SwingUtilities.replaceUIInputMap(list, JComponent.WHEN_FOCUSED,
 710                                            inputMap);
 711 
 712         LazyActionMap.installLazyActionMap(list, BasicListUI.class,
 713                                            "List.actionMap");
 714     }
 715 
 716     InputMap getInputMap(int condition) {
 717         if (condition == JComponent.WHEN_FOCUSED) {
 718             InputMap keyMap = (InputMap)DefaultLookup.get(
 719                              list, this, "List.focusInputMap");
 720             InputMap rtlKeyMap;
 721 
 722             if (isLeftToRight ||
 723                 ((rtlKeyMap = (InputMap)DefaultLookup.get(list, this,
 724                               "List.focusInputMap.RightToLeft")) == null)) {
 725                     return keyMap;
 726             } else {
 727                 rtlKeyMap.setParent(keyMap);
 728                 return rtlKeyMap;
 729             }
 730         }
 731         return null;
 732     }
 733 
 734     /**
 735      * Unregisters keyboard actions installed from
 736      * {@code installKeyboardActions}.
 737      * This method is called at uninstallUI() time - subclassess should
 738      * ensure that all of the keyboard actions registered at installUI
 739      * time are removed here.
 740      *
 741      * @see #installUI
 742      */
 743     protected void uninstallKeyboardActions() {
 744         SwingUtilities.replaceUIActionMap(list, null);
 745         SwingUtilities.replaceUIInputMap(list, JComponent.WHEN_FOCUSED, null);
 746     }
 747 
 748 
 749     /**
 750      * Creates and installs the listeners for the JList, its model, and its
 751      * selectionModel.  This method is called at installUI() time.
 752      *
 753      * @see #installUI
 754      * @see #uninstallListeners
 755      */
 756     protected void installListeners()


 903         }
 904         if (list.getBackground() instanceof UIResource) {
 905             list.setBackground(null);
 906         }
 907         if (list.getSelectionBackground() instanceof UIResource) {
 908             list.setSelectionBackground(null);
 909         }
 910         if (list.getSelectionForeground() instanceof UIResource) {
 911             list.setSelectionForeground(null);
 912         }
 913         if (list.getCellRenderer() instanceof UIResource) {
 914             list.setCellRenderer(null);
 915         }
 916         if (list.getTransferHandler() instanceof UIResource) {
 917             list.setTransferHandler(null);
 918         }
 919     }
 920 
 921 
 922     /**
 923      * Initializes {@code this.list} by calling {@code installDefaults()},
 924      * {@code installListeners()}, and {@code installKeyboardActions()}
 925      * in order.
 926      *
 927      * @see #installDefaults
 928      * @see #installListeners
 929      * @see #installKeyboardActions
 930      */
 931     public void installUI(JComponent c)
 932     {
 933         @SuppressWarnings("unchecked")
 934         JList<Object> tmp = (JList)c;
 935         list = tmp;
 936 
 937         layoutOrientation = list.getLayoutOrientation();
 938 
 939         rendererPane = new CellRendererPane();
 940         list.add(rendererPane);
 941 
 942         columnCount = 1;
 943 
 944         updateLayoutStateNeeded = modelChanged;
 945         isLeftToRight = list.getComponentOrientation().isLeftToRight();
 946 
 947         installDefaults();
 948         installListeners();
 949         installKeyboardActions();
 950     }
 951 
 952 
 953     /**
 954      * Uninitializes {@code this.list} by calling {@code uninstallListeners()},
 955      * {@code uninstallKeyboardActions()}, and {@code uninstallDefaults()}
 956      * in order.  Sets this.list to null.
 957      *
 958      * @see #uninstallListeners
 959      * @see #uninstallKeyboardActions
 960      * @see #uninstallDefaults
 961      */
 962     public void uninstallUI(JComponent c)
 963     {
 964         uninstallListeners();
 965         uninstallDefaults();
 966         uninstallKeyboardActions();
 967 
 968         cellWidth = cellHeight = -1;
 969         cellHeights = null;
 970 
 971         listWidth = listHeight = -1;
 972 
 973         list.remove(rendererPane);
 974         rendererPane = null;
 975         list = null;


1040                 int minRow = convertModelToRow(minIndex);
1041                 int maxRow = convertModelToRow(maxIndex);
1042 
1043                 if (minRow != maxRow) {
1044                     minBounds.x = 0;
1045                     minBounds.width = list.getWidth();
1046                 }
1047             }
1048             else if (minBounds.x != maxBounds.x) {
1049                 // Different columns
1050                 minBounds.y = 0;
1051                 minBounds.height = list.getHeight();
1052             }
1053             minBounds.add(maxBounds);
1054         }
1055         return minBounds;
1056     }
1057 
1058     /**
1059      * Gets the bounds of the specified model index, returning the resulting
1060      * bounds, or null if {@code index} is not valid.
1061      */
1062     private Rectangle getCellBounds(JList<?> list, int index) {
1063         maybeUpdateLayoutState();
1064 
1065         int row = convertModelToRow(index);
1066         int column = convertModelToColumn(index);
1067 
1068         if (row == -1 || column == -1) {
1069             return null;
1070         }
1071 
1072         Insets insets = list.getInsets();
1073         int x;
1074         int w = cellWidth;
1075         int y = insets.top;
1076         int h;
1077         switch (layoutOrientation) {
1078         case JList.VERTICAL_WRAP:
1079         case JList.HORIZONTAL_WRAP:
1080             if (isLeftToRight) {


1266         }
1267         if (layoutOrientation == JList.VERTICAL_WRAP) {
1268             if (column < (columnCount - 1)) {
1269                 return rowsPerColumn;
1270             }
1271             return list.getModel().getSize() - (columnCount - 1) *
1272                         rowsPerColumn;
1273         }
1274         // JList.HORIZONTAL_WRAP
1275         int diff = columnCount - (columnCount * rowsPerColumn -
1276                                   list.getModel().getSize());
1277 
1278         if (column >= diff) {
1279             return Math.max(0, rowsPerColumn - 1);
1280         }
1281         return rowsPerColumn;
1282     }
1283 
1284     /**
1285      * Returns the model index for the specified display location.
1286      * If {@code column}x{@code row} is beyond the length of the
1287      * model, this will return the model size - 1.
1288      */
1289     private int getModelIndex(int column, int row) {
1290         switch (layoutOrientation) {
1291         case JList.VERTICAL_WRAP:
1292             return Math.min(list.getModel().getSize() - 1, rowsPerColumn *
1293                             column + Math.min(row, rowsPerColumn-1));
1294         case JList.HORIZONTAL_WRAP:
1295             return Math.min(list.getModel().getSize() - 1, row * columnCount +
1296                             column);
1297         default:
1298             return row;
1299         }
1300     }
1301 
1302     /**
1303      * Returns the closest column to the passed in location.
1304      */
1305     private int convertLocationToColumn(int x, int y) {
1306         if (cellWidth > 0) {


1309             }
1310             Insets insets = list.getInsets();
1311             int col;
1312             if (isLeftToRight) {
1313                 col = (x - insets.left) / cellWidth;
1314             } else {
1315                 col = (list.getWidth() - x - insets.right - 1) / cellWidth;
1316             }
1317             if (col < 0) {
1318                 return 0;
1319             }
1320             else if (col >= columnCount) {
1321                 return columnCount - 1;
1322             }
1323             return col;
1324         }
1325         return 0;
1326     }
1327 
1328     /**
1329      * Returns the row that the model index {@code index} will be
1330      * displayed in..
1331      */
1332     private int convertModelToRow(int index) {
1333         int size = list.getModel().getSize();
1334 
1335         if ((index < 0) || (index >= size)) {
1336             return -1;
1337         }
1338 
1339         if (layoutOrientation != JList.VERTICAL && columnCount > 1 &&
1340                                                    rowsPerColumn > 0) {
1341             if (layoutOrientation == JList.VERTICAL_WRAP) {
1342                 return index % rowsPerColumn;
1343             }
1344             return index / columnCount;
1345         }
1346         return index;
1347     }
1348 
1349     /**
1350      * Returns the column that the model index {@code index} will be
1351      * displayed in.
1352      */
1353     private int convertModelToColumn(int index) {
1354         int size = list.getModel().getSize();
1355 
1356         if ((index < 0) || (index >= size)) {
1357             return -1;
1358         }
1359 
1360         if (layoutOrientation != JList.VERTICAL && rowsPerColumn > 0 &&
1361                                                    columnCount > 1) {
1362             if (layoutOrientation == JList.VERTICAL_WRAP) {
1363                 return index / rowsPerColumn;
1364             }
1365             return index % columnCount;
1366         }
1367         return 0;
1368     }
1369 
1370     /**


1445                 }
1446                 if (cellHeights == null) {
1447                     cellHeights = new int[dataModelSize];
1448                 }
1449                 for(int index = 0; index < dataModelSize; index++) {
1450                     cellHeights[index] = 0;
1451                 }
1452             }
1453         }
1454 
1455         columnCount = 1;
1456         if (layoutOrientation != JList.VERTICAL) {
1457             updateHorizontalLayoutState(fixedCellWidth, fixedCellHeight);
1458         }
1459     }
1460 
1461     /**
1462      * Invoked when the list is layed out horizontally to determine how
1463      * many columns to create.
1464      * <p>
1465      * This updates the {@code rowsPerColumn,}{@code columnCount},
1466      * {@code preferredHeight} and potentially {@code cellHeight}
1467      * instance variables.
1468      */
1469     private void updateHorizontalLayoutState(int fixedCellWidth,
1470                                              int fixedCellHeight) {
1471         int visRows = list.getVisibleRowCount();
1472         int dataModelSize = list.getModel().getSize();
1473         Insets insets = list.getInsets();
1474 
1475         listHeight = list.getHeight();
1476         listWidth = list.getWidth();
1477 
1478         if (dataModelSize == 0) {
1479             rowsPerColumn = columnCount = 0;
1480             preferredHeight = insets.top + insets.bottom;
1481             return;
1482         }
1483 
1484         int height;
1485 
1486         if (fixedCellHeight != -1) {


1542 
1543     private Handler getHandler() {
1544         if (handler == null) {
1545             handler = new Handler();
1546         }
1547         return handler;
1548     }
1549 
1550     /**
1551      * Mouse input, and focus handling for JList.  An instance of this
1552      * class is added to the appropriate java.awt.Component lists
1553      * at installUI() time.  Note keyboard input is handled with JComponent
1554      * KeyboardActions, see installKeyboardActions().
1555      * <p>
1556      * <strong>Warning:</strong>
1557      * Serialized objects of this class will not be compatible with
1558      * future Swing releases. The current serialization support is
1559      * appropriate for short term storage or RMI between applications running
1560      * the same version of Swing.  As of 1.4, support for long term storage
1561      * of all JavaBeans&trade;
1562      * has been added to the {@code java.beans} package.
1563      * Please see {@link java.beans.XMLEncoder}.
1564      *
1565      * @see #createMouseInputListener
1566      * @see #installKeyboardActions
1567      * @see #installUI
1568      */
1569     @SuppressWarnings("serial") // Same-version serialization only
1570     public class MouseInputHandler implements MouseInputListener
1571     {
1572         public void mouseClicked(MouseEvent e) {
1573             getHandler().mouseClicked(e);
1574         }
1575 
1576         public void mouseEntered(MouseEvent e) {
1577             getHandler().mouseEntered(e);
1578         }
1579 
1580         public void mouseExited(MouseEvent e) {
1581             getHandler().mouseExited(e);
1582         }


1656     /**
1657      * Returns an instance of {@code FocusListener}.
1658      *
1659      * @return an instance of {@code FocusListener}
1660      */
1661     protected FocusListener createFocusListener() {
1662         return getHandler();
1663     }
1664 
1665     /**
1666      * The ListSelectionListener that's added to the JLists selection
1667      * model at installUI time, and whenever the JList.selectionModel property
1668      * changes.  When the selection changes we repaint the affected rows.
1669      * <p>
1670      * <strong>Warning:</strong>
1671      * Serialized objects of this class will not be compatible with
1672      * future Swing releases. The current serialization support is
1673      * appropriate for short term storage or RMI between applications running
1674      * the same version of Swing.  As of 1.4, support for long term storage
1675      * of all JavaBeans&trade;
1676      * has been added to the {@code java.beans} package.
1677      * Please see {@link java.beans.XMLEncoder}.
1678      *
1679      * @see #createListSelectionListener
1680      * @see #getCellBounds
1681      * @see #installUI
1682      */
1683     @SuppressWarnings("serial") // Same-version serialization only
1684     public class ListSelectionHandler implements ListSelectionListener
1685     {
1686         public void valueChanged(ListSelectionEvent e)
1687         {
1688             getHandler().valueChanged(e);
1689         }
1690     }
1691 
1692 
1693     /**
1694      * Creates an instance of {@code ListSelectionHandler} that's added to
1695      * the {@code JLists} by selectionModel as needed.  Subclasses can override
1696      * this method to return a custom {@code ListSelectionListener}, e.g.


1716         return getHandler();
1717     }
1718 
1719 
1720     private void redrawList() {
1721         list.revalidate();
1722         list.repaint();
1723     }
1724 
1725 
1726     /**
1727      * The {@code ListDataListener} that's added to the {@code JLists} model at
1728      * {@code installUI time}, and whenever the JList.model property changes.
1729      * <p>
1730      * <strong>Warning:</strong>
1731      * Serialized objects of this class will not be compatible with
1732      * future Swing releases. The current serialization support is
1733      * appropriate for short term storage or RMI between applications running
1734      * the same version of Swing.  As of 1.4, support for long term storage
1735      * of all JavaBeans&trade;
1736      * has been added to the {@code java.beans} package.
1737      * Please see {@link java.beans.XMLEncoder}.
1738      *
1739      * @see JList#getModel
1740      * @see #maybeUpdateLayoutState
1741      * @see #createListDataListener
1742      * @see #installUI
1743      */
1744     @SuppressWarnings("serial") // Same-version serialization only
1745     public class ListDataHandler implements ListDataListener
1746     {
1747         public void intervalAdded(ListDataEvent e) {
1748             getHandler().intervalAdded(e);
1749         }
1750 
1751 
1752         public void intervalRemoved(ListDataEvent e)
1753         {
1754             getHandler().intervalRemoved(e);
1755         }
1756 


1785      * @see #installUI
1786      */
1787     protected ListDataListener createListDataListener() {
1788         return getHandler();
1789     }
1790 
1791 
1792     /**
1793      * The PropertyChangeListener that's added to the JList at
1794      * installUI time.  When the value of a JList property that
1795      * affects layout changes, we set a bit in updateLayoutStateNeeded.
1796      * If the JLists model changes we additionally remove our listeners
1797      * from the old model.  Likewise for the JList selectionModel.
1798      * <p>
1799      * <strong>Warning:</strong>
1800      * Serialized objects of this class will not be compatible with
1801      * future Swing releases. The current serialization support is
1802      * appropriate for short term storage or RMI between applications running
1803      * the same version of Swing.  As of 1.4, support for long term storage
1804      * of all JavaBeans&trade;
1805      * has been added to the {@code java.beans} package.
1806      * Please see {@link java.beans.XMLEncoder}.
1807      *
1808      * @see #maybeUpdateLayoutState
1809      * @see #createPropertyChangeListener
1810      * @see #installUI
1811      */
1812     @SuppressWarnings("serial") // Same-version serialization only
1813     public class PropertyChangeHandler implements PropertyChangeListener
1814     {
1815         public void propertyChange(PropertyChangeEvent e)
1816         {
1817             getHandler().propertyChange(e);
1818         }
1819     }
1820 
1821 
1822     /**
1823      * Creates an instance of {@code PropertyChangeHandler} that's added to
1824      * the {@code JList} by {@code installUI()}. Subclasses can override this method
1825      * to return a custom {@code PropertyChangeListener}, e.g.


2430         }
2431     }
2432 
2433 
2434     private class Handler implements FocusListener, KeyListener,
2435                           ListDataListener, ListSelectionListener,
2436                           MouseInputListener, PropertyChangeListener,
2437                           BeforeDrag {
2438         //
2439         // KeyListener
2440         //
2441         private String prefix = "";
2442         private String typedString = "";
2443         private long lastTime = 0L;
2444 
2445         /**
2446          * Invoked when a key has been typed.
2447          *
2448          * Moves the keyboard focus to the first element whose prefix matches the
2449          * sequence of alphanumeric keys pressed by the user with delay less
2450          * than value of {@code timeFactor} property (or 1000 milliseconds
2451          * if it is not defined). Subsequent same key presses move the keyboard
2452          * focus to the next object that starts with the same letter until another
2453          * key is pressed, then it is treated as the prefix with appropriate number
2454          * of the same letters followed by first typed another letter.
2455          */
2456         public void keyTyped(KeyEvent e) {
2457             JList<?> src = (JList)e.getSource();
2458             ListModel<?> model = src.getModel();
2459 
2460             if (model.getSize() == 0 || e.isAltDown() ||
2461                     BasicGraphicsUtils.isMenuShortcutKeyDown(e) ||
2462                     isNavigationKey(e)) {
2463                 // Nothing to select
2464                 return;
2465             }
2466             boolean startingFromSelection = true;
2467 
2468             char c = e.getKeyChar();
2469 
2470             long time = e.getWhen();


< prev index next >