001 /* JAPI - (Yet another (hopefully) useful) Java API 002 * 003 * Copyright (C) 2004-2006 Christian Hujer 004 * 005 * This program is free software; you can redistribute it and/or 006 * modify it under the terms of the GNU General Public License as 007 * published by the Free Software Foundation; either version 2 of the 008 * License, or (at your option) any later version. 009 * 010 * This program is distributed in the hope that it will be useful, but 011 * WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013 * General Public License for more details. 014 * 015 * You should have received a copy of the GNU General Public License 016 * along with this program; if not, write to the Free Software 017 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 018 * 02111-1307, USA. 019 */ 020 021 package net.sf.japi.swing; 022 023 import java.awt.Component; 024 import java.awt.event.ActionEvent; 025 import java.util.ArrayList; 026 import java.util.List; 027 import java.util.logging.Level; 028 import java.util.logging.Logger; 029 import javax.swing.AbstractAction; 030 import javax.swing.ButtonGroup; 031 import javax.swing.JCheckBoxMenuItem; 032 import javax.swing.JDialog; 033 import javax.swing.JFrame; 034 import javax.swing.JMenu; 035 import javax.swing.JRadioButtonMenuItem; 036 import javax.swing.UIManager; 037 import static javax.swing.SwingUtilities.updateComponentTreeUI; 038 import static javax.swing.UIManager.getInstalledLookAndFeels; 039 import static javax.swing.UIManager.getLookAndFeel; 040 import static javax.swing.UIManager.installLookAndFeel; 041 import static javax.swing.UIManager.setLookAndFeel; 042 043 /** A class that manages look and feel and provides a corresponding menu. 044 * If you want your frames and dialogs to be default look and feel decorated, you currently must invoke the corresponding method {@link 045 * #setDefaultLookAndFeelDecorated(boolean)} before creating any instances of JFrame or JDialog. 046 * @todo find a method to update the isDefaultLookAndFeelDecorated state of Frames. 047 * @todo perhaps this class should be more a component manager than just a LookAndFeelManager? 048 * @author <a href="mailto:chris@riedquat.de">Christian Hujer</a> 049 */ 050 public final class LookAndFeelManager { 051 052 /** The Root Component(s) for which to update the look and feel. */ 053 private final List<Component> roots = new ArrayList<Component>(); 054 055 /** Action for look and feel decoration change. */ 056 private final LAFDecoAction lafDecoAction = new LAFDecoAction(); 057 058 static { 059 try { 060 installLookAndFeel("Windows", "net.sf.japi.swing.WindowsLookAndFeel"); 061 } catch (final Exception e) { 062 Logger.getLogger("net.sf.japi").log(Level.INFO, "lafUnavailable", e); 063 } 064 JFrame.setDefaultLookAndFeelDecorated(true); 065 JDialog.setDefaultLookAndFeelDecorated(true); 066 } 067 068 /** Create a LookAndFeelManager. */ 069 public LookAndFeelManager() { 070 } 071 072 /** Add a Component to the roots. 073 * @param comp Component to add to the roots 074 */ 075 public void add(final Component comp) { 076 if (comp != null && !roots.contains(comp)) { 077 roots.add(comp); 078 } 079 } 080 081 /** Provide a menu which allows the user to choose from installed look and feels. 082 * @return menu with selectable look and feels 083 */ 084 public JMenu createMenu() { 085 return fillMenu(new JMenu(ActionFactory.getFactory("net.sf.japi.swing").createAction(true, "laf"))); 086 } 087 088 /** Fill a menu with look and feel selection items. 089 * @param menu Menu to fill 090 * @return menu for convenience 091 */ 092 public JMenu fillMenu(final JMenu menu) { 093 final String active = getLookAndFeel().getClass().getName(); 094 final ButtonGroup bg = new ButtonGroup(); 095 for (final UIManager.LookAndFeelInfo lafInfo : getInstalledLookAndFeels()) { 096 final JRadioButtonMenuItem mi = new JRadioButtonMenuItem(new LAFAction(lafInfo)); // TODO: Cache LAFActions 097 if (lafInfo.getClassName().equals(active)) { 098 mi.setSelected(true); 099 } 100 bg.add(mi); 101 menu.add(mi); 102 } 103 menu.add(lafDecoAction.createJCheckBoxMenuItem()); 104 return menu; 105 } 106 107 /** Remove a Component to the roots. 108 * @param comp Component to remove from the roots 109 */ 110 public void remove(final Component comp) { 111 roots.remove(comp); 112 } 113 114 /** Set whether JFrames and JDialogs should use the default look and feel decoration. 115 * Also updates all JFrames and JDialogs managed. 116 * @param defaultLookAndFeelDecorated <code>true</code> for decoration from default look and feel, <code>false</code> for decoration from os 117 * @see JFrame#setDefaultLookAndFeelDecorated(boolean) 118 * @see JDialog#setDefaultLookAndFeelDecorated(boolean) 119 */ 120 public void setDefaultLookAndFeelDecorated(final boolean defaultLookAndFeelDecorated) { 121 JFrame.setDefaultLookAndFeelDecorated(defaultLookAndFeelDecorated); 122 JDialog.setDefaultLookAndFeelDecorated(defaultLookAndFeelDecorated); 123 for (final Component comp : roots) { 124 if (comp instanceof JFrame || comp instanceof JDialog) { 125 updateComponentTreeUI(comp); 126 } 127 } 128 } 129 130 /** LookAndFeel Change Action. 131 * @author $Author: christianhujer $ 132 * @version $Id: LookAndFeelManager.java,v 1.8 2006/03/13 00:34:51 christianhujer Exp $ 133 */ 134 private final class LAFAction extends AbstractAction { 135 136 /** Serial Version. */ 137 @SuppressWarnings({"AnalyzingVariableNaming"}) 138 private static final long serialVersionUID = 1L; 139 140 /** Class name of look and feel. 141 * @serial include 142 */ 143 private final String className; 144 145 /** Create a LAFAction. 146 * @param lafInfo LookAndFeelInfo 147 */ 148 LAFAction(final UIManager.LookAndFeelInfo lafInfo) { 149 putValue(NAME, lafInfo.getName()); 150 className = lafInfo.getClassName(); 151 } 152 153 /** {@inheritDoc} */ 154 public void actionPerformed(final ActionEvent e) { 155 //noinspection CatchGenericClass,OverlyBroadCatchBlock 156 try { 157 setLookAndFeel(className); 158 for (final Component comp : roots) { 159 updateComponentTreeUI(comp); 160 } 161 } catch (final Exception ex) { 162 System.err.println(ex); 163 } 164 } 165 166 /** {@inheritDoc} */ 167 @Override protected Object clone() throws CloneNotSupportedException { 168 return super.clone(); 169 } 170 171 } // class LAFAction 172 173 /** LookAndFeelDecoration Action. */ 174 private final class LAFDecoAction extends AbstractAction { 175 176 /** Serial Version. */ 177 @SuppressWarnings({"AnalyzingVariableNaming"}) 178 private static final long serialVersionUID = 1L; 179 180 /** The list of JMenuItems created for this Action. */ 181 private final List<JCheckBoxMenuItem> menuItems = new ArrayList<JCheckBoxMenuItem>(); 182 183 /** {@inheritDoc} */ 184 public void actionPerformed(final ActionEvent e) { 185 setDefaultLookAndFeelDecorated(!JFrame.isDefaultLookAndFeelDecorated()); 186 } 187 188 /** Set the default look and feel decoration state. 189 * @param defaultLookAndFeelDecorated <code>true</code> if default look and feel decorated, otherwise <code>false</code> 190 */ 191 private void setDefaultLookAndFeelDecorated(final boolean defaultLookAndFeelDecorated) { 192 LookAndFeelManager.this.setDefaultLookAndFeelDecorated(defaultLookAndFeelDecorated); 193 for (final JCheckBoxMenuItem menuItem : menuItems) { 194 menuItem.setSelected(defaultLookAndFeelDecorated); 195 } 196 } 197 198 /** Create a JCheckBoxMenuItem. 199 * @return JCHeckBoxMenuItem for the associated look and feel 200 */ 201 public JCheckBoxMenuItem createJCheckBoxMenuItem() { 202 final JCheckBoxMenuItem menuItem = new JCheckBoxMenuItem(this); 203 menuItems.add(menuItem); 204 return menuItem; 205 } 206 207 /** {@inheritDoc} */ 208 @Override protected Object clone() throws CloneNotSupportedException { 209 return super.clone(); 210 } 211 212 } // class LAFDecoAction 213 214 } // class LookAndFeelManager