Clover coverage report - XJavaDoc - 1.1 Coverage timestamp: Sun Oct 3 2004 19:56:54 BST FRAMES NO FRAMES |
file stats: | LOC: | 905 |  | Methods: | 32
| NCLOC: | 494 |  | Classes: | 1
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover
Source file | Conditionals | Statements | Methods | TOTAL
XDoc.java | 62.1% | 71.7% | 65.6% | 68.1% |

1 |  |
     /*
2 |  |
      * Copyright (c) 2001-2003 The XDoclet team
3 |  |
      * All rights reserved.
4 |  |
      */
5 |  |
     package xjavadoc;
6 |  |
7 |  |
     import java.io.BufferedReader;
8 |  |
     import java.io.IOException;
9 |  |
     import java.io.StringReader;
10 |  |
     import java.util.*;
11 |  |
     import xjavadoc.event.XDocListener;
12 |  |
     import xjavadoc.event.XDocEvent;
13 |  |
     import xjavadoc.event.XTagListener;
14 |  |
     import xjavadoc.event.XTagEvent;
15 |  |
16 |  |
     /**
17 |  |
      * Represents documentation
18 |  |
      *
19 |  |
      * @author    Aslak Hellesøy
20 |  |
      * @created   20. mars 2003
21 |  |
      */
22 |  |
     public final class XDoc implements XTagListener
