/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Liquid Look and Feel *
* *
* Author, Miroslav Lazarevic *
* *
* For licensing information and credits, please refer to the *
* comment in file com.birosoft.liquid.LiquidLookAndFeel *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
package com.birosoft.liquid;
import com.birosoft.liquid.skin.Skin;
import java.awt.Color;
import java.awt.Component;
import java.awt.ComponentOrientation;
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.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.ComboBoxEditor;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.KeyStroke;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicComboBoxUI;
import javax.swing.plaf.basic.BasicComboPopup;
import javax.swing.plaf.basic.ComboPopup;
public class LiquidComboBoxUI extends BasicComboBoxUI {
static int comboBoxButtonSize = 18;
private int prevSelectedItem;
private Skin skinCombo;
public static ComponentUI createUI(final JComponent c) {
// If we used an transparent toolbutton skin we would have to add:
c.setOpaque(false);
// 20060608 MEV - Moved this to OpaquePropertyChangeListener so it could be removed later
c.addPropertyChangeListener("opaque",
new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
c.setOpaque(false);
}
});
return new LiquidComboBoxUI();
}
protected void installListeners() {
super.installListeners();
// comboBox.addPropertyChangeListener("opaque", new OpaquePropertyChangeListener(comboBox));
}
protected void uninstallListeners() {
super.uninstallListeners();
// comboBox.removePropertyChangeListener("opaque", OpaquePropertyChangeListener.getComponentListener(comboBox));
}
public void installUI(JComponent c) {
super.installUI(c);
addKeyboardActions((JComboBox) c);
}
public void uninstallUI(JComponent c) {
super.uninstallUI(c);
}
/**
* Paint the combobox component.
* <I>NOTE: This code was moved here from the LiquidComboBoxButton class because the
* editor would be completely obscured by the combo skin for an editable combobox.</I>
* @param g
* @param c
*/
public void paint(Graphics g, JComponent c) {
int index = ((LiquidComboBoxButton)arrowButton).getIndexForState();
// 20060213 MEV - Correction to highlight when has focus
// index = (comboBox.hasFocus() && !comboBox.isEditable() ? 1 : index);
// Paint the Combo
getSkinCombo().draw(g, index, comboBox.getWidth(), comboBox.getHeight());
}
protected ComboBoxEditor createEditor() {
return new LiquidComboBoxEditor.UIResource();
}
protected ComboPopup createPopup() {
return new LiquidComboPopup(comboBox);
}
protected JButton createArrowButton() {
JButton button = new LiquidComboBoxButton(comboBox,
new LiquidCheckBoxIcon(), comboBox.isEditable(),
currentValuePane, listBox);
button.setMargin(new Insets(0, 0, 0, 0));
button.setFocusable(false);
return button;
}
public PropertyChangeListener createPropertyChangeListener() {
return new LiquidPropertyChangeListener();
}
/**
* Dominik Schwald <d.schwald@nextbyte.de> wrote this method. I did some
* improvments. Thank you Dominik.
*/
private void addKeyboardActions(final JComboBox cb) {
// [ENTER] --> show List
KeyStroke ksEnter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,
KeyEvent.VK_UNDEFINED);
cb.registerKeyboardAction(new ActionListener() {
public void actionPerformed(ActionEvent e) {
prevSelectedItem = cb.getSelectedIndex();
if (cb.isPopupVisible()) {
cb.hidePopup();
} else {
cb.showPopup();
}
}
}, ksEnter, JComponent.WHEN_FOCUSED);
// [ESC] --> hide List
KeyStroke ksESC = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE,
KeyEvent.VK_UNDEFINED);
cb.registerKeyboardAction(new ActionListener() {
public void actionPerformed(ActionEvent e) {
cb.hidePopup();
cb.setSelectedIndex(prevSelectedItem);
}
}, ksESC, JComponent.WHEN_FOCUSED);
// [down arrow] --> next selection
KeyStroke ksDown = KeyStroke.getKeyStroke(KeyEvent.VK_DOWN,
KeyEvent.VK_UNDEFINED);
cb.registerKeyboardAction(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (!cb.isPopupVisible()) {
cb.showPopup();
return;
}
if (cb.getSelectedIndex() <= (cb.getItemCount() - 2)) {
cb.setSelectedIndex(cb.getSelectedIndex() + 1);
} else if ((cb.getSelectedIndex() == -1) &&
(cb.getItemCount() > 0)) {
cb.setSelectedIndex(0);
} else {
Toolkit.getDefaultToolkit().beep();
}
}
}, ksDown, JComponent.WHEN_FOCUSED);
// [right arrow] --> next selection
KeyStroke ksRight = KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT,
KeyEvent.VK_UNDEFINED);
cb.registerKeyboardAction(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (cb.getSelectedIndex() <= (cb.getItemCount() - 2)) {
cb.setSelectedIndex(cb.getSelectedIndex() + 1);
} else if ((cb.getSelectedIndex() == -1) &&
(cb.getItemCount() > 0)) {
cb.setSelectedIndex(0);
} else {
Toolkit.getDefaultToolkit().beep();
}
}
}, ksRight, JComponent.WHEN_FOCUSED);
// [up arrow] --> previous selection
KeyStroke ksUp = KeyStroke.getKeyStroke(KeyEvent.VK_UP,
KeyEvent.VK_UNDEFINED);
cb.registerKeyboardAction(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (cb.getSelectedIndex() > 0) {
cb.setSelectedIndex(cb.getSelectedIndex() - 1);
} else if ((cb.getSelectedIndex() == -1) &&
(cb.getItemCount() > 0)) {
cb.setSelectedIndex(0);
} else {
Toolkit.getDefaultToolkit().beep();
}
}
}, ksUp, JComponent.WHEN_FOCUSED);
// [left arrow] --> previous selection
KeyStroke ksLeft = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT,
KeyEvent.VK_UNDEFINED);
cb.registerKeyboardAction(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (cb.getSelectedIndex() > 0) {
cb.setSelectedIndex(cb.getSelectedIndex() - 1);
} else if ((cb.getSelectedIndex() == -1) &&
(cb.getItemCount() > 0)) {
cb.setSelectedIndex(0);
} else {
Toolkit.getDefaultToolkit().beep();
}
}
}, ksLeft, JComponent.WHEN_FOCUSED);
}
/**
* 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 MetouiaComboBoxLayoutManager();
}
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 = comboBoxButtonSize;
}
if (comboBox.getComponentOrientation().isLeftToRight()) {
// Liquid style editor rectangle
return new Rectangle(insets.left + 8, insets.top,
width - (insets.left + insets.right + buttonSize) - 7,
height - (insets.top + insets.bottom) - 2);
} 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();
}
public Dimension getMinimumSize(JComponent c) {
if (c == null) {
return new Dimension();
}
if (!isMinimumSizeDirty) {
return new Dimension(cachedMinimumSize);
}
Dimension size = null;
if (!comboBox.isEditable() && (arrowButton != null) &&
arrowButton instanceof LiquidComboBoxButton) {
LiquidComboBoxButton button = (LiquidComboBoxButton) arrowButton;
Insets buttonInsets = new Insets(0, 0, 0, 0);
Insets insets = comboBox.getInsets();
size = getDisplaySize();
size.width += (comboBoxButtonSize + insets.left + insets.right); // Hack
size.width += (buttonInsets.left + buttonInsets.right);
size.width += (buttonInsets.right +
button.getComboIcon().getIconWidth());
size.height += (insets.top + insets.bottom);
size.height += (buttonInsets.top + buttonInsets.bottom);
size.height = Math.max(21, size.height);
} else if (comboBox.isEditable() && (arrowButton != null) &&
(editor != null)) {
size = super.getMinimumSize(c);
Insets margin = arrowButton.getMargin();
Insets insets = comboBox.getInsets();
size.height += (margin.top + margin.bottom);
size.height += (insets.top + insets.bottom);
//size.height = Math.max(20,size.height);
} else {
size = super.getMinimumSize(c);
}
cachedMinimumSize.setSize(size.width, size.height);
isMinimumSizeDirty = false;
return new Dimension(cachedMinimumSize);
}
/**
* 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 LiquidPropertyChangeListener
extends BasicComboBoxUI.PropertyChangeHandler {
public void propertyChange(PropertyChangeEvent e) {
super.propertyChange(e);
String propertyName = e.getPropertyName();
if (propertyName.equals("editable")) {
LiquidComboBoxButton button = (LiquidComboBoxButton) arrowButton;
button.setIconOnly(comboBox.isEditable());
comboBox.repaint();
} 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);
} else if (propertyName.equals("componentOrientation")) {
LiquidComboBoxButton button = (LiquidComboBoxButton) arrowButton;
button.setComponentOrientation((ComponentOrientation) e.getNewValue());
}
}
}
/**
* 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 MetouiaComboBoxLayoutManager implements LayoutManager {
public void addLayoutComponent(String name, Component comp) {
}
public void removeLayoutComponent(Component comp) {
}
public Dimension preferredLayoutSize(Container parent) {
return parent.getPreferredSize();
}
public Dimension minimumLayoutSize(Container parent) {
return parent.getMinimumSize();
}
public void layoutContainer(Container parent) {
JComboBox cb = (JComboBox) parent;
int width = cb.getWidth();
int height = cb.getHeight();
Rectangle cvb = null;
if (comboBox.isEditable()) {
if (editor != null) {
cvb = rectangleForCurrentValue2();
editor.setBounds(cvb);
}
if (arrowButton != null) {
if (editor != null && cvb != null) {
int start = cvb.x + cvb.width;
arrowButton.setBounds(start, 0, width - start, height);
} else {
arrowButton.setBounds(0, 0, width, height);
}
}
} else {
arrowButton.setBounds(0, 0, width, height);
}
}
}
/**
* 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 LiquidComboPopup extends BasicComboPopup {
/**
*
*/
private static final long serialVersionUID = 2072608971254412076L;
public LiquidComboPopup(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);
}
}
public Skin getSkinCombo()
{
if (skinCombo == null)
{
// RtoL stuff boolean leftToRight = comboBox.getComponentOrientation().isLeftToRight();
// RtoL stuff if( leftToRight )
// RtoL stuff {
skinCombo = new Skin("combobox.png", 4, 10, 6, 18, 4);
// RtoL stuff }
// RtoL stuff else
// RtoL stuff {
// RtoL stuff skinCombo = new Skin("comboboxrtl.png", 4, 18, 4, 10, 6);
// RtoL stuff }
}
return skinCombo;
}
}