/* * 04/26/2010 * * FastListUI.java - A JList UI implementation that computes the preferred size * of all cells really fast, to facilitate lists of possibly thousands of items * rendered with HTML, which is slow with BasicListUI extensions. * * This library is distributed under a modified BSD license. See the included * RSyntaxTextArea.License.txt file for details. */ package org.fife.ui.autocomplete; import java.awt.Color; import java.awt.Dimension; import java.awt.SystemColor; import javax.swing.JViewport; import javax.swing.ListCellRenderer; import javax.swing.ListModel; import javax.swing.UIManager; import javax.swing.plaf.basic.BasicListUI; /** * A custom list UI, used by the completion choices list. If the number of * completion choices is "large," it does a fast estimate of the preferred * width and height of list items. This allows HTML renderers to be used (such * as {@link CompletionCellRenderer}), with thousands of completion choices, * with no performance penalty. With standard BasicListUI subclasses, this can * cause very poor performance <b>each time</b> the list is displayed, which * is bad for lists that are repeatedly hidden and re-displayed, such as * completion choices. This is all because the calculation to get the * preferred size of each list item, when it is displayed with HTML, is slow. * * @author Robert Futrell * @version 1.0 */ class FastListUI extends BasicListUI { /** * Whether the selection background was overridden (usually because of * Nimbus) so we know to manually uninstall the color we installed. */ private boolean overriddenBackground; /** * Whether the selection foreground was overridden (usually because of * Nimbus) so we know to manually uninstall the color we installed. */ private boolean overriddenForeground; /** * If there are more than this many completions in a single list, this * UI will estimate the cell width and height needed for each item instead * of computing it, for performance reasons. */ private static final int ESTIMATION_THRESHOLD = 200; private Color determineSelectionBackground() { Color c = UIManager.getColor("List.selectionBackground"); if (c==null) { c = UIManager.getColor("nimbusSelectionBackground"); if (c==null) { // Not Nimbus, but still need a value - fallback c = UIManager.getColor("textHighlight"); if (c==null) { c = SystemColor.textHighlight; } } } // Nimbus unfortunately requires a Color, not a ColorUIResource, for // the background override to work. This causes this color to "stick" // even if the LAF is changed to something else later. "c" here may // actually be a ColorUIResource return new Color(c.getRGB());//new ColorUIResource(c); } private Color determineSelectionForeground() { Color c = UIManager.getColor("List.selectionForeground"); if (c==null) { c = UIManager.getColor("nimbusSelectedText"); if (c==null) { // Not Nimbus, but still need a value - fallback c = UIManager.getColor("textHighlightText"); if (c==null) { c = SystemColor.textHighlightText; } } } // Nimbus unfortunately requires Color, not ColorUIResource, and "c" // may actually be a ColorUIResource return new Color(c.getRGB()); } /** * Overridden to ensure we have selection background/foreground colors * defined, even if we're in some weirdo LAF such as Nimbus which doesn't * define them. Since FastListUI extends BasicListUI, we need these values * to be defined. */ @Override protected void installDefaults() { super.installDefaults(); if (list.getSelectionBackground()==null) { list.setSelectionBackground(determineSelectionBackground()); overriddenBackground = true; } if (list.getSelectionForeground()==null) { list.setSelectionForeground(determineSelectionForeground()); overriddenForeground = true; } } /** * Overridden to work around a Nimbus issue. */ @Override protected void uninstallDefaults() { super.uninstallDefaults(); if (overriddenBackground) { list.setSelectionBackground(null); } if (overriddenForeground) { list.setSelectionForeground(null); } } /** * Recalculates the cell width and height of each cell in the list. This * method is overridden to do a fast estimation if the completion list is * too long, to improve performance for lists with huge amounts of * completions. */ @Override protected void updateLayoutState() { ListModel model = list.getModel(); int itemCount = model.getSize(); // If the item count is small enough to run fast on practically all // machines, go ahead and use the super implementation to determine // the optimal cell sizes. if (itemCount<ESTIMATION_THRESHOLD) { super.updateLayoutState(); return; } // Otherwise, assume all cells are the same height as the first cell, // and estimate the necessary width. ListCellRenderer renderer = list.getCellRenderer(); cellWidth = list.getWidth(); if (list.getParent() instanceof JViewport) { // Always true for us cellWidth = list.getParent().getWidth(); } //System.out.println(cellWidth); // We're getting a fixed cell height for all cells cellHeights = null; if (renderer!=null && itemCount>0) { Object value = model.getElementAt(0); java.awt.Component c = renderer.getListCellRendererComponent(list, value, 0, false, false); rendererPane.add(c); Dimension cellSize = c.getPreferredSize(); cellHeight = cellSize.height; cellWidth = Math.max(cellWidth, cellSize.width); } else { cellHeight = 20; } } }