KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openide > src > ElementFormat


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.openide.src;
21
22 import java.text.*;
23 import java.util.*;
24 import java.io.*;
25 import java.lang.reflect.Modifier JavaDoc;
26
27 import org.openide.src.*;
28 import org.openide.util.NbBundle;
29
30 /** A format used to print members of the source hierarchy.
31 * It is sometimes used for code generation of elements, and also
32 * for formatting the display names of the nodes representing
33 * the hierarchy.
34 * <P>
35 *
36 * This format is similar to {@link MessageFormat}.
37 * It also uses special characters in the pattern and replaces them with strings,
38 * depending on the code.
39 * <P>
40 * For example:
41 * <p><CODE><PRE>
42 * ElementFormat fmt = new ElementFormat ("{m} {r} {n} ({p})");
43 * MethodElement method = getMethodSomewhere ();
44 * System.out.println (fmt.format (method));
45 * </PRE></CODE>
46 * <p>...should print something like this: <code>"public int method(int,char)"</code>
47 *
48 * <p>The substitution codes are:
49 * <UL>
50 * <LI> <code>{m}</code> Modifiers
51 * <LI> <code>{n}</code> Name
52 * <LI> <code>{C}</code> Name of class (with all outerclasses)
53 * <LI> <code>{f}</code> Full name of element with package
54 * <LI> <code>{t}</code> Type
55 * <LI> <code>{r}</code> Return type
56 * <LI> <code>{s}</code> Superclass
57 * <LI> <code>{c}</code> Static (for initializers)
58 * <LI> <code>{p}</code> Parameters with types but not variable names (e.g. <code>"int,char"</code>).
59 * <LI> <code>{a}</code> Parameters with types and names (e.g. <code>"int x,char c"</code>).
60 * <LI> <code>{i}</code> Interfaces
61 * <LI> <code>{e}</code> Exceptions
62 * </UL>
63 *
64 * <P>
65 * The following table shows which codes may be used
66 * to format which kinds of element. An asterisk means
67 * the code may be used, a hyphen means it cannot:
68 *
69 * <p><CODE><PRE>
70 * character | m n f C t r s c p a i e
71 * ----------------------------------------------------
72 * Initializer | - - - - - - - * - - - -
73 * Field | * * * - * - - - - - - -
74 * Constructor | * * * - - - - - * * - *
75 * Method | * * * - - * - - * * - *
76 * Class | * * * * - - * - - - * -
77 * Interface | * * * * - - - - - - * -
78 * </PRE></CODE>
79 *
80 * <p>The grammar for expressions:
81 *
82 * <p><code><pre>
83 * messageFormatPattern := string ( "{" messageFormatElement "}" string )*
84 *
85 * messageFormatElement := simple_argument { "," prefix "," suffix }
86 *
87 * messageFormatElement := array_argument { "," prefix "," suffix { "," delim } }
88 *
89 * simple_argument := "m" | "n" | "f" | "C" | "t" | "r" | "s" | "c"
90 *
91 * array_argument := "p" | "a" | "i" | "e"
92 *
93 * prefix := string
94 *
95 * suffix := string
96 *
97 * delim := string
98 *
99 * </pre></code>
100 *
101 * <p>Comments on the previous grammar:
102 * <UL>
103 * <LI> <code>simple_argument</code> - arguments which are replaced by a single string
104 * <LI> <code>array_argument</code> - arguments for arrays (parameters, ...)
105 * <LI> <code>prefix</code> - prefix before the format element if nonempty
106 * <LI> <code>suffix</code> - suffix after the format element if nonempty
107 * <LI> <code>delim</code> - delimiter between the members of the array
108 * <LI> <code>string</code> - a bare string, or enclosed in double quotes if necessary
109 * (e.g. if it contains a comma)
110 * </UL>
111 *
112 * <P>
113 * Example formats:
114 * <UL>
115 * <LI> For a method which doesn't throw any exceptions: <code>{e,throws ,}</code> => <code>""</code>
116 * <LI> For a method which throws <code>IOException</code>: <code>{e,throws ,</code>} => <code>"throws IOException"</code>
117 * <LI> Method parameters #1: <code>{p,,,-}</code> => <code>"int-int-int"</code>
118 * <LI> Method parameters #2: <code>{p,(,),", "}</code> => <code>"(int, int, int)"</code>
119 * </UL>
120 * <p>The default delimiter is a comma.
121 * <p>This class <em>currently</em> has a default property editor
122 * in the property editor search path for the IDE.
123 *
124 * @author Petr Hamernik
125 */

