KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jdesktop > swing > actions > ActionContainerFactory


1 /*
2  * $Id: ActionContainerFactory.java,v 1.4 2005/01/26 20:00:59 davidson1 Exp $
3  *
4  * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
5  * Santa Clara, California 95054, U.S.A. All rights reserved.
6  */

7 package org.jdesktop.swing.actions;
8
9 import java.util.Arrays JavaDoc;
10 import java.util.HashMap JavaDoc;
11 import java.util.Iterator JavaDoc;
12 import java.util.List JavaDoc;
13 import java.util.Map JavaDoc;
14
15 import javax.swing.AbstractButton JavaDoc;
16 import javax.swing.Action JavaDoc;
17 import javax.swing.ButtonGroup JavaDoc;
18 import javax.swing.Icon JavaDoc;
19 import javax.swing.JButton JavaDoc;
20 import javax.swing.JCheckBoxMenuItem JavaDoc;
21 import javax.swing.JComponent JavaDoc;
22 import javax.swing.JMenu JavaDoc;
23 import javax.swing.JMenuBar JavaDoc;
24 import javax.swing.JMenuItem JavaDoc;
25 import javax.swing.JPopupMenu JavaDoc;
26 import javax.swing.JRadioButtonMenuItem JavaDoc;
27 import javax.swing.JToggleButton JavaDoc;
28 import javax.swing.JToolBar JavaDoc;
29
30 /**
31  * Creates user interface elements based on action ids and lists of action ids.
32  * All action ids must be represent actions managed by the ActionManager.
33  * <p>
34  * <h3>Action Lists</h3>
35  * Use a the create..(List) methods to construct containers of actions like menu
36  * bars, menus, popups and toolbars from actions represented as action ids in a
37  * <i>java.util.List</i>. Each element in the action-list can be one of 3 types:
38  * <ul>
39  * <li>action id: corresponds to an action managed by the ActionManager
40  * <li>null: indicates a separator should be inserted.
41  * <li>java.util.List: represents a submenu. See the note below which describes
42  * the configuration of menus.
43  * </li>
44  * The order of elements in an action-list determines the arrangement of the ui
45  * components which are contructed from the action-list.
46  * <p>
47  * For a menu or submenu, the first element in the action-list represents a menu
48  * and subsequent elements represent menu items or separators (if null).
49  * <p>
50  * This class can be used as a general component factory which will construct
51  * components from Actions if the <code>create&lt;comp&gt;(Action,...)</code>
52  * methods are used.
53  *
54  * @see ActionManager
55  */

