001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package javax.swing;
018:
019: import java.awt.Color;
020: import java.awt.Dimension;
021: import java.awt.Font;
022: import java.awt.Insets;
023: import java.awt.KeyboardFocusManager;
024: import java.beans.PropertyChangeListener;
025: import java.io.File;
026: import java.io.FileInputStream;
027: import java.io.IOException;
028: import java.io.Serializable;
029: import java.util.ArrayList;
030: import java.util.Arrays;
031: import java.util.HashSet;
032: import java.util.LinkedList;
033: import java.util.List;
034: import java.util.Locale;
035: import java.util.Properties;
036: import java.util.Set;
037:
038: import javax.swing.border.Border;
039: import javax.swing.event.SwingPropertyChangeSupport;
040: import javax.swing.plaf.ComponentUI;
041: import javax.swing.plaf.multi.MultiLookAndFeel;
042:
043: import org.apache.harmony.x.swing.Utilities;
044:
045: import org.apache.harmony.x.swing.internal.nls.Messages;
046:
047: /**
048: * <p>
049: * <i>UIManager</i>
050: * </p>
051: * <h3>Implementation Notes:</h3>
052: * <ul>
053: * <li>The <code>serialVersionUID</code> fields are explicitly declared as
054: * a performance optimization, not as a guarantee of serialization
055: * compatibility.</li>
056: * </ul>
057: */
058: public class UIManager implements Serializable {
059: private static final long serialVersionUID = -7909287654867514204L;
060:
061: public static class LookAndFeelInfo {
062: private String name;
063: private String className;
064:
065: public LookAndFeelInfo(final String name, final String className) {
066: this .name = name;
067: this .className = className;
068: }
069:
070: @Override
071: public String toString() {
072: return this .getClass().getName() + "[" + name + " "
073: + className + "]";
074: }
075:
076: public String getName() {
077: return name;
078: }
079:
080: public String getClassName() {
081: return className;
082: }
083:
084: @Override
085: public boolean equals(final Object object) {
086: if (object == null) {
087: return false;
088: }
089: if (!(object instanceof LookAndFeelInfo)) {
090: return false;
091: }
092: LookAndFeelInfo info = (LookAndFeelInfo) object;
093:
094: return getName() != null
095: && getName().equals(info.getName())
096: && getClassName() != null
097: && getClassName().equals(info.getClassName());
098: }
099: }
100:
101: private static final String PROPERTIES_FILE_PATH = System
102: .getProperty("java.home")
103: + File.separator
104: + "lib"
105: + File.separator
106: + "swing.properties";
107:
108: private static final String METAL_LOOK_AND_FEEL_CLASS = "javax.swing.plaf.metal.MetalLookAndFeel";
109:
110: private static final String DEFAULT_LAF = "swing.defaultlaf";
111: private static final String SYSTEM_LAF = "swing.systemlaf";
112: private static final String CROSSPLATFORM_LAF = "swing.crossplatformlaf";
113: private static final String INSTALLED_LAFS = "swing.installedlafs";
114: private static final String INSTALLED_LAF = "swing.installedlaf";
115: private static final String AUXILIARY_LAFS = "swing.auxiliarylaf";
116: private static final String MULTIPLEXING_LAF = "swing.plaf.multiplexinglaf";
117:
118: private static final String LOOK_AND_FEEL_PROPERTY = "lookAndFeel";
119:
120: private static final LookAndFeelInfo[] ALL_LFS = new LookAndFeelInfo[] { new LookAndFeelInfo(
121: "Metal", METAL_LOOK_AND_FEEL_CLASS) };
122:
123: private static LookAndFeel lookAndFeel;
124: private static UIDefaults uiDefaults = new UIDefaults();
125: private static Properties props;
126: private static List<LookAndFeelInfo> installedLFs;
127: private static SwingPropertyChangeSupport propertyChangeSupport = new SwingPropertyChangeSupport(
128: UIManager.class);
129: private static UIDefaults userUIDefaults;
130: private static LookAndFeel multiplexingLaf;
131: private static final Set<LookAndFeel> auxillaryLafs = new HashSet<LookAndFeel>();
132:
133: static {
134: initialize();
135: }
136:
137: public static Border getBorder(final Object obj, final Locale locale) {
138: return getDefaults().getBorder(obj, locale);
139: }
140:
141: public static Border getBorder(final Object obj) {
142: return getDefaults().getBorder(obj);
143: }
144:
145: public static Icon getIcon(final Object obj, final Locale locale) {
146: return getDefaults().getIcon(obj, locale);
147: }
148:
149: public static Icon getIcon(final Object obj) {
150: return getDefaults().getIcon(obj);
151: }
152:
153: public static String getString(final Object obj) {
154: return getDefaults().getString(obj);
155: }
156:
157: public static String getString(final Object obj, final Locale locale) {
158: return getDefaults().getString(obj, locale);
159: }
160:
161: public static Font getFont(final Object obj, final Locale locale) {
162: return getDefaults().getFont(obj, locale);
163: }
164:
165: public static Font getFont(final Object obj) {
166: return getDefaults().getFont(obj);
167: }
168:
169: public static Color getColor(final Object obj, final Locale locale) {
170: return getDefaults().getColor(obj, locale);
171: }
172:
173: public static Color getColor(final Object obj) {
174: return getDefaults().getColor(obj);
175: }
176:
177: public static int getInt(final Object obj, final Locale locale) {
178: return getDefaults().getInt(obj, locale);
179: }
180:
181: public static int getInt(final Object obj) {
182: return getDefaults().getInt(obj);
183: }
184:
185: public static Insets getInsets(final Object obj) {
186: return getDefaults().getInsets(obj);
187: }
188:
189: public static Insets getInsets(final Object obj, final Locale locale) {
190: return getDefaults().getInsets(obj, locale);
191: }
192:
193: public static Dimension getDimension(final Object obj) {
194: return getDefaults().getDimension(obj);
195: }
196:
197: public static Dimension getDimension(final Object obj,
198: final Locale locale) {
199: return getDefaults().getDimension(obj, locale);
200: }
201:
202: public static boolean getBoolean(final Object obj) {
203: return getDefaults().getBoolean(obj);
204: }
205:
206: public static boolean getBoolean(final Object obj,
207: final Locale locale) {
208: return getDefaults().getBoolean(obj, locale);
209: }
210:
211: public static Object get(final Object obj, final Locale locale) {
212: return getDefaults().get(obj, locale);
213: }
214:
215: public static Object put(final Object key, final Object obj) {
216: return getUserUIDefaults().put(key, obj);
217: }
218:
219: public static ComponentUI getUI(final JComponent comp) {
220: if ((multiplexingLaf != null)
221: && (!auxillaryLafs.isEmpty())
222: && (multiplexingLaf.getDefaults().get(
223: comp.getUIClassID()) != null)) {
224: /*
225: * Note that multiplexingLaf.getDefaults().getUI(comp) may return UI
226: * from defaultlaf if threre are no auxiliary UIs for the comp
227: */
228: return multiplexingLaf.getDefaults().getUI(comp);
229: }
230: return getDefaults().getUI(comp);
231: }
232:
233: public static Object get(final Object obj) {
234: return getDefaults().get(obj);
235: }
236:
237: public static void installLookAndFeel(final String name,
238: final String className) {
239: installLookAndFeel(new LookAndFeelInfo(name, className));
240: }
241:
242: public static void setInstalledLookAndFeels(
243: final LookAndFeelInfo[] lfs) {
244: installedLFs = new LinkedList<LookAndFeelInfo>(Arrays
245: .asList(lfs));
246: }
247:
248: public static void installLookAndFeel(final LookAndFeelInfo lfInfo) {
249: if (installedLFs == null) {
250: installedLFs = new LinkedList<LookAndFeelInfo>();
251: }
252: installedLFs.add(lfInfo);
253: }
254:
255: public static LookAndFeelInfo[] getInstalledLookAndFeels() {
256: return installedLFs.toArray(new LookAndFeelInfo[installedLFs
257: .size()]);
258: }
259:
260: public static UIDefaults getLookAndFeelDefaults() {
261: return lookAndFeel.getDefaults();
262: }
263:
264: public static UIDefaults getDefaults() {
265: return uiDefaults;
266: }
267:
268: public static void setLookAndFeel(final String str)
269: throws ClassNotFoundException, InstantiationException,
270: IllegalAccessException, UnsupportedLookAndFeelException {
271: setLookAndFeel((LookAndFeel) Class.forName(str, false,
272: ClassLoader.getSystemClassLoader()).newInstance());
273: }
274:
275: public static void setLookAndFeel(LookAndFeel laf)
276: throws UnsupportedLookAndFeelException {
277: if (laf == lookAndFeel) {
278: return;
279: }
280: if (!laf.isSupportedLookAndFeel()) {
281: throw new UnsupportedLookAndFeelException(Messages
282: .getString("swing.2E", laf)); //$NON-NLS-1$
283: }
284: LookAndFeel oldValue = lookAndFeel;
285: if (lookAndFeel != null) {
286: lookAndFeel.uninitialize();
287: }
288: lookAndFeel = laf;
289: lookAndFeel.initialize();
290:
291: final UIDefaults uiDefs = lookAndFeel.getDefaults();
292: uiDefaults = new UIDefaults() {
293: private static final long serialVersionUID = -4220137347255884538L;
294:
295: @Override
296: public Object get(final Object key, final Locale locale) {
297: Object result = getUserUIDefaults().get(key, locale);
298: if (result != null) {
299: return result;
300: }
301: result = uiDefs != null ? uiDefs.get(key, locale)
302: : null;
303: if (result != null) {
304: return result;
305: }
306:
307: return super .get(key, locale);
308: }
309:
310: @Override
311: public Object put(final Object key, final Object value) {
312: return UIManager.put(key, value);
313: }
314:
315: @Override
316: public synchronized void clear() {
317: getUserUIDefaults().clear();
318: }
319: };
320:
321: propertyChangeSupport.firePropertyChange(
322: LOOK_AND_FEEL_PROPERTY, oldValue, laf);
323: }
324:
325: /**
326: * Adds the auxiliary look and feel if the look and feel hasn't been added
327: * before.
328: */
329: public static void addAuxiliaryLookAndFeel(final LookAndFeel lf) {
330: if ((lf.isSupportedLookAndFeel())
331: && (auxillaryLafs.add(lf)/* <-The addition goes here */)) {
332: /*
333: * Initialization of mutiplexing laf placed here due to relatively
334: * small amount of progrmas uses multiplexing. So, the multi look and feel
335: * defined only if there is any auxiliary laf
336: */
337: if (multiplexingLaf == null) {
338: multiplexingLaf = getMultiPlexingLaf();
339: }
340: }
341: }
342:
343: public static boolean removeAuxiliaryLookAndFeel(
344: final LookAndFeel lf) {
345: return auxillaryLafs.remove(lf);
346: }
347:
348: public static LookAndFeel[] getAuxiliaryLookAndFeels() {
349: return auxillaryLafs.toArray(new LookAndFeel[] {});
350: }
351:
352: public static LookAndFeel getLookAndFeel() {
353: return lookAndFeel;
354: }
355:
356: public static String getSystemLookAndFeelClassName() {
357: String result = (String) getProperty(SYSTEM_LAF, null);
358: if (result != null) {
359: return result;
360: }
361:
362: String lfClass = getSystemLFClassFromCustomList();
363: if (lfClass != null) {
364: return lfClass;
365: }
366:
367: return getCrossPlatformLookAndFeelClassName();
368: }
369:
370: public static String getCrossPlatformLookAndFeelClassName() {
371: return (String) getProperty(CROSSPLATFORM_LAF,
372: METAL_LOOK_AND_FEEL_CLASS);
373: }
374:
375: public static void removePropertyChangeListener(
376: final PropertyChangeListener l) {
377: propertyChangeSupport.removePropertyChangeListener(l);
378: }
379:
380: public static void addPropertyChangeListener(
381: final PropertyChangeListener l) {
382: propertyChangeSupport.addPropertyChangeListener(l);
383: }
384:
385: public static PropertyChangeListener[] getPropertyChangeListeners() {
386: return propertyChangeSupport.getPropertyChangeListeners();
387: }
388:
389: /**
390: * Load properties from the swing.properties file
391: * @param String filePath
392: * @return Properties props
393: */
394: private static Properties loadSwingProperties() {
395: Properties result = new Properties();
396: try {
397: result.load(new FileInputStream(PROPERTIES_FILE_PATH));
398: } catch (final IOException ignored) {
399: }
400:
401: return result;
402: }
403:
404: private static void initialize() {
405: props = loadSwingProperties();
406: setDefaultLookAndFeel();
407: installedLFs = new ArrayList<LookAndFeelInfo>(
408: getDefaultInstalledLFs());
409: fillAuxillaryLafs();
410: KeyboardFocusManager.getCurrentKeyboardFocusManager()
411: .setDefaultFocusTraversalPolicy(
412: new LayoutFocusTraversalPolicy());
413: }
414:
415: private static void setDefaultLookAndFeel() {
416: try {
417: setLookAndFeel((String) getProperty(DEFAULT_LAF,
418: METAL_LOOK_AND_FEEL_CLASS));
419: } catch (final ClassNotFoundException e) {
420: e.printStackTrace();
421: } catch (final InstantiationException e) {
422: e.printStackTrace();
423: } catch (final IllegalAccessException e) {
424: e.printStackTrace();
425: } catch (final UnsupportedLookAndFeelException e) {
426: e.printStackTrace();
427: }
428: }
429:
430: private static Object getProperty(final String name,
431: final String defaultValue) {
432: String property = System.getProperty(name);
433: if (property != null) {
434: return property;
435: } else if ((props != null) && (props.containsKey(name))) {
436: return props.getProperty(name);
437: }
438:
439: return defaultValue;
440: }
441:
442: private static List<LookAndFeelInfo> getDefaultInstalledLFs() {
443: if (getProperty(INSTALLED_LAFS, null) != null) {
444: return getInstalledLFsFromPropertyFile();
445: }
446: List<LookAndFeelInfo> result = new LinkedList<LookAndFeelInfo>();
447: for (int i = 0; i < ALL_LFS.length; i++) {
448: try {
449: if (((LookAndFeel) Class.forName(
450: ALL_LFS[i].getClassName()).newInstance())
451: .isSupportedLookAndFeel()) {
452: result.add(ALL_LFS[i]);
453: }
454: } catch (Exception e) {
455: }
456: }
457: return result;
458: }
459:
460: /**
461: * Return the array of the installed properties from the swing.properties file
462: * Format:
463: * swing.installedlafs = <LF name0>,<LF name1>
464: * swing.installedlaf.<LF name0>.name = <LF name>
465: * swing.installedlaf.<LF name0>.class = <LF class>
466: * ...
467: * @return LookAndFeelInfo[]
468: */
469: private static List<LookAndFeelInfo> getInstalledLFsFromPropertyFile() {
470: String lfNames = props.getProperty(INSTALLED_LAFS);
471: if (lfNames == null) {
472: return new LinkedList<LookAndFeelInfo>();
473: }
474: String[] names = lfNames.split(",");
475: List<LookAndFeelInfo> result = new LinkedList<LookAndFeelInfo>();
476: for (int i = 0; i < names.length; i++) {
477: String token = names[i];
478: String lfNameProperty = new StringBuffer(INSTALLED_LAF)
479: .append(".").append(token).append(".name")
480: .toString();
481: String lfClassProperty = new StringBuffer(INSTALLED_LAF)
482: .append(".").append(token).append(".class")
483: .toString();
484:
485: String lfName = props.getProperty(lfNameProperty);
486: String lfClass = props.getProperty(lfClassProperty);
487:
488: if (!Utilities.isEmptyString(lfName)
489: && !Utilities.isEmptyString(lfClass)) {
490: result.add(new LookAndFeelInfo(lfName, lfClass));
491: }
492: }
493:
494: return result;
495: }
496:
497: private static String getSystemLFClassFromCustomList() {
498: LookAndFeelInfo[] installedLookAndFeels = getInstalledLookAndFeels();
499: for (int i = 0; i < installedLookAndFeels.length; i++) {
500: try {
501: String className = installedLookAndFeels[i].className;
502: LookAndFeel lf = (LookAndFeel) Class.forName(className)
503: .newInstance();
504: if (lf.isNativeLookAndFeel()) {
505: return className;
506: }
507: } catch (final Exception ignored) {
508: }
509: }
510:
511: return null;
512: }
513:
514: /**
515: * Verifies the "swing.plaf.multiplexinglaf" and sets the defined look and
516: * feel as multiplexing. In the case of error of the property is undefined
517: * returns defaulr multiplexing laf
518: *
519: * @return the look and feel used as Multiplexing
520: */
521: private static LookAndFeel getMultiPlexingLaf() {
522: if (props.getProperty(MULTIPLEXING_LAF) != null) {
523: try {
524: return (LookAndFeel) Class.forName(MULTIPLEXING_LAF,
525: false, ClassLoader.getSystemClassLoader())
526: .newInstance();
527: } catch (Exception ignored) {
528: // Compartibility
529: }
530: }
531: return new MultiLookAndFeel();
532: }
533:
534: /**
535: * The private method used while UIManager initialization to obtain
536: * auxillary look and feels if any
537: */
538: private static void fillAuxillaryLafs() {
539: String auxProperty = props.getProperty(AUXILIARY_LAFS);
540: if (auxProperty != null) {
541: for (String auxLafName : auxProperty.split(",")) { //$NON-NLS-1$
542: try {
543: addAuxiliaryLookAndFeel((LookAndFeel) Class
544: .forName(auxLafName, false,
545: ClassLoader.getSystemClassLoader())
546: .newInstance());
547: } catch (Exception ignored) {
548: // Compartibility
549: }
550: }
551: }
552: }
553:
554: /**
555: * Default values specified by user
556: * @return UIDefaults userUIDefaults
557: */
558: private static UIDefaults getUserUIDefaults() {
559: if (userUIDefaults == null) {
560: userUIDefaults = new UIDefaults();
561: }
562:
563: return userUIDefaults;
564: }
565: }
|