001: /*
002: * $Id: JGraphEditorFactory.java,v 1.3 2006/02/02 14:13:07 gaudenz Exp $
003: * Copyright (c) 2001-2005, Gaudenz Alder
004: *
005: * All rights reserved.
006: *
007: * See LICENSE file for license details. If you are unable to locate
008: * this file please contact info (at) jgraph (dot) com.
009: */
010: package com.jgraph.editor;
011:
012: import java.awt.Component;
013: import java.awt.Container;
014: import java.awt.Dimension;
015: import java.beans.PropertyChangeEvent;
016: import java.beans.PropertyChangeListener;
017: import java.util.Hashtable;
018: import java.util.Map;
019:
020: import javax.accessibility.AccessibleContext;
021: import javax.accessibility.AccessibleState;
022: import javax.swing.AbstractButton;
023: import javax.swing.ButtonGroup;
024: import javax.swing.ImageIcon;
025: import javax.swing.JButton;
026: import javax.swing.JCheckBoxMenuItem;
027: import javax.swing.JMenu;
028: import javax.swing.JMenuBar;
029: import javax.swing.JMenuItem;
030: import javax.swing.JPopupMenu;
031: import javax.swing.JRadioButtonMenuItem;
032: import javax.swing.JScrollPane;
033: import javax.swing.JSplitPane;
034: import javax.swing.JTabbedPane;
035: import javax.swing.JToggleButton;
036: import javax.swing.JToolBar;
037: import javax.swing.KeyStroke;
038:
039: import org.jgraph.JGraph;
040: import org.jgraph.graph.GraphLayoutCache;
041: import org.w3c.dom.Node;
042: import org.w3c.dom.NodeList;
043:
044: import com.jgraph.editor.factory.JGraphEditorDiagramPane;
045: import com.jgraph.editor.factory.JGraphEditorFactoryMethod;
046: import com.jgraph.editor.factory.JGraphEditorToolbox;
047:
048: /**
049: * Class that creates the UI elements of a JGraph editor. It uses the actions
050: * and tools from the {@link #kit} to create menu bars, toolbars, toolboxes and
051: * popup menus.
052: */
053: public class JGraphEditorFactory {
054:
055: /**
056: * Defines the nodename for separators.
057: */
058: public static final String NODENAME_SEPARATOR = "separator";
059:
060: /**
061: * Defines the nodename for items.
062: */
063: public static final String NODENAME_ITEM = "item";
064:
065: /**
066: * Defines the nodename for menus.
067: */
068: public static final String NODENAME_MENU = "menu";
069:
070: /**
071: * Defines the nodename for groups.
072: */
073: public static final String NODENAME_GROUP = "group";
074:
075: /**
076: * Defines the suffix for actionname resources. This is used to replace the
077: * default action name, which is its key, eg.
078: * <code>openFile.label=Open...</code>.
079: */
080: public static final String SUFFIX_ACTION = ".action";
081:
082: /**
083: * Defines the suffix for toolname resources. This is used to replace the
084: * default tool name, which is its key, eg.
085: * <code>openFile.label=Open...</code>.
086: */
087: public static final String SUFFIX_TOOL = ".tool";
088:
089: /**
090: * Defines the suffix for label resources, eg.
091: * <code>open.label=Open...</code>.
092: */
093: public static final String SUFFIX_LABEL = ".label";
094:
095: /**
096: * Defines the suffix for icon resources, eg.
097: * <code>open.icon=/com/jgraph/pad/images/open.gif</code>.
098: */
099: public static final String SUFFIX_ICON = ".icon";
100:
101: /**
102: * Defines the suffix for mnemonic resources, eg.
103: * <code>open.mnemonic=o</code>.
104: */
105: public static final String SUFFIX_MNEMONIC = ".mnemonic";
106:
107: /**
108: * Defines the suffix for shortcut resources, eg.
109: * <code>open.shortcut=control O</code>.
110: */
111: public static final String SUFFIX_SHORTCUT = ".shortcut";
112:
113: /**
114: * Defines the suffix for tooltip resources, eg.
115: * <code>open.tooltip=Open a file</code>.
116: */
117: public static final String SUFFIX_TOOLTIP = ".tooltip";
118:
119: /**
120: * Constant for menubar creation.
121: */
122: protected static final int ITEMTYPE_MENUBAR = 0;
123:
124: /**
125: * Constant for toolbar creation.
126: */
127: protected static final int ITEMTYPE_TOOLBAR = 1;
128:
129: /**
130: * Shared separator instance.
131: */
132: protected static final Component SEPARATOR = new JButton();
133:
134: /**
135: * Holds the (name, factory method) pairs
136: */
137: protected Map factoryMethods = new Hashtable();
138:
139: /**
140: * References the editor kit.
141: */
142: protected JGraphEditorKit kit;
143:
144: /**
145: * Constructs an empty factory.
146: */
147: public JGraphEditorFactory() {
148: // empty
149: }
150:
151: /**
152: * Constructs a factory for the specified kit.
153: */
154: public JGraphEditorFactory(JGraphEditorKit kit) {
155: setKit(kit);
156: }
157:
158: /**
159: * Returns the editor kit.
160: *
161: * @return Returns the kit.
162: */
163: public JGraphEditorKit getKit() {
164: return kit;
165: }
166:
167: /**
168: * Sets the editor kit to provide actions and tools.
169: *
170: * @param kit
171: * The kit to set.
172: */
173: public void setKit(JGraphEditorKit kit) {
174: this .kit = kit;
175: }
176:
177: /**
178: * Adds the specified factory method.
179: *
180: * @param method
181: * The factory method to add.
182: * @return Returns the previous factory method for <code>name</code>.
183: */
184: public Object addMethod(JGraphEditorFactoryMethod method) {
185: if (method != null)
186: return factoryMethods.put(method.getName(), method);
187: return null;
188: }
189:
190: /**
191: * Returns the factory method for the specified name or <code>null</code>
192: * if no such factory method can be found.
193: *
194: * @param name
195: * The name that identifies the factory method.
196: * @return Returns the factory method under <code>name</code> or
197: * <code>null</code>.
198: */
199: public JGraphEditorFactoryMethod getMethod(String name) {
200: if (name != null)
201: return (JGraphEditorFactoryMethod) factoryMethods.get(name);
202: return null;
203: }
204:
205: /**
206: * Shortcut method to {@link #executeMethod(String, Node)} with a null
207: * configuration.
208: *
209: * @param factoryMethod
210: * The name of the factory method to executed.
211: * @return Returns the return value of
212: * {@link JGraphEditorFactoryMethod#createInstance(Node)} on
213: * <code>factoryMethod</code>.
214: */
215: public Component executeMethod(String factoryMethod) {
216: return executeMethod(factoryMethod, null);
217: }
218:
219: /**
220: * Executes {@link JGraphEditorFactoryMethod#createInstance(Node)} on the
221: * factory method under <code>factoryMethod</code> passing
222: * <code>configuration</code> along as an argument and returns the return
223: * value of the invoked method.
224: *
225: * @param factoryMethod
226: * The name of the factory method to executed.
227: * @param configuration
228: * The configuration to pass to
229: * {@link JGraphEditorFactoryMethod#createInstance(Node)}.
230: * @return Returns the return value of
231: * {@link JGraphEditorFactoryMethod#createInstance(Node)} on
232: * <code>factoryMethod</code>.
233: *
234: * @see #getMethod(String)
235: */
236: public Component executeMethod(String factoryMethod,
237: Node configuration) {
238: JGraphEditorFactoryMethod method = getMethod(factoryMethod);
239: if (method != null)
240: return method.createInstance(configuration);
241: return null;
242: }
243:
244: /**
245: * Shortcut method to {@link JGraphEditorResources#getString(String)}.
246: *
247: * @return Returns the resource string for <code>key</code>.
248: */
249: protected String getString(String key) {
250: return JGraphEditorResources.getString(key);
251: }
252:
253: /**
254: * Shortcut method to
255: * {@link JGraphEditorSettings#getKeyAttributeValue(Node)}.
256: */
257: protected String getKey(Node node) {
258: return JGraphEditorSettings.getKeyAttributeValue(node);
259: }
260:
261: /**
262: * Returns the action for the resource under <code>key+SUFFIX_ACTION</code>
263: * from the editor kit. If no such resource exists then the action for
264: * <code>key</code> is returned or <code>null</code> if no action can be
265: * found.
266: *
267: * @return Returns the action for the <code>key+SUFFIX_ACTION</code>
268: * resource or the action for <code>key</code>.
269: *
270: * @see #getString(String)
271: * @see JGraphEditorKit#getAction(String)
272: */
273: public JGraphEditorAction getAction(String key) {
274: String tmp = getString(key + SUFFIX_ACTION);
275: if (tmp != null)
276: key = tmp;
277: return getKit().getAction(key);
278: }
279:
280: /**
281: * Returns the tool for the resource under <code>key+SUFFIX_TOOL</code>
282: * from the editor kit. If no such resource exists then the tool for
283: * <code>key</code> is returned or <code>null</code> if no tool can be
284: * found.
285: *
286: * @return Returns the tool for the <code>key+SUFFIX_TOOL</code> resource
287: * or the tool for <code>key</code>.
288: *
289: * @see #getString(String)
290: * @see JGraphEditorKit#getTool(String)
291: */
292: public JGraphEditorTool getTool(String key) {
293: String tmp = getString(key + SUFFIX_TOOL);
294: if (tmp != null)
295: key = tmp;
296: return getKit().getTool(key);
297: }
298:
299: //
300: // General Items
301: //
302:
303: /**
304: * Returns a new diagram pane for the specified diagram by creating a new
305: * graph using the {@link #createGraph(GraphLayoutCache)} method and
306: * wrapping it up in a {@link JGraphEditorDiagramPane}.
307: *
308: * @param diagram
309: * The diagram that contains the graph to be used.
310: * @return Returns a new diagram pane for <code>diagram</code>.
311: */
312: public JGraphEditorDiagramPane createDiagramPane(
313: JGraphEditorDiagram diagram) {
314: JGraph graph = createGraph(diagram.getGraphLayoutCache());
315: JGraphEditorDiagramPane pane = new JGraphEditorDiagramPane(
316: diagram, graph);
317: return pane;
318: }
319:
320: /**
321: * Returns a new graph for the specified <code>cache</code>. This
322: * implementation creates a new graph using
323: * {@link JGraph#JGraph(GraphLayoutCache)}.
324: *
325: * @param cache
326: * The layout cache that defines the graph.
327: * @return Returns a new graph for <code>cache</code>.
328: */
329: public JGraph createGraph(GraphLayoutCache cache) {
330: return new JGraph(cache);
331: }
332:
333: /**
334: * Returns a new {@link JScrollPane} containing the specified component.
335: *
336: * @return Returns a new scrollpane containing the specified component.
337: */
338: public JScrollPane createScrollPane(Component component) {
339: JScrollPane scrollPane = new JScrollPane(component);
340: scrollPane.setFocusable(false);
341: scrollPane.getHorizontalScrollBar().setFocusable(false);
342: scrollPane.getVerticalScrollBar().setFocusable(false);
343: return scrollPane;
344: }
345:
346: /**
347: * Returns a new {@link JSplitPane} containing the specified component with
348: * the specified orientation.
349: *
350: * @return Returns a new splitpane containing the the specified components.
351: */
352: public JSplitPane createSplitPane(Component first,
353: Component second, int orientation) {
354: JSplitPane splitPane = new JSplitPane(orientation, first,
355: second);
356: splitPane.setBorder(null);
357: splitPane.setFocusable(false);
358: return splitPane;
359: }
360:
361: /**
362: * Returns a new empty {@link JTabbedPane}.
363: *
364: * @return Returns a new tabbed pane.
365: */
366: public JTabbedPane createTabbedPane(int tabPlacement) {
367: JTabbedPane tabPane = new JTabbedPane(tabPlacement);
368: tabPane.setFocusable(false);
369: return tabPane;
370: }
371:
372: //
373: // Toolbox
374: //
375:
376: /**
377: * Returns a new {@link JGraphEditorToolbox} configured using
378: * {@link #configureToolbox(JGraphEditorToolbox, Node)}.
379: *
380: * @param configuration
381: * The configuration to create the toolbox with.
382: * @return Returns a new toolbox.
383: */
384: public JGraphEditorToolbox createToolbox(Node configuration) {
385: JGraphEditorToolbox toolbox = new JGraphEditorToolbox();
386: configureToolbox(toolbox, configuration);
387: return toolbox;
388: }
389:
390: /**
391: * Hook for subclassers to configure a new toolbox based on
392: * <code>configuration</code>.
393: *
394: * @param toolbox
395: * The toolbox to be configured.
396: * @param configuration
397: * The configuration to configure the toolbox with.
398: *
399: * @see #createToolboxButton(JGraphEditorTool)
400: */
401: protected void configureToolbox(final JGraphEditorToolbox toolbox,
402: Node configuration) {
403: if (configuration != null) {
404: ButtonGroup group = new ButtonGroup();
405: NodeList nodes = configuration.getChildNodes();
406: for (int i = 0; i < nodes.getLength(); i++) {
407: Node child = nodes.item(i);
408: String key = getKey(child);
409:
410: final JGraphEditorTool tool = getTool(key);
411: if (tool != null) {
412: AbstractButton button = createToolboxButton(tool);
413: group.add(button);
414: toolbox.add(button);
415:
416: // Selects the first button in the toolbox
417: if (toolbox.getComponentCount() == 1) {
418: button.setSelected(true);
419: toolbox.setSelectionTool(tool);
420: toolbox.setDefaultButton(button);
421: }
422:
423: // Update the selection tool in the enclosing
424: // toolbox when the button is selected.
425: button.getAccessibleContext()
426: .addPropertyChangeListener(
427: new PropertyChangeListener() {
428: public void propertyChange(
429: PropertyChangeEvent evt) {
430: if (evt
431: .getPropertyName()
432: .equals(
433: AccessibleContext.ACCESSIBLE_STATE_PROPERTY)
434: && evt
435: .getNewValue() != null
436: && evt
437: .getNewValue()
438: .equals(
439: AccessibleState.SELECTED)) {
440: toolbox
441: .setSelectionTool(tool);
442: }
443: }
444: });
445:
446: } else if (key != null) {
447:
448: // Tries to execute factory method and add result.
449: Component c = executeMethod(key, configuration);
450: if (c != null) {
451: toolbox.add(c);
452: toolbox.addSeparator(new Dimension(3, 0));
453: }
454: } else if (child.getNodeName().equals(
455: NODENAME_SEPARATOR)) {
456: toolbox.addSeparator();
457: }
458: }
459: }
460: }
461:
462: /**
463: * Returns a new {@link JToggleButton} button configured for
464: * <code>tool</code> by calling
465: * {@link #configureAbstractButton(AbstractButton, String)}.
466: *
467: * @param tool
468: * The tool to create the toolbox button for.
469: * @return Returns a new toolbox.
470: */
471: protected AbstractButton createToolboxButton(JGraphEditorTool tool) {
472: AbstractButton button = new JToggleButton();
473: configureAbstractButton(button, tool.getName());
474: return button;
475: }
476:
477: /**
478: * Hook for subclassers to configure a toolbox button for <code>tool</code>.
479: *
480: * @param button
481: * The button to be configured.
482: * @param name
483: * The name of the tool or action to configure the button for.
484: */
485: protected void configureAbstractButton(AbstractButton button,
486: String name) {
487: button.setFocusable(false);
488: button.setText("");
489:
490: // Configures the tooltip
491: String tip = getString(name + SUFFIX_TOOLTIP);
492: if (tip == null)
493: tip = getString(name + SUFFIX_LABEL);
494: button.setToolTipText((tip != null) ? tip : name);
495:
496: // Configures the icon and size
497: ImageIcon icon = JGraphEditorResources.getImage(getString(name
498: + SUFFIX_ICON));
499: if (icon != null) {
500: button.setIcon(icon);
501: Dimension d = new Dimension(icon.getIconWidth() + 8, icon
502: .getIconHeight() + 10);
503: button.setMaximumSize(d);
504: button.setPreferredSize(d);
505: }
506: }
507:
508: //
509: // Menus
510: //
511:
512: /**
513: * Returns a new {@link JMenuBar} configured using
514: * {@link #configureMenuBar(Container, Node)}.
515: *
516: * @param configuration
517: * The configuration to create the menubar with.
518: * @return Returns a new toolbox.
519: */
520: public JMenuBar createMenuBar(Node configuration) {
521: JMenuBar menuBar = new JMenuBar();
522: configureMenuBar(menuBar, configuration);
523: return menuBar;
524: }
525:
526: /**
527: * Returns a new {@link JPopupMenu} configured using
528: * {@link #configureMenuBar(Container, Node)}.
529: *
530: * @param configuration
531: * The configuration to create the popup menu with.
532: * @return Returns a new toolbox.
533: */
534: public JPopupMenu createPopupMenu(Node configuration) {
535: JPopupMenu menuBar = new JPopupMenu();
536: configureMenuBar(menuBar, configuration);
537: return menuBar;
538: }
539:
540: /**
541: * Hook for subclassers to configure a new menu based on
542: * <code>configuration</code>. This is used for menubars and submenus.
543: *
544: * @param menu
545: * The menu to be configured.
546: * @param configuration
547: * The configuration to configure the menubar with.
548: *
549: * @see #createMenuItem(Node, boolean)
550: */
551: protected void configureMenuBar(Container menu, Node configuration) {
552: if (configuration != null) {
553: String key = getKey(configuration);
554: if (menu instanceof JMenu) {
555: JMenu tmp = (JMenu) menu;
556: tmp.setText(getString(key + SUFFIX_LABEL));
557:
558: // Configures the mnemonic
559: String mnemonic = getString(key + SUFFIX_MNEMONIC);
560: if (mnemonic != null && mnemonic.length() > 0)
561: tmp.setMnemonic(mnemonic.toCharArray()[0]);
562: }
563:
564: NodeList nodes = configuration.getChildNodes();
565: for (int i = 0; i < nodes.getLength(); i++) {
566: Node child = nodes.item(i);
567: String name = child.getNodeName();
568:
569: Component c = executeMethod(getKey(child), child);
570: if (c != null) {
571: menu.add(c);
572: } else if (name.equals(NODENAME_MENU)) {
573:
574: // Creates and adds a submenu
575: Container subMenu = createMenu(child);
576: configureMenuBar(subMenu, child); // recurse
577: menu.add(subMenu);
578:
579: } else if (name.equals(NODENAME_GROUP)) {
580:
581: // Creates a button group
582: ButtonGroup group = new ButtonGroup();
583: NodeList groupNodes = child.getChildNodes();
584: for (int j = 0; j < groupNodes.getLength(); j++) {
585: Node groupChild = groupNodes.item(j);
586: if (groupChild.getNodeName().equals(
587: NODENAME_ITEM)) {
588: AbstractButton button = createMenuItem(
589: groupChild, true);
590: if (button != null) {
591: menu.add(button);
592: group.add(button);
593: }
594: }
595: }
596:
597: // Create Item
598: } else if (name.equals(NODENAME_ITEM)) {
599: AbstractButton item = createMenuItem(child, false);
600: if (item != null)
601: menu.add(item);
602: } else if (name.equals(NODENAME_SEPARATOR)
603: && menu instanceof JMenu) {
604: ((JMenu) menu).addSeparator();
605: } else if (name.equals(NODENAME_SEPARATOR)
606: && menu instanceof JPopupMenu) {
607: ((JPopupMenu) menu).addSeparator();
608: }
609: }
610: }
611: }
612:
613: /**
614: * Hook for subclassers to create a new menu. This implementation returns a
615: * new instance of {@link JMenuBar}.
616: *
617: * @param configuration
618: * The configuration to create the menu with.
619: * @return Returns a new menubar.
620: */
621: protected Container createMenu(Node configuration) {
622: return new JMenu();
623: }
624:
625: /**
626: * Returns a new {@link JCheckBoxMenuItem} or {@link JMenuItem} configured
627: * using {@link #configureActionItem(AbstractButton, JGraphEditorAction)}.
628: *
629: * @param configuration
630: * The configuration to create the menu item with.
631: * @param radio
632: * Whether the created item should be a
633: * {@link JRadioButtonMenuItem}.
634: * @return Returns a new menu item.
635: */
636: public AbstractButton createMenuItem(Node configuration,
637: boolean radio) {
638: JGraphEditorAction action = getAction(getKey(configuration));
639: if (action != null) {
640: AbstractButton item = (radio) ? new JRadioButtonMenuItem()
641: : (action.isToggleAction()) ? new JCheckBoxMenuItem()
642: : new JMenuItem();
643: configureActionItem(item, action);
644: return item;
645: }
646: return null;
647: }
648:
649: /**
650: * Hook for subclassers to configure an action item for <code>action</code>.
651: * Valid action items are toolbar buttons and menu items, but not toolbox
652: * buttons.
653: *
654: * @param button
655: * The button to be configured.
656: * @param action
657: * The action to configure the button for.
658: */
659: public void configureActionItem(AbstractButton button,
660: JGraphEditorAction action) {
661: String name = action.getName();
662: button.setFocusable(false);
663: button.setAction(action);
664: button.setEnabled(action.isEnabled());
665: button.setSelected(action.isSelected());
666:
667: // Listens to changes of the action state and upates the button
668: action
669: .addPropertyChangeListener(createActionChangeListener(button));
670:
671: // Configures the label
672: String label = getString(name + SUFFIX_LABEL);
673: button.setText((label != null && label.length() > 0) ? label
674: : name);
675:
676: // Configures the icon
677: ImageIcon icon = JGraphEditorResources.getImage(getString(name
678: + SUFFIX_ICON));
679: if (icon != null)
680: button.setIcon(icon);
681:
682: // Configures the mnemonic
683: String mnemonic = getString(name + SUFFIX_MNEMONIC);
684: if (mnemonic != null && mnemonic.length() > 0)
685: button.setMnemonic(mnemonic.toCharArray()[0]);
686:
687: // Configures the tooltip
688: String tooltip = getString(name + SUFFIX_TOOLTIP);
689: if (tooltip != null)
690: button.setToolTipText(tooltip);
691:
692: // Configures the shortcut aka. accelerator
693: String shortcut = getString(name + SUFFIX_SHORTCUT);
694: if (shortcut != null && button instanceof JMenuItem)
695: ((JMenuItem) button).setAccelerator(KeyStroke
696: .getKeyStroke(shortcut));
697: }
698:
699: //
700: // Toolbar
701: //
702:
703: /**
704: * Returns a new {@link JToolBar} configured using
705: * {@link #configureToolBar(Container, Node)}.
706: *
707: * @param configuration
708: * The configuration to create the toolbar with.
709: * @return Returns a new toolbar.
710: */
711: public JToolBar createToolBar(Node configuration) {
712: JToolBar toolBar = new JToolBar();
713: configureToolBar(toolBar, configuration);
714: return toolBar;
715:
716: }
717:
718: /**
719: * Hook for subclassers to configure a toolbar with
720: * <code>configuration</code>.
721: *
722: * @param toolBar
723: * The toolBar to be configured.
724: * @param configuration
725: * The configuration to configure the toolbar with.
726: */
727: protected void configureToolBar(Container toolBar,
728: Node configuration) {
729: if (configuration != null) {
730: NodeList nodes = configuration.getChildNodes();
731: for (int i = 0; i < nodes.getLength(); i++) {
732: Node child = nodes.item(i);
733: String name = child.getNodeName();
734:
735: Component c = executeMethod(getKey(child), child);
736: if (c != null) {
737: toolBar.add(c);
738: } else if (name.equals(NODENAME_ITEM)) {
739: AbstractButton button = createToolBarButton(child);
740: if (button != null)
741: toolBar.add(button);
742: } else if (name.equals(NODENAME_SEPARATOR)
743: && toolBar instanceof JToolBar) {
744: ((JToolBar) toolBar).addSeparator();
745: }
746: }
747: }
748: }
749:
750: /**
751: * Returns a new {@link JToggleButton} or {@link JButton} configured using
752: * {@link #configureActionItem(AbstractButton, JGraphEditorAction)} and
753: * {@link #configureAbstractButton(AbstractButton, String)} (in this order).
754: *
755: * @param configuration
756: * The configuration to create the toolbar with.
757: * @return Returns a new toolbar.
758: */
759: protected AbstractButton createToolBarButton(Node configuration) {
760: JGraphEditorAction action = getAction(getKey(configuration));
761: if (action != null) {
762: AbstractButton button = null;
763: if (action.isToggleAction())
764: button = new JToggleButton();
765: else
766: button = new JButton();
767: configureActionItem(button, action);
768: configureAbstractButton(button, action.getName());
769: return button;
770: }
771: return null;
772: }
773:
774: /**
775: * Returns a new property change listener that updates <code>button</code>
776: * according to property change events.
777: *
778: * @param button
779: * The button to create the listener for.
780: * @return Returns a new property change listener for actions.
781: */
782: public PropertyChangeListener createActionChangeListener(
783: AbstractButton button) {
784: return new ActionChangedListener(button);
785: }
786:
787: /**
788: * Updates <code>button</code> based on property change events.
789: */
790: protected class ActionChangedListener implements
791: PropertyChangeListener {
792:
793: /**
794: * References the button that is to be updated.
795: */
796: AbstractButton button;
797:
798: /**
799: * Constructs a action changed listener for the specified button.
800: *
801: * @param button
802: * The button to create the listener for.
803: */
804: ActionChangedListener(AbstractButton button) {
805: this .button = button;
806: }
807:
808: /**
809: * Updates the button state based on changes of the action state.
810: */
811: public void propertyChange(PropertyChangeEvent e) {
812: String propertyName = e.getPropertyName();
813: if (propertyName.equals("enabled")) {
814: Boolean enabledState = (Boolean) e.getNewValue();
815: button.setEnabled(enabledState.booleanValue());
816: } else if (propertyName
817: .equals(JGraphEditorAction.PROPERTY_ISSELECTED)) {
818: Boolean selectedState = (Boolean) e.getNewValue();
819: if (selectedState != null) {
820: boolean selected = selectedState.booleanValue();
821: if (button instanceof JCheckBoxMenuItem)
822: ((JCheckBoxMenuItem) button).setState(selected);
823: else if (button instanceof JRadioButtonMenuItem)
824: ((JRadioButtonMenuItem) button)
825: .setSelected(selected);
826: else if (button instanceof JToggleButton)
827: ((JToggleButton) button).setSelected(selected);
828: }
829: }
830: }
831: }
832:
833: }
|