001: package net.suberic.util.swing;
002:
003: import javax.swing.*;
004: import java.util.*;
005: import javax.swing.plaf.metal.*;
006:
007: import net.suberic.util.*;
008:
009: /**
010: * A class that allows one to apply arbitrary styles to individual
011: * Components.
012: */
013: public class ThemeManager implements ValueChangeListener, ItemCreator,
014: ItemListChangeListener {
015:
016: private ItemManager manager;
017: private WeakHashMap listenerList = new WeakHashMap();
018: private VariableBundle sourceBundle;
019: private String resourceString;
020:
021: /**
022: * Creates a ThemeManager.
023: */
024: public ThemeManager(String newResourceString, VariableBundle bundle) {
025: resourceString = newResourceString;
026: sourceBundle = bundle;
027: createThemes();
028: }
029:
030: /**
031: * Creates the Theme entries.
032: */
033: private void createThemes() {
034: manager = new ItemManager(resourceString, sourceBundle, this );
035: manager.addItemListChangeListener(this );
036: }
037:
038: /**
039: * Applies the given Theme to the component.
040: */
041: public void applyTheme(MetalTheme theme,
042: java.awt.Component component)
043: throws UnsupportedLookAndFeelException {
044: LookAndFeel laf = UIManager.getLookAndFeel();
045: if (laf instanceof MetalLookAndFeel) {
046: MetalLookAndFeel oldMlaf = ((MetalLookAndFeel) laf);
047: MetalTheme oldMt = getDefaultTheme();
048: // not that that really matters.
049:
050: if (theme != null) {
051: oldMlaf.setCurrentTheme(theme);
052: MetalLookAndFeel newMlaf = new MetalLookAndFeel();
053: UIManager.setLookAndFeel(newMlaf);
054: SwingUtilities.updateComponentTreeUI(component);
055: oldMlaf.setCurrentTheme(oldMt);
056: UIManager.setLookAndFeel(oldMlaf);
057: } else {
058: SwingUtilities.updateComponentTreeUI(component);
059: }
060: } else {
061: throw new UnsupportedLookAndFeelException(
062: "Expected MetalLookAndFeel, got "
063: + laf.getClass().getName());
064: }
065: }
066:
067: /**
068: * updates the given Component with the configuration from the given
069: * ThemeSupporter.
070: */
071: public void updateUI(ThemeSupporter ui, java.awt.Component component)
072: throws UnsupportedLookAndFeelException {
073: updateUI(ui, component, false);
074: }
075:
076: /**
077: * updates the given Component with the configuration from the given
078: * ThemeSupporter.
079: */
080: public void updateUI(ThemeSupporter ui,
081: java.awt.Component component, boolean force)
082: throws UnsupportedLookAndFeelException {
083: MetalTheme newTheme = ui.getTheme(this );
084: MetalTheme oldTheme = ui.getCurrentTheme();
085: if (!force) {
086: if (newTheme != oldTheme) {
087: applyTheme(newTheme, component);
088: ui.setCurrentTheme(newTheme);
089: }
090: } else {
091: applyTheme(newTheme, component);
092: if (newTheme != oldTheme) {
093: ui.setCurrentTheme(newTheme);
094: }
095: }
096: }
097:
098: /**
099: * Gets the default configuration for the system.
100: */
101: public MetalTheme getDefaultTheme() {
102: String defaultString = sourceBundle.getProperty(resourceString
103: + "._default", "");
104: if (defaultString != null && !defaultString.equals("")) {
105: return getTheme(defaultString);
106: }
107:
108: return null;
109: }
110:
111: /**
112: * Gets the named configuration, or null if no such configuration
113: * exists.
114: */
115: public MetalTheme getTheme(String configID) {
116: if (configID == null)
117: return null;
118:
119: Item returnValue = manager.getItem(configID);
120: if (returnValue == null)
121: return null;
122: else if (returnValue instanceof MetalTheme)
123: return (MetalTheme) returnValue;
124: else if (returnValue instanceof ThemeWrapperItem)
125: return ((ThemeWrapperItem) returnValue).getWrappedTheme();
126: else
127: return null;
128:
129: //return (MetalTheme) manager.getItem(configID);
130: }
131:
132: /**
133: * Called when a ui value changes.
134: */
135: public void valueChanged(String changedValue) {
136:
137: }
138:
139: /**
140: * As defined in net.suberic.util.ItemListChangeListener.
141: *
142: * This listens for ItemListChangeEvents, which result from changes to the
143: * resourceString property. The result is just that the event is passed
144: * to listeners to this object.
145: */
146: public void itemListChanged(ItemListChangeEvent e) {
147: fireItemListChanged(e);
148: }
149:
150: /**
151: * This notifies all listeners that the Theme list has changed.
152: */
153: public void fireItemListChanged(ItemListChangeEvent e) {
154: Iterator iter = listenerList.keySet().iterator();
155: while (iter.hasNext())
156: ((ItemListChangeListener) iter.next()).itemListChanged(e);
157: }
158:
159: /**
160: * This adds a listener.
161: */
162: public void addItemListListener(ItemListChangeListener newListener) {
163: listenerList.put(newListener, null);
164: }
165:
166: /**
167: * This removes a listener.
168: */
169: public void removeItemListListener(
170: ItemListChangeListener oldListener) {
171: listenerList.remove(oldListener);
172: }
173:
174: /**
175: * Creates an item from the given sourceBundle, resourceString, and itemId.
176: *
177: * Creates a new Theme object.
178: */
179: public Item createItem(VariableBundle sourceBundle,
180: String resourceString, String itemId) {
181: if (itemId != null && itemId.equals("Ocean")) {
182: ThemeWrapperItem wrapper = new ThemeWrapperItem(
183: sourceBundle, resourceString, itemId);
184: try {
185: Class oceanThemeClass = Class
186: .forName("javax.swing.plaf.metal.OceanTheme");
187: MetalTheme oceanTheme = (MetalTheme) oceanThemeClass
188: .newInstance();
189: wrapper.setWrappedTheme(oceanTheme);
190: return wrapper;
191: } catch (Exception e) {
192: // probably not in jdk 1.5. ignore.
193: }
194: }
195:
196: return new ConfigurableMetalTheme(sourceBundle, resourceString,
197: itemId);
198: }
199:
200: }
|