001: package abbot.editor;
002:
003: import java.awt.*;
004: import java.awt.event.*;
005: import javax.swing.*;
006: import java.util.*;
007:
008: import abbot.util.*;
009:
010: /** Preserves the current LAF for a given component hierarchy. */
011: public class LookAndFeelPreserver {
012: private LookAndFeel laf;
013: private Map owned = new WeakHashMap();
014: /** Avoid GC of weak reference. */
015: private AWTEventListener listener;
016:
017: private Frame frame;
018: /** This panel detects any global attempts to set the UI for all
019: components. It can then restore the proper LAF for all registered
020: components. We use this pseudo-listener instead of listening to a
021: "lookAndFeel" property change since the UI components may have
022: updateUI called an arbitrary time (or not at all) after
023: UIManager.setLookAndFeel is called (which triggers the property change
024: notification).
025: */
026: private JPanel trigger;
027:
028: public LookAndFeelPreserver(Component c) {
029: this (UIManager.getLookAndFeel(), c);
030: }
031:
032: public LookAndFeelPreserver(final LookAndFeel laf, Component c) {
033: this .laf = laf;
034: add(c);
035: listener = new AWTEventListener() {
036: public void eventDispatched(AWTEvent e) {
037: if (e.getID() == ContainerEvent.COMPONENT_ADDED) {
038: componentAdded(((ContainerEvent) e).getChild());
039: }
040: }
041: };
042: new WeakAWTEventListener(listener,
043: AWTEvent.CONTAINER_EVENT_MASK);
044: String name = "updateComponentTreeUI Listener";
045: frame = new Frame(name);
046: frame.setName(name);
047: trigger = new JPanel() {
048: private boolean initialized;
049: {
050: initialized = true;
051: }
052:
053: public void updateUI() {
054: if (initialized) {
055: SwingUtilities.invokeLater(new LAFRestorer(laf,
056: owned));
057: }
058: }
059: };
060: frame.add(trigger);
061: }
062:
063: /** Add a component on which to preserve the LAF. */
064: public void add(final Component c) {
065: owned.put(c, Boolean.TRUE);
066: if (c instanceof Window) {
067: Window[] subs = ((Window) c).getOwnedWindows();
068: for (int i = 0; i < subs.length; i++) {
069: add(subs[i]);
070: }
071: }
072: }
073:
074: private void componentAdded(Component c) {
075: Window w = AWT.getWindow(c);
076: if (w != null) {
077: if (owned.containsKey(w)
078: || owned.containsKey(w.getParent())) {
079: if (!owned.containsKey(w))
080: add(w);
081: SwingUtilities.invokeLater(new LAFRestorer(laf, c));
082: }
083: }
084: }
085:
086: private static class LAFRestorer implements Runnable {
087: private LookAndFeel laf;
088: private Map map;
089:
090: public LAFRestorer(LookAndFeel laf, Component c) {
091: this (laf, new WeakHashMap());
092: map.put(c, Boolean.TRUE);
093: }
094:
095: public LAFRestorer(LookAndFeel laf, Map map) {
096: this .laf = laf;
097: this .map = map;
098: }
099:
100: public void run() {
101: LookAndFeel current = UIManager.getLookAndFeel();
102: if (current != laf && current != null
103: && !current.equals(laf)) {
104: try {
105: UIManager.setLookAndFeel(laf);
106: Iterator iter = map.keySet().iterator();
107: while (iter.hasNext()) {
108: Component c = (Component) iter.next();
109: SwingUtilities.updateComponentTreeUI(c);
110: }
111: UIManager.setLookAndFeel(current);
112: } catch (UnsupportedLookAndFeelException e) {
113: // ignore
114: }
115: }
116: }
117: }
118: }
|