package com.vividsolutions.jump.workbench.ui.toolbox; import java.awt.Component; import java.awt.Container; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Vector; import javax.swing.DefaultComboBoxModel; import javax.swing.JComboBox; import javax.swing.JToggleButton; import javax.swing.SwingUtilities; import javax.swing.event.InternalFrameAdapter; import javax.swing.event.InternalFrameEvent; import javax.swing.text.JTextComponent; import com.vividsolutions.jump.util.Blackboard; import com.vividsolutions.jump.util.Block; import com.vividsolutions.jump.util.LangUtil; import com.vividsolutions.jump.util.OrderedMap; import com.vividsolutions.jump.workbench.WorkbenchContext; import com.vividsolutions.jump.workbench.model.LayerManager; import com.vividsolutions.jump.workbench.ui.GUIUtil; import com.vividsolutions.jump.workbench.ui.LayerComboBox; import com.vividsolutions.jump.workbench.ui.WorkbenchFrame; import com.vividsolutions.jump.workbench.ui.WorkbenchToolBar; /** * Stores the state of the component and its descendants on the Blackboard of * the LayerManager (if any) of the current JInternalFrame. Thus, when the * user switches JInternalFrames, the component will change its state to reflect * the new context. * <p> * Designed to be trivial to use: simply instantiate one if you want to use one. * (Make sure the toolbox's Components are initialized first). * Note that not all Components are supported; currently the ToolboxStateManager * will save the state for the following components only: JTextComponent, * JToggleButton (including JCheckBox), JComboBox. */ public class ToolboxStateManager { private static int keyIndex = 0; private OrderedMap componentClassToStrategyMap = new OrderedMap() { { put(JTextComponent.class, new Strategy() { protected void addActionListener( ActionListener actionListener, Component component) { ((JTextComponent) component).getDocument() .addDocumentListener(GUIUtil.toDocumentListener( actionListener)); } protected Object getToolboxValue(Component component) { return ((JTextComponent) component).getText(); } protected void setToolboxValue(Object value, Component component) { ((JTextComponent) component).setText((String) value); } }); put(JToggleButton.class, new Strategy() { protected void addActionListener( ActionListener actionListener, Component component) { ((JToggleButton) component).addActionListener(actionListener); } protected Object getToolboxValue(Component component) { return new Boolean(((JToggleButton) component).isSelected()); } protected void setToolboxValue(Object value, Component component) { ((JToggleButton) component).setSelected(((Boolean) value).booleanValue()); } }); put(LayerComboBox.class, new Strategy() { protected void addActionListener( ActionListener actionListener, Component component) { ((LayerComboBox) component).getModel() .addListDataListener(GUIUtil.toListDataListener( actionListener)); } protected Object getDefaultValue(Object initialToolboxValue, Component component) { LayerManager layerManager = (LayerManager)LangUtil.ifNull(((WorkbenchFrame) SwingUtilities .getAncestorOfClass(WorkbenchFrame.class, component)).getContext().getLayerManager(), new LayerManager()); return new Object[] { layerManager.size() > 0 ? layerManager.iterator().next() : null, layerManager }; } protected Object getToolboxValue(Component component) { return new Object[] { ((LayerComboBox) component).getSelectedItem(), ((LayerComboBox) component).getLayerManager() }; } protected void setToolboxValue(Object value, Component component) { ((LayerComboBox) component).setLayerManager(((LayerManager) ((Object[]) value)[1])); ((LayerComboBox) component).setSelectedItem(((Object[]) value)[0]); } }); put(JComboBox.class, new Strategy() { protected void addActionListener( ActionListener actionListener, Component component) { ((JComboBox) component).addActionListener(actionListener); ((JComboBox) component).getModel() .addListDataListener(GUIUtil.toListDataListener( actionListener)); } protected Object getToolboxValue(Component component) { Vector items = new Vector(); for (int i = 0; i < ((JComboBox) component).getItemCount(); i++) { items.add(((JComboBox) component).getItemAt(i)); } return new Object[] { ((JComboBox) component).getSelectedItem(), items }; } protected void setToolboxValue(Object value, Component component) { ((JComboBox) component).setModel(new DefaultComboBoxModel( ((Vector) ((Object[]) value)[1]))); ((JComboBox) component).setSelectedItem(((Object[]) value)[0]); } }); } }; private WorkbenchContext workbenchContext; private Blackboard dummyBlackboard = new Blackboard(); public ToolboxStateManager(ToolboxDialog toolbox) { this(toolbox, new HashMap()); } public ToolboxStateManager(ToolboxDialog toolbox, Map customComponentClassToStrategyMap) { this.workbenchContext = toolbox.getContext(); componentClassToStrategyMap.putAll(customComponentClassToStrategyMap); monitor(toolbox); } private Blackboard getBlackboard() { return (workbenchContext.getLayerManager() == null) ? dummyBlackboard : workbenchContext.getLayerManager() .getBlackboard(); } private ToolboxStateManager monitor(Component component) { //Skip CursorTools! [Jon Aquino 1/12/2004] if (null != SwingUtilities.getAncestorOfClass(WorkbenchToolBar.class, component)) { return this; } for (Iterator i = componentClassToStrategyMap.keyList().iterator(); i.hasNext();) { Class componentClass = (Class) i.next(); if (componentClass.isInstance(component)) { ((Strategy) componentClassToStrategyMap.get(componentClass)).monitor(component, this); //Don't go any deeper [Jon Aquino] return this; } } if (component instanceof Container) { for (int i = 0; i < ((Container) component).getComponentCount(); i++) { monitor(((Container) component).getComponent(i)); } } return this; } public static abstract class Strategy { private boolean updating = false; public void monitor(final Component component, final ToolboxStateManager manager) { final String key = ToolboxStateManager.class.getName() + " - " + ++keyIndex; final Object initialValue = getToolboxValue(component); final Block updateBlackboardBlock = new Block() { public Object yield() { updating = true; try { setToolboxValue(manager.getBlackboard().get(key, getDefaultValue(initialValue, component)), component); } finally { updating = false; } return null; } }; ActionListener actionListener = new ActionListener() { public void actionPerformed(ActionEvent e) { if (updating) { return; } manager.getBlackboard().put(key, getToolboxValue(component)); } }; updateBlackboardBlock.yield(); actionListener.actionPerformed(null); addActionListener(actionListener, component); GUIUtil.addInternalFrameListener(manager.workbenchContext.getWorkbench() .getFrame() .getDesktopPane(), new InternalFrameAdapter() { public void internalFrameActivated(InternalFrameEvent e) { updateBlackboardBlock.yield(); } public void internalFrameDeactivated(InternalFrameEvent e) { //Handles case: one task frame, and it gets closed. [Jon Aquino] updateBlackboardBlock.yield(); } }); } protected Object getDefaultValue(Object initialToolboxValue, Component component) { return initialToolboxValue; } protected abstract void addActionListener( ActionListener actionListener, Component component); protected abstract Object getToolboxValue(Component component); protected abstract void setToolboxValue(Object value, Component component); } }