/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Tiny Look and Feel * * * * (C) Copyright 2003 - 2007 Hans Bickel * * * * For licensing information and credits, please refer to the * * comment in file de.muntjak.tinylookandfeel.TinyLookAndFeel * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ package de.muntjak.tinylookandfeel; 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.MouseEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import javax.swing.ComboBoxEditor; import javax.swing.ComboBoxModel; import javax.swing.DefaultListCellRenderer; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.ListCellRenderer; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicComboBoxUI; import javax.swing.plaf.basic.BasicComboPopup; import javax.swing.plaf.basic.ComboPopup; import javax.swing.plaf.metal.MetalComboBoxIcon; import javax.swing.plaf.metal.MetalComboBoxUI; /** * TinyComboBoxUI * * @version 1.3 * @author Hans Bickel */ public class TinyComboBoxUI extends BasicComboBoxUI { // Flag for calculating the display size protected boolean isDisplaySizeDirty = true; // Cached the size that the display needs to render the largest item protected Dimension cachedDisplaySize = new Dimension(0, 0); public static ComponentUI createUI(JComponent c) { return new TinyComboBoxUI(); } public void paint(Graphics g, JComponent c) { } protected ComboBoxEditor createEditor() { return new TinyComboBoxEditor.UIResource(); } protected ComboPopup createPopup() { return new MetalComboPopup(comboBox); } protected JButton createArrowButton() { JButton button = new TinyComboBoxButton(comboBox, new MetalComboBoxIcon(), comboBox.isEditable(), currentValuePane, listBox); button.setMargin(new Insets(0, 0, 0, 0)); button.putClientProperty("isComboBoxButton", Boolean.TRUE); return button; } protected void installComponents() { super.installComponents(); if(arrowButton != null) { arrowButton.setFocusable(false); } } public PropertyChangeListener createPropertyChangeListener() { return new TinyPropertyChangeListener(); } /** * This inner class is marked "public" due to a compiler bug. * This class should be treated as a "protected" inner class. * Instantiate it only within subclasses of <FooUI>. */ public class TinyPropertyChangeListener extends BasicComboBoxUI.PropertyChangeHandler { public void propertyChange(PropertyChangeEvent e) { super.propertyChange(e); String propertyName = e.getPropertyName(); if(propertyName.equals("editable")) { TinyComboBoxButton button = (TinyComboBoxButton)arrowButton; button.setIconOnly(comboBox.isEditable()); isMinimumSizeDirty = true; isDisplaySizeDirty = true; comboBox.revalidate(); } // else if(propertyName.equals("font")) { // isMinimumSizeDirty = true; // isDisplaySizeDirty = true; // comboBox.revalidate(); // } else if(propertyName.equals("background")) { Color color = (Color) e.getNewValue(); listBox.setBackground(color); } else if(propertyName.equals("foreground")) { Color color = (Color) e.getNewValue(); listBox.setForeground(color); } } } /** * As of Java 2 platform v1.4 this method is no longer used. Do not call or * override. All the functionality of this method is in the * MetalPropertyChangeListener. * * @deprecated As of Java 2 platform v1.4. */ protected void editablePropertyChanged(PropertyChangeEvent e) { } protected LayoutManager createLayoutManager() { return new TinyComboBoxLayoutManager(); } /** * This inner class is marked "public" due to a compiler bug. * This class should be treated as a "protected" inner class. * Instantiate it only within subclasses of <FooUI>. */ public class TinyComboBoxLayoutManager implements LayoutManager { public void addLayoutComponent(String name, Component comp) { } public void removeLayoutComponent(Component comp) { } public Dimension preferredLayoutSize(Container parent) { JComboBox cb = (JComboBox) parent; return parent.getPreferredSize(); } public Dimension minimumLayoutSize(Container parent) { JComboBox cb = (JComboBox) parent; return parent.getMinimumSize(); } public void layoutContainer(Container parent) { JComboBox cb = (JComboBox) parent; int width = cb.getWidth(); int height = cb.getHeight(); Rectangle cvb; if (comboBox.isEditable()) { if (arrowButton != null) { arrowButton.setBounds(width - Theme.comboButtonWidth[Theme.derivedStyle[Theme.style]], 0, Theme.comboButtonWidth[Theme.derivedStyle[Theme.style]], height); } if (editor != null) { cvb = rectangleForCurrentValue2(); editor.setBounds(cvb); } } else { arrowButton.setBounds(0, 0, width, height); } } } protected Rectangle rectangleForCurrentValue2() { int width = comboBox.getWidth(); int height = comboBox.getHeight(); Insets insets = getInsets(); int buttonSize = height - (insets.top + insets.bottom); if (arrowButton != null) { buttonSize = Theme.comboButtonWidth[Theme.derivedStyle[Theme.style]]; } if (comboBox.getComponentOrientation().isLeftToRight()) { return new Rectangle(insets.left, insets.top, width - (insets.left + insets.right + buttonSize), height - (insets.top + insets.bottom)); } else { return new Rectangle( insets.left + buttonSize, insets.top, width - (insets.left + insets.right + buttonSize), height - (insets.top + insets.bottom)); } } /** * As of Java 2 platform v1.4 this method is no * longer used. * * @deprecated As of Java 2 platform v1.4. */ protected void removeListeners() { if (propertyChangeListener != null) { comboBox.removePropertyChangeListener(propertyChangeListener); } } // These two methods were overloaded and made public. This was probably a // mistake in the implementation. The functionality that they used to // provide is no longer necessary and should be removed. However, // removing them will create an uncompatible API change. public void configureEditor() { super.configureEditor(); } public void unconfigureEditor() { super.unconfigureEditor(); } /** * @param c the combo box */ public Dimension getMinimumSize(JComponent c) { if(!isMinimumSizeDirty) { isDisplaySizeDirty = true; // 1.3 return new Dimension(cachedMinimumSize); } // changed in 1.3 Insets insets = Theme.comboInsets[Theme.style]; Dimension size = getDisplaySize(); size.width += Theme.comboButtonWidth[Theme.derivedStyle[Theme.style]]; size.width += insets.left + insets.right; size.height += insets.top + insets.bottom; cachedMinimumSize.setSize(size.width, size.height); isMinimumSizeDirty = false; return new Dimension(cachedMinimumSize); } /** * Copied from BasicComboBoxUI, because isDisplaySizeDirty was declared private!? * Returns the calculated size of the display area. The display area is the * portion of the combo box in which the selected item is displayed. This * method will use the prototype display value if it has been set. * <p> * For combo boxes with a non trivial number of items, it is recommended to * use a prototype display value to significantly speed up the display * size calculation. * * @return the size of the display area calculated from the combo box items * @see javax.swing.JComboBox#setPrototypeDisplayValue */ protected Dimension getDisplaySize() { if(!isDisplaySizeDirty) { return new Dimension(cachedDisplaySize); } Dimension result = new Dimension(); ListCellRenderer renderer = comboBox.getRenderer(); if(renderer == null) { renderer = new DefaultListCellRenderer(); } Object prototypeValue = comboBox.getPrototypeDisplayValue(); if(prototypeValue != null) { // Calculates the dimension based on the prototype value result = getSizeForComponent(renderer.getListCellRendererComponent( listBox, prototypeValue, -1, false, false)); } else { // Calculate the dimension by iterating over all the elements in the combo // box list. ComboBoxModel model = comboBox.getModel(); int modelSize = model.getSize(); Dimension d; Component cpn; if(modelSize > 0) { for (int i = 0; i < modelSize ; i++ ) { // Calculates the maximum height and width based on the largest // element d = getSizeForComponent(renderer.getListCellRendererComponent( listBox, model.getElementAt(i), -1, false, false)); result.width = Math.max(result.width,d.width); result.height = Math.max(result.height,d.height); } } else { result = getDefaultSize(); if(comboBox.isEditable()) { result.width = 100; } } } if(comboBox.isEditable()) { Dimension d = editor.getPreferredSize(); result.width = Math.max(result.width, d.width); result.height = Math.max(result.height, d.height); } // Set the cached value cachedDisplaySize.setSize(result.width, result.height); isDisplaySizeDirty = false; return result; } /* * Copied from BasicComboBoxUI. */ protected Dimension getSizeForComponent(Component comp) { currentValuePane.add(comp); comp.setFont(comboBox.getFont()); Dimension d = comp.getPreferredSize(); currentValuePane.remove(comp); return d; } /** * This inner class is marked "public" due to a compiler bug. * This class should be treated as a "protected" inner class. * Instantiate it only within subclasses of <FooUI>. * * This class is now obsolete and doesn't do anything and * is only included for backwards API compatibility. Do not call or * override. * * @deprecated As of Java 2 platform v1.4. */ public class MetalComboPopup extends BasicComboPopup { public MetalComboPopup(JComboBox cBox) { super(cBox); } // This method was overloaded and made public. This was probably // mistake in the implementation. The functionality that they used to // provide is no longer necessary and should be removed. However, // removing them will create an uncompatible API change. public void delegateFocus(MouseEvent e) { super.delegateFocus(e); } } }