/*******************************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* 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;
/**
* TinyComboBoxUI
*
* @version 1.3
* @author Hans Bickel
*/
@SuppressWarnings (
{ "all" } )
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.
*/
private 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 );
}
}
}