Files
ByteEdit/src/org/fife/ui/autocomplete/FastListUI.java
T
2021-03-07 15:22:55 +01:00

158 lines
5.5 KiB
Java

/*
* 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
* AutoComplete.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;
}
}
}