[Schmitzm-commits] r1655 - trunk/schmitzm-core/src/main/java/de/schmitzm/swing

scm-commit@wald.intevation.org scm-commit at wald.intevation.org
Fri Jul 29 12:42:05 CEST 2011


Author: mojays
Date: 2011-07-29 12:42:05 +0200 (Fri, 29 Jul 2011)
New Revision: 1655

Added:
   trunk/schmitzm-core/src/main/java/de/schmitzm/swing/JList.java
   trunk/schmitzm-core/src/main/java/de/schmitzm/swing/UIManagerDefaults.java
Log:
new JList: like the standard swing component, but with manually set gray background in disabled state
new UIManagerDefaults (taken from http://tips4java.wordpress.com/2008/10/09/uimanager-defaults/)

Added: trunk/schmitzm-core/src/main/java/de/schmitzm/swing/JList.java
===================================================================
--- trunk/schmitzm-core/src/main/java/de/schmitzm/swing/JList.java	2011-07-28 19:49:15 UTC (rev 1654)
+++ trunk/schmitzm-core/src/main/java/de/schmitzm/swing/JList.java	2011-07-29 10:42:05 UTC (rev 1655)
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focusing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Tzeggai - additional utility classes
+ ******************************************************************************/
+package de.schmitzm.swing;
+
+import java.util.Vector;
+
+import javax.swing.JTextField;
+import javax.swing.ListModel;
+import javax.swing.UIManager;
+
+/**
+ * {@link javax.swing.JList} which background is grayed like
+ * {@link JTextField} in disabled state.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ */
+public class JList extends javax.swing.JList {
+  
+  /**
+   * Creates a new list.
+   */
+  public JList() {
+    super();
+  }
+
+  /**
+   * Creates a new list.
+   */
+  public JList(ListModel dataModel) {
+    super(dataModel);
+  }
+
+  /**
+   * Creates a new list.
+   */
+  public JList(Object[] listData) {
+    super(listData);
+  }
+
+  /**
+   * Creates a new list.
+   */
+  public JList(Vector<?> listData) {
+    super(listData);
+  }
+
+  /**
+   * When component is disabled, the background color is set to
+   * {@code UIManager.getColor("TextField.inactiveBackground")} so
+   * it is grayed like a text field.
+   */
+  @Override
+  public void setEnabled(boolean enabled) {
+    if ( enabled ) {
+      // normal background in enabled mode
+      setBackground( UIManager.getColor("List.background") );
+    } else {
+      // grayed background in disabled mode
+      setBackground( UIManager.getColor("TextField.inactiveBackground") );
+    }
+    super.setEnabled(enabled);
+  }
+
+}

Added: trunk/schmitzm-core/src/main/java/de/schmitzm/swing/UIManagerDefaults.java
===================================================================
--- trunk/schmitzm-core/src/main/java/de/schmitzm/swing/UIManagerDefaults.java	2011-07-28 19:49:15 UTC (rev 1654)
+++ trunk/schmitzm-core/src/main/java/de/schmitzm/swing/UIManagerDefaults.java	2011-07-29 10:42:05 UTC (rev 1655)
@@ -0,0 +1,726 @@
+package de.schmitzm.swing;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.image.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.plaf.*;
+import javax.swing.table.*;
+
+/**
+ *  This programs uses the information found in the UIManager
+ *  to create a table of key/value pairs for each Swing component.<br>
+ *  <br>
+ *  <b>
+ *  Taken from <a href="http://tips4java.wordpress.com/2008/10/09/uimanager-defaults/">
+ *  {@code http://tips4java.wordpress.com/2008/10/09/uimanager-defaults/}</a>
+ *  </b>
+ */
+public class UIManagerDefaults implements ActionListener, ItemListener
+{
+	private final static String[] COLUMN_NAMES = {"Key", "Value", "Sample"};
+	private static String selectedItem;
+
+	private JComponent contentPane;
+	private JMenuBar menuBar;
+	private JComboBox comboBox;
+	private JRadioButton byComponent;
+	private JTable table;
+	private TreeMap<String, TreeMap<String, Object>> items;
+	private HashMap<String, DefaultTableModel> models;
+
+	/*
+	 *  Constructor
+	 */
+	public UIManagerDefaults()
+	{
+		items = new TreeMap<String, TreeMap<String, Object>>();
+		models = new HashMap<String, DefaultTableModel>();
+
+		contentPane = new JPanel( new BorderLayout() );
+		contentPane.add(buildNorthComponent(), BorderLayout.NORTH);
+		contentPane.add(buildCenterComponent(), BorderLayout.CENTER);
+
+		resetComponents();
+	}
+
+	/*
+	 *  The content pane should be added to a high level container
+	 */
+	public JComponent getContentPane()
+	{
+		return contentPane;
+	}
+
+	/*
+	 *  A menu can also be added which provides the ability to switch
+	 *  between different LAF's.
+	 */
+	public JMenuBar getMenuBar()
+	{
+		if (menuBar == null)
+			menuBar = createMenuBar();
+
+		return menuBar;
+	}
+
+	/*
+	 *  This panel is added to the North of the content pane
+	 */
+	private JComponent buildNorthComponent()
+	{
+		comboBox = new JComboBox();
+
+		JLabel label = new JLabel("Select Item:");
+		label.setDisplayedMnemonic('S');
+		label.setLabelFor( comboBox );
+
+		byComponent = new JRadioButton("By Component", true);
+		byComponent.setMnemonic('C');
+		byComponent.addActionListener( this );
+
+		JRadioButton byValueType = new JRadioButton("By Value Type");
+		byValueType.setMnemonic('V');
+		byValueType.addActionListener( this );
+
+		ButtonGroup group = new ButtonGroup();
+		group.add(byComponent);
+		group.add(byValueType);
+
+		JPanel panel = new JPanel();
+		panel.setBorder( new EmptyBorder(15, 0, 15, 0) );
+		panel.add( label );
+		panel.add( comboBox );
+		panel.add( byComponent );
+		panel.add( byValueType );
+		return panel;
+	}
+
+	/*
+	 *  This panel is added to the Center of the content pane
+	 */
+	private JComponent buildCenterComponent()
+	{
+		DefaultTableModel model = new DefaultTableModel(COLUMN_NAMES, 0);
+		table = new JTable(model);
+		table.setAutoCreateColumnsFromModel( false );
+		table.getColumnModel().getColumn(0).setPreferredWidth(250);
+		table.getColumnModel().getColumn(1).setPreferredWidth(500);
+		table.getColumnModel().getColumn(2).setPreferredWidth(100);
+		table.getColumnModel().getColumn(2).setCellRenderer( new SampleRenderer() );
+		Dimension d = table.getPreferredSize();
+		d.height = 350;
+		table.setPreferredScrollableViewportSize( d );
+
+		return new JScrollPane( table );
+	}
+
+	/*
+	 *  When the LAF is changed we need to reset the content pane
+	 */
+	public void resetComponents()
+	{
+		items.clear();
+		models.clear();
+		((DefaultTableModel)table.getModel()).setRowCount(0);
+
+		buildItemsMap();
+
+		Vector<String> comboBoxItems = new Vector<String>(50);
+		Iterator keys = items.keySet().iterator();
+
+		while (keys.hasNext())
+		{
+			Object key = keys.next();
+			comboBoxItems.add( (String)key );
+		}
+
+		comboBox.removeItemListener( this );
+		comboBox.setModel( new DefaultComboBoxModel( comboBoxItems ) );
+		comboBox.setSelectedIndex(-1);
+		comboBox.addItemListener( this );
+		comboBox.requestFocusInWindow();
+
+		if (selectedItem != null)
+			comboBox.setSelectedItem(selectedItem);
+	}
+
+	/*
+	 *	The item map will contain items for each component or
+	 *  items for each attribute type.
+	 */
+	private TreeMap buildItemsMap()
+	{
+		UIDefaults defaults = UIManager.getLookAndFeelDefaults();
+
+		//  Build of Map of items and a Map of attributes for each item
+
+		for ( Enumeration enumm = defaults.keys(); enumm.hasMoreElements(); )
+		{
+			Object key = enumm.nextElement();
+			Object value = defaults.get( key );
+
+			String itemName = getItemName(key.toString(), value);
+
+			if (itemName == null) continue;
+
+			//  Get the attribute map for this componenent, or
+			//  create a map when one is not found
+
+			TreeMap<String, Object> attributeMap = items.get( itemName );
+
+			if (attributeMap == null)
+			{
+				attributeMap = new TreeMap<String, Object>();
+				items.put(itemName, attributeMap);
+			}
+
+			//  Add the attribute to the map for this componenent
+
+			attributeMap.put(key.toString(), value );
+		}
+
+		return items;
+	}
+
+	/*
+	 *  Parse the key to determine the item name to use
+	 */
+	private String getItemName(String key, Object value)
+	{
+		//  Seems like this is an old check required for JDK1.4.2
+
+		if (key.startsWith("class") || key.startsWith("javax"))
+			return null;
+
+		if (byComponent.isSelected())
+			return getComponentName(key, value);
+		else
+			return getValueName(key, value);
+	}
+
+	private String getComponentName(String key, Object value)
+	{
+		//  The key is of the form:
+		//  "componentName.componentProperty", or
+		//  "componentNameUI", or
+		//  "someOtherString"
+
+		String componentName;
+
+		int pos = key.indexOf( "." );
+
+		if (pos != -1)
+		{
+			componentName = key.substring( 0, pos );
+		}
+		else if (key.endsWith( "UI" ) )
+		{
+			componentName = key.substring( 0, key.length() - 2 );
+		}
+		else if (value instanceof ColorUIResource)
+		{
+			componentName = "System Colors";
+		}
+		else
+		{
+			componentName = "Miscellaneous";
+		}
+
+		//  Fix inconsistency
+
+		if (componentName.equals("Checkbox"))
+			componentName = "CheckBox";
+
+		return componentName;
+	}
+
+	private String getValueName(String key, Object value)
+	{
+		if (value instanceof Icon)
+			return "Icon";
+		else if (value instanceof Font)
+			return "Font";
+		else if (value instanceof Border)
+			return "Border";
+		else if (value instanceof Color)
+			return "Color";
+		else if (value instanceof Insets)
+			return "Insets";
+		else if (value instanceof Boolean)
+			return "Boolean";
+		else if (value instanceof Dimension)
+			return "Dimension";
+		else if (value instanceof Number)
+			return "Number";
+		else if (key.endsWith("UI"))
+			return "UI";
+		else if (key.endsWith("InputMap"))
+			return "InputMap";
+		else if (key.endsWith("RightToLeft"))
+			return "InputMap";
+		else if (key.endsWith("radient"))
+			return "Gradient";
+		else
+		{
+			return "The Rest";
+		}
+	}
+
+	/**
+	 *  Create menu bar
+	 */
+	private JMenuBar createMenuBar()
+	{
+		JMenuBar menuBar = new JMenuBar();
+
+		menuBar.add( createFileMenu() );
+		menuBar.add( createLAFMenu() );
+
+		return menuBar;
+	}
+
+	/**
+	 *  Create menu items for the Application menu
+	 */
+	private JMenu createFileMenu()
+	{
+		JMenu menu = new JMenu("Application");
+		menu.setMnemonic('A');
+
+		menu.addSeparator();
+		menu.add( new ExitAction() );
+
+		return menu;
+	}
+
+	/**
+	 *  Create menu items for the Look & Feel menu
+	 */
+	private JMenu createLAFMenu()
+	{
+		ButtonGroup bg = new ButtonGroup();
+
+		JMenu menu = new JMenu("Look & Feel");
+		menu.setMnemonic('L');
+
+		String lafId = UIManager.getLookAndFeel().getID();
+		UIManager.LookAndFeelInfo[] lafInfo = UIManager.getInstalledLookAndFeels();
+
+		for (int i = 0; i < lafInfo.length; i++)
+		{
+			String laf = lafInfo[i].getClassName();
+			String name= lafInfo[i].getName();
+
+			Action action = new ChangeLookAndFeelAction(this, laf, name);
+			JRadioButtonMenuItem mi = new JRadioButtonMenuItem( action );
+			menu.add( mi );
+			bg.add( mi );
+
+			if (name.equals(lafId))
+			{
+				mi.setSelected(true);
+			}
+		}
+
+		return menu;
+	}
+
+	/*
+	 *  Implement the ActionListener interface
+	 */
+	public void actionPerformed(ActionEvent e)
+	{
+		selectedItem = null;
+		resetComponents();
+		comboBox.requestFocusInWindow();
+	}
+
+	/*
+	 *  Implement the ItemListener interface
+	 */
+	public void itemStateChanged(ItemEvent e)
+	{
+		String itemName = (String)e.getItem();
+		changeTableModel( itemName );
+		updateRowHeights();
+		selectedItem = itemName;
+	}
+
+	/*
+	 *  Change the TabelModel in the table for the selected item
+	 */
+	private void changeTableModel(String itemName)
+	{
+		//  The model has been created previously so just use it
+
+		DefaultTableModel model = models.get( itemName );
+
+		if (model != null)
+		{
+			table.setModel( model );
+			return;
+		}
+
+		//  Create a new model for the requested item
+		//  and add the attributes of the item to the model
+
+		model = new DefaultTableModel(COLUMN_NAMES, 0);
+		Map attributes = (Map)items.get( itemName );
+
+		Iterator ai = attributes.keySet().iterator();
+
+		while (ai.hasNext())
+		{
+			String attribute = (String)ai.next();
+			Object value = attributes.get(attribute);
+
+			Vector<Object> row = new Vector<Object>(3);
+			row.add(attribute);
+
+			if (value != null)
+			{
+				row.add( value.toString() );
+
+				if (value instanceof Icon)
+					value = new SafeIcon( (Icon)value );
+
+				row.add( value );
+			}
+			else
+			{
+				row.add( "null" );
+				row.add( "" );
+			}
+
+			model.addRow( row );
+		}
+
+		table.setModel( model );
+		models.put(itemName, model);
+	}
+
+	/*
+	 *  Some rows containing icons, may need to be sized taller to fully
+	 *  display the icon.
+	 */
+	private void updateRowHeights()
+	{
+		try
+		{
+			for (int row = 0; row < table.getRowCount(); row++)
+			{
+				int rowHeight = table.getRowHeight();
+
+				for (int column = 0; column < table.getColumnCount(); column++)
+				{
+					Component comp = table.prepareRenderer(table.getCellRenderer(row, column), row, column);
+					rowHeight = Math.max(rowHeight, comp.getPreferredSize().height);
+				}
+
+				table.setRowHeight(row, rowHeight);
+			}
+		}
+		catch(ClassCastException e) {}
+	}
+
+	/**
+	 * Thanks to Jeanette for the use of this code found at:
+	 *
+	 * https://jdnc-incubator.dev.java.net/source/browse/jdnc-incubator/src/kleopatra/java/org/jdesktop/swingx/renderer/UIPropertiesViewer.java?rev=1.2&view=markup
+	 *
+	 * Some ui-icons misbehave in that they unconditionally class-cast to the
+	 * component type they are mostly painted on. Consequently they blow up if
+	 * we are trying to paint them anywhere else (f.i. in a renderer).
+	 *
+	 * This Icon is an adaption of a cool trick by Darryl Burke found at
+	 * http://tips4java.wordpress.com/2008/12/18/icon-table-cell-renderer
+	 *
+	 * The base idea is to instantiate a component of the type expected by the icon,
+	 * let it paint into the graphics of a bufferedImage and create an ImageIcon from it.
+	 * In subsequent calls the ImageIcon is used.
+	 *
+	 */
+	public static class SafeIcon implements Icon
+	{
+		private Icon wrappee;
+		private Icon standIn;
+
+		public SafeIcon(Icon wrappee)
+		{
+			this.wrappee = wrappee;
+		}
+
+		@Override
+		public int getIconHeight()
+		{
+			return wrappee.getIconHeight();
+		}
+
+		@Override
+		public int getIconWidth()
+		{
+			return wrappee.getIconWidth();
+		}
+
+		@Override
+		public void paintIcon(Component c, Graphics g, int x, int y)
+		{
+			if (standIn == this)
+			{
+				paintFallback(c, g, x, y);
+			}
+			else if (standIn != null)
+			{
+				standIn.paintIcon(c, g, x, y);
+			}
+			else
+			{
+				try
+				{
+				   wrappee.paintIcon(c, g, x, y);
+				}
+				catch (ClassCastException e)
+				{
+					createStandIn(e, x, y);
+					standIn.paintIcon(c, g, x, y);
+				}
+			}
+		}
+
+		/**
+		 * @param e
+		 */
+		private void createStandIn(ClassCastException e, int x, int y)
+		{
+			try
+			{
+				Class<?> clazz = getClass(e);
+				JComponent standInComponent = getSubstitute(clazz);
+				standIn = createImageIcon(standInComponent, x, y);
+			}
+			catch (Exception e1)
+			{
+				// something went wrong - fallback to this painting
+				standIn = this;
+			}
+		}
+
+		private Icon createImageIcon(JComponent standInComponent, int x, int y)
+		{
+			BufferedImage image = new BufferedImage(getIconWidth(), getIconHeight(), BufferedImage.TYPE_INT_ARGB);
+			Graphics g = image.createGraphics();
+			try
+			{
+				wrappee.paintIcon(standInComponent, g, 0, 0);
+				return new ImageIcon(image);
+			}
+			finally
+			{
+				g.dispose();
+			}
+		}
+
+		/**
+		 * @param clazz
+		 * @throws IllegalAccessException
+		 */
+		private JComponent getSubstitute(Class<?> clazz) throws IllegalAccessException
+		{
+			JComponent standInComponent;
+
+			try
+			{
+				standInComponent = (JComponent) clazz.newInstance();
+			}
+			catch (InstantiationException e)
+			{
+				standInComponent = new AbstractButton() {};
+				((AbstractButton) standInComponent).setModel(new DefaultButtonModel());
+			}
+			return standInComponent;
+		}
+
+		private Class<?> getClass(ClassCastException e) throws ClassNotFoundException
+		{
+			String className = e.getMessage();
+			className = className.substring(className.lastIndexOf(" ") + 1);
+			return Class.forName(className);
+
+		}
+
+		private void paintFallback(Component c, Graphics g, int x, int y)
+		{
+			g.drawRect(x, y, getIconWidth(), getIconHeight());
+			g.drawLine(x, y, x + getIconWidth(), y + getIconHeight());
+			g.drawLine(x + getIconWidth(), y, x, y + getIconHeight());
+		}
+
+	}
+
+
+	/*
+	 *  Render the value based on its class.
+	 */
+	class SampleRenderer extends JLabel implements TableCellRenderer
+	{
+		public SampleRenderer()
+		{
+			super();
+			setHorizontalAlignment( SwingConstants.CENTER );
+			setOpaque(true);
+		}
+
+		public Component getTableCellRendererComponent(
+			JTable table, Object sample, boolean isSelected, boolean hasFocus, int row, int column)
+		{
+			setBackground( null );
+			setBorder( null );
+			setIcon( null );
+			setText( "" );
+
+			if ( sample instanceof Color )
+			{
+				setBackground( (Color)sample );
+			}
+			else if ( sample instanceof Border )
+			{
+				setBorder( (Border)sample );
+			}
+			else if ( sample instanceof Font )
+			{
+				setText( "Sample" );
+				setFont( (Font)sample );
+			}
+			else if ( sample instanceof Icon )
+			{
+				setIcon( (Icon)sample );
+			}
+
+			return this;
+		}
+
+		/*
+		 *  Some icons are painted using inner classes and are not meant to be
+		 *  shared by other items. This code will catch the
+		 *  ClassCastException that is thrown.
+		 */
+		public void paint(Graphics g)
+		{
+			try
+			{
+				super.paint(g);
+			}
+			catch(Exception e)
+			{
+//				System.out.println(e);
+//				System.out.println(e.getStackTrace()[0]);
+			}
+		}
+	}
+
+	/*
+	 *  Change the LAF and recreate the UIManagerDefaults so that the properties
+	 *  of the new LAF are correctly displayed.
+	 */
+	class ChangeLookAndFeelAction extends AbstractAction
+	{
+		private UIManagerDefaults defaults;
+		private String laf;
+
+		protected ChangeLookAndFeelAction(UIManagerDefaults defaults, String laf, String name)
+		{
+			this.defaults = defaults;
+			this.laf = laf;
+			putValue(Action.NAME, name);
+			putValue(Action.SHORT_DESCRIPTION, getValue(Action.NAME));
+		}
+
+		public void actionPerformed(ActionEvent e)
+		{
+			try
+			{
+				UIManager.setLookAndFeel( laf );
+				defaults.resetComponents();
+
+				JMenuItem mi = (JMenuItem) e.getSource();
+				JPopupMenu popup = (JPopupMenu) mi.getParent();
+				JRootPane rootPane = SwingUtilities.getRootPane( popup.getInvoker() );
+				SwingUtilities.updateComponentTreeUI( rootPane );
+
+				//  Use custom decorations when supported by the LAF
+
+				JFrame frame = (JFrame)SwingUtilities.windowForComponent(rootPane);
+				frame.dispose();
+
+				if (UIManager.getLookAndFeel().getSupportsWindowDecorations())
+				{
+					frame.setUndecorated(true);
+				    frame.getRootPane().setWindowDecorationStyle(JRootPane.FRAME);
+				}
+				else
+				{
+					frame.setUndecorated(false);
+				}
+
+				frame.setVisible(true);
+			}
+			catch (Exception ex)
+			{
+				System.out.println("Failed loading L&F: " + laf);
+				System.out.println(ex);
+			}
+		}
+	}
+
+	/*
+	 *	Close the frame
+	 */
+	class ExitAction extends AbstractAction
+	{
+		public ExitAction()
+		{
+			putValue(Action.NAME, "Exit");
+			putValue(Action.SHORT_DESCRIPTION, getValue(Action.NAME));
+			putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_X));
+		}
+
+		public void actionPerformed(ActionEvent e)
+		{
+			System.exit(0);
+		}
+	}
+
+	/*
+	 *  Build a GUI using the content pane and menu bar of UIManagerDefaults
+	 */
+	private static void createAndShowGUI()
+	{
+		UIManagerDefaults application = new UIManagerDefaults();
+
+		JFrame.setDefaultLookAndFeelDecorated(true);
+   		JFrame frame = new JFrame("UIManager Defaults");
+		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+		frame.setJMenuBar( application.getMenuBar() );
+  		frame.getContentPane().add(application.getContentPane());
+		frame.pack();
+		frame.setLocationRelativeTo( null );
+		frame.setVisible( true );
+	}
+
+	/*
+	 *  UIManagerDefaults Main. Called only if we're an application.
+	 */
+	public static void main(String[] args)
+	{
+		SwingUtilities.invokeLater(new Runnable()
+		{
+			public void run()
+			{
+				createAndShowGUI();
+			}
+		});
+	}
+}



More information about the Schmitzm-commits mailing list