56 public class ActionContainerFactory {
57
58     private ActionManager manager;
59
60     // Map between group id + component and the ButtonGroup
61
private Map JavaDoc groupMap;
62
63     /**
64      * Constructs an container factory which uses managed actions.
65      *
66      * @param manager use the actions managed with this manager for
67      * constructing ui componenents.
68      */

69     public ActionContainerFactory(ActionManager manager) {
70         setActionManager(manager);
71     }
72
73     /**
74      * Gets the ActionManager instance. If the ActionManager has not been explicitly
75      * set then the default ActionManager instance will be used.
76      *
77      * @return the ActionManager used by the ActionContainerFactory.
78      * @see #setActionManager
79      */

80     public ActionManager getActionManager() {
81         if (manager == null) {
82             manager = ActionManager.getInstance();
83         }
84         return manager;
85     }
86
87     /**
88      * Sets the ActionManager instance that will be used by this
89      * ActionContainerFactory
90      */

91     public void setActionManager(ActionManager manager) {
92         ActionManager oldManager = this.manager;
93         if (oldManager != null) {
94             oldManager.setFactory(null);
95         }
96         this.manager = manager;
97         
98         if (manager != null) {
99             manager.setFactory(this);
100         }
101     }
102
103     /**
104      * Constructs a toolbar from an action-list id. By convention,
105      * the identifier of the main toolbar should be "main-toolbar"
106      *
107      * @param list a list of action ids used to construct the toolbar.
108      * @return the toolbar or null
109      */

110     private JToolBar JavaDoc createToolBar(Object JavaDoc[] list) {
111         return createToolBar(Arrays.asList(list));
112     }
113
114     /**
115      * Constructs a toolbar from an action-list id. By convention,
116      * the identifier of the main toolbar should be "main-toolbar"
117      *
118      * @param list a list of action ids used to construct the toolbar.
119      * @return the toolbar or null
120      */

121     public JToolBar JavaDoc createToolBar(List JavaDoc list) {
122         JToolBar JavaDoc toolbar = new JToolBar JavaDoc();
123         Iterator JavaDoc iter = list.iterator();
124         while(iter.hasNext()) {
125             Object JavaDoc element = iter.next();
126
127             if (element == null) {
128                 toolbar.addSeparator();
129             } else {
130                 AbstractButton JavaDoc button = createButton(element, toolbar);
131                 // toolbar buttons shouldn't steal focus
132
button.setFocusable(false);
133                 toolbar.add(button);
134             }
135         }
136         return toolbar;
137     }
138
139
140     /**
141      * Constructs a popup menu from an array of action ids.
142      *
143      * @param list an array of action ids used to construct the popup.
144      * @return the popup or null
145      */

146     private JPopupMenu JavaDoc createPopup(Object JavaDoc[] list) {
147         return createPopup(Arrays.asList(list));
148     }
149
150     /**
151      * Constructs a popup menu from a list of action ids.
152      *
153      * @param list a list of action ids used to construct the popup.
154      * @return the popup or null
155      */

156     public JPopupMenu JavaDoc createPopup(List JavaDoc list) {
157         JPopupMenu JavaDoc popup = new JPopupMenu JavaDoc();
158         Iterator JavaDoc iter = list.iterator();
159         while(iter.hasNext()) {
160             Object JavaDoc element = iter.next();
161
162             if (element == null) {
163                 popup.addSeparator();
164             } else if (element instanceof List JavaDoc) {
165                 JMenu JavaDoc newMenu= createMenu((List JavaDoc)element);
166                 if (newMenu!= null) {
167                     popup.add(newMenu);
168                 }
169             } else {
170                 popup.add(createMenuItem(element, popup));
171             }
172         }
173         return popup;
174     }
175
176     /**
177      * Constructs a menu tree from a list of actions or lists of lists or actions.
178      *
179      * @param list a list which represents the root item.
180      * @return a menu bar which represents the menu bar tree
181      */

182     public JMenuBar JavaDoc createMenuBar(List JavaDoc list) {
183         JMenuBar JavaDoc menubar = new JMenuBar JavaDoc();
184         JMenu JavaDoc menu = null;
185
186         Iterator JavaDoc iter = list.iterator();
187         while(iter.hasNext()) {
188             Object JavaDoc element = iter.next();
189
190             if (element == null) {
191                 if (menu != null) {
192                     menu.addSeparator();
193                 }
194             } else if (element instanceof List JavaDoc) {
195                 menu = createMenu((List JavaDoc)element);
196                 if (menu != null) {
197                     menubar.add(menu);
198                 }
199             } else {
200                 if (menu != null) {
201                     menu.add(createMenuItem(element, menu));
202                 }
203             }
204         }
205         return menubar;
206     }
207
208
209     /**
210      * Creates and returns a menu from a List which represents actions, separators
211      * and sub-menus. The menu
212      * constructed will have the attributes from the first action in the List.
213      * Subsequent actions in the list represent menu items.
214      *
215      * @param list a list of action ids used to construct the menu and menu items.
216      * the first element represents the action used for the menu,
217      * @return the constructed JMenu or null
218      */

219     public JMenu JavaDoc createMenu(List JavaDoc list) {
220         // The first item will be the action for the JMenu
221
Action JavaDoc action = getAction(list.get(0));
222         if (action == null) {
223             return null;
224         }
225         JMenu JavaDoc menu = new JMenu JavaDoc(action);
226
227         // The rest of the items represent the menu items.
228
Iterator JavaDoc iter = list.listIterator(1);
229         while(iter.hasNext()) {
230             Object JavaDoc element = iter.next();
231             if (element == null) {
232                 menu.addSeparator();
233             } else if (element instanceof List JavaDoc) {
234                 JMenu JavaDoc newMenu = createMenu((List JavaDoc)element);
235                 if (newMenu != null) {
236                     menu.add(newMenu);
237                 }
238             } else {
239                 menu.add(createMenuItem(element, menu));
240             }
241         }
242         return menu;
243     }
244
245
246     /**
247      * Convenience method to get the action from an ActionManager.
248      */

249     private Action JavaDoc getAction(Object JavaDoc id) {
250         Action JavaDoc action = getActionManager().getAction(id);
251         if (action == null) {
252             throw new RuntimeException JavaDoc("ERROR: No Action for " + id);
253         }
254         return action;
255     }
256
257     /**
258      * Returns the button group corresponding to the groupid
259      *
260      * @param groupid the value of the groupid attribute for the action element
261      * @param container a container which will further identify the ButtonGroup
262      */

263     private ButtonGroup JavaDoc getGroup(String JavaDoc groupid, JComponent JavaDoc container) {
264         if (groupMap == null) {
265             groupMap = new HashMap JavaDoc();
266         }
267         int intCode = groupid.hashCode();
268         if (container != null) {
269             intCode ^= container.hashCode();
270         }
271         Integer JavaDoc hashCode = new Integer JavaDoc(intCode);
272
273         ButtonGroup JavaDoc group = (ButtonGroup JavaDoc)groupMap.get(hashCode);
274         if (group == null) {
275             group = new ButtonGroup JavaDoc();
276             groupMap.put(hashCode, group);
277         }
278         return group;
279     }
280
281     /**
282      * Creates a menu item based on the attributes of the action element.
283      * Will return a JMenuItem, JRadioButtonMenuItem or a JCheckBoxMenuItem
284      * depending on the context of the Action.
285      *
286      * @return a JMenuItem or subclass depending on type.
287      */

288     private JMenuItem JavaDoc createMenuItem(Object JavaDoc id, JComponent JavaDoc container) {
289         return createMenuItem(getAction(id), container);
290     }
291
292
293     /**
294      * Creates a menu item based on the attributes of the action element.
295      * Will return a JMenuItem, JRadioButtonMenuItem or a JCheckBoxMenuItem
296      * depending on the context of the Action.
297      *
298      * @param action a mangaged Action
299      * @param container the parent container may be null for non-group actions.
300      * @return a JMenuItem or subclass depending on type.
301      */

302     public JMenuItem JavaDoc createMenuItem(Action JavaDoc action, JComponent JavaDoc container) {
303         JMenuItem JavaDoc menuItem = null;
304         if (action instanceof AbstractActionExt) {
305             AbstractActionExt ta = (AbstractActionExt)action;
306
307             if (ta.isStateAction()) {
308                 String JavaDoc groupid = (String JavaDoc)ta.getGroup();
309                 if (groupid != null) {
310                     // If this action has a groupid attribute then it's a
311
// GroupAction
312
menuItem = createRadioButtonMenuItem(getGroup(groupid, container),
313                                                          (AbstractActionExt)action);
314                 } else {
315                     menuItem = createCheckBoxMenuItem((AbstractActionExt)action);
316                 }
317             }
318         }
319
320         if (menuItem == null) {
321             menuItem= new JMenuItem JavaDoc(action);
322             configureMenuItem(menuItem, action);
323         }
324         return menuItem;
325     }
326
327     /**
328      * Creates a menu item based on the attributes of the action.
329      * Will return a JMenuItem, JRadioButtonMenuItem or a JCheckBoxMenuItem
330      * depending on the context of the Action.
331      *
332      * @param action an action used to create the menu item
333      * @return a JMenuItem or subclass depending on type.
334      */

335     public JMenuItem JavaDoc createMenuItem(Action JavaDoc action) {
336         return createMenuItem(action, null);
337     }
338
339
340     /**
341      * Creates a button based on the attributes of the action element.
342      * Will return a JButton or a JToggleButton.
343      */

344     private AbstractButton JavaDoc createButton(Object JavaDoc id, JComponent JavaDoc container) {
345         return createButton(getAction(id), container);
346     }
347
348     /**
349      * Creates a button based on the attributes of the action. If the container
350      * parameter is non-null then it will be used to uniquely identify
351      * the returned component within a ButtonGroup. If the action doesn't
352      * represent a grouped component then this value can be null.
353      *
354      * @param action an action used to create the button
355      * @param container the parent container to uniquely identify
356      * grouped components or null
357      * @return will return a JButton or a JToggleButton.
358      */

359     public AbstractButton JavaDoc createButton(Action JavaDoc action, JComponent JavaDoc container) {
360         if (action == null) {
361             return null;
362         }
363
364         AbstractButton JavaDoc button = null;
365         if (action instanceof AbstractActionExt) {
366             // Check to see if we should create a toggle button
367
AbstractActionExt ta = (AbstractActionExt)action;
368
369             if (ta.isStateAction()) {
370                 // If this action has a groupid attribute then it's a
371
// GroupAction
372
String JavaDoc groupid = (String JavaDoc)ta.getGroup();
373                 if (groupid == null) {
374                     button = createToggleButton(ta);
375                 } else {
376                     button = createToggleButton(ta, getGroup(groupid, container));
377                 }
378             }
379         }
380
381         if (button == null) {
382             // Create a regular button
383
button = new JButton JavaDoc(action);
384             configureButton(button, action);
385         }
386         return button;
387     }
388
389     /**
390      * Creates a button based on the attributes of the action.
391      *
392      * @param action an action used to create the button
393      * @return will return a JButton or a JToggleButton.
394      */

395     public AbstractButton JavaDoc createButton(Action JavaDoc action) {
396         return createButton(action, null);
397     }
398
399     /**
400      * Adds and configures a toggle button.
401      * @param a an abstraction of a toggle action.
402      */

403     private JToggleButton JavaDoc createToggleButton(AbstractActionExt a) {
404         return createToggleButton(a, null);
405     }
406
407     /**
408      * Adds and configures a toggle button.
409      * @param a an abstraction of a toggle action.
410      * @param group the group to add the toggle button or null
411      */

412     private JToggleButton JavaDoc createToggleButton(AbstractActionExt a, ButtonGroup JavaDoc group) {
413         JToggleButton JavaDoc button = new JToggleButton JavaDoc(a);
414         button.addItemListener(a);
415         button.setSelected(a.isSelected());
416         if (group != null) {
417             group.add(button);
418         }
419         configureToggleButton(button, a);
420         return button;
421     }
422
423     /**
424      * This method will be called after toggle buttons are created.
425      * Override for custom configuration but the overriden method should be called
426      * first.
427      *
428      * @param button the button to be configured
429      * @param action the action used to construct the menu item.
430      */

431     protected void configureToggleButton(JToggleButton JavaDoc button, Action JavaDoc action) {
432         configureButton(button, action);
433
434         // The PropertyChangeListener that gets added
435
// to the Action doesn't know how to handle the "selected" property change
436
// in the meantime, the corect thing to do is to add another PropertyChangeListener
437
// to the AbstractActionExt until this is fixed.
438
action.addPropertyChangeListener(new ToggleActionPropertyChangeListener(button));
439     }
440
441
442     /**
443      * This method will be called after buttons created from an action.
444      * Override for custom configuration.
445      *
446      * @param button the button to be configured
447      * @param action the action used to construct the menu item.
448      */

449     protected void configureButton(AbstractButton JavaDoc button, Action JavaDoc action) {
450         if (action.getValue(Action.SHORT_DESCRIPTION) == null) {
451             button.setToolTipText((String JavaDoc)action.getValue(Action.NAME));
452         }
453         // Use the large icon for toolbar buttons.
454
if (action.getValue(AbstractActionExt.LARGE_ICON) != null) {
455             button.setIcon((Icon JavaDoc)action.getValue(AbstractActionExt.LARGE_ICON));
456         }
457         // Don't show the text under the toolbar buttons if they have an icon
458
if (button.getIcon() != null) {
459             button.setText("");
460         }
461     }
462
463     /**
464      * This method will be called after toggle type menu items (like
465      * JRadioButtonMenuItem and JCheckBoxMenuItem) are created.
466      * Override for custom configuration but the overriden method should be called
467      * first.
468      *
469      * @param menuItem the menu item to be configured
470      * @param action the action used to construct the menu item.
471      */

472     protected void configureToggleMenuItem(JMenuItem JavaDoc menuItem, Action JavaDoc action) {
473         configureMenuItem(menuItem, action);
474
475         // The PropertyChangeListener that gets added
476
// to the Action doesn't know how to handle the "selected" property change
477
// in the meantime, the corect thing to do is to add another PropertyChangeListener
478
// to the AbstractActionExt until this is fixed.
479
action.addPropertyChangeListener(new ToggleActionPropertyChangeListener(menuItem));
480     }
481
482
483     /**
484      * This method will be called after menu items are created.
485      * Override for custom configuration.
486      *
487      * @param menuItem the menu item to be configured
488      * @param action the action used to construct the menu item.
489      */

490     protected void configureMenuItem(JMenuItem JavaDoc menuItem, Action JavaDoc action) {
491     }
492
493     /**
494      * Helper method to add a checkbox menu item.
495      */

496     private JCheckBoxMenuItem JavaDoc createCheckBoxMenuItem(AbstractActionExt a) {
497         JCheckBoxMenuItem JavaDoc mi = new JCheckBoxMenuItem JavaDoc(a);
498         mi.addItemListener(a);
499         mi.setSelected(a.isSelected());
500
501         configureToggleMenuItem(mi, a);
502         return mi;
503     }
504
505     /**
506      * Helper method to add a radio button menu item.
507      */

508     private JRadioButtonMenuItem JavaDoc createRadioButtonMenuItem(ButtonGroup JavaDoc group,
509                                                                   AbstractActionExt a) {
510         JRadioButtonMenuItem JavaDoc mi = new JRadioButtonMenuItem JavaDoc(a);
511         mi.addItemListener(a);
512         mi.setSelected(a.isSelected());
513         if (group != null) {
514             group.add(mi);
515         }
516         configureToggleMenuItem(mi, a);
517         return mi;
518     }
519 }
520
Popular Tags