KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > lib > editor > codetemplates > CodeTemplateParameterImpl


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.lib.editor.codetemplates;
21
22 import java.util.ArrayList JavaDoc;
23 import java.util.Collection JavaDoc;
24 import java.util.Collections JavaDoc;
25 import java.util.LinkedHashMap JavaDoc;
26 import java.util.Iterator JavaDoc;
27 import java.util.Map JavaDoc;
28 import javax.swing.text.Position JavaDoc;
29 import org.netbeans.lib.editor.codetemplates.spi.CodeTemplateInsertRequest;
30 import org.netbeans.lib.editor.codetemplates.spi.CodeTemplateParameter;
31 import org.netbeans.lib.editor.util.swing.MutablePositionRegion;
32
33 /**
34  * Implementation of the code template parameter.
35  *
36  * @author Miloslav Metelka
37  */

38 public final class CodeTemplateParameterImpl {
39
40     private static final String JavaDoc NULL_PARAMETER_NAME = "<null>"; // NOI18N
41

42     private static final String JavaDoc NULL_HINT_NAME = "<null>"; // NOI18N
43

44     private static final String JavaDoc TRUE_HINT_VALUE = "true"; // NOI18N
45

46     /**
47      * Get parameter implementation from parameter instance.
48      */

49     public static CodeTemplateParameterImpl get(CodeTemplateParameter parameter) {
50         return CodeTemplateSpiPackageAccessor.get().getImpl(parameter);
51     }
52     
53     /**
54      * Insert handler - may be null e.g. when parsing for completion item rendering.
55      */

56     private final CodeTemplateInsertHandler handler;
57     
58     private final CodeTemplateParameter parameter;
59     
60     private String JavaDoc value;
61     
62     private int parametrizedTextStartOffset;
63     
64     private int parametrizedTextEndOffset;
65     
66     private CodeTemplateParameter master;
67     
68     private Collection JavaDoc slaves;
69     
70     private Collection JavaDoc slavesUnmodifiable;
71     
72     private String JavaDoc name;
73     
74     private Map JavaDoc hints;
75     
76     private Map JavaDoc hintsUnmodifiable;
77     
78     private SyncDocumentRegion region;
79     
80     private MutablePositionRegion positionRegion;
81     
82     private boolean editable;
83     
84     private boolean userModified;
85
86
87     CodeTemplateParameterImpl(CodeTemplateInsertHandler handler,
88     String JavaDoc parametrizedText, int parametrizedTextOffset) {
89         this.handler = handler; // handler may be null for completion item parsing
90
this.parametrizedTextStartOffset = parametrizedTextOffset;
91        
92         // Ensure the CodeTemplateSpiPackageAccessor gets registered
93
CodeTemplateInsertRequest.class.getName();
94
95         this.parameter = CodeTemplateSpiPackageAccessor.get().createParameter(this);
96         parseParameterContent(parametrizedText);
97     }
98     
99     public CodeTemplateParameter getParameter() {
100         return parameter;
101     }
102
103     public CodeTemplateInsertHandler getHandler() {
104         return handler;
105     }
106     
107     /**
108      * Get name of this parameter as parsed from the code template description's text.
109      */

110     public String JavaDoc getName() {
111         return name;
112     }
113     
114     public String JavaDoc getValue() {
115         return isSlave() ? master.getValue()
116                 : ((handler != null && handler.isInserted()) ? handler.getDocParameterValue(this) : value);
117     }
118     
119     public void setValue(String JavaDoc newValue, boolean fromAPI) {
120         if (isSlave()) {
121             throw new IllegalStateException JavaDoc("Cannot set value for slave parameter"); // NOI18N
122
}
123         if (newValue == null) {
124             throw new NullPointerException JavaDoc("newValue cannot be null"); // NOI18N
125
}
126         if (!newValue.equals(value)) {
127             if (fromAPI) {
128                 if (!handler.isReleased()) {
129                     if (handler.isInserted()) { // already inserted in the document
130
handler.setDocParameterValue(this, newValue);
131                     } else { // not yet inserted => set the default value
132
this.value = newValue;
133                     }
134                 }
135                 
136             } else { // change not from api
137
this.value = newValue;
138             }
139             
140             handler.resetCachedInsertText();
141         }
142     }
143     
144     public boolean isEditable() {
145         return editable;
146     }
147     
148     public boolean isUserModified() {
149         return userModified;
150     }
151     
152     void markUserModified() {
153         this.userModified = true;
154     }
155     
156     /**
157      * @return &gt;=0 index of the '${' in the parametrized text.
158      */

159     public int getParametrizedTextStartOffset() {
160         return parametrizedTextStartOffset;
161     }
162     
163     /**
164      * If the parameter is unclosed the offset will point past the end
165      * of the parametrized text.
166      *
167      * @return &gt;=0 end offset of the parameter in the parametrized text
168      * pointing right after the closing '}' of the parameter.
169      */

170     public int getParametrizedTextEndOffset() {
171         return parametrizedTextEndOffset;
172     }
173
174     public int getInsertTextOffset() {
175         if (handler != null) {
176             if (!handler.isInserted()) {
177                 handler.checkInsertTextBuilt();
178             }
179             return (positionRegion != null)
180                     ? positionRegion.getStartOffset() - handler.getInsertOffset()
181                     : 0;
182         } else { // handler is null
183
return (positionRegion != null) ? positionRegion.getStartOffset() : 0;
184         }
185     }
186
187     void resetPositions(Position JavaDoc startPosition, Position JavaDoc endPosition) {
188         if (positionRegion == null) {
189             positionRegion = new MutablePositionRegion(startPosition, endPosition);
190         } else {
191             positionRegion.reset(startPosition, endPosition);
192         }
193     }
194
195     public MutablePositionRegion getPositionRegion() {
196         return positionRegion;
197     }
198
199     public Map JavaDoc getHints() {
200         return (hintsUnmodifiable != null) ? hintsUnmodifiable : Collections.EMPTY_MAP;
201     }
202     
203     public CodeTemplateParameter getMaster() {
204         return master;
205     }
206     
207     public Collection JavaDoc getSlaves() {
208         return (slaves != null) ? slaves : Collections.EMPTY_LIST;
209     }
210     
211     public boolean isSlave() {
212         return (master != null);
213     }
214     
215     SyncDocumentRegion getRegion() {
216         return region;
217     }
218     
219     void setRegion(SyncDocumentRegion region) {
220         this.region = region;
221     }
222     
223     /**
224      * Mark that this parameter will be slave of the given master parameter.
225      */

226     void markSlave(CodeTemplateParameter master) {
227         CodeTemplateParameterImpl masterImpl = paramImpl(master);
228         if (getMaster() != null) {
229             throw new IllegalStateException JavaDoc(toString() + " already slave of " + master); // NOI18N
230
}
231         setMaster(master);
232         masterImpl.addSlave(getParameter());
233         
234         // reparent slaves as well
235
if (slaves != null) {
236             for (Iterator JavaDoc it = slaves.iterator(); it.hasNext();) {
237                 CodeTemplateParameterImpl paramImpl = paramImpl((CodeTemplateParameter)it.next());
238                 paramImpl.setMaster(master);
239                 masterImpl.addSlave(paramImpl.getParameter());
240             }
241             slaves.clear();
242         }
243     }
244     
245     private static CodeTemplateParameterImpl paramImpl(CodeTemplateParameter param) {
246         return CodeTemplateSpiPackageAccessor.get().getImpl(param);
247     }
248     
249     /**
250      * Initialize the hints of this parameter by parsing
251      * parameter's text from the given parametrized text
252      * at the offset given in the constructor.
253      *
254      * @param parametrizedText text to parse at the offset given in the constructor.
255      * @return index of the '}' where the parameter ends
256      * or <code>parametrizedText.length()</code> if the parameter is unclosed.
257      */

258     private void parseParameterContent(String JavaDoc parametrizedText) {
259         int index = parametrizedTextStartOffset + 2;
260         String JavaDoc hintName = null;
261         String JavaDoc hintValue = null;
262         boolean afterEquals = false;
263         int nameStartIndex = -1;
264         boolean insideStringLiteral = false;
265         StringBuffer JavaDoc stringLiteralText = new StringBuffer JavaDoc();
266
267         while (true) {
268             // Search for names or "..." values separated by whitespace
269
String JavaDoc completedString = null;
270             if (index >= parametrizedText.length()) {
271                 break;
272             }
273             char ch = parametrizedText.charAt(index);
274
275             if (insideStringLiteral) { // inside string constant "..."
276
if (ch == '"') { // string ends
277
insideStringLiteral = false;
278                     completedString = stringLiteralText.toString();
279                     stringLiteralText.setLength(0); // clear the string buffer
280

281                 } else if (ch == '\\') {
282                     index = escapedChar(parametrizedText,
283                             index + 1, stringLiteralText);
284                 } else { // regular char
285
stringLiteralText.append(ch);
286                 }
287
288             } else { // not string hint
289
if (Character.isWhitespace(ch) || ch == '=' || ch == '}') {
290                     if (nameStartIndex != -1) { // name found
291
completedString = parametrizedText.substring(
292                                 nameStartIndex, index);
293                         nameStartIndex = -1;
294                     } else {
295                         // No name was accounted
296
}
297
298                 } else if (ch == '"') { // starting string literal
299
insideStringLiteral = true;
300
301                 } else { // starting or inside name
302
if (nameStartIndex == -1) {
303                         nameStartIndex = index;
304                     }
305                 }
306             }
307
308             if (completedString != null) {
309                 if (name == null) { // First string will be parameter's name
310
name = completedString;
311                 } else { // hints
312
if (hints == null) { // Create hints
313
hints = new LinkedHashMap JavaDoc(4);
314                         hintsUnmodifiable = Collections.unmodifiableMap(hints);
315                     }
316                     
317                     if (hintName == null) { // no current hint's name
318
if (afterEquals) { // hint's value
319
// Hint name was not filled in
320
hints.put(NULL_HINT_NAME, completedString);
321                             afterEquals = false;
322                             // hintName stays null
323

324                         } else { // will be hint name
325
hintName = completedString;
326                         }
327                         
328                     } else { // hint's name is non-null
329
if (afterEquals) { // hint's value
330
hints.put(hintName, completedString);
331                             afterEquals = false;
332                             hintName = null;
333                             
334                         } else { // next hint
335
hints.put(hintName, TRUE_HINT_VALUE);
336                             hintName = completedString;
337                         }
338                     }
339                 }
340             }
341             
342             if (!insideStringLiteral) {
343                 if (ch == '=') {
344                     afterEquals = true;
345                 } else if (ch == '}') { // end of the parameter
346
if (hintName != null) { // true-value hint
347
hints.put(hintName, TRUE_HINT_VALUE);
348                         hintName = null;
349                     }
350                     break;
351                 }
352             }
353             
354             index++; // move to next char
355
}
356         
357         if (name == null) {
358             name = NULL_PARAMETER_NAME;
359         }
360         
361         // Determine default parameter's value
362
String JavaDoc defaultValue = (String JavaDoc)getHints().get(CodeTemplateParameter.DEFAULT_VALUE_HINT_NAME);
363         if (defaultValue == null) { // implicit value will be name of the parameter
364
defaultValue = name;
365         }
366         value = defaultValue;
367         
368         if (name.equals(CodeTemplateParameter.CURSOR_PARAMETER_NAME)) {
369             editable = false;
370             value = "";
371         } else if (name.equals(CodeTemplateParameter.SELECTION_PARAMETER_NAME)) {
372             editable = false;
373             if (handler != null) {
374                 value = handler.getComponent().getSelectedText();
375                 if (value == null)
376                     value = ""; //NOI18N
377
else if (getHints().get(CodeTemplateParameter.LINE_HINT_NAME) != null && !value.endsWith("\n")) //NOI18N
378
value += "\n"; //NOI18N
379
}
380         } else {
381             editable = !isHintValueFalse(CodeTemplateParameter.EDITABLE_HINT_NAME);
382         }
383         
384         parametrizedTextEndOffset = index + 1;
385     }
386     
387     private boolean isHintValueFalse(String JavaDoc hintName) {
388         String JavaDoc hintValue = (String JavaDoc)getHints().get(hintName);
389         return (hintValue != null) && "false".equals(hintValue.toLowerCase()); // NOI18N
390
}
391     
392     /**
393      * Called after '\' was found in the text to complete the escaped
394      * character and append it to the given output.
395      *
396      * @param text non-null text to be scanned.
397      * @param index index after '\' in the text to be used for finding
398      * the target character.
399      * @param output non-null output to which the resulting character should
400      * be appended.
401      * @return index of the next character to read.
402      */

403     private int escapedChar(CharSequence JavaDoc text, int index, StringBuffer JavaDoc output) {
404         if (index == text.length()) {
405             output.append('\\');
406         } else {
407             switch (text.charAt(index++)) {
408                 case '\\':
409                     output.append('\\');
410                     break;
411                 case 'n':
412                     output.append('\n');
413                     break;
414                 case 'r':
415                     output.append('\r');
416                     break;
417                 case '"':
418                     output.append('"');
419                     break;
420                 case '\'':
421                     output.append('\'');
422                     break;
423                     
424                 case 'u': // Unicode sequence
425
int value = 0;
426                     for (int i = 0; i < 4; i++) {
427                         if (index < text.length()) {
428                             char ch = text.charAt(index);
429                             if (ch >= '0' && ch <= '9') {
430                                 value = (value << 4) + (ch - '0');
431                             } else if (ch >= 'a' && ch <= 'f') {
432                                 value = (value << 4) + 10 + (ch - 'a');
433                             } else if (ch >= 'A' && ch <= 'F') {
434                                 value = (value << 4) + 10 + (ch - 'F');
435                             } else { // invalid char
436
break;
437                             }
438                         }
439                         index++;
440                     }
441                     output.append(value);
442                     break;
443                     
444                 default: // not known char => append '\'
445
index--;
446                     output.append('\\');
447                     break;
448             }
449         }
450
451         return index; // index of the next read
452
}
453     
454     private void addSlave(CodeTemplateParameter slave) {
455         if (slaves == null) {
456             slaves = new ArrayList JavaDoc(2);
457             slavesUnmodifiable = Collections.unmodifiableCollection(slaves);
458         }
459         slaves.add(slave);
460     }
461     
462     private void setMaster(CodeTemplateParameter master) {
463         this.master = master;
464     }
465     
466     public String JavaDoc toString() {
467         return "name=" + getName() + ", slave=" + isSlave() // NOI18N
468
+ ", value=" + getValue(); // NOI18N
469
}
470
471 }
472
Popular Tags