23 |  |
     {
24 |  |
         public static int  instanceCount = 0;
25 |  |
26 |  |
         /**
27 |  |
          * Platform specific NEWLINE. Javadoc will use this as new line.
28 |  |
          */
29 |  |
         private final static String NEWLINE = System.getProperty( "line.separator" );
30 |  |
31 |  |
         /**
32 |  |
          * Default comment
33 |  |
          */
34 |  |
         private final static String EMPTY_COMMENT = "/**\n */";
35 |  |
36 |  |
         /**
37 |  |
          * Maps tag name to List. The Collection contains XTag instances whose name =
38 |  |
          * name (the map key). The tags in the Lists are ordered by occurrance
39 |  |
          */
40 |  |
         private Map        _tagMap;
41 |  |
42 |  |
         /**
43 |  |
          * Token (which is linked in the AST) that holds the string representation of
44 |  |
          * the doc. Needed for printing out the class.
45 |  |
          */
46 |  |
         private Token      _javadocToken;
47 |  |
48 |  |
         private XProgramElement _owner;
49 |  |
50 |  |
         /**
51 |  |
          * Contains all the tags in the doc, in order of occurrence.
52 |  |
          */
53 |  |
         private List _tags;
54 |  |
         /**
55 |  |
          * description of program element
56 |  |
          */
57 |  |
         private String     _commentText = "";
58 |  |
         /**
59 |  |
          * first sentence of comment text
60 |  |
          */
61 |  |
         private String     _firstSentence;
62 |  |
63 |  |
         private boolean    _dirty = true;
64 |  |
65 |  |
         private Set        _docListeners = new HashSet();
66 |  |
67 |  |
         private final XTagFactory _tagFactory;
68 |  |
69 |  |
         /**
70 |  |
          * Describe what the XDoc constructor does
71 |  |
          *
72 |  |
          * @param javadocToken  Describe what the parameter does
73 |  |
          * @param owner         Describe what the parameter does
74 |  |
          * @param tagFactory    Describe what the parameter does
75 |  |
          */
76 | 698 |
         public XDoc( Token javadocToken, XProgramElement owner, XTagFactory tagFactory )
77 |  |
         {
78 | 698 |
             instanceCount++;
79 | 698 |
             if( javadocToken == null )
80 |  |
             {
81 | 0 |
                 _javadocToken = Token.newToken( NodeParserConstants.FORMAL_COMMENT );
82 |  |
             }
83 |  |
             else
84 |  |
             {
85 | 698 |
                 _javadocToken = javadocToken;
86 |  |
             }
87 | 698 |
             _owner = owner;
88 | 698 |
             _tagFactory = tagFactory;
89 | 698 |
             if( _javadocToken.image == null )
90 |  |
             {
91 |  |
                 // the passed token was not from source code, but was created because no javadoc existed.
92 | 0 |
                 _javadocToken.image = EMPTY_COMMENT;
93 |  |
             }
94 |  |
         }
95 |  |
96 |  |
         /**
97 |  |
          * Convert a tag name from the old colon-separated form to the new preferred dot-separated form.
98 |  |
          *
99 |  |
          * @param tagName  The name of the tag
100 |  |
          * @return         Preferred form of the tag
101 |  |
          */
102 | 5628 |
         public static String dotted( final String tagName )
103 |  |
         {
104 | 5628 |
             return tagName.replace( ':', '.' );
105 |  |
         }
106 |  |
107 | 1130 |
         private final static String tokenizeAndTrim( final String s )
108 |  |
         {
109 | 1130 |
             StringBuffer sb = new StringBuffer();
110 | 1130 |
             StringTokenizer st = new StringTokenizer( s );
111 |  |
112 | 1130 |
             while( st.hasMoreTokens() )
113 |  |
             {
114 | 8748 |
                 sb.append( st.nextToken() ).append( " " );
115 |  |
             }
116 | 1130 |
             return sb.toString().trim();
117 |  |
         }
118 |  |
119 |  |
         /**
120 |  |
          * Gets the Owner attribute of the XDoc object
121 |  |
          *
122 |  |
          * @return   The Owner value
123 |  |
          */
124 | 710 |
         public XProgramElement getOwner()
125 |  |
         {
126 | 710 |
             return _owner;
127 |  |
         }
128 |  |
129 |  |
         /**
130 |  |
          * Returns all the tags in this doc with the specified tagName (not
131 |  |
          * superclasses). If No tags are found, an empty Collection is returned.
132 |  |
          *
133 |  |
          * @param tagName  the name of the tags to return (without the 'at')
134 |  |
          * @return         A Collection of XTag
135 |  |
          */
136 | 8 |
         public List getTags( String tagName )
137 |  |
         {
138 | 8 |
             return getTags( tagName, false );
139 |  |
         }
140 |  |
141 |  |
         /**
142 |  |
          * Returns all the tags with the specified tagName. If No tags are found, an
143 |  |
          * empty Collection is returned.
144 |  |
          *
145 |  |
          * @param tagName       the name of the tags to return (without the 'at')
146 |  |
          * @param superclasses  if this is true, return tags from superclasses too.
147 |  |
          * @return              A Collection of XTag
148 |  |
          */
149 | 696 |
         public List getTags( String tagName, boolean superclasses )
150 |  |
         {
151 |  |
152 | 696 |
             tagName = dotted( tagName );
153 | 696 |
             if( _dirty )
154 |  |
             {
155 | 684 |
                 parse();
156 |  |
             }
157 |  |
158 | 696 |
             ensureTagMapInitialised();
159 |  |
160 | 696 |
             List tags = ( List ) _tagMap.get( tagName );
161 |  |
162 | 696 |
             if( !superclasses )
163 |  |
             {
164 | 172 |
                 if( tags == null )
165 |  |
                 {
166 | 128 |
                     tags = AbstractProgramElement.EMPTY_LIST;
167 |  |
                 }
168 | 172 |
                 return Collections.unmodifiableList( tags );
169 |  |
             }
170 |  |
             else
171 |  |
             {
172 |  |
                 // Make a new Collection where we append all tags from this and super
173 | 524 |
                 LinkedList superTags = new LinkedList();
174 |  |
175 |  |
                 // Add tags from this doc if any.
176 | 524 |
                 if( tags != null )
177 |  |
                 {
178 | 186 |
                     superTags.addAll( tags );
179 |  |
                 }
180 |  |
181 |  |
                 // Now add tags from super
182 | 524 |
                 XDoc superDoc = getSuperDoc();
183 |  |
184 | 524 |
                 if( superDoc != null )
185 |  |
                 {
186 | 18 |
                     superTags.addAll( superDoc.getTags( tagName, true ) );
187 |  |
                 }
188 |  |
189 |  |
                 // Now add tags from implemented interfaces
190 |  |
                 // TODO: How are we going to ensure uniqueness ...
191 |  |
                 // we could get to the same interface tag twice
192 | 524 |
                 Iterator docs = getAllSuperDocs().iterator();
193 | 524 |
                 while ( docs.hasNext() )
194 |  |
                 {
195 | 160 |
                     XDoc interfaceDoc = (XDoc) docs.next();
196 |  |
                     // Perhaps the last argument to getTagAttributeValue() should be true
197 | 160 |
                     List interfaceTags = interfaceDoc.getTags( tagName, false );
198 | 160 |
                     superTags.addAll( interfaceTags );
199 |  |
                 }
200 |  |
201 | 524 |
                 return Collections.unmodifiableList( superTags );
202 |  |
             }
203 |  |
         }
204 |  |
205 |  |
         /**
206 |  |
          * Returns all the tags in this doc (not superclasses). If No tags are found,
207 |  |
          * an empty Collection is returned.
208 |  |
          *
209 |  |
          * @return   A Collection of XTag
210 |  |
          */
211 | 18 |
         public List getTags()
212 |  |
         {
213 | 18 |
             return getTags( false );
214 |  |
         }
215 |  |
216 |  |
         /**
217 |  |
          * Returns all the tags. If no tags are found, an
218 |  |
          * empty List is returned.
219 |  |
          *
220 |  |
          * @param superclasses  if this is true, return tags from superclasses too.
221 |  |
          * @return              A List of XTag
222 |  |
          */
223 | 22 |
         public List getTags( boolean superclasses )
224 |  |
         {
225 |  |
226 | 22 |
             if( _dirty )
227 |  |
             {
228 | 8 |
                 parse();
229 |  |
             }
230 | 22 |
             if( !superclasses )
231 |  |
             {
232 | 18 |
                 if( _tags == null )
233 |  |
                 {
234 | 0 |
                     return AbstractProgramElement.EMPTY_LIST;
235 |  |
                 }
236 |  |
                 else
237 |  |
                 {
238 | 18 |
                     return _tags;
239 |  |
                 }
240 |  |
             }
241 |  |
             else
242 |  |
             {
243 |  |
                 // Make a new Collection where we append all tags from this and super
244 | 4 |
                 LinkedList tags = new LinkedList();
245 |  |
246 |  |
                 // Add tags from this doc if any.
247 | 4 |
                 if( _tags != null )
248 |  |
                 {
249 | 4 |
                     tags.addAll( _tags );
250 |  |
                 }
251 |  |
252 |  |
                 // Now add tags from super
253 | 4 |
                 XDoc superDoc = getSuperDoc();
254 |  |
255 | 4 |
                 if( superDoc != null )
256 |  |
                 {
257 | 2 |
                     tags.addAll( superDoc.getTags( true ) );
258 |  |
                 }
259 |  |
260 |  |
                 // Now add tags from implemented interfaces
261 |  |
                 // TODO: How are we going to ensure uniqueness ...
262 |  |
                 // we could get to the same interface tag twice
263 | 4 |
                 Iterator docs = getAllSuperDocs().iterator();
264 | 4 |
                 while ( docs.hasNext() )
265 |  |
                 {
266 | 0 |
                     XDoc interfaceDoc = (XDoc) docs.next();
267 |  |
                     // Perhaps the last argument to getTagAttributeValue() should be true
268 | 0 |
                     List interfaceTags = interfaceDoc.getTags( false );
269 | 0 |
                     tags.addAll( interfaceTags );
270 |  |
                 }
271 |  |
272 | 4 |
                 return Collections.unmodifiableList( tags );
273 |  |
             }
274 |  |
         }
275 |  |
276 |  |
         /**
277 |  |
          * Get the first tag of name tagName from this doc.  Superclasses are not searched.
278 |  |
          *
279 |  |
          * @param tagName  the name of the tag
280 |  |
          * @return         the tag
281 |  |
          */
282 | 4 |
         public XTag getTag( String tagName )
283 |  |
         {
284 | 4 |
             return getTag( tagName, false );
285 |  |
         }
286 |  |
287 |  |
         /**
288 |  |
          * Get the first tag of name tagName.
289 |  |
          *
290 |  |
          * @param tagName       the name of the tag to get (without the 'at')
291 |  |
          * @param superclasses  if this is true, return tags from superclasses too.
292 |  |
          * @return              the first XTag with name equal to tagName
293 |  |
          */
294 | 4 |
         public XTag getTag( String tagName, boolean superclasses )
295 |  |
         {
296 | 4 |
             tagName = dotted( tagName );
297 |  |
298 | 4 |
             Collection tags = getTags( tagName, superclasses );
299 |  |
300 | 4 |
             if( tags.size() == 0 )
301 |  |
             {
302 | 0 |
                 return null;
303 |  |
             }
304 |  |
             else
305 |  |
             {
306 | 4 |
                 return ( XTag ) tags.iterator().next();
307 |  |
             }
308 |  |
         }
309 |  |
310 |  |
         /**
311 |  |
          * Returns the tag attribute value. Does not look in superclasses. If nothing
312 |  |
          * is found, null is returned.
313 |  |
          *
314 |  |
          * @param tagName        The name of the tag to look for (without the 'at')
315 |  |
          * @param attributeName  The name of the attribute to look for within the tag.
316 |  |
          * @return               The value of the tag attribute.
317 |  |
          */
318 | 0 |
         public String getTagAttributeValue( String tagName, String attributeName )
319 |  |
         {
320 | 0 |
             return getTagAttributeValue( tagName, attributeName, false );
321 |  |
         }
322 |  |
323 |  |
         /**
324 |  |
          * Returns the tag attribute value. If superclasses is true, the first
325 |  |
          * occurrence is returned when walking up the class hierarchy. If nothing is
326 |  |
          * found, null is returned.
327 |  |
          *
328 |  |
          * @param tagName        The name of the tag to look for (without the 'at')
329 |  |
          * @param attributeName  The name of the attribute to look for within the tag.
330 |  |
          * @param superclasses   Set it to true to look in superclasses too.
331 |  |
          * @return               The value of the tag attribute.
332 |  |
          */
333 | 2 |
         public String getTagAttributeValue( String tagName, String attributeName, boolean superclasses )
334 |  |
         {
335 | 2 |
             tagName = dotted( tagName );
336 |  |
337 |  |
             // Get all the tags, loop over them and return the first occurrence of the attribute.
338 | 2 |
             for( Iterator tags = getTags( tagName ).iterator(); tags.hasNext();  )
339 |  |
             {
340 | 2 |
                 XTag tag = ( XTag ) tags.next();
341 | 2 |
                 String attributeValue = tag.getAttributeValue( attributeName );
342 |  |
343 | 2 |
                 if( attributeValue != null )
344 |  |
                 {
345 |  |
                     // found one! Return that.
346 | 2 |
                     return attributeValue;
347 |  |
                 }
348 |  |
             }
349 |  |
350 |  |
             // Couldn't find anything here. Ask superclasses
351 |  |
352 | 0 |
             if( superclasses )
353 |  |
             {
354 | 0 |
                 XDoc superDoc = getSuperDoc();
355 |  |
356 | 0 |
                 if( superDoc != null )
357 |  |
                 {
358 |  |
                     // prefer tags defined on a superclass to tags on interfaces
359 | 0 |
                     String superclassTagValue = superDoc.getTagAttributeValue( tagName, attributeName, true );
360 | 0 |
                     if (superclassTagValue!=null) return superclassTagValue;
361 |  |
                 }
362 |  |
363 |  |
364 |  |
                 // check interfaces!
365 | 0 |
                 Iterator docs = getAllSuperDocs().iterator();
366 | 0 |
                 while ( docs.hasNext() )
367 |  |
                 {
368 | 0 |
                     XDoc interfaceDoc = (XDoc) docs.next();
369 |  |
                     // Note: this will do a "depth first" search, is that desirable?
370 |  |
                     // Perhaps the last argument to getTagAttributeValue() should be false
371 | 0 |
                     String tagValue = interfaceDoc.getTagAttributeValue( tagName, attributeName, true );
372 | 0 |
                     if (tagValue!=null) return tagValue;
373 |  |
                 }
374 |  |
375 |  |
                 // We've come to an end. Nothing found. Return null;
376 | 0 |
                 return null;
377 |  |
378 |  |
             }
379 |  |
             else
380 |  |
             {
381 |  |
                 // Don't look in superclasses or implemented interfaces. Just return null;
382 | 0 |
                 return null;
383 |  |
             }
384 |  |
         }
385 |  |
386 |  |
         /**
387 |  |
          * return description of program element
388 |  |
          *
389 |  |
          * @return   description of program element
390 |  |
          */
391 | 0 |
         public String getCommentText()
392 |  |
         {
393 | 0 |
             if( _dirty )
394 |  |
             {
395 | 0 |
                 parse();
396 |  |
             }
397 | 0 |
             return _commentText;
398 |  |
         }
399 |  |
400 |  |
         /**
401 |  |
          * Return the first sentence of the text of the comment for this doc item.
402 |  |
          *
403 |  |
          * @return   First sentence
404 |  |
          */
405 | 10 |
         public String getFirstSentence()
406 |  |
         {
407 | 10 |
             if( _dirty )
408 |  |
             {
409 | 6 |
                 parse();
410 |  |
             }
411 |  |
412 | 10 |
             if( _firstSentence == null )
413 |  |
             {
414 |  |
                 // Ok, we only have one sentence
415 | 10 |
                 if( _commentText.indexOf( '.' ) == -1 )
416 |  |
                 {
417 | 4 |
                     _firstSentence = _commentText;
418 | 4 |
                     return _firstSentence;
419 |  |
                 }
420 |  |
421 |  |
                 // Let's look for the first sentence separator. It should be a dot followed
422 |  |
                 // by a blank, tab or line terminator.
423 | 6 |
                 int fromIndex = 0;
424 |  |
425 | 6 |
                 while( fromIndex < _commentText.length() - 1 && _firstSentence == null )
426 |  |
                 {
427 | 8 |
                     int dotIndex = _commentText.indexOf( '.', fromIndex );
428 |  |
429 | 8 |
                     if( dotIndex != -1 && dotIndex < _commentText.length() - 1 )
430 |  |
                     {
431 | 6 |
                         if( " \t\r\n".indexOf( _commentText.charAt( dotIndex + 1 ) ) != -1 )
432 | 4 |
                             _firstSentence = _commentText.substring( 0, dotIndex + 1 );
433 |  |
                         else
434 | 2 |
                             fromIndex = dotIndex + 1;
435 |  |
                     }
436 |  |
                     else
437 | 2 |
                         _firstSentence = _commentText;
438 |  |
                 }
439 |  |
440 |  |
                 // We didn't find a proper first sentence separator. So we only have
441 |  |
                 // one sentence.
442 | 6 |
                 if( _firstSentence == null )
443 |  |
                 {
444 | 0 |
                     _firstSentence = _commentText;
445 |  |
                 }
446 |  |
             }
447 |  |
448 | 6 |
             return _firstSentence;
449 |  |
         }
450 |  |
451 |  |
         /**
452 |  |
          * Set the text of the comment for this doc item.
453 |  |
          *
454 |  |
          * @param commentText  The new comment text
455 |  |
          */
456 | 0 |
         public void setCommentText( String commentText )
457 |  |
         {
458 | 0 |
             if( _dirty )
459 |  |
             {
460 | 0 |
                 parse();
461 |  |
             }
462 | 0 |
             _commentText = commentText;
463 | 0 |
             _firstSentence = null;
464 | 0 |
             fireDocChanged();
465 |  |
         }
466 |  |
467 |  |
         /**
468 |  |
          * Returns true if the tag exists. Does not look in superclasses.
469 |  |
          *
470 |  |
          * @param tagName  The name of the tag to look for (without the 'at')
471 |  |
          * @return         true if the tag exists
472 |  |
          */
473 | 0 |
         public boolean hasTag( String tagName )
474 |  |
         {
475 | 0 |
             return hasTag( tagName, false );
476 |  |
         }
477 |  |
478 |  |
         /**
479 |  |
          * Returns true if the tag exists.
480 |  |
          *
481 |  |
          * @param tagName       The name of the tag to look for (without the 'at')
482 |  |
          * @param superclasses  If true, look in superclasses too.
483 |  |
          * @return              true if the tag exists
484 |  |
          */
485 | 0 |
         public boolean hasTag( String tagName, boolean superclasses )
486 |  |
         {
487 | 0 |
             return getTags( tagName, superclasses ).size() != 0;
488 |  |
         }
489 |  |
490 |  |
         /**
491 |  |
          * Utility method to set the value of a tag attribute. If the tag doesn't
492 |  |
          * exist, it is created. If the attribute doesn't exist it is created. If the
493 |  |
          * tag attribute exists, it is updated.
494 |  |
          *
495 |  |
          * @param tagName                The new name of the tag to update (without the
496 |  |
          * @param tagIndex               The index of the tag to update, in case there
497 |  |
          *      are several tags with the same name.
498 |  |
          * @param attributeName          The attribute name
499 |  |
          * @param attributeValue         The new attribute value
500 |  |
          * @return                       the updated tag
501 |  |
          * @exception XJavaDocException
502 |  |
          */
503 | 6 |
         public XTag updateTagValue( String tagName, String attributeName, String attributeValue, int tagIndex ) throws XJavaDocException
504 |  |
         {
505 | 6 |
             XTag tag = null;
506 | 6 |
             List tags = getTags( tagName );
507 |  |
508 | 6 |
             if( tags.size() == 0 || tags.size() <= tagIndex )
509 |  |
             {
510 |  |
                 //debug("@" + tagName + " at index " + tagIndex + " doesn't exist. creating new tag");
511 |  |
                 // There was no such tags. Create a new one.
512 | 4 |
                 String tagValue = attributeName + "=\"" + attributeValue + "\"";
513 |  |
514 | 4 |
                 tag = addTag_Impl( tagName, tagValue, -1 );
515 |  |
             }
516 |  |
             else
517 |  |
             {
518 |  |
                 // Iterate to the tag at the right index
519 | 2 |
                 Iterator tagIterator = tags.iterator();
520 |  |
521 | 2 |
                 for( int i = 0; i < tagIndex; i++ )
522 |  |
                 {
523 | 0 |
                     tag = (XTag) tagIterator.next();
524 |  |
                 }
525 | 2 |
                 if( tag != null )
526 |  |
                 {
527 | 0 |
                     tag.setAttribute( attributeName, attributeValue );
528 |  |
                 }
529 |  |
             }
530 | 6 |
             return tag;
531 |  |
         }
532 |  |
533 |  |
         /**
534 |  |
          * Add doc listener interested in changes.
535 |  |
          *
536 |  |
          * @param docListener  doc listener to register
537 |  |
          */
538 | 0 |
         public void addDocListener( XDocListener docListener )
539 |  |
         {
540 | 0 |
             _docListeners.add( docListener );
541 |  |
         }
542 |  |
543 |  |
         /**
544 |  |
          * remove doc listener
545 |  |
          *
546 |  |
          * @param docListener
547 |  |
          */
548 | 0 |
         public void removeDocListener( XDocListener docListener )
549 |  |
         {
550 | 0 |
             _docListeners.remove( docListener );
551 |  |
         }
552 |  |
553 |  |
         /**
554 |  |
          * Returns a String representation of this doc.
555 |  |
          *
556 |  |
          * @return   a String representation of this doc.
557 |  |
          */
558 | 8 |
         public String toString()
559 |  |
         {
560 | 8 |
             if( _dirty )
561 |  |
             {
562 | 0 |
                 parse();
563 |  |
             }
564 |  |
565 | 8 |
             StringBuffer sb = new StringBuffer( "/**" ).append( NEWLINE );
566 |  |
567 | 8 |
             if( !_commentText.trim().equals( "" ) )
568 |  |
             {
569 | 6 |
                 appendWhiteSpaces( sb ).append( " * " ).append( _commentText ).append( NEWLINE );
570 | 6 |
                 appendWhiteSpaces( sb ).append( " * " ).append( NEWLINE );
571 |  |
             }
572 |  |
573 |  |
     //        addSpaces(sb, _javadocToken).append(" * ").append(NEWLINE);
574 |  |
575 | 8 |
             for( Iterator tags = getTags().iterator(); tags.hasNext();  )
576 |  |
             {
577 | 18 |
                 XTag tag = ( XTag ) tags.next();
578 |  |
579 | 18 |
                 appendWhiteSpaces( sb ).append( " * @" ).append( tag.getName() );
580 |  |
581 | 18 |
                 Collection attributeNames = tag.getAttributeNames();
582 |  |
583 | 18 |
                 if( attributeNames.size() == 0 )
584 |  |
                 {
585 |  |
                     // no parameters, or malformed
586 | 6 |
                     sb.append( ' ' ).append( tag.getValue() ).append( NEWLINE );
587 |  |
                 }
588 |  |
                 else
589 |  |
                 {
590 | 12 |
                     sb.append( NEWLINE );
591 | 12 |
                     for( Iterator attrs = attributeNames.iterator(); attrs.hasNext();  )
592 |  |
                     {
593 | 18 |
                         String attibuteName = ( String ) attrs.next();
594 | 18 |
                         String attributeValue = tag.getAttributeValue( attibuteName );
595 |  |
596 | 18 |
                         appendWhiteSpaces( sb ).append( " *    " ).append( attibuteName ).append( "=\"" ).append( attributeValue ).append( "\"" ).append( NEWLINE );
597 |  |
                     }
598 |  |
                 }
599 |  |
             }
600 | 8 |
             appendWhiteSpaces( sb ).append( " */" );
601 |  |
602 | 8 |
             return sb.toString();
603 |  |
         }
604 |  |
605 |  |
         /**
606 |  |
          * update token
607 |  |
          */
608 | 8 |
         public void updateToken()
609 |  |
         {
610 | 8 |
             _javadocToken.image = toString();
611 |  |
         }
612 |  |
613 |  |
         /**
614 |  |
          * Removes tag. Note that XTag objects are compared by identity.
615 |  |
          *
616 |  |
          * @param tag  tag to be removed
617 |  |
          * @return     true if it was removed
618 |  |
          */
619 | 0 |
         public boolean removeTag( XTag tag )
620 |  |
         {
621 | 0 |
             boolean removed = _tags.remove( tag );
622 |  |
623 | 0 |
             if( removed )
624 |  |
             {
625 |  |
                 // purge it from tag map too
626 | 0 |
                 ensureTagMapInitialised();
627 |  |
628 | 0 |
                 Collection tags = ( Collection ) _tagMap.get( dotted( tag.getName() ) );
629 |  |
630 | 0 |
                 tags.remove( tag );
631 | 0 |
                 fireDocChanged();
632 |  |
             }
633 | 0 |
             return removed;
634 |  |
         }
635 |  |
636 |  |
         /**
637 |  |
          * Add a tag to the doc item.
638 |  |
          *
639 |  |
          * @param tagName                  The name of the tag to add
640 |  |
          * @param text                     The value of the tag
641 |  |
          * @return                         The created XTag
642 |  |
          * @throws TagValidationException  if validation is activated (in XTagFactory)
643 |  |
          *      and tagName is not among the registered tags.
644 |  |
          */
645 | 0 |
         public XTag addTag( String tagName, String text )
646 |  |
         {
647 | 0 |
             if( _dirty )
648 |  |
             {
649 | 0 |
                 parse();
650 |  |
             }
651 |  |
652 | 0 |
             XTag rtag = addTag_Impl( tagName, text, -1 );
653 |  |
654 |  |
             // fire doc change event
655 | 0 |
             fireDocChanged();
656 | 0 |
             return rtag;
657 |  |
         }
658 |  |
659 |  |
         /**
660 |  |
          * receive change notification from xtag
661 |  |
          *
662 |  |
          * @param event
663 |  |
          */
664 | 0 |
         public void tagChanged( XTagEvent event )
665 |  |
         {
666 |  |
             // invalidate attribute value cache
667 |  |
             // for tag in question
668 | 0 |
             if( event.getSource() instanceof XTag )
669 |  |
             {
670 |  |
                 //XTag tag = ( XTag ) event.getSource();
671 |  |
672 |  |
                 /*
673 |  |
                  * if( tagAttrValueCurrent != null )
674 |  |
                  * {
675 |  |
                  * tagAttrValueCurrent.remove( tag.getName() );
676 |  |
                  * }
677 |  |
                  */
678 | 0 |
                 fireDocChanged();
679 |  |
             }
680 |  |
         }
681 |  |
682 |  |
         /**
683 |  |
          * Returns the doc in the superclass. If the super element is null, or not from
684 |  |
          * source, null is returned.
685 |  |
          *
686 |  |
          * @return   the superclass' doc
687 |  |
          */
688 | 528 |
         private XDoc getSuperDoc()
689 |  |
         {
690 | 528 |
             XProgramElement superElement = _owner.getSuperElement();
691 |  |
692 | 528 |
             if( superElement != null )
693 |  |
             {
694 | 20 |
                 return superElement.getDoc();
695 |  |
             }
696 |  |
             else
697 |  |
             {
698 | 508 |
                 return null;
699 |  |
             }
700 |  |
         }
701 |  |
702 |  |
         /**
703 |  |
          * Returns the doc in all the superclasses. If the super element is null, or not from
704 |  |
          * source, an empty list is returned.
705 |  |
          *
706 |  |
          * @return   A List of XDoc
707 |  |
          */
708 | 528 |
         private List getAllSuperDocs()
709 |  |
         {
710 | 528 |
             List superElements = _owner.getSuperInterfaceElements();
711 |  |
712 | 528 |
             if ( superElements!=null )
713 |  |
             {
714 | 528 |
                 List result = new ArrayList();
715 | 528 |
                 Iterator elements = superElements.iterator();
716 | 528 |
                 while ( elements.hasNext() )
717 |  |
                 {
718 | 160 |
                     XDoc doc = ( (XProgramElement) elements.next() ).getDoc();
719 | 160 |
                     result.add(doc);
720 |  |
                 }
721 | 528 |
                 return result;
722 |  |
             }
723 |  |
             else
724 |  |
             {
725 | 0 |
                 return Collections.EMPTY_LIST;
726 |  |
             }
727 |  |
         }
728 |  |
729 | 1406 |
         private final void ensureTagMapInitialised()
730 |  |
         {
731 | 1406 |
             if( _tagMap == null )
732 |  |
             {
733 | 694 |
                 _tagMap = new TreeMap();
734 |  |
             }
735 |  |
         }
736 |  |
737 |  |
         /**
738 |  |
          * Creates and adds a tag
739 |  |
          *
740 |  |
          * @param tagName                     The name of the tag (without the 'at')
741 |  |
          * @param text                        The raw content of the tag
742 |  |
          * @param lineNumber                  The feature to be added to the Tag_Impl
743 |  |
          *      attribute
744 |  |
          * @return                            An instance of XTag, created by the
745 |  |
          *      current XTagFactory
746 |  |
          * @exception TagValidationException
747 |  |
          */
748 | 710 |
         private XTag addTag_Impl( String tagName, String text, int lineNumber ) throws TagValidationException
749 |  |
         {
750 | 710 |
             tagName = dotted( tagName );
751 |  |
752 | 710 |
             ensureTagMapInitialised();
753 |  |
754 | 710 |
             Collection tags = ( Collection ) _tagMap.get( tagName );
755 |  |
756 | 710 |
             if( tags == null )
757 |  |
             {
758 | 612 |
                 tags = new LinkedList();
759 | 612 |
                 _tagMap.put( tagName, tags );
760 |  |
             }
761 |  |
762 | 710 |
             if( _tags == null )
763 |  |
             {
764 | 426 |
                 _tags = new LinkedList();
765 |  |
             }
766 |  |
767 | 710 |
             XTag tag = _tagFactory.createTag( tagName, text, this, lineNumber );
768 |  |
769 |  |
             // We want to be notified when this tag changes
770 | 710 |
             tag.addTagListener( this );
771 |  |
772 |  |
             // Add to the Collection in the map
773 | 710 |
             tags.add( tag );
774 |  |
775 |  |
             // Add to the global tag list
776 | 710 |
             _tags.add( tag );
777 |  |
778 | 710 |
             return tag;
779 |  |
         }
780 |  |
781 |  |
         /**
782 |  |
          * fire docChange event
783 |  |
          */
784 | 0 |
         private void fireDocChanged()
785 |  |
         {
786 | 0 |
             for( Iterator i = _docListeners.iterator(); i.hasNext();  )
787 |  |
             {
788 | 0 |
                 XDocListener docListener = ( XDocListener ) i.next();
789 |  |
790 | 0 |
                 docListener.docChanged( new XDocEvent( this ) );
791 |  |
             }
792 |  |
793 |  |
             // also set containing class to dirty
794 | 0 |
             if( _owner != null )
795 |  |
             {
796 | 0 |
                 XClass clazz = _owner instanceof XClass ? ( XClass ) _owner : _owner.getContainingClass();
797 |  |
798 | 0 |
                 clazz.setDirty();
799 |  |
             }
800 |  |
         }
801 |  |
802 |  |
         /**
803 |  |
          * Add some white space to the string being built up in toString().
804 |  |
          *
805 |  |
          * @param sb  StringBuffer that the text is being built in
806 |  |
          * @return    the StringBuffer
807 |  |
          */
808 | 56 |
         private StringBuffer appendWhiteSpaces( StringBuffer sb )
809 |  |
         {
810 | 56 |
             return sb.append( "   " );
811 |  |
             /*
812 |  |
              * Token tk = _programElementToken;
813 |  |
              * while (tk.previous != null && isTabOrSpace(tk.previous)) {
814 |  |
              * tk = tk.previous;
815 |  |
              * }
816 |  |
              * while (tk.next != null && tk != _programElementToken) {
817 |  |
              * sb.append(tk.image);
818 |  |
              * tk = tk.next;
819 |  |
              * }
820 |  |
              * return sb;
821 |  |
              */
822 |  |
         }
823 |  |
824 |  |
         /**
825 |  |
          * Parse token into comments, tags and tag attributes. We remove excess spaces.
826 |  |
          *
827 |  |
          * @exception TagValidationException
828 |  |
          */
829 | 698 |
         private void parse() throws TagValidationException
830 |  |
         {
831 | 698 |
             if( _dirty )
832 |  |
             {
833 |  |
                 //debug("parse");
834 |  |
                 // We must read line by line, since a @tags can only begin as the first token of a line.
835 | 698 |
                 JavaDocReader javaDocReader = new JavaDocReader( new StringReader( _javadocToken.image ) );
836 | 698 |
                 BufferedReader in = new BufferedReader( javaDocReader );
837 | 698 |
                 StringBuffer docElement = new StringBuffer();
838 | 698 |
                 String tagName = null;
839 | 698 |
                 String line = null;
840 |  |
841 | 698 |
                 int tagStartLine = -1;
842 |  |
843 | 698 |
                 try
844 |  |
                 {
845 | ? |
                     while( ( line = in.readLine() ) != null )
846 |  |
                     {
847 | 2402 |
                         if( line.startsWith( "@" ) )
848 |  |
                         {
849 |  |
                             // remember the line number where the tag starts.
850 | 706 |
                             tagStartLine = _javadocToken.beginLine + javaDocReader.getLineOffset();
851 |  |
852 |  |
                             // It's a new tag
853 | 706 |
                             if( tagName == null )
854 |  |
                             {
855 |  |
                                 // what we've been reading so far has been a general comment.
856 | 424 |
                                 _commentText = tokenizeAndTrim( docElement.toString() );
857 |  |
                             }
858 |  |
                             else
859 |  |
                             {
860 |  |
                                 // Add the previous tag
861 | 282 |
                                 addTag_Impl( tagName, tokenizeAndTrim( docElement.toString() ), tagStartLine );
862 |  |
                             }
863 | 706 |
                             docElement = new StringBuffer();
864 |  |
865 | 706 |
                             StringTokenizer st = new StringTokenizer( line );
866 |  |
867 | 706 |
                             tagName = st.nextToken().substring( 1 );
868 | 706 |
                             docElement.append( line.substring( tagName.length() + 1 ).trim() ).append( ' ' );
869 |  |
                         }
870 |  |
                         else
871 |  |
                         {
872 |  |
                             // It's the continuation of a tag or a comment, or start of comment;
873 | 1696 |
                             if( docElement == null )
874 |  |
                             {
875 |  |
                                 // It was the start of the comment
876 | 0 |
                                 docElement = new StringBuffer();
877 |  |
                             }
878 | 1696 |
                             docElement.append( line.trim() ).append( ' ' );
879 |  |
                         }
880 |  |
                     }
881 | 698 |
                     if( tagName == null )
882 |  |
                     {
883 |  |
                         // what we've been reading so far has been a general comment.
884 | 274 |
                         _commentText = docElement.toString().trim();
885 |  |
                     }
886 |  |
                     else
887 |  |
                     {
888 |  |
                         // Add the previous tag
889 | 424 |
                         addTag_Impl( tagName, tokenizeAndTrim( docElement.toString() ), tagStartLine );
890 |  |
                     }
891 |  |
                 }
892 |  |
                 catch( IOException e )
893 |  |
                 {
894 | 0 |
                     e.printStackTrace();
895 |  |
                 }
896 |  |
                 catch( StringIndexOutOfBoundsException e )
897 |  |
                 {
898 | 0 |
                     e.printStackTrace();
899 |  |
                 }
900 | 698 |
                 _dirty = false;
901 |  |
             }
902 |  |
         }
903 |  |
904 |  |
     }
905 |  |