package test; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.KeyEvent; import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.TreeMap; import javax.swing.AbstractAction; import javax.swing.AbstractButton; import javax.swing.Action; import javax.swing.ButtonGroup; import javax.swing.DefaultButtonModel; import javax.swing.DefaultComboBoxModel; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JRadioButton; import javax.swing.JRadioButtonMenuItem; import javax.swing.JRootPane; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.LookAndFeel; import javax.swing.Painter; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.UIDefaults; import javax.swing.UIManager; import javax.swing.border.Border; import javax.swing.border.EmptyBorder; import javax.swing.plaf.ColorUIResource; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableCellRenderer; import org.pushingpixels.substance.api.SubstanceLookAndFeel; import org.pushingpixels.substance.api.skin.SubstanceBusinessLookAndFeel; import org.pushingpixels.substance.api.skin.SubstanceMarinerLookAndFeel; /** * * http://www.camick.com/java/source/UIManagerDefaults.java */ public class UIManagerDefaults implements ActionListener, ItemListener { private final static String[] COLUMN_NAMES = {"Key", "Value", "Sample"}; private static String selectedItem; private final JComponent contentPane; private JMenuBar menuBar; private JComboBox comboBox; private JRadioButton byComponent; private JTable table; private final TreeMap<String, TreeMap<String, Object>> items; private final 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 */ private void resetComponents() { items.clear(); models.clear(); ((DefaultTableModel) table.getModel()).setRowCount(0); buildItemsMap(); List<String> comboBoxItems = new ArrayList<String>(50); Iterator keys = items.keySet().iterator(); while (keys.hasNext()) { Object key = keys.next(); comboBoxItems.add((String) key); } comboBox.removeAllItems(); comboBox.removeItemListener(this); comboBox.setModel(new DefaultComboBoxModel(comboBoxItems.toArray())); comboBox.setSelectedIndex(-1); comboBox.addItemListener(this); comboBox.requestFocusInWindow(); if (selectedItem != null && comboBoxItems.contains(selectedItem)) { System.out.println(" >> selectedItem : " + selectedItem); System.out.println(" >> comboBoxItems : "); for (String s : comboBoxItems) { System.out.println(" - " + s); } 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 = componentNameEndOffset(key); 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 int componentNameEndOffset(String key) { // Handle Nimbus properties first // "ComboBox.scrollPane", "Table.editor" and "Tree.cellEditor" // have different format even within the Nimbus properties. // (the component name is specified in quotes) if (key.startsWith("\"")) { return key.indexOf("\"", 1) + 1; } int pos = key.indexOf(":"); if (pos != -1) { return pos; } pos = key.indexOf("["); if (pos != -1) { return pos; } // Handle normal properties return key.indexOf("."); } 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 (value instanceof Painter) { return "Painter"; } 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 mb = new JMenuBar(); mb.add(createFileMenu()); mb.add(createLAFMenu()); return mb; } /** * 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 lafMenu; private ButtonGroup lafButtonGroup; private String lafId; private JMenu createLAFMenu() { String lafCalssName; String lafName; lafButtonGroup = new ButtonGroup(); lafMenu = new JMenu("Look & Feel"); lafMenu.setMnemonic('L'); lafId = UIManager.getLookAndFeel().getID(); UIManager.installLookAndFeel("Substance Business", SubstanceBusinessLookAndFeel.class.getName()); UIManager.installLookAndFeel("Substance Mariner", SubstanceMarinerLookAndFeel.class.getName()); UIManager.LookAndFeelInfo[] lafInfo = UIManager.getInstalledLookAndFeels(); for (UIManager.LookAndFeelInfo lafInfo1 : lafInfo) { lafCalssName = lafInfo1.getClassName(); lafName = lafInfo1.getName(); Action action = new ChangeLookAndFeelAction(this, lafCalssName, lafName); JRadioButtonMenuItem mi = new JRadioButtonMenuItem(action); lafMenu.add(mi); lafButtonGroup.add(mi); if (lafName.equals(lafId)) { mi.setSelected(true); } } return lafMenu; } /* * Implement the ActionListener interface */ @Override public void actionPerformed(ActionEvent e) { selectedItem = null; resetComponents(); comboBox.requestFocusInWindow(); } /* * Implement the ItemListener interface */ @Override 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); List<Object> row = new ArrayList<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.toArray()); } 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 final 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() { private static final long serialVersionUID = 1L; }; ((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. */ private class SampleRenderer extends JLabel implements TableCellRenderer { private static final long serialVersionUID = 1L; public SampleRenderer() { super(); setHorizontalAlignment(SwingConstants.CENTER); setOpaque(true); } @Override 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. */ @Override 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. */ private class ChangeLookAndFeelAction extends AbstractAction { private static final long serialVersionUID = 1L; private final UIManagerDefaults defaults; private final 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)); } @Override public void actionPerformed(ActionEvent e) { try { defaults.resetComponents(); UIManager.setLookAndFeel(laf); 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); ex.printStackTrace(); } } } /* * Close the frame */ private class ExitAction extends AbstractAction { private static final long serialVersionUID = 1L; public ExitAction() { putValue(Action.NAME, "Exit"); putValue(Action.SHORT_DESCRIPTION, getValue(Action.NAME)); putValue(Action.MNEMONIC_KEY, KeyEvent.VK_X); } @Override 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() { @Override public void run() { createAndShowGUI(); } }); } }