KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openide > util > actions > SystemAction


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.openide.util.actions;
21
22 import java.awt.Color JavaDoc;
23 import java.awt.Component JavaDoc;
24 import java.awt.Dimension JavaDoc;
25 import java.awt.Graphics JavaDoc;
26 import java.awt.Image JavaDoc;
27 import java.awt.event.ActionEvent JavaDoc;
28 import java.awt.image.BufferedImage JavaDoc;
29 import java.net.URL JavaDoc;
30 import java.util.ArrayList JavaDoc;
31 import java.util.Arrays JavaDoc;
32 import java.util.HashSet JavaDoc;
33 import java.util.List JavaDoc;
34 import java.util.Set JavaDoc;
35 import java.util.logging.Logger JavaDoc;
36 import javax.swing.Action JavaDoc;
37 import javax.swing.Icon JavaDoc;
38 import javax.swing.ImageIcon JavaDoc;
39 import javax.swing.JComponent JavaDoc;
40 import javax.swing.JLabel JavaDoc;
41 import javax.swing.JPopupMenu JavaDoc;
42 import javax.swing.JToolBar JavaDoc;
43 import org.openide.util.HelpCtx;
44 import org.openide.util.SharedClassObject;
45 import org.openide.util.Utilities;
46
47 /**
48 * A base class for user-visible actions.
49 * <P>
50 * Implements the Swing {@link Action} interface to enable use
51 * with the Swing action model.
52 * <p>An action class is a <em>singleton</em>, i.e. should generally contain no instance state.
53 * Rather, subclassing and use of abstract protected methods should be used
54 * to create variants of the action.
55 * <p>While it is possible to subclass this class directly--for example, if your "action"
56 * is really a placeholder for a popup menu that shows other actions--most people will
57 * prefer to use one of the subclasses, which are more convenient.
58 *
59 * @author Ian Formanek, Jaroslav Tulach
60 */