126 public final class ElementFormat extends Format {
127
128     // ============== Static part =================================
129

130     /** Serial UID */
131     static final long serialVersionUID = 3775521938640169753L;
132
133     /** Magic characters for all kinds of the formating tags.
134     * The position of the characters is used as index to the following array.
135     */

136     private static final String JavaDoc PROPERTIES_NAMES_INDEX = "mnfCtrscpaie"; // NOI18N
137

138     /** Array of names of all kinds properties which could be included
139     * in the pattern string.
140     */

141     private static final String JavaDoc[] PROPERTIES_NAMES = {
142         ElementProperties.PROP_MODIFIERS, //m
143
ElementProperties.PROP_NAME, //n
144
ElementProperties.PROP_NAME, //f
145
ElementProperties.PROP_NAME, //C
146
ElementProperties.PROP_TYPE, //t
147
ElementProperties.PROP_RETURN, //r
148
ElementProperties.PROP_SUPERCLASS, //s
149
ElementProperties.PROP_STATIC, //c
150
ElementProperties.PROP_PARAMETERS, //p
151
ElementProperties.PROP_PARAMETERS, //a
152
ElementProperties.PROP_INTERFACES, //i
153
ElementProperties.PROP_EXCEPTIONS //e
154
};
155
156     /** Status constants for the parser. */
157     private static final byte STATUS_OUTSIDE = 0;
158     private static final byte STATUS_INSIDE = 1;
159     private static final byte STATUS_RBRACE = 2;
160
161     // ================ Non-static part ===============================
162

163     /** Pattern - the string which is given in the constructor. */
164     private String JavaDoc pattern;
165
166     /** The current value of "source" property */ // NOI18N
167
private boolean source;
168
169     /** List of parts of the formated string. Elements of this list are
170     * either String objects either Tag.
171     */

172     private transient LinkedList list;
173
174     // ================ Public methods =================================
175

176     /** Create a new format.
177     * See documentation for the class for the syntax of the format argument.
178     * @param pattern the pattern describing the format
179     */

180     public ElementFormat(String JavaDoc pattern) {
181         applyPattern(pattern);
182         source = true;
183     }
184
185     /** Set whether the formating is used for code generation.
186     * Default value is <CODE>true</CODE>.
187     * @param source <CODE>true</CODE> means that all Identifier and Type objects
188     * used in formating are evaluated by <CODE>getSourceName</CODE>
189     * method. Otherwise (<CODE>false</CODE>) the getFullName() is
190     * called.
191     */

192     public void setSourceFormat(boolean source) {
193         this.source = source;
194     }
195
196     /** Test if this format generate strings in source format or fully
197     * qualified format.
198     * @return the source flag
199     */

200     public boolean isSourceFormat() {
201         return source;
202     }
203
204     /** Get the pattern.
205     * @return the current pattern
206     */

207     public String JavaDoc getPattern() {
208         return pattern;
209     }
210
211     /** Format an object.
212     * @param o should be an {@link Element}
213     * @param toAppendTo the string buffer to format to
214     * @param pos currently ignored
215     * @return the same string buffer it was passed (for convenient chaining)
216     * @throws IllegalArgumentException if the object was not really an <code>Element</code>
217     */

218     public StringBuffer JavaDoc format(Object JavaDoc o, StringBuffer JavaDoc toAppendTo, FieldPosition pos) {
219         try {
220             Element element = (Element) o;
221             Iterator it = list.iterator();
222             while (it.hasNext()) {
223                 Object JavaDoc obj = it.next();
224                 if (obj instanceof String JavaDoc) {
225                     toAppendTo.append((String JavaDoc)obj);
226                 }
227                 else {
228                     ((Tag)obj).format(element, toAppendTo);
229                 }
230             }
231             return toAppendTo;
232         }
233         catch (ClassCastException JavaDoc e) {
234             throw new IllegalArgumentException JavaDoc(NbBundle.getMessage(ElementFormat.class, "MSG_badArgument"));
235         }
236     }
237
238     /** Formats an element.
239     * @param element the element to be printed
240     * @return the formatted string using the pattern
241     */

242     public String JavaDoc format(Element element) {
243         return format(element, new StringBuffer JavaDoc(), null).toString();
244     }
245
246     /** Test whether a property could affect the formatting.
247     * I.e., if that property would be read due to one of the control codes in the pattern.
248     * @param prop the property name from {@link ElementProperties}
249     * @return <code>true</code> if so
250     */

251     public boolean dependsOnProperty(String JavaDoc prop) {
252         Iterator it = list.iterator();
253         while (it.hasNext()) {
254             Object JavaDoc obj = it.next();
255             if (obj instanceof Tag) {
256                 int index = PROPERTIES_NAMES_INDEX.indexOf(((Tag)obj).kind);
257                 if (PROPERTIES_NAMES[index].equals(prop))
258                     return true;
259             }
260         }
261         return false;
262     }
263
264     /** Don't parse objects.
265     * @param source ignored
266     * @param status ignored
267     * @return <code>null</code> in the default implementation
268     */

269     public Object JavaDoc parseObject (String JavaDoc source, ParsePosition status) {
270         return null;
271     }
272
273     /** Reads the object and initialize fields. */
274     private void readObject(ObjectInputStream s) throws ClassNotFoundException JavaDoc, IOException {
275         s.defaultReadObject();
276         applyPattern(pattern);
277     }
278
279     // ====================== Private part ===================================
280

281     /** Parse the pattern. */
282     private void applyPattern(String JavaDoc pattern) {
283         this.pattern = pattern;
284         list = new LinkedList();
285
286         byte status = STATUS_OUTSIDE;
287         StringTokenizer tokenizer = new StringTokenizer(pattern, "{}", true); // NOI18N
288
while (tokenizer.hasMoreTokens()) {
289             String JavaDoc token = tokenizer.nextToken();
290             switch (status) {
291
292             case STATUS_OUTSIDE:
293                 if (token.equals("}")) // NOI18N
294
throw new IllegalArgumentException JavaDoc(NbBundle.getMessage(ElementFormat.class, "MSG_badPattern"));
295                 if (token.equals("{")) // NOI18N
296
status = STATUS_INSIDE;
297                 else
298                     list.add(token);
299                 break;
300
301             case STATUS_INSIDE:
302                 if ((token.equals("{")) || (token.equals("}"))) // NOI18N
303
throw new IllegalArgumentException JavaDoc(NbBundle.getMessage(ElementFormat.class, "MSG_badPattern"));
304                 list.add(createTag(token));
305                 status = STATUS_RBRACE;
306                 break;
307
308             case STATUS_RBRACE:
309                 if (!token.equals("}")) // NOI18N
310
throw new IllegalArgumentException JavaDoc(NbBundle.getMessage(ElementFormat.class, "MSG_badPattern"));
311                 status = STATUS_OUTSIDE;
312                 break;
313
314             }
315         }
316     }
317
318     /** Creates the appropriate tag for the given String.
319     * @param s The string which is between the brackets in the pattern.
320     * @return the tag object.
321     */

322     private Tag createTag(String JavaDoc s) {
323         if (s.length() > 0) {
324             char c = s.charAt(0);
325             String JavaDoc[] params = new String JavaDoc[0];
326
327             if (s.length() > 1) {
328                 if ((s.length() < 2) || (s.charAt(1) != ','))
329                     throw new IllegalArgumentException JavaDoc(NbBundle.getMessage(ElementFormat.class, "MSG_badPattern"));
330                 params = parseParams(s.substring(2));
331             }
332
333             if ("mnfCtrsc".indexOf(c) != -1) { // NOI18N
334
switch (params.length) {
335                 case 0: return new Tag(c, "", ""); // NOI18N
336
case 2: return new Tag(c, params[0], params[1]);
337                 }
338             }
339             else if ("paie".indexOf(c) != -1) { // NOI18N
340
switch (params.length) {
341                 case 0: return new ArrayTag(c, "", "", ", "); // NOI18N
342
case 2: return new ArrayTag(c, params[0], params[1], ", "); // NOI18N
343
case 3: return new ArrayTag(c, params[0], params[1], params[2]);
344                 }
345             }
346         }
347         throw new IllegalArgumentException JavaDoc(NbBundle.getMessage(ElementFormat.class, "MSG_badPattern"));
348     }
349
350     /** Parse the parameters of the tag.
351     * @param string of the params delimited by commas
352     * @return the array of the params.
353     */

354     private String JavaDoc[] parseParams(String JavaDoc s) {
355         StringTokenizer tokenizer = new StringTokenizer(s, ",", true); // NOI18N
356
ArrayList list = new ArrayList();
357         StringBuffer JavaDoc token = new StringBuffer JavaDoc();
358         boolean comma = false;
359         boolean inString = false;
360
361         while (tokenizer.hasMoreTokens()) {
362             String JavaDoc t = tokenizer.nextToken();
363
364             if (inString) {
365                 token.append(t);
366                 if (t.endsWith("\"")) { // NOI18N
367
if (token.length() > 1)
368                         token.setLength(token.length() - 1);
369                     list.add(token.toString());
370                     token.setLength(0);
371                     inString = false;
372                     comma = true;
373                 }
374                 continue;
375             }
376
377             if (t.equals(",")) { // NOI18N
378
if (comma)
379                     comma = false;
380                 else
381                     list.add(""); // NOI18N
382
continue;
383             }
384
385             if (comma)
386                 throw new IllegalArgumentException JavaDoc(NbBundle.getMessage(ElementFormat.class, "MSG_badPattern"));
387
388             String JavaDoc stringToAdd = t;
389
390             if (t.startsWith("\"")) { // NOI18N
391
if ((t.endsWith("\"")) && (t.length() > 1)) { // NOI18N
392
stringToAdd = (t.length() <= 2) ? "" : t.substring(1, t.length() - 1); // NOI18N
393
}
394                 else {
395                     token.append(t.substring(1));
396                     inString = true;
397                     continue;
398                 }
399             }
400
401             list.add(stringToAdd);
402             comma = true;
403             token.setLength(0);
404         }
405         if (!comma)
406             list.add(""); // NOI18N
407

408         String JavaDoc[] ret = new String JavaDoc[list.size()];
409         list.toArray(ret);
410         return ret;
411     }
412
413     private static void resolveClassName (StringBuffer JavaDoc sb, ClassElement element) {
414         ClassElement c = element.getDeclaringClass ();
415         if (c == null) {
416             sb.append (element.getName ().getName ());
417             return;
418         }
419         resolveClassName (sb, c);
420         sb.append ('.').append (element.getName ().getName ());
421     }
422
423     /** Convert the Indentifier to string depending on "source" flag.
424     */

425     String JavaDoc identifierToString(Identifier id) {
426         return source ? id.getSourceName() : id.getFullName();
427     }
428
429     /** Convert the Type to String depending on "source" flag.
430     */

431     String JavaDoc typeToString(Type id) {
432         return source ? id.getSourceString() : id.getFullString();
433     }
434
435     /** Tag for simple types - m,n,t,r,s,c */
436     private class Tag extends Object JavaDoc implements Serializable {
437         /** Tag character */
438         char kind;
439
440         /** Prefix of the tag */
441         String JavaDoc prefix;
442
443         /** Suffix of the tag */
444         String JavaDoc suffix;
445
446         static final long serialVersionUID =4946774706959011193L;
447         /** Creates the tag. */
448         Tag(char kind, String JavaDoc prefix, String JavaDoc suffix) {
449             this.kind = kind;
450             this.prefix = prefix;
451             this.suffix = suffix;
452         }
453
454         /** Formats this tag for the given element.
455         * @param element Element to be formated.
456         * @param buf StringBuffer where to add the formated string.
457         */

458         void format(Element element, StringBuffer JavaDoc buf) {
459             try {
460                 int mark = buf.length();
461                 buf.append(prefix);
462
463                 switch (kind) {
464                 case 'm':
465                     buf.append(Modifier.toString(((MemberElement)element).getModifiers()));
466                     break;
467
468                 case 'n':
469                     buf.append(identifierToString(((MemberElement)element).getName()));
470                     break;
471
472                 case 'f':
473                     buf.append(((MemberElement)element).getName().getFullName());
474                     break;
475
476                 case 'C':
477                     resolveClassName (buf, (ClassElement)element);
478                     break;
479
480                 case 't':
481                     buf.append(typeToString(((FieldElement)element).getType()));
482                     break;
483
484                 case 'r':
485                     buf.append(typeToString(((MethodElement)element).getReturn()));
486                     break;
487
488                 case 's':
489                     Identifier id = ((ClassElement)element).getSuperclass();
490                     if (id != null)
491                         buf.append(identifierToString(id));
492                     break;
493
494                 case 'c':
495                     if (((InitializerElement)element).isStatic())
496                         buf.append(Modifier.toString(Modifier.STATIC));
497                     break;
498                 }
499
500                 if (buf.length() > mark + prefix.length()) {
501                     buf.append(suffix);
502                 }
503                 else {
504                     buf.setLength(mark);
505                 }
506             }
507             catch (ClassCastException JavaDoc e) {
508                 throw new IllegalArgumentException JavaDoc(NbBundle.getMessage(ElementFormat.class, "MSG_badPattern"));
509             }
510         }
511     }
512
513     /** Tag for arrays - params, exceptions, interfaces.
514     */

515     private class ArrayTag extends Tag {
516         /** Delimiter */
517         String JavaDoc delim;
518
519         static final long serialVersionUID =2060398944304753010L;
520         /** Creates new array tag. */
521         ArrayTag(char kind, String JavaDoc prefix, String JavaDoc suffix, String JavaDoc delim) {
522             super(kind, prefix, suffix);
523             this.delim = delim;
524         }
525
526         /** Formats this tag for the given element.
527         * @param element Element to be formated.
528         * @param buf StringBuffer where to add the formated string.
529         */

530         void format(Element element, StringBuffer JavaDoc buf) {
531             try {
532                 int mark = buf.length();
533                 buf.append(prefix);
534
535                 switch (kind) {
536                 case 'e':
537                     Identifier[] ids = ((ConstructorElement)element).getExceptions();
538                     for (int i = 0; i < ids.length; i++) {
539                         if (i > 0)
540                             buf.append(delim);
541                         buf.append(identifierToString(ids[i]));
542                     }
543                     break;
544
545                 case 'p':
546                 case 'a':
547                     MethodParameter[] args = ((ConstructorElement)element).getParameters();
548                     for (int i = 0; i < args.length; i++) {
549                         if (i > 0)
550                             buf.append(delim);
551                         if (kind == 'a') {
552                             args[i].getAsString(buf, source);
553                         }
554                         else {
555                             args[i].getType().getAsString(buf, source);
556                         }
557                     }
558                     break;
559
560                 case 'i':
561                     ids = ((ClassElement)element).getInterfaces();
562                     for (int i = 0; i < ids.length; i++) {
563                         if (i > 0)
564                             buf.append(delim);
565                         buf.append(identifierToString(ids[i]));
566                     }
567                     break;
568                 }
569
570                 if (buf.length() > mark + prefix.length()) {
571                     buf.append(suffix);
572                 }
573                 else {
574                     buf.setLength(mark);
575                 }
576             }
577             catch (ClassCastException JavaDoc e) {
578                 throw new IllegalArgumentException JavaDoc(NbBundle.getMessage(ElementFormat.class, "MSG_badPattern"));
579             }
580         }
581     }
582 }
583
Popular Tags