Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/apache/batik/util/gui/resource/MenuFactory.java


1   /*
2   
3      Copyright 2000-2001,2003  The Apache Software Foundation 
4   
5      Licensed under the Apache License, Version 2.0 (the "License");
6      you may not use this file except in compliance with the License.
7      You may obtain a copy of the License at
8   
9          http://www.apache.org/licenses/LICENSE-2.0
10  
11     Unless required by applicable law or agreed to in writing, software
12     distributed under the License is distributed on an "AS IS" BASIS,
13     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14     See the License for the specific language governing permissions and
15     limitations under the License.
16  
17   */
18  package org.apache.batik.util.gui.resource;
19  
20  import java.awt.Event;
21  import java.awt.event.KeyEvent;
22  import java.net.URL;
23  import java.util.Iterator;
24  import java.util.List;
25  import java.util.MissingResourceException;
26  import java.util.ResourceBundle;
27  
28  import javax.swing.AbstractButton;
29  import javax.swing.Action;
30  import javax.swing.ButtonGroup;
31  import javax.swing.ImageIcon;
32  import javax.swing.JCheckBoxMenuItem;
33  import javax.swing.JComponent;
34  import javax.swing.JMenu;
35  import javax.swing.JMenuBar;
36  import javax.swing.JMenuItem;
37  import javax.swing.JRadioButtonMenuItem;
38  import javax.swing.JSeparator;
39  import javax.swing.KeyStroke;
40  
41  /**
42   * This class represents a menu factory which builds
43   * menubars and menus from the content of a resource file. <br>
44   *
45   * The resource entries format is (for a menubar named 'MenuBar'):<br>
46   * <pre>
47   *   MenuBar           = Menu1 Menu2 ...
48   *
49   *   Menu1.type        = RADIO | CHECK | MENU | ITEM
50   *   Menu1             = Item1 Item2 - Item3 ...
51   *   Menu1.text        = text 
52   *   Menu1.icon        = icon_name 
53   *   Menu1.mnemonic    = mnemonic 
54   *   Menu1.accelerator = accelerator
55   *   Menu1.action      = action_name
56   *   Menu1.selected    = true | false
57   *   Menu1.enabled     = true | false
58   *   ...
59   * mnemonic is a single character
60   * accelerator is of the form: mod+mod+...+X
61   *   where mod is Shift, Meta, Alt or Ctrl
62   * '-' represents a separator
63   * </pre>
64   * All entries are optional except the '.type' entry
65   * Consecutive RADIO items are put in a ButtonGroup
66   *
67   * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
68   * @version $Id: MenuFactory.java,v 1.8 2005/03/27 08:58:37 cam Exp $
69   */
70  public class MenuFactory extends ResourceManager {
71      // Constants
72      //
73      private final static String TYPE_MENU          = "MENU";
74      private final static String TYPE_ITEM          = "ITEM";
75      private final static String TYPE_RADIO         = "RADIO";
76      private final static String TYPE_CHECK         = "CHECK";
77      private final static String SEPARATOR          = "-";
78  
79      private final static String TYPE_SUFFIX        = ".type";
80      private final static String TEXT_SUFFIX        = ".text";
81      private final static String MNEMONIC_SUFFIX    = ".mnemonic";
82      private final static String ACCELERATOR_SUFFIX = ".accelerator";
83      private final static String ACTION_SUFFIX      = ".action";
84      private final static String SELECTED_SUFFIX    = ".selected";
85      private final static String ENABLED_SUFFIX     = ".enabled";
86      private final static String ICON_SUFFIX        = ".icon";
87  
88      /**
89       * The table which contains the actions
90       */
91      private ActionMap actions;
92  
93      /**
94       * The current radio group
95       */
96      private ButtonGroup buttonGroup;
97  
98      /**
99       * Creates a new menu factory
100      * @param rb the resource bundle that contains the menu bar
101      *           description.
102      * @param am the actions to add to menu items
103      */
104     public MenuFactory(ResourceBundle rb, ActionMap am) {
105         super(rb);
106         actions = am;
107   buttonGroup = null;
108     }
109 
110     /**
111      * Creates and returns a swing menu bar
112      * @param name the name of the menu bar in the resource bundle
113      * @throws MissingResourceException if one of the keys that compose the
114      *         menu is missing.
115      *         It is not thrown if the mnemonic, the accelerator and the
116      *         action keys are missing
117      * @throws ResourceFormatException if the mnemonic is not a single
118      *         character and if the accelerator is malformed
119      * @throws MissingListenerException if an item action is not found in the
120      *         action map
121      */
122     public JMenuBar createJMenuBar(String name)
123   throws MissingResourceException,
124                ResourceFormatException,
125          MissingListenerException {
126         JMenuBar result = new JMenuBar();
127         List     menus  = getStringList(name);
128         Iterator it     = menus.iterator();
129 
130         while (it.hasNext()) {
131             result.add(createJMenuComponent((String)it.next()));
132         }
133         return result;
134     }
135 
136     /**
137      * Creates and returns a menu item or a separator
138      * @param name the name of the menu item or "-" to create a separator
139      * @throws MissingResourceException if key is not the name of a menu item.
140      *         It is not thrown if the mnemonic, the accelerator and the
141      *         action keys are missing
142      * @throws ResourceFormatException in case of malformed entry
143      * @throws MissingListenerException if an item action is not found in the
144      *         action map
145      */
146     protected JComponent createJMenuComponent(String name)
147   throws MissingResourceException,
148          ResourceFormatException,
149          MissingListenerException {
150   if (name.equals(SEPARATOR)) {
151       buttonGroup = null;
152       return new JSeparator();
153   }
154         String     type = getString(name+TYPE_SUFFIX);
155         JComponent item = null;
156 
157   if (type.equals(TYPE_RADIO)) {
158       if (buttonGroup == null) {
159     buttonGroup = new ButtonGroup();
160       }
161   } else {
162       buttonGroup = null;
163   }
164 
165         if (type.equals(TYPE_MENU)) {
166             item = createJMenu(name);
167         } else if (type.equals(TYPE_ITEM)) {
168             item = createJMenuItem(name);
169         } else if (type.equals(TYPE_RADIO)) {
170             item = createJRadioButtonMenuItem(name);
171       buttonGroup.add((AbstractButton)item);
172         } else if (type.equals(TYPE_CHECK)) {
173             item = createJCheckBoxMenuItem(name);
174         } else {
175       throw new ResourceFormatException("Malformed resource",
176                 bundle.getClass().getName(),
177                 name+TYPE_SUFFIX);
178   }
179   
180         return item;
181     }
182 
183     /**
184      * Creates and returns a new swing menu
185      * @param name the name of the menu bar in the resource bundle
186      * @throws MissingResourceException if one of the keys that compose the
187      *         menu is missing.
188      *         It is not thrown if the mnemonic, the accelerator and the
189      *         action keys are missing
190      * @throws ResourceFormatException if the mnemonic is not a single
191      *         character.
192      * @throws MissingListenerException if a item action is not found in the
193      *         action map.
194      */
195     public JMenu createJMenu(String name)
196   throws MissingResourceException,
197          ResourceFormatException,
198          MissingListenerException {
199         JMenu result = new JMenu(getString(name+TEXT_SUFFIX));
200         initializeJMenuItem(result, name);
201 
202         List     items = getStringList(name);
203         Iterator it    = items.iterator();
204 
205         while (it.hasNext()) {
206             result.add(createJMenuComponent((String)it.next()));
207         }
208         return result;
209     }
210 
211     /**
212      * Creates and returns a new swing menu item
213      * @param name the name of the menu item
214      * @throws MissingResourceException if one of the keys that compose the
215      *         menu item is missing.
216      *         It is not thrown if the mnemonic, the accelerator and the
217      *         action keys are missing
218      * @throws ResourceFormatException if the mnemonic is not a single
219      *         character.
220      * @throws MissingListenerException if then item action is not found in
221      *         the action map.
222      */
223     public JMenuItem createJMenuItem(String name)
224   throws MissingResourceException,
225          ResourceFormatException,
226          MissingListenerException {
227         JMenuItem result = new JMenuItem(getString(name+TEXT_SUFFIX));
228         initializeJMenuItem(result, name);
229         return result;
230     }
231 
232     /**
233      * Creates and returns a new swing radio button menu item
234      * @param name the name of the menu item
235      * @throws MissingResourceException if one of the keys that compose the
236      *         menu item is missing.
237      *         It is not thrown if the mnemonic, the accelerator and the
238      *         action keys are missing
239      * @throws ResourceFormatException if the mnemonic is not a single
240      *         character.
241      * @throws MissingListenerException if then item action is not found in
242      *         the action map.
243      */
244     public JRadioButtonMenuItem createJRadioButtonMenuItem(String name)
245   throws MissingResourceException,
246          ResourceFormatException,
247          MissingListenerException {
248         JRadioButtonMenuItem result;
249   result = new JRadioButtonMenuItem(getString(name+TEXT_SUFFIX));
250         initializeJMenuItem(result, name);
251 
252         // is the item selected?
253   try {
254       result.setSelected(getBoolean(name+SELECTED_SUFFIX));
255   } catch (MissingResourceException e) {
256   }
257   
258         return result;
259     }
260 
261     /**
262      * Creates and returns a new swing check box menu item
263      * @param name the name of the menu item
264      * @throws MissingResourceException if one of the keys that compose the
265      *         menu item is missing.
266      *         It is not thrown if the mnemonic, the accelerator and the
267      *         action keys are missing
268      * @throws ResourceFormatException if the mnemonic is not a single
269      *         character.
270      * @throws MissingListenerException if then item action is not found in
271      *         the action map.
272      */
273     public JCheckBoxMenuItem createJCheckBoxMenuItem(String name)
274   throws MissingResourceException,
275          ResourceFormatException,
276          MissingListenerException {
277         JCheckBoxMenuItem result;
278         result = new JCheckBoxMenuItem(getString(name+TEXT_SUFFIX));
279         initializeJMenuItem(result, name);
280 
281         // is the item selected?
282   try {
283       result.setSelected(getBoolean(name+SELECTED_SUFFIX));
284   } catch (MissingResourceException e) {
285   }
286   
287         return result;
288     }
289 
290     /**
291      * Initializes a swing menu item
292      * @param item the menu item to initialize
293      * @param name the name of the menu item
294      * @throws ResourceFormatException if the mnemonic is not a single
295      *         character.
296      * @throws MissingListenerException if then item action is not found in
297      *         the action map.
298      */
299     protected void initializeJMenuItem(JMenuItem item, String name)
300   throws ResourceFormatException,
301          MissingListenerException {
302         // Action
303   try {
304       Action a = actions.getAction(getString(name+ACTION_SUFFIX));
305       if (a == null) {
306     throw new MissingListenerException("", "Action",
307                                                    name+ACTION_SUFFIX);
308       }
309       item.setAction(a);
310             item.setText(getString(name+TEXT_SUFFIX));
311       if (a instanceof JComponentModifier) {
312     ((JComponentModifier)a).addJComponent(item);
313       }
314   } catch (MissingResourceException e) {
315   }
316 
317   // Icon
318   try {
319       String s = getString(name+ICON_SUFFIX);
320       URL url  = actions.getClass().getResource(s);
321       if (url != null) {
322     item.setIcon(new ImageIcon(url));
323       }
324   } catch (MissingResourceException e) {
325   }
326 
327         // Mnemonic
328   try {
329       String str = getString(name+MNEMONIC_SUFFIX);
330       if (str.length() == 1) {
331     item.setMnemonic(str.charAt(0));
332       } else {
333     throw new ResourceFormatException("Malformed mnemonic",
334               bundle.getClass().getName(),
335               name+MNEMONIC_SUFFIX);
336       }
337   } catch (MissingResourceException e) {
338   }
339 
340         // Accelerator
341   try {
342       if (!(item instanceof JMenu)) {
343     String str = getString(name+ACCELERATOR_SUFFIX);
344     KeyStroke ks = toKeyStroke(str);
345     if (ks != null) {
346         item.setAccelerator(ks);
347     } else {
348         throw new ResourceFormatException
349                         ("Malformed accelerator",
350                          bundle.getClass().getName(),
351                          name+ACCELERATOR_SUFFIX);
352     }
353       }
354   } catch (MissingResourceException e) {
355   }
356 
357         // is the item enabled?
358   try {
359       item.setEnabled(getBoolean(name+ENABLED_SUFFIX));
360   } catch (MissingResourceException e) {
361   }
362     }
363 
364     /**
365      * Translate a string into a key stroke.
366      * See the class comment for details
367      * @param str a string
368      */
369     protected KeyStroke toKeyStroke(String str) {
370         int    state = 0;
371         int    code  = 0;
372         int    modif = 0;
373         int    i     = 0;
374 
375         while (state != 100 && i < str.length()) {
376             char curr = Character.toUpperCase(str.charAt(i));
377             
378             switch (state) {
379             case 0 :
380                 code = curr;
381                 switch (curr) {
382                 case 'C': state = 1; break;
383                 case 'A': state = 5; break;
384                 case 'M': state = 8; break;
385                 case 'S': state = 12; break;
386                 default:
387                     state = 100;
388                 }
389                 break;
390 
391             case 1 : state = (curr == 'T') ? 2 : 100; break;
392             case 2 : state = (curr == 'R') ? 3 : 100; break;
393             case 3 : state = (curr == 'L') ? 4 : 100; break;
394             case 4 : state = (curr == '+') ? 0 : 100;
395                 if (state == 0) {
396                     modif |= Event.CTRL_MASK;
397                 }
398                 break;
399             case 5 : state = (curr == 'L') ? 6 : 100; break;
400             case 6 : state = (curr == 'T') ? 7 : 100; break;
401             case 7 : state = (curr == '+') ? 0 : 100;
402                 if (state == 0) {
403                     modif |= Event.ALT_MASK;
404                 }
405                 break;
406             case 8 : state = (curr == 'E') ? 9 : 100; break;
407             case 9 : state = (curr == 'T') ? 10: 100; break;
408             case 10: state = (curr == 'A') ? 11: 100; break;
409             case 11: state = (curr == '+') ? 0 : 100;
410                 if (state == 0) {
411                     modif |= Event.META_MASK;
412                 }
413                 break;
414             case 12: state = (curr == 'H') ? 13: 100; break;
415             case 13: state = (curr == 'I') ? 14: 100; break;
416             case 14: state = (curr == 'F') ? 15: 100; break;
417             case 15: state = (curr == 'T') ? 16: 100; break;
418             case 16: state = (curr == '+') ? 0 : 100;
419                 if (state == 0) {
420                     modif |= Event.SHIFT_MASK;
421                 }
422                 break;
423             }
424             i++;
425         }
426         if (code > 0 && modif > 0) {
427             if (i < str.length()) {
428                 char curr = Character.toUpperCase(str.charAt(i));
429                 switch (code) {
430                 case 'U':
431                     if (str.length() - i != 1 || curr != 'P') {
432                         break;
433                     }
434                     code = KeyEvent.VK_UP;
435                     break;
436                 case 'L':
437                     if (str.length() - i != 3 ||
438                         curr != 'E' ||
439                         Character.toUpperCase(str.charAt(i + 1)) != 'F' ||
440                         Character.toUpperCase(str.charAt(i + 2)) != 'T') {
441                         break;
442                     }
443                     code = KeyEvent.VK_LEFT;
444                     break;
445                 case 'D':
446                     if (str.length() - i != 3 ||
447                         curr != 'O' ||
448                         Character.toUpperCase(str.charAt(i + 1)) != 'W' ||
449                         Character.toUpperCase(str.charAt(i + 2)) != 'N') {
450                         break;
451                     }
452                     code = KeyEvent.VK_DOWN;
453                     break;
454                 case 'R':
455                     if (str.length() - i != 4 ||
456                         curr != 'I' ||
457                         Character.toUpperCase(str.charAt(i + 1)) != 'G' ||
458                         Character.toUpperCase(str.charAt(i + 2)) != 'H' ||
459                         Character.toUpperCase(str.charAt(i + 3)) != 'T') {
460                         break;
461                     }
462                     code = KeyEvent.VK_RIGHT;
463                 }
464             }
465             return KeyStroke.getKeyStroke(code, modif);
466         }
467         return null;
468     }
469 }