61 public abstract class SystemAction extends SharedClassObject implements Action JavaDoc, HelpCtx.Provider {
62
63     private static final Logger JavaDoc LOG = Logger.getLogger(SystemAction.class.getName());
64
65     /** Name of property indicating whether or not the action is enabled. */
66     public static final String JavaDoc PROP_ENABLED = "enabled"; // NOI18N
67

68     /** Name of property for the action's display icon. */
69     public static final String JavaDoc PROP_ICON = "icon"; // NOI18N
70

71     /** Name of property for the action's display icon, if textual. */
72     private static final String JavaDoc PROP_ICON_TEXTUAL = "iconTextual"; // NOI18N
73
private static Icon JavaDoc BLANK_ICON = new Icon JavaDoc() {
74         public void paintIcon(Component JavaDoc c, Graphics JavaDoc g, int x, int y) {}
75         public int getIconWidth() {
76             return 16;
77         }
78         public int getIconHeight() {
79             return 16;
80         }
81     };
82     private static final Set JavaDoc<String JavaDoc> relativeIconResourceClasses = new HashSet JavaDoc<String JavaDoc>(200);
83
84     // Matches NB 3.4 w/ openide-compat.jar; see #26491
85
private static final long serialVersionUID = -8361232596876856810L;
86
87     /** Obtain a singleton instance of the action with a specified class.
88     * If there already is a instance then it is returned, otherwise
89     * a new one is created.
90     *
91     * @param actionClass the class of the action to find
92     * @return the singleton action instance
93     * @exception ClassCastException if the class is not <code>SystemAction</code>
94     * @exception IllegalArgumentException if the instance cannot be created
95     */

96     public static <T extends SystemAction> T get(Class JavaDoc<T> actionClass) {
97         return findObject(actionClass, true);
98     }
99
100     /** Get a human presentable name of the action.
101     * This may be
102     * presented as an item in a menu.
103     * <p>Using the normal menu presenters, an included ampersand
104     * before a letter will be treated as the name of a mnemonic.
105     * @return the name of the action
106     */

107     public abstract String JavaDoc getName();
108
109     /** Get a help context for the action.
110     * @return the help context for this action
111     */

112     public abstract HelpCtx getHelpCtx();
113
114     /** Test whether the action is currently enabled.
115     * @return <code>true</code> if so
116     */

117     public boolean isEnabled() {
118         return getProperty(PROP_ENABLED).equals(Boolean.TRUE);
119     }
120
121     /** Set whether the action should be enabled.
122     * @param value <code>true</code> to enable it
123     */

124     public void setEnabled(boolean value) {
125         putProperty(PROP_ENABLED, value ? Boolean.TRUE : Boolean.FALSE, true);
126     }
127
128     /** Set a property in the singleton. This property is common for all instances
129     * of the same class.
130     *
131     * @param name the name of the property
132     * @param value the value
133     */

134     public final void putValue(String JavaDoc name, Object JavaDoc value) {
135         putProperty(name, value, true);
136
137         // Could handle putValue (SMALL_ICON, ImageIcon icon) but not
138
// really that important.
139
}
140
141     /** Get a property in the singleton. Values are shared among all instances of the same class.
142     * The special tokens {@link Action#NAME}, {@link Action#SMALL_ICON} and "iconBase" are also recognized
143     * and delegated to {@link #getName}, {@link #getIcon} and {@link #iconResource} resp.
144     * @param name the name of the property
145     * @return the value
146     */

147     public final Object JavaDoc getValue(String JavaDoc name) {
148         if ("iconBase".equals(name)) { // NOI18N
149

150             return iconResource();
151         }
152
153         Object JavaDoc val = getProperty(name);
154
155         if (val == null) {
156             if (NAME.equals(name)) {
157                 val = getName();
158             } else if (SMALL_ICON.equals(name)) {
159                 val = getIcon();
160             }
161         }
162
163         return val;
164     }
165
166     /** Actually perform the action.
167     * Specified in {@link java.awt.event.ActionListener#actionPerformed}.
168     * <p>In some cases, the implementation may have an empty body,
169     * if the presenters handle the performing of the action in a different way
170     * than by calling this method.
171     * <p>Since 4.11, will be performed directly in the event thread.
172     * @param ev the event triggering the action
173     */

174     public abstract void actionPerformed(ActionEvent JavaDoc ev);
175
176     /** Initialize the action.
177     * The default implementation just enabled it.
178     */

179     @Override JavaDoc
180     protected void initialize() {
181         putProperty(PROP_ENABLED, Boolean.TRUE);
182
183         super.initialize();
184     }
185
186     /** Indicate whether action state should be cleared after the last action of this class is deleted.
187     * @return <code>false</code> in the default implementation
188     */

189     @Override JavaDoc
190     protected boolean clearSharedData() {
191         return false;
192     }
193
194     /** Set the action's display icon.
195     * @param icon the icon
196     */

197     public final void setIcon(Icon JavaDoc icon) {
198         putProperty(PROP_ICON, icon, true);
199         putProperty(PROP_ICON_TEXTUAL, icon);
200     }
201
202     /** Get the action's display icon.
203     * @return the icon
204     * @throws IllegalStateException if an icon could not be created
205     */

206     public final Icon JavaDoc getIcon() {
207         return getIcon(false);
208     }
209
210     /** Get the action's display icon, possibly creating a text label.
211     * @param createLabel if <code>true</code>, create a textual icon if otherwise there
212     * would be none; if <code>false</code>, create a blank icon
213     * @return an icon
214     * @throws IllegalStateException if an icon could not be created
215     */

216     public final Icon JavaDoc getIcon(boolean createLabel) {
217         synchronized (getLock()) {
218             Icon JavaDoc img = (Icon JavaDoc) getProperty(createLabel ? PROP_ICON_TEXTUAL : PROP_ICON);
219
220             if (img == null) {
221                 // create the icon from the resource
222
String JavaDoc resName = iconResource();
223
224                 if (resName != null) {
225                     if (resName.indexOf('/') == -1) {
226                         // Old action that used a relative path to the icon.
227
// (If it used a relative path going down a directory, tough luck.
228
// It was never documented that you could use relative paths.
229
// apisupport templates did it, but they put icons in the same dir.)
230
String JavaDoc clazz = getClass().getName();
231                         URL JavaDoc u = getClass().getResource(resName);
232
233                         if (u != null) {
234                             img = new ImageIcon JavaDoc(u);
235
236                             if (relativeIconResourceClasses.add(clazz)) {
237                                 LOG.warning("Deprecated relative path in " + clazz + ".iconResource (cf. #20072)");
238                             }
239                         } else {
240                             LOG.warning("No such icon from " + clazz + ": " + resName);
241                         }
242                     } else {
243                         // Hopefully an absolute path, but again (#26887) might be relative.
244
Image JavaDoc i = Utilities.loadImage(resName, true);
245
246                         if (i != null) {
247                             // OK, the normal case.
248
img = new ImageIcon JavaDoc(i);
249                         } else {
250                             // Check for an old-style relative path.
251
URL JavaDoc u = getClass().getResource(resName);
252                             String JavaDoc clazz = getClass().getName();
253
254                             if (u != null) {
255                                 // OK, but warn.
256
img = new ImageIcon JavaDoc(u);
257
258                                 if (relativeIconResourceClasses.add(clazz)) {
259                                     LOG.warning("Deprecated relative path in " + clazz + ".iconResource (cf. #26887)");
260                                 }
261                             } else {
262                                 // Really can't find it.
263
LOG.warning("No such icon from " + clazz + ": " + resName);
264                             }
265                         }
266                     }
267
268                     putProperty(PROP_ICON, img);
269                     putProperty(PROP_ICON_TEXTUAL, img);
270                 }
271             }
272
273             if (img == null) {
274                 if (createLabel) {
275                     String JavaDoc text = getName();
276                     if (text.endsWith("...")) { // NOI18N
277
text = text.substring(0, text.length() - 3);
278                     }
279                     text = text.trim();
280                     int ampr = text.indexOf('&');
281                     if (ampr != -1) {
282                         text = new StringBuffer JavaDoc(text).deleteCharAt(ampr).toString();
283                     }
284                     img = new ComponentIcon(new JLabel JavaDoc(text));
285                     putProperty(PROP_ICON_TEXTUAL, img);
286                 } else {
287                     img = BLANK_ICON;
288                     putProperty(PROP_ICON, img);
289                 }
290             }
291
292             return img;
293         }
294     }
295
296     /** Specify the proper resource name for the action's icon.
297     * May be overridden by subclasses; the default is to have no icon.
298     * Typically this should be a 16x16 color GIF.
299     * Do not use relative paths nor an initial slash.
300     * If e.g. myIcon.gif is accompanied with myIcon_pressed.gif, myIcon_disabled.gif
301     * and/or myIcon_rollover.gif these images are used to call methods on JButton.setPressedIcon(),
302     * JButton.setDisabledIcon() and/or JButton.setRolloverIcon() with appropriate images.
303     * Please check <a HREF="@org-openide-awt@/org/openide/awt/Actions.html#connect(AbstractButton,%20Action)">Actions.connect</a> for
304     * additional info how this is achieved (using special "iconBase" key for getValue).
305     * As of APIs version 3.24, this path will be used for a localized search automatically.
306     * If you do not want an icon, do <em>not</em> override this to return a blank icon. Leave it null,
307     * but call <code>putValue("noIconInMenu", Boolean.TRUE)</code> to make sure that no extra space is allotted for an icon in the menu item.
308     * @return the resource name for the icon, e.g. <code>com/mycom/mymodule/myIcon.gif</code>; or <code>null</code> to have no icon (make a text label)
309     */

310     protected String JavaDoc iconResource() {
311         return null;
312     }
313
314     /** Create the default toolbar representation of an array of actions.
315     * Null items in the array will add a separator to the toolbar.
316     *
317     * @param actions actions to show in the generated toolbar
318     * @return a toolbar instance displaying them
319     */

320     public static JToolBar JavaDoc createToolbarPresenter(SystemAction[] actions) {
321         JToolBar JavaDoc p = new JToolBar JavaDoc();
322         for (SystemAction action : actions) {
323             if (action == null) {
324                 p.addSeparator();
325             } else if (action instanceof Presenter.Toolbar) {
326                 p.add(((Presenter.Toolbar) action).getToolbarPresenter());
327             }
328         }
329         return p;
330     }
331
332     /** Concatenate two arrays of actions.
333     * @param actions1 first array of actions to link
334     * @param actions2 second array of actions to link
335     * @return an array of both sets of actions in the same order
336     */

337     public static SystemAction[] linkActions(SystemAction[] actions1, SystemAction[] actions2) {
338         List JavaDoc<SystemAction> l = new ArrayList JavaDoc<SystemAction>(Arrays.asList(actions1));
339         l.addAll(Arrays.asList(actions2));
340
341         return l.toArray(actions1);
342     }
343
344     /** Create the default popup menu representation of an array of actions.
345     * @param actions actions to show in the generated menu
346     * @return a popup menu displaying them
347     *
348     * @deprecated Use {@link org.openide.util.Utilities#actionsToPopup}
349     */

350     @Deprecated JavaDoc
351     public static JPopupMenu JavaDoc createPopupMenu(SystemAction[] actions) {
352         return Utilities.actionsToPopup(actions, Utilities.actionsGlobalContext());
353     }
354
355     /** Icon based on a component (such as a text label).
356     * Just draws that component as an image.
357     */

358     private static class ComponentIcon extends ImageIcon JavaDoc {
359         private JComponent JavaDoc comp;
360         private BufferedImage JavaDoc image;
361
362         /** Create an icon.
363         * @param comp a component, which must be unattached to a container
364         * and should not be used for other purposes
365         */

366         public ComponentIcon(JComponent JavaDoc comp) {
367             if (comp.getParent() != null) {
368                 throw new IllegalArgumentException JavaDoc();
369             }
370
371             this.comp = comp;
372
373             Dimension JavaDoc size = comp.getPreferredSize();
374
375             // Careful! If you have e.g. a JLabel with empty text, width = 0 => exceptions.
376
// Must make sure it is at least a reasonable size.
377
comp.setSize(Math.max(size.width, 16), Math.max(size.height, 16));
378         }
379
380         protected void loadImage(Image JavaDoc i) {
381         }
382
383         public void paintIcon(Component JavaDoc c, Graphics JavaDoc g, int x, int y) {
384             // When enabled, tracks color choices of container:
385
comp.setBackground(c.getBackground());
386             comp.setForeground(c.getForeground());
387
388             Graphics JavaDoc clip = g.create(x, y, getIconWidth(), getIconHeight());
389             comp.paint(clip);
390         }
391
392         public int getIconWidth() {
393             return comp.getWidth();
394         }
395
396         public int getIconHeight() {
397             return comp.getHeight();
398         }
399
400         // Needed because this is called directly from e.g.
401
// AbstractButton.getDisabledIcon to pass to GrayFilter,
402
// rather than going through the Icon interface.
403
public Image JavaDoc getImage() {
404             if (image == null) {
405                 image = new BufferedImage JavaDoc(getIconWidth(), getIconHeight(), BufferedImage.TYPE_INT_ARGB);
406
407                 // [PENDING] this is obviously ugly, but how should we decide what is the
408
// default fg for the Main Window toolbar area? Background is irrelevant,
409
// since we use alpha channel. But have to guess at the foreground.
410
comp.setForeground(Color.black);
411                 comp.paint(image.getGraphics());
412             }
413
414             return image;
415         }
416     }
417 }
418
Popular Tags