001: package net.sourceforge.squirrel_sql.plugins.laf;
002:
003: /*
004: * Copyright (C) 2001-2006 Colin Bell
005: * colbell@users.sourceforge.net
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * as published by the Free Software Foundation; either version 2
010: * of the License, or any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
020: */
021: import java.awt.Frame;
022: import java.io.BufferedInputStream;
023: import java.io.File;
024: import java.io.FileInputStream;
025: import java.io.IOException;
026: import java.net.URL;
027: import java.util.ArrayList;
028: import java.util.HashMap;
029: import java.util.Iterator;
030: import java.util.List;
031: import java.util.Map;
032: import java.util.MissingResourceException;
033: import java.util.Properties;
034: import javax.swing.JDialog;
035: import javax.swing.JFrame;
036: import javax.swing.LookAndFeel;
037: import javax.swing.SwingUtilities;
038: import javax.swing.UIDefaults;
039: import javax.swing.UIManager;
040: import javax.swing.UnsupportedLookAndFeelException;
041: import javax.swing.UIManager.LookAndFeelInfo;
042: import net.sourceforge.squirrel_sql.fw.gui.FontInfo;
043: import net.sourceforge.squirrel_sql.fw.util.MyURLClassLoader;
044: import net.sourceforge.squirrel_sql.fw.util.log.ILogger;
045: import net.sourceforge.squirrel_sql.fw.util.log.LoggerController;
046: import net.sourceforge.squirrel_sql.client.IApplication;
047: import net.sourceforge.squirrel_sql.client.Version;
048: import net.sourceforge.squirrel_sql.client.plugin.PluginResources;
049:
050: /**
051: * Register of Look and Feels.
052: *
053: * @author <A HREF="mailto:colbell@users.sourceforge.net">Colin Bell</A>
054: */
055: class LAFRegister {
056: private final static int FONT_KEYS_ARRAY_OTHER = 0;
057: private final static int FONT_KEYS_ARRAY_MENU = 1;
058: private final static int FONT_KEYS_ARRAY_STATIC = 2;
059: /** Logger for this class. */
060: private static ILogger s_log = LoggerController
061: .createLogger(LAFRegister.class);
062: // TODO: What about these
063: // Viewport.font, ColorChooser.font, InternalFrame.font,
064: // OptionPane.font, "Panel.font",
065: // ScrollPane.font, DesktopIcon.font
066: private final static String[][] FONT_KEYS = {
067: // Editable Text
068: { "EditorPane.font", "List.font", "TextArea.font",
069: "TextField.font", "PasswordField.font",
070: "Table.font", "TableHeader.font", "TextPane.font",
071: "Tree.font", },
072: // Menus
073: { "CheckBoxMenuItem.acceleratorFont",
074: "CheckBoxMenuItem.font", "Menu.acceleratorFont",
075: "Menu.font", "MenuBar.font",
076: "MenuItem.acceleratorFont", "MenuItem.font",
077: "PopupMenu.font",
078: "RadioButtonMenuItem.acceleratorFont",
079: "RadioButtonMenuItem.font", },
080: // Static text
081: { "Button.font", "CheckBox.font", "ComboBox.font",
082: "InternalFrame.titleFont", "Label.font",
083: "ProgressBar.font", "RadioButton.font",
084: "TabbedPane.font", "TitledBorder.font",
085: "ToggleButton.font", "ToolBar.font",
086: "ToolTip.font", }, };
087: /** Application API. */
088: private IApplication _app;
089: /** Look and Feel plugin. */
090: private LAFPlugin _plugin;
091: /** Classloader for Look and Feel classes. */
092: private MyURLClassLoader _lafClassLoader;
093: /**
094: * Collection of <TT>ILookAndFeelController</TT> objects keyed by
095: * the Look and Feel class name.
096: */
097: private Map<String, ILookAndFeelController> _lafControllers = new HashMap<String, ILookAndFeelController>();
098: /**
099: * Default LAF controller. Used if a specialised one isn't available for
100: * the LAF in _lafControllers.
101: */
102: private ILookAndFeelController _dftLAFController = new DefaultLookAndFeelController();
103: /** <UI defaults prior to us modifying them. */
104: private UIDefaults _origUIDefaults;
105:
106: /**
107: * Ctor. Load all Look and Feels from the Look and Feel folder. Set the
108: * current Look and Feel to that specified in the application preferences.
109: *
110: * @param app Application API.
111: * @param plugin The LAF plugin.
112: *
113: * @throws IllegalArgumentException
114: * If <TT>IApplication</TT>, or <TT>LAFPlugin</TT> are <TT>null</TT>.
115: */
116: LAFRegister(IApplication app, LAFPlugin plugin)
117: throws IllegalArgumentException {
118: super ();
119: if (app == null) {
120: throw new IllegalArgumentException(
121: "Null IApplication passed");
122: }
123: if (plugin == null) {
124: throw new IllegalArgumentException("Null LAFPlugin passed");
125: }
126: _app = app;
127: _plugin = plugin;
128: // Save the current UI defaults.
129: _origUIDefaults = (UIDefaults) UIManager.getDefaults().clone();
130: installLookAndFeels();
131: installLookAndFeelControllers(plugin);
132: try {
133: applyPreferences();
134: setLookAndFeel(true);
135: } catch (Throwable ex) {
136: s_log.error("Error setting Look and Feel", ex);
137: }
138: try {
139: updateApplicationFonts();
140: } catch (Throwable ex) {
141: s_log.error("Error updating application fonts", ex);
142: }
143: }
144:
145: LAFPlugin getPlugin() {
146: return _plugin;
147: }
148:
149: /**
150: * Return the class loader used to load the Look and Feels.
151: *
152: * @return the ClassLoader used to load the look and feels.
153: */
154: ClassLoader getLookAndFeelClassLoader() {
155: return _lafClassLoader;
156: }
157:
158: /**
159: * Get a Look and Feel Controller for the passed L&F class name.
160: *
161: * @param lafClassName Look and Feel class name to get controller for.
162: *
163: * @return L&F Controller.
164: *
165: * @throws IllegalArgumentException Thrown if <TT>null</TT>
166: * <TT>lafClassName</TT> passed.
167: */
168: ILookAndFeelController getLookAndFeelController(String lafClassName) {
169: if (lafClassName == null) {
170: throw new IllegalArgumentException("lafClassName == null");
171: }
172: ILookAndFeelController ctrl = _lafControllers.get(lafClassName);
173: if (ctrl == null) {
174: ctrl = _dftLAFController;
175: }
176: return ctrl;
177: }
178:
179: /**
180: * Set the font that the application uses for statusbars.
181: */
182: void updateStatusBarFont() {
183: if (_plugin.getLAFPreferences().isStatusBarFontEnabled()) {
184: _app.getFontInfoStore().setStatusBarFontInfo(
185: _plugin.getLAFPreferences().getStatusBarFontInfo());
186: }
187: }
188:
189: /**
190: * Set the current Look and Feel to that specified in the app preferences.
191: */
192: void setLookAndFeel(boolean force) throws ClassNotFoundException,
193: IllegalAccessException, InstantiationException,
194: UnsupportedLookAndFeelException {
195: final LAFPreferences prefs = _plugin.getLAFPreferences();
196: final String lafClassName = prefs.getLookAndFeelClassName();
197: // Get Look and Feel class object.
198: Class<?> lafClass = null;
199: if (_lafClassLoader != null) {
200: lafClass = Class.forName(lafClassName, true,
201: _lafClassLoader);
202: } else {
203: lafClass = Class.forName(lafClassName);
204: }
205: // Get the new Look and Feel object.
206: final LookAndFeel laf = (LookAndFeel) lafClass.newInstance();
207: // If a different LAF to the current one has been requested then
208: // change to the requested LAF.
209: LookAndFeel curLaf = UIManager.getLookAndFeel();
210: s_log.debug(curLaf);
211: if (force || curLaf == null
212: || !curLaf.getName().equals(laf.getName())) {
213: ILookAndFeelController lafCont = getLookAndFeelController(lafClassName);
214: lafCont.aboutToBeInstalled(this , laf);
215:
216: // Set Look and Feel.
217: if (_lafClassLoader != null) {
218: UIManager.setLookAndFeel(laf);
219: UIManager.getLookAndFeelDefaults().put("ClassLoader",
220: _lafClassLoader);
221: } else {
222: UIManager.setLookAndFeel(laf);
223: }
224:
225: lafCont.hasBeenInstalled(this , laf);
226: updateAllFrames();
227: }
228: }
229:
230: void applyPreferences() {
231: final LAFPreferences prefs = _plugin.getLAFPreferences();
232: JFrame.setDefaultLookAndFeelDecorated(prefs
233: .getCanLAFSetBorder());
234: JDialog.setDefaultLookAndFeelDecorated(prefs
235: .getCanLAFSetBorder());
236: }
237:
238: /**
239: * Update the applications fonts.
240: */
241: void updateApplicationFonts() {
242: final LAFPreferences prefs = _plugin.getLAFPreferences();
243: FontInfo fi = prefs.getMenuFontInfo();
244: String[] keys = FONT_KEYS[FONT_KEYS_ARRAY_MENU];
245: for (int i = 0; i < keys.length; ++i) {
246: if (prefs.isMenuFontEnabled()) {
247: if (fi != null) {
248: UIManager.put(keys[i], fi.createFont());
249: }
250: } else {
251: UIManager
252: .put(keys[i], _origUIDefaults.getFont(keys[i]));
253: }
254: }
255: fi = prefs.getStaticFontInfo();
256: keys = FONT_KEYS[FONT_KEYS_ARRAY_STATIC];
257: for (int i = 0; i < keys.length; ++i) {
258: if (prefs.isStaticFontEnabled()) {
259: if (fi != null) {
260: UIManager.put(keys[i], fi.createFont());
261: }
262: } else {
263: UIManager
264: .put(keys[i], _origUIDefaults.getFont(keys[i]));
265: }
266: }
267: fi = prefs.getOtherFontInfo();
268: keys = FONT_KEYS[FONT_KEYS_ARRAY_OTHER];
269: for (int i = 0; i < keys.length; ++i) {
270: if (prefs.isOtherFontEnabled()) {
271: if (fi != null) {
272: UIManager.put(keys[i], fi.createFont());
273: }
274: } else {
275: UIManager
276: .put(keys[i], _origUIDefaults.getFont(keys[i]));
277: }
278: }
279: }
280:
281: /**
282: * Update all open frames for the new Look and Feel info.
283: */
284: private void updateAllFrames() {
285: Frame[] frames = Frame.getFrames();
286: if (frames != null) {
287: for (int i = 0; i < frames.length; ++i) {
288: SwingUtilities.updateComponentTreeUI(frames[i]);
289: frames[i].pack();
290: }
291: }
292: }
293:
294: /**
295: * Install Look and Feels from their jars.
296: */
297: private void installLookAndFeels() {
298: // Map of JAR file URLs containing LAFs keyed by the LAF class name.
299: final Map<String, URL> lafs = loadInstallProperties();
300: // Retrieve URLs of all the Look and Feel jars and store in lafUrls.
301: final List<URL> lafUrls = new ArrayList<URL>();
302: for (Iterator<URL> it = lafs.values().iterator(); it.hasNext();) {
303: lafUrls.add(it.next());
304: }
305: // Create a ClassLoader for all the LAF jars. Install all Look and Feels
306: // into the UIManager.
307: try {
308: URL[] urls = new URL[lafUrls.size()];
309: _lafClassLoader = new MyURLClassLoader(lafUrls
310: .toArray(urls));
311: for (Iterator<String> it = lafs.keySet().iterator(); it
312: .hasNext();) {
313: String className = it.next();
314: Class<?> lafClass = Class.forName(className, false,
315: _lafClassLoader);
316: try {
317: LookAndFeel laf = (LookAndFeel) lafClass
318: .newInstance();
319: if (laf.isSupportedLookAndFeel()) {
320: LookAndFeelInfo info = new LookAndFeelInfo(laf
321: .getName(), lafClass.getName());
322: UIManager.installLookAndFeel(info);
323: }
324: } catch (Throwable th) {
325: s_log.error("Error occured loading Look and Feel: "
326: + lafClass.getName(), th);
327: }
328: }
329: } catch (Throwable th) {
330: s_log
331: .error(
332: "Error occured trying to load Look and Feel classes",
333: th);
334: }
335: }
336:
337: /**
338: * Install the controllers for those LAFs that require them.
339: *
340: * @param plugin The LAF plugin.
341: */
342: private void installLookAndFeelControllers(LAFPlugin plugin) {
343: try {
344: _lafControllers.put(
345: SkinLookAndFeelController.SKINNABLE_LAF_CLASS_NAME,
346: new SkinLookAndFeelController(plugin));
347: } catch (Throwable ex) {
348: s_log.error("Error installing SkinLookAndFeelController",
349: ex);
350: }
351: try {
352: _lafControllers.put(
353: OyoahaLookAndFeelController.OA_LAF_CLASS_NAME,
354: new OyoahaLookAndFeelController(plugin));
355: } catch (Throwable ex) {
356: s_log.error("Error installing OyoahaLookAndFeelController",
357: ex);
358: }
359: try {
360: PlasticLookAndFeelController ctrl = new PlasticLookAndFeelController(
361: plugin, this );
362: String[] ar = PlasticLookAndFeelController.LAF_CLASS_NAMES;
363: for (int i = 0; i < ar.length; ++i) {
364: _lafControllers.put(ar[i], ctrl);
365: }
366: } catch (Throwable ex) {
367: s_log
368: .error(
369: "Error installing PlasticLookAndFeelController",
370: ex);
371: }
372: try {
373: MetalLookAndFeelController ctrl = new MetalLookAndFeelController(
374: plugin, this );
375: _lafControllers.put(
376: MetalLookAndFeelController.METAL_LAF_CLASS_NAME,
377: ctrl);
378: } catch (Throwable ex) {
379: s_log
380: .error(
381: "Error installing PlasticLookAndFeelController",
382: ex);
383: }
384: try {
385: _lafControllers.put(
386: TonicLookAndFeelController.TONIC_LAF_CLASS_NAME,
387: new TonicLookAndFeelController(plugin));
388: } catch (Throwable ex) {
389: s_log.error("Error installing SkinLookAndFeelController",
390: ex);
391: }
392: // Initialize all the LAF controllers.
393: for (Iterator<ILookAndFeelController> it = _lafControllers
394: .values().iterator(); it.hasNext();) {
395: it.next().initialize();
396: }
397: }
398:
399: /**
400: * Load the installation properties and return a <TT>Map</TT>
401: * keyed by the class name of the LAF and containing a URL to the jar file
402: * that contains the LAF.
403: *
404: * @return Map
405: */
406: private Map<String, URL> loadInstallProperties() {
407: Map<String, URL> lafs = new HashMap<String, URL>();
408: // Directory containing the standard LAF jar files.
409: final File stdLafJarDir = _plugin.getLookAndFeelFolder();
410: // Load info about the standard LAFs that come with this plugin.
411: PluginResources rsrc = _plugin.getResources();
412: for (int i = 0; /* forever */; ++i) {
413: try {
414: String className = rsrc
415: .getString(LAFPluginResources.IKeys.CLASSNAME
416: + i);
417: if (className == null || className.length() == 0) {
418: break;
419: }
420: String jarName = rsrc
421: .getString(LAFPluginResources.IKeys.JAR + i);
422: if (jarName == null || jarName.length() == 0) {
423: break;
424: }
425:
426: // Some LAFs don't work under Java 6 or later.
427: if (Version.isJDK16OrAbove()
428: && (jarName.equalsIgnoreCase("metouia.jar") || jarName
429: .equalsIgnoreCase("oalnf.jar"))) {
430: continue;
431: }
432:
433: File file = new File(stdLafJarDir, jarName);
434: try {
435: if (file.isFile() && file.exists()) {
436: lafs.put(className, file.toURL());
437: }
438: } catch (IOException ex) {
439: s_log.error(
440: "Error occured reading Look and Feel jar: "
441: + file.getAbsolutePath(), ex);
442: }
443: } catch (MissingResourceException ignore) {
444: // We have read in all properties.
445: break;
446: }
447: }
448: // Load info about any extra LAFs supplied by the user.
449: try {
450: final File extraLafsDir = _plugin.getUsersExtraLAFFolder();
451: File extraFile = new File(extraLafsDir,
452: ILAFConstants.USER_EXTRA_LAFS_PROPS_FILE);
453: BufferedInputStream is = new BufferedInputStream(
454: new FileInputStream(extraFile));
455: try {
456: Properties props = new Properties();
457: props.load(is);
458: for (int i = 0; /* forever */; ++i) {
459: String className = props
460: .getProperty(LAFPluginResources.IKeys.CLASSNAME
461: + i);
462: if (className == null || className.length() == 0) {
463: break;
464: }
465: String jarName = props
466: .getProperty(LAFPluginResources.IKeys.JAR
467: + i);
468: if (jarName == null || jarName.length() == 0) {
469: break;
470: }
471: File file = new File(extraLafsDir, jarName);
472: try {
473: if (file.isFile() && file.exists()) {
474: lafs.put(className, file.toURL());
475: }
476: } catch (IOException ex) {
477: s_log.error(
478: "Error occured reading Look and Feel jar: "
479: + file.getAbsolutePath(), ex);
480: }
481: }
482: } finally {
483: is.close();
484: }
485: } catch (IOException ex) {
486: s_log.error(
487: "Error occured loading extra LAFs property file",
488: ex);
489: }
490: return lafs;
491: }
492: }
|