KickJava   Java API By Example, From Geeks To Geeks.

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


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 java.awt.event.ActionEvent JavaDoc;
23 import java.beans.PropertyChangeEvent JavaDoc;
24 import java.beans.PropertyChangeListener JavaDoc;
25 import java.util.Map JavaDoc;
26 import java.util.HashMap JavaDoc;
27 import java.util.Iterator JavaDoc;
28 import javax.swing.Action JavaDoc;
29 import javax.swing.text.BadLocationException JavaDoc;
30 import javax.swing.text.Document JavaDoc;
31 import javax.swing.text.JTextComponent JavaDoc;
32 import javax.swing.text.Caret JavaDoc;
33 import org.netbeans.lib.editor.util.CharSequenceUtilities;
34 import org.netbeans.lib.editor.util.swing.DocumentUtilities;
35
36 /** Abbreviation support allowing to expand defined character sequences
37 * into the expanded strings or call the arbitrary action.
38 *
39 * @author Miloslav Metelka
40 * @version 1.00
41 */

42
43 public class Abbrev implements SettingsChangeListener, PropertyChangeListener JavaDoc {
44     
45     /**
46      * Test whether the abbreviation expansion is disabled
47      * at the caret position in the given component's document.
48      *
49      * @param component non-null text component.
50      * @return true if the abbreviation can be expanded or false if not.
51      */

52     public static boolean isAbbrevDisabled(JTextComponent JavaDoc component) {
53         Document JavaDoc doc = component.getDocument();
54         if (doc instanceof BaseDocument) {
55             BaseDocument bdoc = (BaseDocument)doc;
56             SyntaxSupport sup = bdoc.getSyntaxSupport();
57             if (sup != null) {
58                 return sup.isAbbrevDisabled(component.getCaretPosition());
59             }
60         }
61         return false; // abbrev not disabled
62
}
63
64     /** Abbreviation accounting string. Here the characters forming
65     * abbreviation are stored.
66     */

67     private StringBuffer JavaDoc abbrevSB = new StringBuffer JavaDoc();
68
69     /** Check whether the document text matches the abbreviation accounting
70     * string.
71     */

72     private boolean checkDocText;
73
74     /** Additional check whether the character right before the abbreviation
75     * string in the text is not accepted by the <tt>addTypedAcceptor</tt>.
76     * This test is only performed if <tt>checkDocText</tt> is true.
77     */

78     private boolean checkTextDelimiter;
79
80     /** Extended UI to which this abbreviation is associated to */
81     protected EditorUI editorUI;
82
83     /** Chars on which to expand acceptor */
84     private Acceptor doExpandAcceptor;
85
86     /** Whether add the typed char */
87     private Acceptor addTypedAcceptor;
88
89     /** Which chars reset abbreviation accounting */
90     private Acceptor resetAcceptor;
91
92     /** Abbreviation map */
93     private HashMap JavaDoc abbrevMap;
94
95     public Abbrev(EditorUI editorUI, boolean checkDocText, boolean checkTextDelimiter) {
96         this.editorUI = editorUI;
97         this.checkDocText = checkDocText;
98         this.checkTextDelimiter = checkTextDelimiter;
99
100         Settings.addSettingsChangeListener(this);
101
102         synchronized (editorUI.getComponentLock()) {
103             // if component already installed in EditorUI simulate installation
104
JTextComponent JavaDoc component = editorUI.getComponent();
105             if (component != null) {
106                 propertyChange(new PropertyChangeEvent JavaDoc(editorUI,
107                                                        EditorUI.COMPONENT_PROPERTY, null, component));
108             }
109
110             editorUI.addPropertyChangeListener(this);
111         }
112     }
113
114     /** Called when settings were changed. The method is called
115     * by editorUI when settings were changed and from constructor.
116     */

117     public void settingsChange(SettingsChangeEvent evt) {
118         Class JavaDoc kitClass = Utilities.getKitClass(editorUI.getComponent());
119
120         if (kitClass != null) {
121             String JavaDoc settingName = (evt != null) ? evt.getSettingName() : null;
122
123             if (settingName == null || SettingsNames.ABBREV_ACTION_MAP.equals(settingName)
124                 || SettingsNames.ABBREV_MAP.equals(settingName)
125             ) {
126                 abbrevMap = new HashMap JavaDoc();
127                 // Inspect action abbrevs
128
Map JavaDoc m = (Map JavaDoc)Settings.getValue(kitClass, SettingsNames.ABBREV_ACTION_MAP);
129                 if (m != null) {
130                     BaseKit kit = Utilities.getKit(editorUI.getComponent());
131                     Iterator JavaDoc iter = m.entrySet().iterator();
132                     while (iter.hasNext()) {
133                         Map.Entry JavaDoc me = (Map.Entry JavaDoc)iter.next();
134                         Object JavaDoc value = me.getValue();
135                         Action JavaDoc a = null;
136                         if (value instanceof String JavaDoc) {
137                             a = kit.getActionByName((String JavaDoc)value);
138                         } else if (value instanceof Action JavaDoc) {
139                             a = (Action JavaDoc)value;
140                         }
141
142                         if (a != null) {
143                             abbrevMap.put(me.getKey(), a);
144                         }
145                     }
146                 }
147                 
148                 m = (Map JavaDoc)Settings.getValue(kitClass, SettingsNames.ABBREV_MAP);
149                 if (m != null) {
150                     Iterator JavaDoc iter = m.entrySet().iterator();
151                     while (iter.hasNext()) {
152                         Map.Entry JavaDoc me = (Map.Entry JavaDoc)iter.next();
153                         Object JavaDoc value = me.getValue();
154                         if (value != null) {
155                             abbrevMap.put(me.getKey(), value);
156                         }
157                     }
158                 }
159             }
160
161             if (settingName == null || SettingsNames.ABBREV_EXPAND_ACCEPTOR.equals(settingName)) {
162                 doExpandAcceptor = SettingsUtil.getAcceptor(kitClass, SettingsNames.ABBREV_EXPAND_ACCEPTOR, AcceptorFactory.FALSE);
163             }
164             if (settingName == null || SettingsNames.ABBREV_ADD_TYPED_CHAR_ACCEPTOR.equals(settingName)) {
165                 addTypedAcceptor = SettingsUtil.getAcceptor(kitClass, SettingsNames.ABBREV_ADD_TYPED_CHAR_ACCEPTOR, AcceptorFactory.FALSE);
166             }
167             if (settingName == null || SettingsNames.ABBREV_RESET_ACCEPTOR.equals(settingName)) {
168                 resetAcceptor = SettingsUtil.getAcceptor(kitClass, SettingsNames.ABBREV_RESET_ACCEPTOR, AcceptorFactory.TRUE);
169             }
170         }
171     }
172
173     public void propertyChange(PropertyChangeEvent JavaDoc evt) {
174         String JavaDoc propName = evt.getPropertyName();
175
176         if (EditorUI.COMPONENT_PROPERTY.equals(propName)) {
177             JTextComponent JavaDoc component = (JTextComponent JavaDoc)evt.getNewValue();
178             if (component != null) { // just installed
179

180                 settingsChange(null);
181
182             } else { // just deinstalled
183
// component = (JTextComponent)evt.getOldValue();
184

185             }
186
187         }
188     }
189
190     /** Reset abbreviation accounting. */
191     public void reset() {
192         abbrevSB.setLength(0);
193     }
194
195     /** Add typed character to abbreviation accounting string. */
196     public void addChar(char ch) {
197         abbrevSB.append(ch);
198     }
199
200     /** Get current abbreviation string */
201     public String JavaDoc getAbbrevString() {
202         return abbrevSB.toString();
203     }
204
205     /** Get mapping table [abbrev, expanded-abbrev] */
206     public Map JavaDoc getAbbrevMap() {
207         return abbrevMap;
208     }
209
210     /** Translate string using abbreviation table
211     * @param abbrev string to translate. Pass null to translate current abbreviation
212     * string
213     * @return expanded abbreviation
214     */

215     public Object JavaDoc translateAbbrev(String JavaDoc abbrev) {
216         String JavaDoc abbStr = (abbrev != null) ? abbrev : abbrevSB.toString();
217         return getAbbrevMap().get(abbStr);
218     }
219
220     /** Checks whether there's valid string to expand and if so it returns it.
221     */

222     public String JavaDoc getExpandString(char typedChar) {
223         return (doExpandAcceptor.accept(typedChar)) ? getExpandString() : null;
224     }
225
226     public String JavaDoc getExpandString() {
227         BaseDocument doc = (BaseDocument)editorUI.getDocument();
228         String JavaDoc abbrevStr = getAbbrevString();
229         int abbrevStrLen = abbrevStr.length();
230         Object JavaDoc expansion = translateAbbrev(abbrevStr);
231         Caret JavaDoc caret = editorUI.getComponent().getCaret();
232         int dotPos = caret.getDot();
233         if (abbrevStr != null && expansion != null
234                 && dotPos >= abbrevStrLen
235            ) {
236             if (checkDocText) {
237                 try {
238                     CharSequence JavaDoc prevChars = DocumentUtilities.getText(doc, dotPos - abbrevStrLen, abbrevStrLen);
239                     if (CharSequenceUtilities.textEquals(prevChars, abbrevStr)) { // abbrev chars really match text
240
if (!checkTextDelimiter || dotPos == abbrevStrLen
241                                 || resetAcceptor.accept(
242                                     doc.getChars(dotPos - abbrevStrLen - 1, 1)[0])
243                            ) {
244                             return abbrevStr;
245                         }
246                     }
247                 } catch (BadLocationException JavaDoc e) {
248                 }
249             }
250         }
251         return null;
252     }
253
254     protected boolean doExpansion(int dotPos, String JavaDoc expandStr, ActionEvent JavaDoc evt)
255     throws BadLocationException JavaDoc {
256         Object JavaDoc expansion = translateAbbrev(expandStr);
257         boolean expanded = false;
258         if (expansion instanceof String JavaDoc) { // expand to string
259
BaseDocument doc = editorUI.getDocument();
260             String JavaDoc ins = (String JavaDoc)expansion;
261             int offset = ins.indexOf('|');
262             if (offset >= 0) {
263                 if (offset > 0) doc.insertString(dotPos, ins.substring(0, offset), null);
264                 if (offset+1 < ins.length()) doc.insertString(dotPos + offset,
265                         ins.substring(offset + 1), null);
266                 Caret JavaDoc caret = editorUI.getComponent().getCaret();
267                 caret.setDot(dotPos + offset);
268             } else {
269                 doc.insertString(dotPos, ins, null);
270             }
271
272             if(ins.indexOf("\n") != -1) { // NOI18N
273
Formatter formatter = doc.getFormatter();
274                 formatter.reformat(doc, dotPos, dotPos + ins.length());
275             }
276             
277             expanded = true;
278         } else if (expansion instanceof Action JavaDoc) {
279             ((Action JavaDoc)expansion).actionPerformed(evt);
280             expanded = true;
281         }
282         return expanded;
283     }
284
285     public boolean expandString(char typedChar, String JavaDoc expandStr, ActionEvent JavaDoc evt)
286     throws BadLocationException JavaDoc {
287         if (expandString(expandStr, evt)) {
288             if (addTypedAcceptor.accept(typedChar)) {
289                 int dotPos = editorUI.getComponent().getCaret().getDot();
290                 editorUI.getDocument().insertString(dotPos, String.valueOf(typedChar), null);
291             }
292             return true;
293         }
294         return false;
295     }
296
297     /** Expand abbreviation on current caret position.
298     * Remove characters back to the word start and insert expanded abbreviation.
299     * @return whether the typed character should be added to the abbreviation or not
300     */

301     public boolean expandString(String JavaDoc expandStr, ActionEvent JavaDoc evt)
302     throws BadLocationException JavaDoc {
303         // Disabled due to code templates
304
if (true) {
305             reset();
306             return true;
307         }
308
309         boolean expanded = false;
310         BaseDocument doc = editorUI.getDocument();
311         doc.atomicLock();
312         try {
313             Caret JavaDoc caret = editorUI.getComponent().getCaret();
314             int pos = caret.getDot() - expandStr.length();
315             doc.remove(pos, expandStr.length());
316             expanded = doExpansion(pos, expandStr, evt);
317         } finally {
318             if (expanded) {
319                 reset();
320             } else {
321                 doc.breakAtomicLock();
322             }
323             doc.atomicUnlock();
324         }
325         return expanded;
326     }
327
328     public boolean checkReset(char typedChar) {
329         if (resetAcceptor.accept(typedChar)) {
330             reset();
331             return true;
332         }
333         return false;
334     }
335
336     public boolean checkAndExpand(char typedChar, ActionEvent JavaDoc evt)
337     throws BadLocationException JavaDoc {
338         boolean doInsert = true;
339         boolean disableAbbrev = false;
340
341         // Check whether the expansion should be prevented
342
// in certain tokens
343
JTextComponent JavaDoc component = editorUI.getComponent();
344         Document JavaDoc doc = component.getDocument();
345         if (doc instanceof BaseDocument) {
346             BaseDocument bdoc = (BaseDocument)doc;
347             SyntaxSupport sup = bdoc.getSyntaxSupport();
348             disableAbbrev = sup.isAbbrevDisabled(component.getCaretPosition());
349         }
350         
351         if (disableAbbrev) {
352             reset();
353         } else {
354             String JavaDoc expandStr = getExpandString(typedChar);
355             if (expandStr != null) { // should expand
356
doInsert = false;
357                 expandString(typedChar, expandStr, evt);
358             } else {
359                 addChar(typedChar);
360             }
361             checkReset(typedChar);
362         }
363         return doInsert;
364     }
365
366     public void checkAndExpand(ActionEvent JavaDoc evt)
367     throws BadLocationException JavaDoc {
368         String JavaDoc expandStr = getExpandString();
369         if (expandStr != null) {
370             expandString(expandStr, evt);
371         }
372     }
373
374 }
375
Popular Tags