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

Quick Search    Search Deep

Source code: org/eclipse/jface/action/Action.java


1   /*******************************************************************************
2    * Copyright (c) 2000, 2004 IBM Corporation and others.
3    * All rights reserved. This program and the accompanying materials 
4    * are made available under the terms of the Common Public License v1.0
5    * which accompanies this distribution, and is available at
6    * http://www.eclipse.org/legal/cpl-v10.html
7    * 
8    * Contributors:
9    *     IBM Corporation - initial API and implementation
10   *******************************************************************************/
11  package org.eclipse.jface.action;
12  
13  
14  import java.util.HashMap;
15  import java.util.Map;
16  import java.util.StringTokenizer;
17  
18  import org.eclipse.jface.resource.ImageDescriptor;
19  import org.eclipse.jface.resource.JFaceResources;
20  import org.eclipse.jface.util.IPropertyChangeListener;
21  import org.eclipse.jface.util.ListenerList;
22  import org.eclipse.jface.util.PropertyChangeEvent;
23  import org.eclipse.swt.SWT;
24  import org.eclipse.swt.events.HelpListener;
25  import org.eclipse.swt.widgets.Control;
26  import org.eclipse.swt.widgets.Event;
27  import org.eclipse.swt.widgets.Menu;
28  
29  /**
30   * The standard abstract implementation of an action.
31   * <p>
32   * Subclasses must implement the <code>IAction.run</code> method to carry out
33   * the action's semantics.
34   * </p>
35   */
36  public abstract class Action implements IAction {
37    /*
38     * The list of default values the action can have. These
39     * values will determine the style of the action.
40     */
41    private static final String VAL_PUSH_BTN = "PUSH_BTN"; //$NON-NLS-1$
42    private static final Integer VAL_RADIO_BTN_ON = new Integer(1);
43    private static final Integer VAL_RADIO_BTN_OFF = new Integer(0);
44    private static final Boolean VAL_TOGGLE_BTN_ON = Boolean.TRUE;
45    private static final Boolean VAL_TOGGLE_BTN_OFF = Boolean.FALSE;
46    private static final IMenuCreator VAL_DROP_DOWN_MENU = new IMenuCreator() {
47      public void dispose() {
48          // do nothing
49      }
50      public Menu getMenu(Control parent) {
51        // do nothing
52        return null;
53      }
54      public Menu getMenu(Menu parent) {
55        // do nothing
56        return null;
57      }
58    };
59  
60    /**
61     * Table of key codes (key type: <code>String</code>,
62     * value type: <code>Integer</code>); <code>null</code>
63     * if not yet initialized.
64     * @see #findKeyCode
65     */
66    private static Map keyCodes = null;
67    
68    /**
69     * Table of key codes (key type: <code>String</code>,
70     * value type: <code>Integer</code>); <code>null</code>
71     * if not yet initialized. The key is the localalized name
72     * of the key as it appears in menus.
73     * @see #findLocalizedKeyCode
74     */
75    private static Map localizedKeyCodes = null;
76  
77    /**
78     * The localized uppercase versions of the modifer 
79     * keys.
80     */
81    private static String LOCALIZED_CTRL;
82    private static String LOCALIZED_SHIFT;
83    private static String LOCALIZED_ALT;
84    private static String LOCALIZED_COMMAND;
85  
86    /**
87     * Table of string representations of keys
88     * (key type: <code>Integer</code>,
89     * value type: <code>String</code>); <code>null</code>>
90     * if not yet initialized.
91     * @see #findKeyString
92     */
93    private static Map keyStrings = null;
94  
95    /**
96     * List of registered listeners (element type: <code>IPropertyChangeListener</code>).
97     */
98    private ListenerList listeners = new ListenerList(3);
99  
100   /**
101    * This action's text, or <code>null</code> if none.
102    */
103   private String text;
104 
105   /**
106    * This action's description, or <code>null</code> if none.
107    */
108   private String description;
109 
110   /**
111    * This action's id, or <code>null</code> if none.
112    */
113   private String id;
114 
115   /**
116    * This action's action definition id, or <code>null</code> if none.
117    */
118   private String actionDefinitionId;
119 
120   /**
121    * This action's tool tip text, or <code>null</code> if none.
122    */
123   private String toolTipText;
124 
125   /**
126    * An action's help listener, or <code>null</code> if none.
127    */
128   private HelpListener helpListener;
129 
130   /**
131    * This action's image, or <code>null</code> if none.
132    */
133   private ImageDescriptor image;
134 
135   /**
136    * This action's hover image, or <code>null</code> if none.
137    */
138   private ImageDescriptor hoverImage;
139 
140   /**
141    * This action's disabled image, or <code>null</code> if none.
142    */
143   private ImageDescriptor disabledImage;
144 
145   /**
146    * Holds the action's menu creator (an IMenuCreator) or checked state (a
147    * Boolean for toggle button, or an Integer for radio button), or
148    * <code>null</code> if neither have been set.
149    * <p>
150    * The value of this field affects the value of <code>getStyle()</code>.
151    * </p>
152    */
153   private Object value = null;
154 
155   /**
156    * This action's accelerator; <code>0</code> means none.
157    */
158   private int accelerator = 0;
159 
160   /**
161    * Indicates this action is enabled.
162    */
163   private boolean enabled = true;
164 
165   /**
166    * Creates a new action with no text and no image.
167    * <p>
168    * Configure the action later using the set methods.
169    * </p>
170    */
171   protected Action() {
172       // do nothing
173   }
174   
175   /**
176    * Creates a new action with the given text and no image.
177    * Calls the zero-arg constructor, then <code>setText</code>.
178    *
179    * @param text the string used as the text for the action, 
180    *   or <code>null</code> if there is no text
181    * @see #setText
182    */
183   protected Action(String text) {
184     this();
185     setText(text);
186   }
187   
188   /**
189    * Creates a new action with the given text and image.
190    * Calls the zero-arg constructor, then <code>setText</code> and <code>setImageDescriptor</code>.
191    *
192    * @param text the action's text, or <code>null</code> if there is no text
193    * @param image the action's image, or <code>null</code> if there is no image
194    * @see #setText
195    * @see #setImageDescriptor
196    */
197   protected Action(String text, ImageDescriptor image) {
198     this(text);
199     setImageDescriptor(image);
200   }
201   
202   /**
203    * Creates a new action with the given text and style.
204    * 
205    * @param text the action's text, or <code>null</code> if there is no text
206    * @param style one of <code>AS_PUSH_BUTTON</code>, <code>AS_CHECK_BOX</code>,
207    *     <code>AS_DROP_DOWN_MENU</code>, <code>AS_RADIO_BUTTON</code>, and
208    *     <code>AS_UNSPECIFIED</code>.
209    */
210   protected Action(String text, int style) {
211     this(text);
212     switch (style) {
213       case AS_PUSH_BUTTON :
214         value = VAL_PUSH_BTN;
215         break;
216       case AS_CHECK_BOX :
217         value = VAL_TOGGLE_BTN_OFF;
218         break;
219       case AS_DROP_DOWN_MENU :
220         value = VAL_DROP_DOWN_MENU;
221         break;
222       case AS_RADIO_BUTTON :
223         value = VAL_RADIO_BTN_OFF;
224         break;
225     }
226   }
227   
228   /* (non-Javadoc)
229    * Method declared on IAction.
230    */
231   public void addPropertyChangeListener(IPropertyChangeListener listener) {
232     listeners.add(listener);
233   }
234 
235   /**
236    * Parses the given accelerator text, and converts it to an accelerator key code.
237    * 
238    * Support for localized modifiers is for backwards compatibility
239    * with 1.0. Use setAccelerator(int) to set accelerators programatically
240    * or the <code>accelerator</code> tag in action definitions in 
241    * plugin.xml.
242    *
243    * @param acceleratorText the accelerator text localized to the current locale
244    * @return the SWT key code, or 0 if there is no accelerator
245    */
246   private static int convertLocalizedAccelerator(String acceleratorText) {
247     int accelerator = 0;
248     StringTokenizer stok = new StringTokenizer(acceleratorText, "+"); //$NON-NLS-1$
249 
250     int keyCode = -1;
251 
252     boolean hasMoreTokens = stok.hasMoreTokens();
253     while (hasMoreTokens) {
254       String token = stok.nextToken();
255       hasMoreTokens = stok.hasMoreTokens();
256       // Every token except the last must be one of the modifiers
257       // Ctrl, Shift, Alt, or Command
258       if (hasMoreTokens) {
259         int modifier = findLocalizedModifier(token);
260         if (modifier != 0) {
261           accelerator |= modifier;
262         } else { //Leave if there are none
263           return 0;
264         }
265       } else {
266         keyCode = findLocalizedKeyCode(token);
267       }
268     }
269     if (keyCode != -1) {
270       accelerator |= keyCode;
271     }
272     return accelerator;
273   }
274 
275   /**
276    * Parses the given accelerator text, and converts it to an accelerator key code.
277    *
278    * @param acceleratorText the accelerator text
279    * @return the SWT key code, or 0 if there is no accelerator
280    */
281   public static int convertAccelerator(String acceleratorText) {
282     int accelerator = 0;
283     StringTokenizer stok = new StringTokenizer(acceleratorText, "+"); //$NON-NLS-1$
284 
285     int keyCode = -1;
286 
287     boolean hasMoreTokens = stok.hasMoreTokens();
288     while (hasMoreTokens) {
289       String token = stok.nextToken();
290       hasMoreTokens = stok.hasMoreTokens();
291       // Every token except the last must be one of the modifiers
292       // Ctrl, Shift, Alt, or Command
293       if (hasMoreTokens) {
294         int modifier = findModifier(token);
295         if (modifier != 0) {
296           accelerator |= modifier;
297         } else { //Leave if there are none
298           return 0;
299         }
300       } else {
301         keyCode = findKeyCode(token);
302       }
303     }
304     if (keyCode != -1) {
305       accelerator |= keyCode;
306     }
307     return accelerator;
308   }
309   /**
310    * Converts an accelerator key code to a string representation.
311    * 
312    * @param keyCode the key code to be translated
313    * @return a string representation of the key code
314    */
315   public static String convertAccelerator(int keyCode) {
316     String modifier = getModifierString(keyCode);
317     String fullKey;
318     if (modifier.equals("")) { //$NON-NLS-1$
319       fullKey = findKeyString(keyCode);
320     } else {
321       fullKey = modifier + "+" + findKeyString(keyCode); //$NON-NLS-1$
322     }
323     return fullKey;
324   }
325   /*
326    * Returns the string representation of the modifiers (Ctrl, Alt, Shift, Command)
327    * of the key event.
328    */
329   private static String getModifierString(int keyCode) {
330     String modString = ""; //$NON-NLS-1$
331 
332     if ((keyCode & SWT.CTRL) != 0) {
333       modString = findModifierString(keyCode & SWT.CTRL);
334     }
335 
336     if ((keyCode & SWT.ALT) != 0) {
337       if (modString.equals("")) { //$NON-NLS-1$
338         modString = findModifierString(keyCode & SWT.ALT);
339       } else {
340         modString = modString + "+" + findModifierString(keyCode & SWT.ALT); //$NON-NLS-1$
341       }
342     }
343 
344     if ((keyCode & SWT.SHIFT) != 0) {
345       if (modString.equals("")) { //$NON-NLS-1$
346         modString = findModifierString(keyCode & SWT.SHIFT);
347       } else {
348         modString = modString + "+" + findModifierString(keyCode & SWT.SHIFT); //$NON-NLS-1$
349       }
350     }
351 
352     if ((keyCode & SWT.COMMAND) != 0) {
353       if (modString.equals("")) { //$NON-NLS-1$
354         modString = findModifierString(keyCode & SWT.COMMAND);
355       } else {
356         modString = modString + "+" + findModifierString(keyCode & SWT.COMMAND); //$NON-NLS-1$
357       }
358     }
359 
360     return modString;
361   }
362   /**
363    * Extracts the accelerator text from the given text.
364    * Returns <code>null</code> if there is no accelerator text,
365    * and the empty string if there is no text after the accelerator delimeter (tab or '@').
366    *
367    * @param text the text for the action
368    * @return the accelerator text, or <code>null</code>
369    */
370   private static String extractAcceleratorText(String text) {
371     int index = text.lastIndexOf('\t');
372     if (index == -1)
373       index = text.lastIndexOf('@');
374     if (index >= 0)
375       return text.substring(index + 1);
376     return null;
377   }
378   /**
379    * Maps a standard keyboard key name to an SWT key code.
380    * Key names are converted to upper case before comparison.
381    * If the key name is a single letter, for example "S", its character code is returned.
382    * <p>
383    * The following key names are known (case is ignored):
384    * <ul>
385    *   <li><code>"BACKSPACE"</code></li>
386    *  <li><code>"TAB"</code></li>
387    *  <li><code>"RETURN"</code></li>
388    *  <li><code>"ENTER"</code></li>
389    *  <li><code>"ESC"</code></li>
390    *  <li><code>"ESCAPE"</code></li>
391    *  <li><code>"DELETE"</code></li>
392    *  <li><code>"SPACE"</code></li>
393    *  <li><code>"ARROW_UP"</code>, <code>"ARROW_DOWN"</code>,
394    *     <code>"ARROW_LEFT"</code>, and <code>"ARROW_RIGHT"</code></li>
395    *  <li><code>"PAGE_UP"</code> and <code>"PAGE_DOWN"</code></li>
396    *  <li><code>"HOME"</code></li>
397    *  <li><code>"END"</code></li>
398    *  <li><code>"INSERT"</code></li>
399    *  <li><code>"F1"</code>, <code>"F2"</code> through <code>"F12"</code></li>
400    * </ul>
401    * </p>
402    *
403    * @param token the key name
404    * @return the SWT key code, <code>-1</code> if no match was found
405    * @see SWT
406    */
407   public static int findKeyCode(String token) {
408     if (keyCodes == null)
409       initKeyCodes();
410     token = token.toUpperCase();
411     Integer i = (Integer) keyCodes.get(token);
412     if (i != null)
413       return i.intValue();
414     if (token.length() == 1)
415       return token.charAt(0);
416     return -1;
417   }
418 
419   /**
420    * Find the supplied code for a localized key. As
421    * #findKeyCode but localized to the current locale.
422    * 
423    * Support for localized modifiers is for backwards compatibility
424    * with 1.0. Use setAccelerator(int) to set accelerators programatically
425    * or the <code>accelerator</code> tag in action definitions in 
426    * plugin.xml.
427    *
428    * @param token the localized key name
429    * @return the SWT key code, <code>-1</code> if no match was found
430    * @see #findKeyCode
431    */
432   private static int findLocalizedKeyCode(String token) {
433     if (localizedKeyCodes == null)
434       initLocalizedKeyCodes();
435     token = token.toUpperCase();
436     Integer i = (Integer) localizedKeyCodes.get(token);
437     if (i != null)
438       return i.intValue();
439     if (token.length() == 1)
440       return token.charAt(0);
441     return -1;
442   }
443   /**
444    * Maps an SWT key code to a standard keyboard key name. The key code is
445    * stripped of modifiers (SWT.CTRL, SWT.ALT, SWT.SHIFT, and SWT.COMMAND). If the key code is
446    * not an SWT code (for example if it a key code for the key 'S'), a string
447    * containing a character representation of the key code is returned.
448    * 
449    * @param keyCode the key code to be translated
450    * @return the string representation of the key code
451    * @see SWT
452    * @since 2.0
453    */
454   public static String findKeyString(int keyCode) {
455     if (keyStrings == null)
456       initKeyStrings();
457     int i = keyCode & ~(SWT.CTRL | SWT.ALT | SWT.SHIFT | SWT.COMMAND);
458     Integer integer = new Integer(i);
459     String result = (String) keyStrings.get(integer);
460     if (result != null)
461       return result;
462     result = new String(new char[] {(char) i });
463     return result;
464   }
465   /**
466    * Maps standard keyboard modifier key names to the corresponding 
467    * SWT modifier bit. The following modifier key names are recognized 
468    * (case is ignored): <code>"CTRL"</code>, <code>"SHIFT"</code>, 
469    * <code>"ALT"</code>, and <code>"COMMAND"</code>.
470    * The given modifier key name is converted to upper case before comparison.
471    *
472    * @param token the modifier key name
473    * @return the SWT modifier bit, or <code>0</code> if no match was found
474    * @see SWT
475    */
476   public static int findModifier(String token) {
477     token = token.toUpperCase();
478     if (token.equals("CTRL")) //$NON-NLS-1$
479       return SWT.CTRL;
480     if (token.equals("SHIFT")) //$NON-NLS-1$
481       return SWT.SHIFT;
482     if (token.equals("ALT")) //$NON-NLS-1$
483       return SWT.ALT;
484     if (token.equals("COMMAND")) //$NON-NLS-1$
485       return SWT.COMMAND;
486     return 0;
487   }
488 
489   /**
490    * Maps the localized modifier names to a code in the same
491    * manner as #findModifier.
492    * 
493    * Support for localized modifiers is for backwards compatibility
494    * with 1.0. Use setAccelerator(int) to set accelerators programatically
495    * or the <code>accelerator</code> tag in action definitions in 
496    * plugin.xml.
497    * 
498    * @see findModifier
499    */
500   private static int findLocalizedModifier(String token) {
501     if (LOCALIZED_CTRL == null)
502       initLocalizedModifiers();
503 
504     token = token.toUpperCase();
505     if (token.equals(LOCALIZED_CTRL)) //$NON-NLS-1$
506       return SWT.CTRL;
507     if (token.equals(LOCALIZED_SHIFT)) //$NON-NLS-1$
508       return SWT.SHIFT;
509     if (token.equals(LOCALIZED_ALT)) //$NON-NLS-1$
510       return SWT.ALT;
511     if (token.equals(LOCALIZED_COMMAND)) //$NON-NLS-1$
512       return SWT.COMMAND;
513     return 0;
514   }
515 
516   /**
517    * Initialize the list of localized modifiers
518    */
519   private static void initLocalizedModifiers() {
520     LOCALIZED_CTRL = JFaceResources.getString("Ctrl").toUpperCase(); //$NON-NLS-1$
521     LOCALIZED_SHIFT = JFaceResources.getString("Shift").toUpperCase(); //$NON-NLS-1$
522     LOCALIZED_ALT = JFaceResources.getString("Alt").toUpperCase(); //$NON-NLS-1$
523     LOCALIZED_COMMAND = JFaceResources.getString("Command").toUpperCase(); //$NON-NLS-1$  
524   }
525 
526   /**
527    * Returns a string representation of an SWT modifier bit (SWT.CTRL,
528    * SWT.ALT, SWT.SHIFT, and SWT.COMMAND). Returns <code>null</code> if the key code 
529    * is not an SWT modifier bit.
530    * 
531    * @param keyCode the SWT modifier bit to be translated
532    * @return the string representation of the SWT modifier bit, or <code>null</code> if the key code was not an SWT modifier bit
533    * @see SWT
534    * @since 2.0
535    */
536   public static String findModifierString(int keyCode) {
537     if (keyCode == SWT.CTRL)
538       return JFaceResources.getString("Ctrl"); //$NON-NLS-1$
539     if (keyCode == SWT.ALT)
540       return JFaceResources.getString("Alt"); //$NON-NLS-1$
541     if (keyCode == SWT.SHIFT)
542       return JFaceResources.getString("Shift"); //$NON-NLS-1$
543     if (keyCode == SWT.COMMAND)
544       return JFaceResources.getString("Command"); //$NON-NLS-1$    
545     return null;
546   }
547   /**
548    * Notifies any property change listeners that a property has changed.
549    * Only listeners registered at the time this method is called are notified.
550    * This method avoids creating an event object if there are no listeners registered,
551    * but calls <code>firePropertyChange(PropertyChangeEvent)</code> if there are.
552    *
553    * @param propertyName the name of the property that has changed
554    * @param oldValue the old value of the property, or <code>null</code> if none
555    * @param newValue the new value of the property, or <code>null</code> if none
556    *
557    * @see IPropertyChangeListener#propertyChange
558    */
559   protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
560     if (!listeners.isEmpty()) {
561       firePropertyChange(new PropertyChangeEvent(this, propertyName, oldValue, newValue));
562     }
563   }
564   /**
565    * Notifies any property change listeners that a property has changed.
566    * Only listeners registered at the time this method is called are notified.
567    *
568    * @param event the property change event
569    *
570    * @see IPropertyChangeListener#propertyChange
571    */
572   protected void firePropertyChange(PropertyChangeEvent event) {
573     Object[] list = this.listeners.getListeners();
574     for (int i = 0; i < list.length; ++i) {
575       ((IPropertyChangeListener) list[i]).propertyChange(event);
576     }
577   }
578   /* (non-Javadoc)
579    * Method declared on IAction.
580    */
581   public int getAccelerator() {
582     return accelerator;
583   }
584 
585   /*(non-Javadoc)
586    * Method declared on IAction.
587    * 
588    */
589   public String getActionDefinitionId() {
590     return actionDefinitionId;
591   }
592 
593   /* (non-Javadoc)
594    * Method declared on IAction.
595    */
596   public String getDescription() {
597     if (description != null)
598       return description;
599     return getToolTipText();
600   }
601   /* (non-Javadoc)
602    * Method declared on IAction.
603    */
604   public ImageDescriptor getDisabledImageDescriptor() {
605     return disabledImage;
606   }
607   /* (non-Javadoc)
608    * Method declared on IAction.
609    */
610   public HelpListener getHelpListener() {
611     return helpListener;
612   }
613   /* (non-Javadoc)
614    * Method declared on IAction.
615    */
616   public ImageDescriptor getHoverImageDescriptor() {
617     return hoverImage;
618   }
619   /* (non-Javadoc)
620    * Method declared on IAction.
621    */
622   public String getId() {
623     return id;
624   }
625   /* (non-Javadoc)
626    * Method declared on IAction.
627    */
628   public ImageDescriptor getImageDescriptor() {
629     return image;
630   }
631   /* (non-Javadoc)
632    * Method declared on IAction.
633    */
634   public IMenuCreator getMenuCreator() {
635     // The default drop down menu value is only used
636     // to mark this action requested style. So do not
637     // return it. For backward compatibility reasons.
638     if (value == VAL_DROP_DOWN_MENU)
639       return null;
640     if (value instanceof IMenuCreator)
641       return (IMenuCreator) value;
642     return null;
643   }
644   /* (non-Javadoc)
645    * Method declared on IAction.
646    */
647   public int getStyle() {
648     // Infer the style from the value field.
649     if (value == VAL_PUSH_BTN || value == null)
650       return AS_PUSH_BUTTON;
651     if (value == VAL_TOGGLE_BTN_ON || value == VAL_TOGGLE_BTN_OFF)
652       return AS_CHECK_BOX;
653     if (value == VAL_RADIO_BTN_ON || value == VAL_RADIO_BTN_OFF)
654       return AS_RADIO_BUTTON;
655     if (value instanceof IMenuCreator)
656       return AS_DROP_DOWN_MENU;
657       
658     // We should never get to this line...
659     return AS_PUSH_BUTTON;
660   }
661   /* (non-Javadoc)
662    * Method declared on IAction.
663    */
664   public String getText() {
665     return text;
666   }
667   /* (non-Javadoc)
668    * Method declared on IAction.
669    */
670   public String getToolTipText() {
671     return toolTipText;
672   }
673   /** 
674    * Initializes the internal key code table.
675    */
676   private static void initKeyCodes() {
677     keyCodes = new HashMap(40);
678 
679     keyCodes.put("BACKSPACE", new Integer(8)); //$NON-NLS-1$
680     keyCodes.put("TAB", new Integer(9)); //$NON-NLS-1$
681     keyCodes.put("RETURN", new Integer(13)); //$NON-NLS-1$
682     keyCodes.put("ENTER", new Integer(13)); //$NON-NLS-1$
683     keyCodes.put("ESCAPE", new Integer(27)); //$NON-NLS-1$
684     keyCodes.put("ESC", new Integer(27)); //$NON-NLS-1$
685     keyCodes.put("DELETE", new Integer(127)); //$NON-NLS-1$
686 
687     keyCodes.put("SPACE", new Integer(' ')); //$NON-NLS-1$
688     keyCodes.put("ARROW_UP", new Integer(SWT.ARROW_UP)); //$NON-NLS-1$
689     keyCodes.put("ARROW_DOWN", new Integer(SWT.ARROW_DOWN)); //$NON-NLS-1$
690     keyCodes.put("ARROW_LEFT", new Integer(SWT.ARROW_LEFT)); //$NON-NLS-1$
691     keyCodes.put("ARROW_RIGHT", new Integer(SWT.ARROW_RIGHT)); //$NON-NLS-1$
692     keyCodes.put("PAGE_UP", new Integer(SWT.PAGE_UP)); //$NON-NLS-1$
693     keyCodes.put("PAGE_DOWN", new Integer(SWT.PAGE_DOWN)); //$NON-NLS-1$
694     keyCodes.put("HOME", new Integer(SWT.HOME)); //$NON-NLS-1$
695     keyCodes.put("END", new Integer(SWT.END)); //$NON-NLS-1$
696     keyCodes.put("INSERT", new Integer(SWT.INSERT)); //$NON-NLS-1$
697     keyCodes.put("F1", new Integer(SWT.F1)); //$NON-NLS-1$
698     keyCodes.put("F2", new Integer(SWT.F2)); //$NON-NLS-1$
699     keyCodes.put("F3", new Integer(SWT.F3)); //$NON-NLS-1$
700     keyCodes.put("F4", new Integer(SWT.F4)); //$NON-NLS-1$
701     keyCodes.put("F5", new Integer(SWT.F5)); //$NON-NLS-1$
702     keyCodes.put("F6", new Integer(SWT.F6)); //$NON-NLS-1$
703     keyCodes.put("F7", new Integer(SWT.F7)); //$NON-NLS-1$
704     keyCodes.put("F8", new Integer(SWT.F8)); //$NON-NLS-1$
705     keyCodes.put("F9", new Integer(SWT.F9)); //$NON-NLS-1$
706     keyCodes.put("F10", new Integer(SWT.F10)); //$NON-NLS-1$
707     keyCodes.put("F11", new Integer(SWT.F11)); //$NON-NLS-1$
708     keyCodes.put("F12", new Integer(SWT.F12)); //$NON-NLS-1$
709   }
710 
711   /** 
712    * Initializes the localized internal key code table.
713    */
714   private static void initLocalizedKeyCodes() {
715     localizedKeyCodes = new HashMap(40);
716 
717     localizedKeyCodes.put(JFaceResources.getString("Backspace").toUpperCase(), new Integer(8)); //$NON-NLS-1$
718     localizedKeyCodes.put(JFaceResources.getString("Tab").toUpperCase(), new Integer(9)); //$NON-NLS-1$
719     localizedKeyCodes.put(JFaceResources.getString("Return").toUpperCase(), new Integer(13)); //$NON-NLS-1$
720     localizedKeyCodes.put(JFaceResources.getString("Enter").toUpperCase(), new Integer(13)); //$NON-NLS-1$
721     localizedKeyCodes.put(JFaceResources.getString("Escape").toUpperCase(), new Integer(27)); //$NON-NLS-1$
722     localizedKeyCodes.put(JFaceResources.getString("Esc").toUpperCase(), new Integer(27)); //$NON-NLS-1$
723     localizedKeyCodes.put(JFaceResources.getString("Delete").toUpperCase(), new Integer(127)); //$NON-NLS-1$
724 
725     localizedKeyCodes.put(JFaceResources.getString("Space").toUpperCase(), new Integer(' ')); //$NON-NLS-1$
726 
727     localizedKeyCodes.put(JFaceResources.getString("Arrow_Up").toUpperCase(), new Integer(SWT.ARROW_UP)); //$NON-NLS-1$
728     localizedKeyCodes.put(JFaceResources.getString("Arrow_Down").toUpperCase(), new Integer(SWT.ARROW_DOWN)); //$NON-NLS-1$
729     localizedKeyCodes.put(JFaceResources.getString("Arrow_Left").toUpperCase(), new Integer(SWT.ARROW_LEFT)); //$NON-NLS-1$
730     localizedKeyCodes.put(JFaceResources.getString("Arrow_Right").toUpperCase(), new Integer(SWT.ARROW_RIGHT)); //$NON-NLS-1$
731     localizedKeyCodes.put(JFaceResources.getString("Page_Up").toUpperCase(), new Integer(SWT.PAGE_UP)); //$NON-NLS-1$
732     localizedKeyCodes.put(JFaceResources.getString("Page_Down").toUpperCase(), new Integer(SWT.PAGE_DOWN)); //$NON-NLS-1$
733     localizedKeyCodes.put(JFaceResources.getString("Home").toUpperCase(), new Integer(SWT.HOME)); //$NON-NLS-1$
734     localizedKeyCodes.put(JFaceResources.getString("End").toUpperCase(), new Integer(SWT.END)); //$NON-NLS-1$
735     localizedKeyCodes.put(JFaceResources.getString("Insert").toUpperCase(), new Integer(SWT.INSERT)); //$NON-NLS-1$
736     localizedKeyCodes.put(JFaceResources.getString("F1").toUpperCase(), new Integer(SWT.F1)); //$NON-NLS-1$
737     localizedKeyCodes.put(JFaceResources.getString("F2").toUpperCase(), new Integer(SWT.F2)); //$NON-NLS-1$
738     localizedKeyCodes.put(JFaceResources.getString("F3").toUpperCase(), new Integer(SWT.F3)); //$NON-NLS-1$
739     localizedKeyCodes.put(JFaceResources.getString("F4").toUpperCase(), new Integer(SWT.F4)); //$NON-NLS-1$
740     localizedKeyCodes.put(JFaceResources.getString("F5").toUpperCase(), new Integer(SWT.F5)); //$NON-NLS-1$
741     localizedKeyCodes.put(JFaceResources.getString("F6").toUpperCase(), new Integer(SWT.F6)); //$NON-NLS-1$
742     localizedKeyCodes.put(JFaceResources.getString("F7").toUpperCase(), new Integer(SWT.F7)); //$NON-NLS-1$
743     localizedKeyCodes.put(JFaceResources.getString("F8").toUpperCase(), new Integer(SWT.F8)); //$NON-NLS-1$
744     localizedKeyCodes.put(JFaceResources.getString("F9").toUpperCase(), new Integer(SWT.F9)); //$NON-NLS-1$
745     localizedKeyCodes.put(JFaceResources.getString("F10").toUpperCase(), new Integer(SWT.F10)); //$NON-NLS-1$
746     localizedKeyCodes.put(JFaceResources.getString("F11").toUpperCase(), new Integer(SWT.F11)); //$NON-NLS-1$
747     localizedKeyCodes.put(JFaceResources.getString("F12").toUpperCase(), new Integer(SWT.F12)); //$NON-NLS-1$
748   }
749 
750   /**
751    * Initializes the internal key string table.
752    */
753   private static void initKeyStrings() {
754     keyStrings = new HashMap(40);
755 
756     keyStrings.put(new Integer(8), JFaceResources.getString("Backspace")); //$NON-NLS-1$
757     keyStrings.put(new Integer(9), JFaceResources.getString("Tab")); //$NON-NLS-1$
758     keyStrings.put(new Integer(13), JFaceResources.getString("Return")); //$NON-NLS-1$
759     keyStrings.put(new Integer(13), JFaceResources.getString("Enter")); //$NON-NLS-1$
760     keyStrings.put(new Integer(27), JFaceResources.getString("Escape")); //$NON-NLS-1$
761     keyStrings.put(new Integer(27), JFaceResources.getString("Esc")); //$NON-NLS-1$
762     keyStrings.put(new Integer(127), JFaceResources.getString("Delete")); //$NON-NLS-1$
763 
764     keyStrings.put(new Integer(' '), JFaceResources.getString("Space")); //$NON-NLS-1$
765 
766     keyStrings.put(new Integer(SWT.ARROW_UP), JFaceResources.getString("Arrow_Up")); //$NON-NLS-1$
767     keyStrings.put(new Integer(SWT.ARROW_DOWN), JFaceResources.getString("Arrow_Down")); //$NON-NLS-1$
768     keyStrings.put(new Integer(SWT.ARROW_LEFT), JFaceResources.getString("Arrow_Left")); //$NON-NLS-1$
769     keyStrings.put(new Integer(SWT.ARROW_RIGHT), JFaceResources.getString("Arrow_Right")); //$NON-NLS-1$
770     keyStrings.put(new Integer(SWT.PAGE_UP), JFaceResources.getString("Page_Up")); //$NON-NLS-1$
771     keyStrings.put(new Integer(SWT.PAGE_DOWN), JFaceResources.getString("Page_Down")); //$NON-NLS-1$
772     keyStrings.put(new Integer(SWT.HOME), JFaceResources.getString("Home")); //$NON-NLS-1$
773     keyStrings.put(new Integer(SWT.END), JFaceResources.getString("End")); //$NON-NLS-1$
774     keyStrings.put(new Integer(SWT.INSERT), JFaceResources.getString("Insert")); //$NON-NLS-1$
775     keyStrings.put(new Integer(SWT.F1), JFaceResources.getString("F1")); //$NON-NLS-1$
776     keyStrings.put(new Integer(SWT.F2), JFaceResources.getString("F2")); //$NON-NLS-1$
777     keyStrings.put(new Integer(SWT.F3), JFaceResources.getString("F3")); //$NON-NLS-1$
778     keyStrings.put(new Integer(SWT.F4), JFaceResources.getString("F4")); //$NON-NLS-1$
779     keyStrings.put(new Integer(SWT.F5), JFaceResources.getString("F5")); //$NON-NLS-1$
780     keyStrings.put(new Integer(SWT.F6), JFaceResources.getString("F6")); //$NON-NLS-1$
781     keyStrings.put(new Integer(SWT.F7), JFaceResources.getString("F7")); //$NON-NLS-1$
782     keyStrings.put(new Integer(SWT.F8), JFaceResources.getString("F8")); //$NON-NLS-1$
783     keyStrings.put(new Integer(SWT.F9), JFaceResources.getString("F9")); //$NON-NLS-1$
784     keyStrings.put(new Integer(SWT.F10), JFaceResources.getString("F10")); //$NON-NLS-1$
785     keyStrings.put(new Integer(SWT.F11), JFaceResources.getString("F11")); //$NON-NLS-1$
786     keyStrings.put(new Integer(SWT.F12), JFaceResources.getString("F12")); //$NON-NLS-1$
787   }
788   /* (non-Javadoc)
789    * Method declared on IAction.
790    */
791   public boolean isChecked() {
792     return value == VAL_TOGGLE_BTN_ON || value == VAL_RADIO_BTN_ON;
793   }
794   /* (non-Javadoc)
795    * Method declared on IAction.
796    */
797   public boolean isEnabled() {
798     return enabled;
799   }
800   /**
801    * Convenience method for removing any optional accelerator text from the given string.
802    * The accelerator text appears at the end of the text, and is separated
803    * from the main part by a single tab character <code>'\t'</code>.
804    *
805    * @param text the text
806    * @return the text sans accelerator
807    */
808   public static String removeAcceleratorText(String text) {
809     int index = text.lastIndexOf('\t');
810     if (index == -1)
811       index = text.lastIndexOf('@');
812     if (index >= 0)
813       return text.substring(0, index);
814     return text;
815   }
816   
817   /**
818    * Convenience method for removing any mnemonics from the given string.
819    * For example, <code>removeMnemonics("&Open")</code> will return <code>"Open"</code>.
820    *
821    * @param text the text
822    * @return the text sans mnemonics
823    * 
824    * @since 3.0
825    */
826   public static String removeMnemonics(String text) {
827     int index = text.indexOf('&');
828     if (index == -1) {
829       return text;
830     }
831     int len = text.length();
832     StringBuffer sb = new StringBuffer(len);
833     int lastIndex = 0;
834     while (index != -1) {
835       // ignore & at the end
836       if (index == len - 1) {
837         break;
838       }
839       // handle the && case
840       if (text.charAt(index + 1) == '&') {
841         ++index;
842       }
843       sb.append(text.substring(lastIndex, index));
844       // skip the &
845       ++index;
846       lastIndex = index;
847       index = text.indexOf('&', index);
848     }
849     if (lastIndex < len) {
850       sb.append(text.substring(lastIndex, len));
851     }
852     return sb.toString();
853   }
854   
855   /* (non-Javadoc)
856    * Method declared on IAction.
857    */
858   public void removePropertyChangeListener(IPropertyChangeListener listener) {
859     listeners.remove(listener);
860   }
861 
862   /**
863    * The default implementation of this <code>IAction</code> method
864    * does nothing.  Subclasses should override this method
865    * if they do not need information from the triggering event,
866    * or override <code>runWithEvent(Event)</code> if they do.
867    */
868   public void run() {
869       // do nothing
870   }
871 
872   /**
873    * The default implementation of this <code>IAction</code> method
874    * ignores the event argument, and simply calls <code>run()</code>.
875    * Subclasses should override this method if they need information 
876    * from the triggering event, or override <code>run()</code> if not.
877    *
878    * @since 2.0
879    */
880   public void runWithEvent(Event event) {
881     run();
882   }
883 
884   /* (non-Javadoc)
885    * Method declared on IAction.
886    */
887   public void setActionDefinitionId(String id) {
888     actionDefinitionId = id;
889   }
890   /* (non-Javadoc)
891    * Method declared on IAction.
892    */
893   public void setChecked(boolean checked) {
894     Object newValue = null;
895     
896     // For backward compatibility, if the style is not
897     // set yet, then convert it to a toggle button.
898     if (value == null || value == VAL_TOGGLE_BTN_ON || value == VAL_TOGGLE_BTN_OFF) {
899       newValue = checked ? VAL_TOGGLE_BTN_ON : VAL_TOGGLE_BTN_OFF;
900     } else if (value == VAL_RADIO_BTN_ON || value == VAL_RADIO_BTN_OFF) {
901       newValue = checked ? VAL_RADIO_BTN_ON : VAL_RADIO_BTN_OFF;
902     } else {
903       // Some other style already, so do nothing.
904       return;
905     }
906 
907     if (newValue != value) {
908       value = newValue;
909       if (checked)
910         firePropertyChange(CHECKED, Boolean.FALSE, Boolean.TRUE);
911       else
912         firePropertyChange(CHECKED, Boolean.TRUE, Boolean.FALSE);
913     }
914   }
915   /* (non-Javadoc)
916    * Method declared on IAction.
917    */
918   public void setDescription(String text) {
919 
920     if ((description == null && text != null) || (description != null && text == null) || (description != null && text != null && !text.equals(description))) {
921       String oldDescription = description;
922       description = text;
923       firePropertyChange(DESCRIPTION, oldDescription, description);
924     }
925   }
926   /* (non-Javadoc)
927    * Method declared on IAction.
928    */
929   public void setDisabledImageDescriptor(ImageDescriptor newImage) {
930     if (disabledImage != newImage) {
931       ImageDescriptor oldImage = disabledImage;
932       disabledImage = newImage;
933       firePropertyChange(IMAGE, oldImage, newImage);
934     }
935   }
936   /* (non-Javadoc)
937    * Method declared on IAction.
938    */
939   public void setEnabled(boolean enabled) {
940     if (enabled != this.enabled) {
941       Boolean oldVal = this.enabled ? Boolean.TRUE : Boolean.FALSE;
942       Boolean newVal = enabled ? Boolean.TRUE : Boolean.FALSE;
943       this.enabled = enabled;
944       firePropertyChange(ENABLED, oldVal, newVal);
945     }
946   }
947   /* (non-Javadoc)
948    * Method declared on IAction.
949    */
950   public void setHelpListener(HelpListener listener) {
951     helpListener = listener;
952   }
953   /* (non-Javadoc)
954    * Method declared on IAction.
955    */
956   public void setHoverImageDescriptor(ImageDescriptor newImage) {
957     if (hoverImage != newImage) {
958       ImageDescriptor oldImage = hoverImage;
959       hoverImage = newImage;
960       firePropertyChange(IMAGE, oldImage, newImage);
961     }
962   }
963   /* (non-Javadoc)
964    * Method declared on IAction.
965    */
966   public void setId(String id) {
967     this.id = id;
968   }
969   /* (non-Javadoc)
970    * Method declared on IAction.
971    */
972   public void setImageDescriptor(ImageDescriptor newImage) {
973     if (image != newImage) {
974       ImageDescriptor oldImage = image;
975       image = newImage;
976       firePropertyChange(IMAGE, oldImage, newImage);
977     }
978   }
979   /**
980    * Sets the menu creator for this action.
981    * <p>
982    * Note that if this method is called, it overrides the check status.
983    * </p>
984    *
985    * @param creator the menu creator, or <code>null</code> if none
986    */
987   public void setMenuCreator(IMenuCreator creator) {
988     // For backward compatibility, if the style is not
989     // set yet, then convert it to a drop down menu.
990     if (value == null) {
991       value = creator;
992       return;
993     }
994     
995     if (value instanceof IMenuCreator)
996       value = creator == null ? VAL_DROP_DOWN_MENU : creator;
997   }
998   /**
999    * Sets the text for this action.
1000   * <p>
1001   * Fires a property change event for the <code>TEXT</code> property
1002   * if the text actually changes as a consequence.
1003   * </p>
1004   * <p>
1005   * The accelerator is identified by the last index of a tab character.  If
1006   * there are no tab characters, then it is identified by the last index of
1007   * a '@' character.  If neither, then there is no accelerator text.  Note
1008   * that if you want to insert a '@' character into the text (but no 
1009   * accelerator, you can simply insert a '@' or a tab at the end of the text. 
1010   * </p>
1011   *
1012   * @param text the text, or <code>null</code> if none
1013   */
1014  public void setText(String text) {
1015    String oldText = this.text;
1016    int oldAccel = this.accelerator;
1017    this.text = text;
1018    if (text != null) {
1019      String acceleratorText = extractAcceleratorText(text);
1020      if (acceleratorText != null) {
1021        int newAccelerator = convertLocalizedAccelerator(acceleratorText);
1022        //Be sure to not wipe out the accelerator if nothing found
1023        if (newAccelerator > 0) {
1024          setAccelerator(newAccelerator);
1025        }
1026      }
1027    }
1028    if (!(this.accelerator == oldAccel && (oldText == null ? this.text == null : oldText.equals(this.text)))) {
1029      firePropertyChange(TEXT, oldText, this.text);
1030    }
1031  }
1032  /**
1033   * Sets the tool tip text for this action.
1034   * <p>
1035   * Fires a property change event for the <code>TOOL_TIP_TEXT</code> property
1036   * if the tool tip text actually changes as a consequence.
1037   * </p>
1038   *
1039   * @param toolTipText the tool tip text, or <code>null</code> if none
1040   */
1041  public void setToolTipText(String toolTipText) {
1042    String oldToolTipText = this.toolTipText;
1043    if (!(oldToolTipText == null ? toolTipText == null : oldToolTipText.equals(toolTipText))) {
1044      this.toolTipText = toolTipText;
1045      firePropertyChange(TOOL_TIP_TEXT, oldToolTipText, toolTipText);
1046    }
1047  }
1048  /*
1049   * @see IAction#setAccelerator(int)
1050   */
1051  public void setAccelerator(int keycode) {
1052    this.accelerator = keycode;
1053  }
1054  
1055  /**
1056   * Reports the outcome of the running of this action via the
1057   * {@link IAction#RESULT} property.
1058   * 
1059   * @param success <code>true</code> if the action succeeded and 
1060   * <code>false</code> if the action failed or was not completed
1061   * @see IAction#RESULT
1062   * @since 3.0
1063   */
1064  public final void notifyResult(boolean success) {
1065    firePropertyChange(RESULT, null, Boolean.valueOf(success));
1066  }
1067
1068}