KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > editor > BaseAction


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.netbeans.editor;
21
22 import org.openide.util.NbBundle;
23 import org.openide.util.RequestProcessor;
24
25 import java.awt.event.ActionEvent JavaDoc;
26 import java.util.logging.Level JavaDoc;
27 import java.util.logging.LogRecord JavaDoc;
28 import java.util.logging.Logger JavaDoc;
29 import javax.swing.Action JavaDoc;
30 import javax.swing.JMenuItem JavaDoc;
31 import javax.swing.text.BadLocationException JavaDoc;
32 import javax.swing.text.TextAction JavaDoc;
33 import javax.swing.text.JTextComponent JavaDoc;
34 import javax.swing.text.Caret JavaDoc;
35
36 /**
37 * This is the parent of majority of the actions. It implements
38 * the necessary resetting depending of what is required
39 * by constructor of target action.
40 * The other thing implemented here is macro recording.
41 *
42 * @author Miloslav Metelka
43 * @version 1.00
44 */

45
46 public abstract class BaseAction extends TextAction JavaDoc {
47
48     /** Text of the menu item in popup menu for this action */
49     public static final String JavaDoc POPUP_MENU_TEXT = "PopupMenuText"; // NOI18N
50

51     /** Prefix for the name of the key for description in locale support */
52     public static final String JavaDoc LOCALE_DESC_PREFIX = "desc-"; // NOI18N
53

54     /** Prefix for the name of the key for popup description in locale support */
55     public static final String JavaDoc LOCALE_POPUP_PREFIX = "popup-"; // NOI18N
56

57     /** Resource for the icon */
58     public static final String JavaDoc ICON_RESOURCE_PROPERTY = "IconResource"; // NOI18N
59

60     /** Remove the selected text at the action begining */
61     public static final int SELECTION_REMOVE = 1;
62
63     /** Reset magic caret position */
64     public static final int MAGIC_POSITION_RESET = 2;
65
66     /** Reset abbreviation accounting to empty string */
67     public static final int ABBREV_RESET = 4;
68
69     /** Prevents adding the new undoable edit to the old one when the next
70     * document change occurs.
71     */

72     public static final int UNDO_MERGE_RESET = 8;
73
74     /** Reset word-match table */
75     public static final int WORD_MATCH_RESET = 16;
76
77     /** Clear status bar text */
78     public static final int CLEAR_STATUS_TEXT = 32;
79
80     /** The action will not be recorded if in macro recording */
81     public static final int NO_RECORDING = 64;
82
83     /** Save current position in the jump list */
84     public static final int SAVE_POSITION = 128;
85
86     /** The name of Action property. If the action has property NO_KEYBINDING set to true, it won't
87      * be listed in editor keybindings customizer list.
88      */

89     public static final String JavaDoc NO_KEYBINDING = "no-keybinding"; //NOI18N
90

91     /** logger for reporting invoked actions */
92     private static Logger JavaDoc UILOG = Logger.getLogger("org.netbeans.ui.actions.editor"); // NOI18N
93

94     /** Bit mask of what should be updated when the action is performed before
95     * the action's real task is invoked.
96     */

97     protected int updateMask;
98     
99     private static boolean recording;
100     private static StringBuffer JavaDoc macroBuffer = new StringBuffer JavaDoc();
101     private static StringBuffer JavaDoc textBuffer = new StringBuffer JavaDoc();
102
103     static final long serialVersionUID =-4255521122272110786L;
104
105     public BaseAction(String JavaDoc name) {
106         this(name, 0);
107     }
108
109     public BaseAction(String JavaDoc name, int updateMask) {
110         super(name);
111         this.updateMask = updateMask;
112     }
113     
114     /** Find a value in resource bundles.
115      * @deprecated this method is deprecated like the LocaleSupport which it uses by default.
116      * It should be replaced by implementing {@link #getShortDescriptionBundleClass()}
117      */

118     protected Object JavaDoc findValue(String JavaDoc key){
119         return LocaleSupport.getString(key);
120     }
121     
122     public Object JavaDoc getValue(String JavaDoc key){
123         Object JavaDoc obj = super.getValue(key);
124
125         if (obj == null){
126             obj = createDefaultValue(key);
127             if (obj != null) {
128                 putValue(key, obj);
129             }
130         }
131
132         return obj;
133     }
134     
135     /**
136      * This method is called when there is no value for the particular key.
137      * <br/>
138      * If the returned value is non-null it is remembered
139      * by {@link #putValue(String, Object)} so in that case this method
140      * is only called once.
141      *
142      * <p>
143      * <b>Note:</b> When overriding this method <code>super</code> implementation
144      * should always be called.
145      *
146      * @param key key for which the default value should be found.
147      * @return default value or null if the default value does not exist
148      * for the given key.
149      */

150     protected Object JavaDoc createDefaultValue(String JavaDoc key) {
151         Object JavaDoc ret = null;
152         if (SHORT_DESCRIPTION.equals(key)) {
153             Class JavaDoc bundleClass = getShortDescriptionBundleClass();
154             if (bundleClass != null) {
155                 // The bundle key is just the action's name
156
String JavaDoc bundleKey = (String JavaDoc)getValue(Action.NAME);
157                 ret = NbBundle.getBundle(bundleClass).getString(bundleKey);
158             } else { // default to slow deprecated findValue()
159
// getDefaultShortDescription() is only called once for non-null ret value
160
ret = getDefaultShortDescription();
161             }
162
163         } else if (POPUP_MENU_TEXT.equals(key)){
164             String JavaDoc bundleKey = LOCALE_POPUP_PREFIX + getValue(Action.NAME);
165             ret = findValue(bundleKey);
166             if (ret == null){
167                 ret = getValue(SHORT_DESCRIPTION);
168             }
169         }
170         return ret;
171     }
172     
173     /**
174      * Get the class in a package where resource bundle for localization
175      * of the short description of this action resides.
176      * <br/>
177      * By default this method returns null.
178      */

179     protected Class JavaDoc getShortDescriptionBundleClass() {
180         return null;
181     }
182     
183     /**
184      * Get the default value for {@link Action#SHORT_DESCRIPTION} property.
185      * <br>
186      * If this method returns non-empty value it will only be called once
187      * (its result will be remembered).
188      *
189      * @return value that will be use as result for
190      * <code>Action.getValue(Action.SHORT_DESCRIPTION)</code>.
191      */

192     protected Object JavaDoc getDefaultShortDescription() {
193         String JavaDoc actionName = (String JavaDoc)getValue(Action.NAME);
194         String JavaDoc localizerKey = LOCALE_DESC_PREFIX + actionName;
195         Object JavaDoc obj = findValue(localizerKey);
196         if (obj==null){
197             obj = findValue(actionName);
198             if (obj==null) obj = actionName;
199         }
200         return obj;
201     }
202
203     /** This method is called once after the action is constructed
204     * and then each time the settings are changed.
205     * @param evt event describing the changed setting name. It's null
206     * if it's called after the action construction.
207     * @param kitClass class of the kit that created the actions
208     */

209     protected void settingsChange(SettingsChangeEvent evt, Class JavaDoc kitClass) {
210     }
211
212     /** This method is made final here as there's an important
213     * processing that must be done before the real action
214     * functionality is performed. It can include the following:
215     * 1. Updating of the target component depending on the update
216     * mask given in action constructor.
217     * 2. Possible macro recoding when the macro recording
218     * is turned on.
219     * The real action functionality should be done in
220     * the method actionPerformed(ActionEvent evt, JTextComponent target)
221     * which must be redefined by the target action.
222     */

223     public final void actionPerformed(final ActionEvent JavaDoc evt) {
224         final JTextComponent JavaDoc target = getTextComponent(evt);
225                               
226         if( recording && 0 == (updateMask & NO_RECORDING) ) {
227             recordAction( target, evt );
228         }
229         
230
231         updateComponent(target);
232
233         if (UILOG.isLoggable(Level.FINE)) {
234             String JavaDoc actionName = getValue(NAME) != null ? getValue(NAME).toString().toLowerCase() : null;
235             if (actionName != null &&
236                 !"default-typed".equals(actionName) && //NOI18N
237
-1 == actionName.indexOf("caret") && //NOI18N
238
-1 == actionName.indexOf("delete") && //NOI18N
239
-1 == actionName.indexOf("selection") && //NOI18N
240
-1 == actionName.indexOf("build-tool-tip") &&//NOI18N
241
-1 == actionName.indexOf("build-popup-menu") &&//NOI18N
242
-1 == actionName.indexOf("-kit-install") //NOI18N
243
) {
244                 LogRecord JavaDoc r = new LogRecord JavaDoc(Level.FINE, "UI_ACTION_EDITOR"); // NOI18N
245
r.setResourceBundle(NbBundle.getBundle(BaseAction.class));
246                 if (evt != null) {
247                     r.setParameters(new Object JavaDoc[] { evt, evt.toString(), this, toString(), getValue(NAME) });
248                 }
249                 r.setLoggerName(UILOG.getName());
250                 UILOG.log(r);
251             }
252         }
253         
254         if (asynchonous()) {
255             RequestProcessor.getDefault().post(new Runnable JavaDoc () {
256                 public void run() {
257                     actionPerformed(evt, target);
258                 }
259             });
260         } else {
261             actionPerformed(evt, target);
262         }
263     }
264     
265     private void recordAction( JTextComponent JavaDoc target, ActionEvent JavaDoc evt ) {
266         if( this == target.getKeymap().getDefaultAction() ) { // defaultKeyTyped
267
textBuffer.append( getFilteredActionCommand(evt.getActionCommand()) );
268         } else { // regular action
269
if( textBuffer.length() > 0 ) {
270                 if( macroBuffer.length() > 0 ) macroBuffer.append( ' ' );
271                 macroBuffer.append( encodeText( textBuffer.toString() ) );
272                 textBuffer.setLength( 0 );
273             }
274             if( macroBuffer.length() > 0 ) macroBuffer.append( ' ' );
275             String JavaDoc name = (String JavaDoc)getValue( Action.NAME );
276             macroBuffer.append( encodeActionName( name ) );
277         }
278     }
279     
280     private String JavaDoc getFilteredActionCommand(String JavaDoc cmd)
281     {
282         if (cmd == null || cmd.length() == 0)
283             return "";
284         char ch = cmd.charAt(0);
285         if ((ch >= 0x20) && (ch != 0x7F))
286             return cmd;
287         else
288             return "";
289     }
290     
291     boolean startRecording( JTextComponent JavaDoc target ) {
292         if( recording ) return false;
293         recording = true;
294         macroBuffer.setLength(0);
295         textBuffer.setLength(0);
296         Utilities.setStatusText( target,
297                 NbBundle.getBundle(BaseAction.class).getString( "macro-recording" ) );
298         return true;
299     }
300     
301     String JavaDoc stopRecording( JTextComponent JavaDoc target ) {
302         if( !recording ) return null;
303
304         if( textBuffer.length() > 0 ) {
305             if( macroBuffer.length() > 0 ) macroBuffer.append( ' ' );
306             macroBuffer.append( encodeText( textBuffer.toString() ) );
307         }
308         String JavaDoc retVal = macroBuffer.toString();
309         recording = false;
310         Utilities.setStatusText( target, "" ); // NOI18N
311
return retVal;
312     }
313     
314     private String JavaDoc encodeText( String JavaDoc s ) {
315         char[] text = s.toCharArray();
316         StringBuffer JavaDoc encoded = new StringBuffer JavaDoc( "\""); // NOI18N
317
for( int i=0; i < text.length; i++ ) {
318             char c = text[i];
319             if( c == '"' || c == '\\' ) encoded.append( '\\' );
320             encoded.append( c );
321         }
322         return encoded.append( '"' ).toString();
323     }
324
325     private String JavaDoc encodeActionName( String JavaDoc s ) {
326         char[] actionName = s.toCharArray();
327         StringBuffer JavaDoc encoded = new StringBuffer JavaDoc();
328         for( int i=0; i < actionName.length; i++ ) {
329             char c = actionName[i];
330             if( Character.isWhitespace( c ) || c == '\\' ) encoded.append( '\\' );
331             encoded.append( c );
332         }
333         return encoded.toString();
334     }
335     
336     /** The target method that performs the real action functionality.
337     * @param evt action event describing the action that occured
338     * @param target target component where the action occured. It's retrieved
339     * by the TextAction.getTextComponent(evt).
340     */

341     public abstract void actionPerformed(ActionEvent JavaDoc evt, JTextComponent JavaDoc target);
342
343     protected boolean asynchonous() {
344         return false;
345     }
346
347     public JMenuItem JavaDoc getPopupMenuItem(JTextComponent JavaDoc target) {
348         return null;
349     }
350
351     public String JavaDoc getPopupMenuText(JTextComponent JavaDoc target) {
352         String JavaDoc txt = (String JavaDoc)getValue(POPUP_MENU_TEXT);
353         if (txt == null) {
354             txt = (String JavaDoc)getValue(NAME);
355         }
356         return txt;
357     }
358
359     /** Update the component according to the update mask specified
360     * in the constructor of the action.
361     * @param target target component to be updated.
362     */

363     public void updateComponent(JTextComponent JavaDoc target) {
364         updateComponent(target, this.updateMask);
365     }
366
367     /** Update the component according to the given update mask
368     * @param target target component to be updated.
369     * @param updateMask mask that specifies what will be updated
370     */

371     public void updateComponent(JTextComponent JavaDoc target, int updateMask) {
372         if (target != null && target.getDocument() instanceof BaseDocument) {
373             BaseDocument doc = (BaseDocument)target.getDocument();
374             boolean writeLocked = false;
375
376             try {
377                 // remove selected text
378
if ((updateMask & SELECTION_REMOVE) != 0) {
379                     writeLocked = true;
380                     doc.extWriteLock();
381                     Caret JavaDoc caret = target.getCaret();
382                     if (caret != null && caret.isSelectionVisible()) {
383                         int dot = caret.getDot();
384                         int markPos = caret.getMark();
385                         if (dot < markPos) { // swap positions
386
int tmpPos = dot;
387                             dot = markPos;
388                             markPos = tmpPos;
389                         }
390                         try {
391                             target.getDocument().remove(markPos, dot - markPos);
392                         } catch (BadLocationException JavaDoc e) {
393                             Utilities.annotateLoggable(e);
394                         }
395                     }
396                 }
397
398                 // reset magic caret position
399
if ((updateMask & MAGIC_POSITION_RESET) != 0) {
400                     if (target.getCaret() != null)
401                         target.getCaret().setMagicCaretPosition(null);
402                 }
403
404                 // reset abbreviation accounting
405
if ((updateMask & ABBREV_RESET) != 0) {
406                     ((BaseTextUI)target.getUI()).getEditorUI().getAbbrev().reset();
407                 }
408
409                 // reset merging of undoable edits
410
if ((updateMask & UNDO_MERGE_RESET) != 0) {
411                     doc.resetUndoMerge();
412                 }
413
414                 // reset word matching
415
if ((updateMask & WORD_MATCH_RESET) != 0) {
416                     ((BaseTextUI)target.getUI()).getEditorUI().getWordMatch().clear();
417                 }
418
419                 // Clear status bar text
420
if (!recording && (updateMask & CLEAR_STATUS_TEXT) != 0) {
421                     Utilities.clearStatusText(target);
422                 }
423
424                 // Save current caret position in the jump-list
425
if ((updateMask & SAVE_POSITION) != 0) {
426                     JumpList.checkAddEntry(target);
427                 }
428
429             } finally {
430                 if (writeLocked) {
431                     doc.extWriteUnlock();
432                 }
433             }
434         }
435     }
436
437 }
438
Popular Tags