1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.xnap.commons.gui.action;
21
22 import java.beans.PropertyChangeEvent;
23 import java.beans.PropertyChangeListener;
24 import javax.swing.AbstractAction;
25 import javax.swing.AbstractButton;
26 import javax.swing.Action;
27 import javax.swing.Icon;
28 import javax.swing.JButton;
29 import javax.swing.JCheckBox;
30 import javax.swing.JCheckBoxMenuItem;
31 import javax.swing.JMenuItem;
32 import javax.swing.JToggleButton;
33 import javax.swing.SwingUtilities;
34 import org.xnap.commons.gui.ToolBarButton;
35 import org.xnap.commons.gui.ToolBarToggleButton;
36 import org.xnap.commons.gui.util.IconHelper;
37 import org.xnap.commons.i18n.I18n;
38 import org.xnap.commons.i18n.I18nFactory;
39
40 /***
41 * Provides an abstract action. All actions should inherit this class,
42 * since it provides a few convenience methods.
43 */
44 public abstract class AbstractXNapAction extends AbstractAction {
45
46 public static final String ICON_FILENAME = "XNapIcon";
47
48 public AbstractXNapAction()
49 {
50 }
51
52 /***
53 * Enables/disables the action in the swing thread by calling
54 * {@link SwingUtilities#invokeLater(java.lang.Runnable)}.
55 * @param enabled parameter passed to {@link Action#setEnabled(boolean)}.
56 */
57 public void setEnabledLater(final boolean enabled)
58 {
59 Runnable runner = new Runnable()
60 {
61 public void run()
62 {
63 setEnabled(enabled);
64 }
65 };
66 SwingUtilities.invokeLater(runner);
67 }
68
69 /***
70 * Convenience method for translating which can be used by subclasses.
71 * <p>
72 * This works because subclasses are in their own package, so the right
73 * resource bundle can be chosen.
74 */
75 protected String tr(String text)
76 {
77 I18n i18n = I18nFactory.getI18n(getClass());
78 return i18n.tr(text);
79 }
80
81 /***
82 * See {@link #tr(String)} and {@link I18n#tr(String, Object[])}.
83 */
84 protected String tr(String text, Object ... objects)
85 {
86 I18n i18n = I18nFactory.getI18n(getClass());
87 return i18n.tr(text, objects);
88 }
89
90
91 public static Icon getIcon(AbstractButton button, String filename)
92 {
93 if (button instanceof JCheckBox || button instanceof JCheckBoxMenuItem) {
94
95 return null;
96 }
97 else if (button instanceof ToolBarButton || button instanceof ToolBarToggleButton) {
98 return IconHelper.getToolBarIcon(filename);
99 }
100 else if (button instanceof JButton || button instanceof JToggleButton) {
101 return IconHelper.getButtonIcon(filename);
102 }
103 else if (button instanceof JMenuItem) {
104 return IconHelper.getMenuIcon(filename);
105 }
106 return null;
107 }
108
109 public static void initialize(AbstractButton button, Action action)
110 {
111 String filename = (String)action.getValue(AbstractXNapAction.ICON_FILENAME);
112
113
114
115 button.setIcon(getIcon(button, (filename != null) ? filename : "does-not-exist"));
116
117 if (action instanceof ToggleAction) {
118 button.setSelected(((ToggleAction)action).isSelected());
119 }
120
121
122
123
124 action.addPropertyChangeListener(new ActionPropertyListener(button));
125 }
126
127 /***
128 * This class is static to allow the garbage collector to finalize the
129 * component although the action is still existant.
130 *
131 * Does this make sense at all? The action still holds a reference to the
132 * button through the listener...
133 *
134 * @author Steffen Pingel
135 */
136 private static class ActionPropertyListener implements PropertyChangeListener {
137
138 private AbstractButton button;
139
140 public ActionPropertyListener(AbstractButton button)
141 {
142 this.button = button;
143 }
144
145 public void propertyChange(PropertyChangeEvent e)
146 {
147 if (e.getPropertyName().equals(ToggleAction.SELECTED)) {
148 button.setSelected(((Boolean)e.getNewValue()).booleanValue());
149 }
150 else if (e.getPropertyName().equals(AbstractXNapAction.ICON_FILENAME)) {
151 String filename = (String)e.getNewValue();
152 button.setIcon(getIcon(button, filename));
153 }
154 }
155
156 }
157
158 }