001: package com.vividsolutions.jump.workbench.ui.toolbox;
002:
003: import java.awt.Component;
004: import java.awt.Container;
005: import java.awt.event.ActionEvent;
006: import java.awt.event.ActionListener;
007: import java.util.HashMap;
008: import java.util.Iterator;
009: import java.util.Map;
010: import java.util.Vector;
011:
012: import javax.swing.DefaultComboBoxModel;
013: import javax.swing.JComboBox;
014: import javax.swing.JToggleButton;
015: import javax.swing.SwingUtilities;
016: import javax.swing.event.InternalFrameAdapter;
017: import javax.swing.event.InternalFrameEvent;
018: import javax.swing.text.JTextComponent;
019:
020: import com.vividsolutions.jump.util.Blackboard;
021: import com.vividsolutions.jump.util.Block;
022: import com.vividsolutions.jump.util.LangUtil;
023: import com.vividsolutions.jump.util.OrderedMap;
024: import com.vividsolutions.jump.workbench.WorkbenchContext;
025: import com.vividsolutions.jump.workbench.model.LayerManager;
026: import com.vividsolutions.jump.workbench.ui.GUIUtil;
027: import com.vividsolutions.jump.workbench.ui.LayerComboBox;
028: import com.vividsolutions.jump.workbench.ui.WorkbenchFrame;
029: import com.vividsolutions.jump.workbench.ui.WorkbenchToolBar;
030:
031: /**
032: * Stores the state of the component and its descendants on the Blackboard of
033: * the LayerManager (if any) of the current JInternalFrame. Thus, when the
034: * user switches JInternalFrames, the component will change its state to reflect
035: * the new context.
036: * <p>
037: * Designed to be trivial to use: simply instantiate one if you want to use one.
038: * (Make sure the toolbox's Components are initialized first).
039: * Note that not all Components are supported; currently the ToolboxStateManager
040: * will save the state for the following components only: JTextComponent,
041: * JToggleButton (including JCheckBox), JComboBox.
042: */
043: public class ToolboxStateManager {
044: private static int keyIndex = 0;
045: private OrderedMap componentClassToStrategyMap = new OrderedMap() {
046:
047: {
048: put(JTextComponent.class, new Strategy() {
049: protected void addActionListener(
050: ActionListener actionListener,
051: Component component) {
052: ((JTextComponent) component)
053: .getDocument()
054: .addDocumentListener(
055: GUIUtil
056: .toDocumentListener(actionListener));
057: }
058:
059: protected Object getToolboxValue(Component component) {
060: return ((JTextComponent) component).getText();
061: }
062:
063: protected void setToolboxValue(Object value,
064: Component component) {
065: ((JTextComponent) component)
066: .setText((String) value);
067: }
068: });
069: put(JToggleButton.class, new Strategy() {
070: protected void addActionListener(
071: ActionListener actionListener,
072: Component component) {
073: ((JToggleButton) component)
074: .addActionListener(actionListener);
075: }
076:
077: protected Object getToolboxValue(Component component) {
078: return new Boolean(((JToggleButton) component)
079: .isSelected());
080: }
081:
082: protected void setToolboxValue(Object value,
083: Component component) {
084: ((JToggleButton) component)
085: .setSelected(((Boolean) value)
086: .booleanValue());
087: }
088: });
089: put(LayerComboBox.class, new Strategy() {
090: protected void addActionListener(
091: ActionListener actionListener,
092: Component component) {
093: ((LayerComboBox) component)
094: .getModel()
095: .addListDataListener(
096: GUIUtil
097: .toListDataListener(actionListener));
098: }
099:
100: protected Object getDefaultValue(
101: Object initialToolboxValue, Component component) {
102: LayerManager layerManager = (LayerManager) LangUtil
103: .ifNull(((WorkbenchFrame) SwingUtilities
104: .getAncestorOfClass(
105: WorkbenchFrame.class,
106: component)).getContext()
107: .getLayerManager(),
108: new LayerManager());
109: return new Object[] {
110: layerManager.size() > 0 ? layerManager
111: .iterator().next() : null,
112: layerManager };
113: }
114:
115: protected Object getToolboxValue(Component component) {
116: return new Object[] {
117: ((LayerComboBox) component)
118: .getSelectedItem(),
119: ((LayerComboBox) component)
120: .getLayerManager() };
121: }
122:
123: protected void setToolboxValue(Object value,
124: Component component) {
125: ((LayerComboBox) component)
126: .setLayerManager(((LayerManager) ((Object[]) value)[1]));
127: ((LayerComboBox) component)
128: .setSelectedItem(((Object[]) value)[0]);
129: }
130: });
131: put(JComboBox.class, new Strategy() {
132: protected void addActionListener(
133: ActionListener actionListener,
134: Component component) {
135: ((JComboBox) component)
136: .addActionListener(actionListener);
137: ((JComboBox) component)
138: .getModel()
139: .addListDataListener(
140: GUIUtil
141: .toListDataListener(actionListener));
142: }
143:
144: protected Object getToolboxValue(Component component) {
145: Vector items = new Vector();
146:
147: for (int i = 0; i < ((JComboBox) component)
148: .getItemCount(); i++) {
149: items.add(((JComboBox) component).getItemAt(i));
150: }
151:
152: return new Object[] {
153: ((JComboBox) component).getSelectedItem(),
154: items };
155: }
156:
157: protected void setToolboxValue(Object value,
158: Component component) {
159: ((JComboBox) component)
160: .setModel(new DefaultComboBoxModel(
161: ((Vector) ((Object[]) value)[1])));
162: ((JComboBox) component)
163: .setSelectedItem(((Object[]) value)[0]);
164: }
165: });
166: }
167: };
168:
169: private WorkbenchContext workbenchContext;
170: private Blackboard dummyBlackboard = new Blackboard();
171:
172: public ToolboxStateManager(ToolboxDialog toolbox) {
173: this (toolbox, new HashMap());
174: }
175:
176: public ToolboxStateManager(ToolboxDialog toolbox,
177: Map customComponentClassToStrategyMap) {
178: this .workbenchContext = toolbox.getContext();
179: componentClassToStrategyMap
180: .putAll(customComponentClassToStrategyMap);
181: monitor(toolbox);
182: }
183:
184: private Blackboard getBlackboard() {
185: return (workbenchContext.getLayerManager() == null) ? dummyBlackboard
186: : workbenchContext.getLayerManager().getBlackboard();
187: }
188:
189: private ToolboxStateManager monitor(Component component) {
190: //Skip CursorTools! [Jon Aquino 1/12/2004]
191: if (null != SwingUtilities.getAncestorOfClass(
192: WorkbenchToolBar.class, component)) {
193: return this ;
194: }
195: for (Iterator i = componentClassToStrategyMap.keyList()
196: .iterator(); i.hasNext();) {
197: Class componentClass = (Class) i.next();
198:
199: if (componentClass.isInstance(component)) {
200: ((Strategy) componentClassToStrategyMap
201: .get(componentClass)).monitor(component, this );
202: //Don't go any deeper [Jon Aquino]
203: return this ;
204: }
205: }
206:
207: if (component instanceof Container) {
208: for (int i = 0; i < ((Container) component)
209: .getComponentCount(); i++) {
210: monitor(((Container) component).getComponent(i));
211: }
212: }
213:
214: return this ;
215: }
216:
217: public static abstract class Strategy {
218: private boolean updating = false;
219:
220: public void monitor(final Component component,
221: final ToolboxStateManager manager) {
222: final String key = ToolboxStateManager.class.getName()
223: + " - " + ++keyIndex;
224: final Object initialValue = getToolboxValue(component);
225: final Block updateBlackboardBlock = new Block() {
226: public Object yield() {
227: updating = true;
228:
229: try {
230: setToolboxValue(manager.getBlackboard()
231: .get(
232: key,
233: getDefaultValue(initialValue,
234: component)), component);
235: } finally {
236: updating = false;
237: }
238: return null;
239: }
240: };
241: ActionListener actionListener = new ActionListener() {
242: public void actionPerformed(ActionEvent e) {
243: if (updating) {
244: return;
245: }
246:
247: manager.getBlackboard().put(key,
248: getToolboxValue(component));
249: }
250: };
251: updateBlackboardBlock.yield();
252: actionListener.actionPerformed(null);
253: addActionListener(actionListener, component);
254: GUIUtil.addInternalFrameListener(manager.workbenchContext
255: .getWorkbench().getFrame().getDesktopPane(),
256: new InternalFrameAdapter() {
257: public void internalFrameActivated(
258: InternalFrameEvent e) {
259: updateBlackboardBlock.yield();
260: }
261:
262: public void internalFrameDeactivated(
263: InternalFrameEvent e) {
264: //Handles case: one task frame, and it gets closed. [Jon Aquino]
265: updateBlackboardBlock.yield();
266: }
267:
268: });
269: }
270:
271: protected Object getDefaultValue(Object initialToolboxValue,
272: Component component) {
273: return initialToolboxValue;
274: }
275:
276: protected abstract void addActionListener(
277: ActionListener actionListener, Component component);
278:
279: protected abstract Object getToolboxValue(Component component);
280:
281: protected abstract void setToolboxValue(Object value,
282: Component component);
283: }
284: }
|