BasicComboBoxUI.java [plain text]
package javax.swing.plaf.basic;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.Rectangle;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.EventListener;
import javax.accessibility.Accessible;
import javax.swing.CellRendererPane;
import javax.swing.ComboBoxEditor;
import javax.swing.ComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.ListCellRenderer;
import javax.swing.SwingConstants;
import javax.swing.UIDefaults;
import javax.swing.UIManager;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import javax.swing.plaf.ComboBoxUI;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicComboPopup;
import javax.swing.plaf.basic.BasicGraphicsUtils;
public class BasicComboBoxUI extends ComboBoxUI
{
protected JButton arrowButton;
protected JComboBox comboBox;
protected Component editor;
protected FocusListener focusListener;
protected boolean hasFocus;
protected ItemListener itemListener;
protected KeyListener keyListener;
private MouseListener mouseListener;
protected JList listBox;
protected ListDataListener listDataListener;
protected ComboPopup popup;
protected KeyListener popupKeyListener;
protected MouseListener popupMouseListener;
protected MouseMotionListener popupMouseMotionListener;
protected PropertyChangeListener propertyChangeListener;
private Color shadow;
private Color darkShadow;
private Color highlight;
private Color lightHighlight;
private Dimension largestItemSize;
private static final Insets borderInsets = new Insets(2, 2, 2, 2);
private static int arrowButtonWidth = 15;
protected Dimension cachedMinimumSize;
protected CellRendererPane currentValuePane;
protected boolean isMinimumSizeDirty;
public BasicComboBoxUI()
{
}
public static ComponentUI createUI(JComponent c)
{
return new BasicComboBoxUI();
}
public void installUI(JComponent c)
{
super.installUI(c);
if (c instanceof JComboBox)
{
comboBox = (JComboBox) c;
comboBox.setOpaque(true);
comboBox.setLayout(createLayoutManager());
installDefaults();
installComponents();
installListeners();
installKeyboardActions();
}
}
public void uninstallUI(JComponent c)
{
uninstallKeyboardActions();
uninstallListeners();
uninstallComponents();
uninstallDefaults();
comboBox = null;
}
protected void installDefaults()
{
UIDefaults defaults = UIManager.getLookAndFeelDefaults();
comboBox.setBackground(defaults.getColor("ComboBox.background"));
comboBox.setFont(defaults.getFont("ComboBox.font"));
comboBox.setForeground(defaults.getColor("ComboBox.foreground"));
shadow = defaults.getColor("Button.shadow");
darkShadow = defaults.getColor("Button.darkShadow");
lightHighlight = defaults.getColor("Button.light");
highlight = defaults.getColor("Button.highlight");
}
protected void installListeners()
{
propertyChangeListener = createPropertyChangeListener();
comboBox.addPropertyChangeListener(propertyChangeListener);
focusListener = createFocusListener();
comboBox.addFocusListener(focusListener);
itemListener = createItemListener();
comboBox.addItemListener(itemListener);
keyListener = createKeyListener();
comboBox.addKeyListener(keyListener);
mouseListener = createMouseListener();
comboBox.addMouseListener(mouseListener);
listDataListener = createListDataListener();
comboBox.getModel().addListDataListener(listDataListener);
configureArrowButton();
}
protected void uninstallDefaults()
{
UIDefaults defaults = UIManager.getLookAndFeelDefaults();
comboBox.setBackground(null);
comboBox.setFont(null);
comboBox.setForeground(null);
shadow = null;
darkShadow = null;
lightHighlight = null;
highlight = null;
}
protected void uninstallListeners()
{
comboBox.removePropertyChangeListener(propertyChangeListener);
propertyChangeListener = null;
comboBox.removeFocusListener(focusListener);
focusListener = null;
comboBox.removeItemListener(itemListener);
itemListener = null;
comboBox.removeKeyListener(keyListener);
keyListener = null;
comboBox.removeMouseListener(mouseListener);
mouseListener = null;
comboBox.getModel().removeListDataListener(listDataListener);
listDataListener = null;
unconfigureArrowButton();
}
protected ComboPopup createPopup()
{
return new BasicComboPopup(comboBox);
}
protected KeyListener createKeyListener()
{
return new KeyHandler();
}
private MouseListener createMouseListener()
{
return new MouseHandler();
}
protected FocusListener createFocusListener()
{
return new FocusHandler();
}
protected ListDataListener createListDataListener()
{
return new ListDataHandler();
}
protected ItemListener createItemListener()
{
return new ItemHandler();
}
protected PropertyChangeListener createPropertyChangeListener()
{
return new PropertyChangeHandler();
}
protected LayoutManager createLayoutManager()
{
return new ComboBoxLayoutManager();
}
protected ListCellRenderer createRenderer()
{
return new BasicComboBoxRenderer();
}
protected ComboBoxEditor createEditor()
{
return new BasicComboBoxEditor();
}
protected void installComponents()
{
arrowButton = createArrowButton();
comboBox.add(arrowButton);
listBox = new JList();
Color background = arrowButton.getBackground();
listBox.setBackground(background);
listBox.setSelectionBackground(background.darker());
Color foreground = arrowButton.getForeground();
listBox.setForeground(foreground);
listBox.setSelectionForeground(foreground);
comboBox.setRenderer(createRenderer());
comboBox.setEditor(createEditor());
editor = comboBox.getEditor().getEditorComponent();
popup = createPopup();
comboBox.revalidate();
}
protected void uninstallComponents()
{
unconfigureArrowButton();
comboBox.remove(arrowButton);
arrowButton = null;
listBox = null;
popup = null;
comboBox.setRenderer(null);
comboBox.setEditor(null);
editor = null;
}
public void addEditor()
{
comboBox.add(editor);
}
public void removeEditor()
{
comboBox.remove(editor);
}
protected void configureEditor()
{
}
protected void unconfigureEditor()
{
}
public void configureArrowButton()
{
arrowButton.addMouseListener(mouseListener);
}
public void unconfigureArrowButton()
{
arrowButton.removeMouseListener(mouseListener);
}
protected JButton createArrowButton()
{
return new BasicArrowButton(BasicArrowButton.SOUTH);
}
public boolean isPopupVisible(JComboBox c)
{
return popup.isVisible();
}
public void setPopupVisible(JComboBox c, boolean v)
{
if (v)
popup.show();
else
popup.hide();
}
public boolean isFocusTraversable(JComboBox c)
{
if (comboBox.isEditable())
return true;
return false;
}
public void paint(Graphics g, JComponent c)
{
if (c instanceof JComboBox)
{
JComboBox cb = (JComboBox) c;
paintBorder(g, comboBox.getBounds(), hasFocus);
Rectangle rect = rectangleForCurrentValue();
paintCurrentValueBackground(g, rect, hasFocus);
paintCurrentValue(g, rect, hasFocus);
}
}
private void paintBorder(Graphics g, Rectangle bounds, boolean hasFocus)
{
int x = 0;
int y = 0;
int width = bounds.width;
int height = bounds.height;
Color oldColor = g.getColor();
if (! arrowButton.getModel().isPressed())
BasicGraphicsUtils.drawEtchedRect(g, x, y, width, height, Color.gray,
Color.white, Color.gray, Color.white);
else
{
g.setColor(darkShadow);
g.drawRect(x, y, width, height);
g.setColor(shadow);
g.drawRect(x + 1, y + 1, width - 3, height - 3);
}
g.setColor(oldColor);
}
public Dimension getPreferredSize(JComponent c)
{
return null;
}
public Dimension getMinimumSize(JComponent c)
{
return null;
}
public Dimension getMaximumSize(JComponent c)
{
return null;
}
public int getAccessibleChildrenCount(JComponent c)
{
return 0;
}
public Accessible getAccessibleChild(JComponent c, int i)
{
return null;
}
protected boolean isNavigationKey(int keyCode)
{
return false;
}
protected void selectNextPossibleValue()
{
int index = comboBox.getSelectedIndex();
if (index != comboBox.getItemCount() - 1)
comboBox.setSelectedIndex(index + 1);
}
protected void selectPreviousPossibleValue()
{
int index = comboBox.getSelectedIndex();
if (index != 0)
comboBox.setSelectedIndex(index - 1);
}
protected void toggleOpenClose()
{
setPopupVisible(comboBox, ! isPopupVisible(comboBox));
}
protected Rectangle rectangleForCurrentValue()
{
Rectangle cbBounds = comboBox.getBounds();
Rectangle rectForCurrentValue = new Rectangle(cbBounds.x
+ borderInsets.left,
cbBounds.y
+ borderInsets.top,
cbBounds.width
- arrowButtonWidth
- borderInsets.left
- borderInsets.right,
cbBounds.height
- borderInsets.top
- borderInsets.bottom);
return rectForCurrentValue;
}
protected Insets getInsets()
{
return new Insets(0, 0, 0, 0);
}
public void paintCurrentValue(Graphics g, Rectangle bounds, boolean hasFocus)
{
if (! comboBox.isEditable())
{
Object currentValue = comboBox.getSelectedItem();
boolean isPressed = arrowButton.getModel().isPressed();
if (currentValue != null)
{
Component comp = comboBox.getRenderer()
.getListCellRendererComponent(listBox,
currentValue,
-1,
isPressed,
isPressed);
if (! comboBox.isEnabled())
comp.setEnabled(false);
g.translate(borderInsets.left, borderInsets.top);
comp.setBounds(0, 0, bounds.width, bounds.height);
comp.paint(g);
g.translate(-borderInsets.left, -borderInsets.top);
}
comboBox.revalidate();
}
else
comboBox.getEditor().setItem(comboBox.getSelectedItem());
}
public void paintCurrentValueBackground(Graphics g, Rectangle bounds,
boolean hasFocus)
{
}
protected Dimension getDefaultSize()
{
return new Dimension(6, 17);
}
protected Dimension getLargestItemSize()
{
ComboBoxModel model = comboBox.getModel();
int numItems = model.getSize();
if (numItems == 0)
{
largestItemSize = getDefaultSize();
return largestItemSize;
}
Dimension size = new Dimension(0, 0);
ListCellRenderer renderer = comboBox.getRenderer();
for (int i = 0; i < numItems; i++)
{
Object item = model.getElementAt(i);
String s = item.toString();
Component comp = renderer.getListCellRendererComponent(listBox, item,
-1, false, false);
if (comp.getPreferredSize().getWidth() > size.getWidth())
size = comp.getPreferredSize();
}
largestItemSize = size;
return largestItemSize;
}
protected void installKeyboardActions()
{
}
protected void uninstallKeyboardActions()
{
}
public class ComboBoxLayoutManager extends Object implements LayoutManager
{
public ComboBoxLayoutManager()
{
}
public void addLayoutComponent(String name, Component comp)
{
}
public void removeLayoutComponent(Component comp)
{
}
public Dimension preferredLayoutSize(Container parent)
{
Dimension d = new Dimension(0, 0);
if (largestItemSize == null)
largestItemSize = getLargestItemSize();
d.width += largestItemSize.getWidth();
d.height += largestItemSize.getHeight();
d.width += arrowButtonWidth;
d.width += borderInsets.left + borderInsets.right;
d.height += borderInsets.left + borderInsets.right;
Insets insets = parent.getInsets();
d.width += insets.left + insets.right;
d.width += insets.left + insets.right;
return d;
}
public Dimension minimumLayoutSize(Container parent)
{
return preferredLayoutSize(parent);
}
public void layoutContainer(Container parent)
{
int editorWidth = comboBox.getBounds().width - arrowButtonWidth - 2;
if (comboBox.isEditable())
editor.setBounds(borderInsets.left, borderInsets.top, editorWidth,
comboBox.getBounds().height - borderInsets.left
- borderInsets.top);
arrowButton.setBounds(editorWidth, 2, arrowButtonWidth,
comboBox.getBounds().height - 4);
comboBox.revalidate();
}
}
public class FocusHandler extends Object implements FocusListener
{
public FocusHandler()
{
}
public void focusGained(FocusEvent e)
{
hasFocus = true;
comboBox.repaint();
}
public void focusLost(FocusEvent e)
{
hasFocus = false;
comboBox.repaint();
popup.hide();
}
}
public class ItemHandler extends Object implements ItemListener
{
public ItemHandler()
{
}
public void itemStateChanged(ItemEvent e)
{
comboBox.repaint();
}
}
public class KeyHandler extends KeyAdapter
{
public KeyHandler()
{
}
public void keyPressed(KeyEvent e)
{
}
}
public class ListDataHandler extends Object implements ListDataListener
{
public ListDataHandler()
{
}
public void contentsChanged(ListDataEvent e)
{
}
public void intervalAdded(ListDataEvent e)
{
int start = e.getIndex0();
int end = e.getIndex1();
ComboBoxModel model = comboBox.getModel();
ListCellRenderer renderer = comboBox.getRenderer();
if (largestItemSize == null)
largestItemSize = new Dimension(0, 0);
for (int i = start - 1; i < end; i++)
{
Object item = model.getElementAt(i);
Component comp = renderer.getListCellRendererComponent(new JList(),
item, -1,
false, false);
if (comp.getPreferredSize().getWidth() > largestItemSize.getWidth())
largestItemSize = comp.getPreferredSize();
}
}
public void intervalRemoved(ListDataEvent e)
{
}
}
public class PropertyChangeHandler extends Object
implements PropertyChangeListener
{
public PropertyChangeHandler()
{
}
public void propertyChange(PropertyChangeEvent e)
{
if (e.getPropertyName().equals(JComboBox.ENABLED_CHANGED_PROPERTY))
{
arrowButton.setEnabled(comboBox.isEnabled());
if (comboBox.isEditable())
comboBox.getEditor().getEditorComponent().setEnabled(comboBox
.isEnabled());
}
else if (e.getPropertyName().equals(JComboBox.EDITABLE_CHANGED_PROPERTY))
{
if (comboBox.isEditable())
{
configureEditor();
addEditor();
}
else
{
unconfigureEditor();
removeEditor();
}
comboBox.revalidate();
comboBox.repaint();
}
}
}
private class MouseHandler extends MouseAdapter
{
public void mousePressed(MouseEvent e)
{
if (comboBox.isEnabled())
{
if (e.getSource() instanceof JComboBox)
{
arrowButton.getModel().setPressed(true);
arrowButton.getModel().setArmed(true);
}
comboBox.repaint();
if (e.getSource() instanceof BasicArrowButton)
toggleOpenClose();
}
}
public void mouseReleased(MouseEvent e)
{
if (comboBox.isEnabled())
{
if (e.getSource() instanceof JComboBox)
{
arrowButton.getModel().setPressed(false);
arrowButton.getModel().setArmed(false);
}
comboBox.repaint();
}
}
}
}