/*
* Copyright(c) 2002-2010, Rob Eden
* All rights reserved.
*/
package com.starlight.ui;
import com.starlight.ValidationKit;
import com.starlight.locale.ResourceKey;
import org.jdesktop.swingx.JXDatePicker;
import org.jdesktop.swingx.JXTable;
import org.jdesktop.swingx.table.TableColumnModelExt;
import javax.swing.*;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* Static functions for working with Swing.
*/
public final class UIKit {
/** Color that should be used on fields that indicate (for example) that the field
* they're labeling does not have valid data. */
private static final Color DEFAULT_ERROR_LABEL_COLOR = Color.RED.darker().darker();
/**
* Hidden constructor
*/
private UIKit() {}
public static Color getNormalLabelColor() {
return UIManager.getColor( "Label.foreground" );
}
public static Color getErrorLabelColor() {
Color color = UIManager.getColor( "starlight.error_label_color" );
if ( color == null ) color = DEFAULT_ERROR_LABEL_COLOR;
return color;
}
/**
* Modify a component's preferred size by changing the height or width.
* If an argument is null, it means to use the value from the component's original
* preferred size.
*
* @param component The component.
* @param height The height.
* @param width The width.
*/
public static void modifyPreferredSize( JComponent component,
Integer width, Integer height ) {
if ( component == null ) return;
if ( height == null && width == null ) return;
Dimension d = component.getPreferredSize();
if ( d == null ) return; // weird
Dimension new_d = new Dimension(
width == null ? d.width : width.intValue(),
height == null ? d.height : height.intValue() );
component.setPreferredSize( new_d );
}
/**
* Modify the font by changing the attributes passed in. If an argument is null, it
* means to use the value from the passed in font.
*
* @param starting_font The original font.
* @param name The name of the font.
* @param style The font style.
* @param size The font size.
*/
public static Font modifyFont( Font starting_font, String name,
Integer style, Integer size ) {
if ( starting_font == null ) return null;
if ( name == null && style == null && size == null ) return starting_font;
return new Font( name == null ? starting_font.getName() : name,
style == null ? starting_font.getStyle() : style.intValue(),
size == null ? starting_font.getSize() : size.intValue() );
}
/**
* Modify the size of the given font. THe given value will be added to the font size
* (so negative values are ok).
*/
public static Font modifyFontSize( Font starting_font, int add_to_size ) {
int original_size = starting_font.getSize();
return modifyFont( starting_font, null, null,
new Integer( original_size + add_to_size) );
}
/**
* This is used in testing of new components to display a frame with the component
* inside. The frame will cause the VM to exit when closed. Basically it does
* everything you need in the main method to display the component.
*/
public static void testComponent( JComponent component ) {
JFrame test = new JFrame( "Test: " + component.getClass().getName() );
test.getContentPane().setLayout( new BorderLayout() );
test.getContentPane().add( component, BorderLayout.CENTER );
test.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
test.pack();
System.out.println( "Frame size: " + test.getSize() );
test.setVisible( true );
}
/**
* Convenience method for constructing labels fast.
*
* @param text The label text.
* @param mnemonic A String from which the mnemonic will be pulled (first
* character), if it's non-null.
* @param label_for The component this is a label for, or null.
*/
public static JLabel createLabel( String text, String mnemonic,
Component label_for ) {
JLabel label = new JLabel( text );
if ( mnemonic != null && mnemonic.length() > 0 ) {
label.setDisplayedMnemonic( mnemonic.charAt( 0 ) );
}
if ( label_for != null ) {
label.setLabelFor( label_for );
// label.setFont( modifyFont( label.getFont(), null, new Integer( Font.BOLD ),
// null ) );
}
return label;
}
/**
* Create a panel that can be used for filler.
*/
public static JPanel createFiller( int width, int height ) {
JPanel panel = new JPanel();
panel.setPreferredSize( new Dimension( width, height ) );
panel.setOpaque( false );
return panel;
}
/**
* Centers a window on the screen
*/
public static void centerWindow( Window win ) {
Point center = GraphicsEnvironment.getLocalGraphicsEnvironment().getCenterPoint();
Dimension win_size = win.getSize();
Point window_point = new Point( center.x - ( win_size.width / 2 ),
center.y - ( win_size.height / 2 ) );
win.setLocation( window_point );
}
/**
* Center a "child" window over a "parent" window.
*
* @param child the window to center
* @param parent the window to center on
*/
public static void centerWindowOnWindow(Window child, Window parent ) {
if ( parent == null ) {
centerWindow( child );
return;
}
Dimension parent_size = parent.getSize();
// Center Frame, Dialogue or Window on window
int x = (parent_size.width - child.getSize().width) / 2;
int y = (parent_size.height - child.getSize().height) / 2;
Point ploc = parent.getLocation();
child.setLocation(ploc.x + x, ploc.y + y);
}
/**
* Draw a component to a buffer and return the image.
*/
public static BufferedImage drawToBuffer( Component component ) {
BufferedImage image = new BufferedImage(
component.getWidth(), component.getHeight(), BufferedImage.TYPE_INT_RGB );
component.paint( image.getGraphics() );
return image;
}
/**
* Function to simplify button creation.
*/
public static JButton createButton( ResourceKey<String> text, String action_command,
ActionListener listener ) {
return createButton( text, action_command, listener, null );
}
/**
* Function to simplify button creation.
*/
public static JButton createButton( ResourceKey<String> text, String action_command,
ActionListener listener, ResourceKey<Icon> image_key ) {
JButton button = new JButton( text == null ? null : text.getValue() );
if ( action_command != null ) button.setActionCommand( action_command );
if ( listener != null ) button.addActionListener( listener );
if ( image_key != null ) {
button.setIcon( image_key.getValue() );
}
return button;
}
/**
* Function to simplify scroll panel creation. This creates the "standard" scroll
* panel (for me): vertical as needed, no horizontal.
*/
public static JScrollPane createScrollPane( JComponent component ) {
return new JScrollPane( component, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER );
}
/**
* Simplify creation of JXDatePickers.
*/
public static JXDatePicker createDatePicker( Date shown_date, Date lower_bound ) {
JXDatePicker picker = new JXDatePicker( shown_date );
picker.setFormats( new SimpleDateFormat( "MM/dd/yy" ),
new SimpleDateFormat( "MM/dd/yyyy" ),
DateFormat.getDateInstance( DateFormat.SHORT ) );
if ( shown_date != null ) picker.getMonthView().setFirstDisplayedDay( shown_date );
if ( lower_bound != null ) picker.getMonthView().setLowerBound( lower_bound );
Dimension pref_size = picker.getPreferredSize();
picker.setPreferredSize( new Dimension( pref_size.width + 4, pref_size.height ) );
return picker;
}
public static void dumpPreferedSizes( Component component ) {
System.out.println( "Prefered Size: " + component.getPreferredSize() + " - " +
component );
if ( !( component instanceof Container ) ) return;
Container container = ( Container ) component;
for ( int i = 0; i < container.getComponentCount(); i++ ) {
dumpPreferedSizes( container.getComponent( i ), " " );
}
}
private static void dumpPreferedSizes( Component component, String indent ) {
System.out.println( indent + component.getPreferredSize() + " - " + component );
if ( !( component instanceof Container ) ) return;
Container container = ( Container ) component;
for ( int i = 0; i < container.getComponentCount(); i++ ) {
dumpPreferedSizes( container.getComponent( i ), indent + " " );
}
}
/**
* Checks to see if the selection in a JList is invalid (outside the range of elements
* in the list). This is necessary for lists with dynamic elements since the
* ListSelectionModel is not connected to the ListModel.
*/
public static boolean checkForInvalidSelection( JList list ) {
int selected_index = list.getSelectedIndex();
if ( selected_index >= list.getModel().getSize() ) {
list.clearSelection();
return true;
}
return false;
}
/**
* Set the width of a table column to the size the column would be when rendering the
* given value. This will use the currently installed renderer with that value.
*
* @param table The table
* @param column The table column
* @param value The prototype value
* @param force If true the max and min size for the column will also be set,
* otherwise only the preferred size is set.
* @param margin Extra padding added to the borders. Note: this will be added
* to both sides, so the extra space will be twice what is given.
*/
public static void autosizeTableColumn( JTable table, int column, Object value,
boolean force, int margin ) {
ValidationKit.checkNonnull( table, "Table" );
TableColumn table_column = table.getColumnModel().getColumn( column );
if ( table instanceof JXTable &&
table.getColumnModel() instanceof TableColumnModelExt ) {
JXTable xtable = ( JXTable ) table;
table_column = ( ( TableColumnModelExt ) xtable.getColumnModel() ).getColumns(
true ).get( column );
}
int width = 0;
// Get width of column header
TableCellRenderer renderer = table_column.getHeaderRenderer();
if ( renderer == null && table.getTableHeader() != null ) {
renderer = table.getTableHeader().getDefaultRenderer();
Component comp = renderer.getTableCellRendererComponent( table,
table_column.getHeaderValue(), false, false, 0, 0 );
width = comp.getPreferredSize().width;
}
// Get the width of the value
renderer = table_column.getCellRenderer();
if ( renderer == null ) {
renderer = table.getDefaultRenderer(
table.getModel().getColumnClass( column ) );
}
if ( renderer == null ) return; // fail quietly?
Component component = renderer.getTableCellRendererComponent( table, value, true,
true, 0, column );
if ( component == null ) return;
width = Math.max( width, component.getPreferredSize().width );
if ( margin > 0 ) width += ( margin * 2 );
table_column.setPreferredWidth( width );
if ( force ) {
table_column.setMaxWidth( width );
table_column.setMinWidth( width );
}
}
/**
* This returns a very short description of the component. Basically it will be the
* component type and name or text, if available. For example:<ul>
* <li>JButton "commit"</li>
* <li>JButton</li></ul>
*/
public static String describeComponent( Component component ) {
if ( component == null ) return "null";
StringBuilder buf = new StringBuilder();
buf.append( component.getClass().getSimpleName() );
if ( component.getName() != null ) {
buf.append( " \"" );
buf.append( component.getName() );
buf.append( '\"' );
}
else {
String text = null;
if ( component instanceof AbstractButton ) {
text = ( ( AbstractButton ) component ).getText();
}
else if ( component instanceof JLabel ) {
text = ( ( JLabel ) component ).getText();
if ( text != null && text.length() > 20 ) {
text = text.substring( 0, 20 );
}
}
else if ( component instanceof TextComponent ) {
text = ( ( TextComponent ) component ).getText();
if ( text != null && text.length() > 20 ) {
text = text.substring( 0, 20 );
}
}
else if ( component instanceof JComboBox ) {
Object selection = ( ( JComboBox ) component ).getSelectedItem();
if ( selection != null ) text = selection.toString();
}
if ( text != null ) {
buf.append( " \"" );
buf.append( text );
buf.append( '\"' );
}
}
return buf.toString();
}
}