1 19 20 package org.netbeans.modules.editor.java; 21 22 import java.awt.event.ActionEvent ; 23 import java.io.IOException ; 24 import java.lang.reflect.Modifier ; 25 import java.net.MalformedURLException ; 26 import java.net.URI ; 27 import java.net.URL ; 28 import java.util.Hashtable ; 29 import java.util.Iterator ; 30 import javax.lang.model.element.Element; 31 import javax.lang.model.element.ElementKind; 32 import javax.lang.model.element.ExecutableElement; 33 import javax.lang.model.element.TypeElement; 34 import javax.lang.model.element.VariableElement; 35 import javax.lang.model.type.ArrayType; 36 import javax.lang.model.type.DeclaredType; 37 import javax.lang.model.type.TypeMirror; 38 import javax.swing.AbstractAction ; 39 import javax.swing.Action ; 40 import com.sun.javadoc.*; 41 import com.sun.javadoc.AnnotationDesc.ElementValuePair; 42 import javax.lang.model.type.TypeKind; 43 import org.netbeans.api.java.source.CancellableTask; 44 import org.netbeans.api.java.source.ClasspathInfo; 45 import org.netbeans.api.java.source.CompilationController; 46 import org.netbeans.api.java.source.ElementHandle; 47 import org.netbeans.api.java.source.ElementUtilities; 48 import org.netbeans.api.java.source.JavaSource; 49 import org.netbeans.api.java.source.JavaSource.Phase; 50 import org.netbeans.api.java.source.SourceUtils; 51 import org.netbeans.api.java.source.UiUtils; 52 import org.netbeans.spi.editor.completion.CompletionDocumentation; 53 import org.openide.filesystems.FileObject; 54 import org.openide.util.Exceptions; 55 import org.openide.util.NbBundle; 56 57 61 public class JavaCompletionDoc implements CompletionDocumentation { 62 63 private ClasspathInfo cpInfo; 64 private Doc doc; 65 private String content = null; 66 private Hashtable <String , ElementHandle<? extends Element>> links = new Hashtable <String , ElementHandle<? extends Element>>(); 67 private int linkCounter = 0; 68 private URL docURL = null; 69 private AbstractAction goToSource = null; 70 71 private static final String PARAM_TAG = "@param"; private static final String RETURN_TAG = "@return"; private static final String THROWS_TAG = "@throws"; private static final String SEE_TAG = "@see"; private static final String SINCE_TAG = "@since"; private static final String INHERIT_DOC_TAG = "@inheritDoc"; private static final String LINKPLAIN_TAG = "@linkplain"; private static final String CODE_TAG = "@code"; private static final String DEPRECATED_TAG = "@deprecated"; 81 public static final JavaCompletionDoc create(CompilationController controller, Element element) { 82 return new JavaCompletionDoc(controller, element, null); 83 } 84 85 private JavaCompletionDoc(CompilationController controller, Element element, URL url) { 86 ElementUtilities eu = controller.getElementUtilities(); 87 this.cpInfo = controller.getClasspathInfo(); 88 this.doc = eu.javaDocFor(element); 89 if (element != null) { 90 final FileObject fo = SourceUtils.getFile(element, controller.getClasspathInfo()); 91 if (fo != null) { 92 final ElementHandle<? extends Element> handle = ElementHandle.create(element); 93 goToSource = new AbstractAction () { 94 public void actionPerformed(ActionEvent evt) { 95 UiUtils.open(fo, handle); 96 } 97 }; 98 } 99 if (url != null) { 100 docURL = url; 101 } else { 102 docURL = SourceUtils.getJavadoc(element, cpInfo); 103 if (docURL != null) { 104 CharSequence fragment = getFragment(element); 105 if (fragment.length() > 0) { 106 try { 107 docURL = new URL (docURL.toExternalForm() + "#" + fragment); } catch (MalformedURLException e) {} 109 } 110 } 111 } 112 } 113 this.content = prepareContent(eu); 114 } 115 116 public String getText() { 117 return content; 118 } 119 120 public URL getURL() { 121 return docURL; 122 } 123 124 public CompletionDocumentation resolveLink(final String link) { 125 final CompletionDocumentation[] ret = new CompletionDocumentation[1]; 126 try { 127 final ElementHandle<? extends Element> linkDoc = links.get(link); 128 FileObject fo = linkDoc != null ? SourceUtils.getFile(linkDoc, cpInfo) : null; 129 JavaSource js = fo != null ? JavaSource.forFileObject(fo) : JavaSource.create(cpInfo); 130 if (js != null) { 131 js.runUserActionTask(new CancellableTask<CompilationController>() { 132 public void run(CompilationController controller) throws IOException { 133 controller.toPhase(Phase.ELEMENTS_RESOLVED); 134 if (linkDoc != null) { 135 ret[0] = new JavaCompletionDoc(controller, linkDoc.resolve(controller), null); 136 } else { 137 int idx = link.indexOf('#'); URI uri = URI.create(idx < 0 ? link : link.substring(0, idx)); 139 if (uri != null) { 140 if (!uri.isAbsolute()) 141 uri = uri.normalize(); 142 String path = uri.toString(); 143 int startIdx = path.lastIndexOf(".."); startIdx = startIdx < 0 ? 0 : startIdx + 3; 145 int endIdx = path.lastIndexOf('.'); if (endIdx >= 0) 147 path = path.substring(startIdx, endIdx); 148 String clsName = path.replace('/', '.'); Element e = controller.getElements().getTypeElement(clsName); 150 if (e != null) { 151 if (idx >= 0) { 152 String fragment = link.substring(idx + 1); 153 idx = fragment.indexOf('('); String name = idx < 0 ? fragment : fragment.substring(0, idx); 155 for (Element member : e.getEnclosedElements()) { 156 if (member.getSimpleName().contentEquals(name) && fragment.contentEquals(getFragment(member))) { 157 e = member; 158 break; 159 } 160 } 161 } 162 ret[0] = new JavaCompletionDoc(controller, e, new URL (docURL, link)); 163 } 164 } 165 } 166 } 167 public void cancel() { 168 } 169 }, true); 170 } 171 } catch (IOException ioe) { 172 Exceptions.printStackTrace(ioe); 173 } 174 return ret[0]; 175 } 176 177 public Action getGotoSourceAction() { 178 return goToSource; 179 } 180 181 private String prepareContent(ElementUtilities eu) { 182 StringBuilder sb = new StringBuilder (); 183 if (doc != null) { 184 if (doc instanceof ProgramElementDoc) { 185 sb.append(getContainingClassOrPacakgeHeader(eu, (ProgramElementDoc)doc)); 186 } 187 if (doc.isMethod() || doc.isConstructor() || doc.isAnnotationTypeElement()) { 188 sb.append(getMethodHeader(eu, (ExecutableMemberDoc)doc)); 189 } else if (doc.isField() || doc.isEnumConstant()) { 190 sb.append(getFieldHeader(eu, (FieldDoc)doc)); 191 } else if (doc.isClass() || doc.isInterface() || doc.isAnnotationType()) { 192 sb.append(getClassHeader(eu, (ClassDoc)doc)); 193 } 194 sb.append("<p>"); if (doc.commentText().length() > 0 || doc.tags().length > 0) { 196 sb.append(getDeprecatedTag(eu, doc)); 197 sb.append(inlineTags(eu, doc, doc.inlineTags())); 198 sb.append("</p><p>"); sb.append(getTags(eu, doc)); 200 } else { 201 String jdText = docURL != null ? HTMLJavadocParser.getJavadocText(docURL, false) : null; 202 if (jdText != null) 203 sb.append(jdText); 204 else 205 sb.append(NbBundle.getMessage(JavaCompletionDoc.class, "javadoc_content_not_found")); } 207 sb.append("</p>"); } else { 209 sb.append(NbBundle.getMessage(JavaCompletionDoc.class, "javadoc_content_not_found")); } 211 return sb.toString(); 212 } 213 214 private CharSequence getContainingClassOrPacakgeHeader(ElementUtilities eu, ProgramElementDoc peDoc) { 215 StringBuilder sb = new StringBuilder (); 216 ClassDoc cls = peDoc.containingClass(); 217 if (cls != null) { 218 Element e = eu.elementFor(cls); 219 if (e != null) { 220 switch(e.getEnclosingElement().getKind()) { 221 case ANNOTATION_TYPE: 222 case CLASS: 223 case ENUM: 224 case INTERFACE: 225 case PACKAGE: 226 if (cls.containingClass() != null || cls.containingPackage() != null) { 227 sb.append("<font size='+0'><b>"); createLink(sb, e, cls.qualifiedName()); 229 sb.append("</b></font>"); } 231 } 232 } 233 } else { 234 PackageDoc pkg = peDoc.containingPackage(); 235 if (pkg != null) { 236 sb.append("<font size='+0'><b>"); createLink(sb, eu.elementFor(pkg), pkg.name()); 238 sb.append("</b></font>"); } 240 } 241 return sb; 242 } 243 244 private CharSequence getMethodHeader(ElementUtilities eu, ExecutableMemberDoc mdoc) { 245 StringBuilder sb = new StringBuilder (); 246 sb.append("<pre>"); sb.append(getAnnotations(eu, mdoc)); 248 int len = sb.length(); 249 sb.append(Modifier.toString(mdoc.modifierSpecifier() &~ Modifier.NATIVE)); 250 len = sb.length() - len; 251 TypeVariable[] tvars = mdoc.typeParameters(); 252 if (tvars.length > 0) { 253 if (len > 0) { 254 sb.append(' '); len++; 256 } 257 sb.append("<"); for (int i = 0; i < tvars.length; i++) { 259 len += appendType(eu, sb, tvars[i], false, true); 260 if (i < tvars.length - 1) { 261 sb.append(","); len++; 263 } 264 } 265 sb.append(">"); len += 2; 267 } 268 if (!mdoc.isConstructor()) { 269 if (len > 0) { 270 sb.append(' '); len++; 272 } 273 len += appendType(eu, sb, ((MethodDoc)mdoc).returnType(), false, false); 274 } 275 String name = mdoc.name(); 276 len += name.length(); 277 sb.append(" <b>").append(name).append("</b>"); if (!mdoc.isAnnotationTypeElement()) { 279 sb.append('('); len++; 281 Parameter[] params = mdoc.parameters(); 282 for(int i = 0; i < params.length; i++) { 283 boolean varArg = i == params.length - 1 && mdoc.isVarArgs(); 284 appendType(eu, sb, params[i].type(), varArg, false); 285 sb.append(' ').append(params[i].name()); String dim = params[i].type().dimension(); 287 if (dim.length() > 0) { 288 if (varArg) 289 dim = dim.substring(2) + "..."; } 291 if (i < params.length - 1) { 292 sb.append(",\n"); appendSpace(sb, len); 294 } 295 } 296 sb.append(')'); } 298 Type[] exs = mdoc.thrownExceptionTypes(); 299 if (exs.length > 0) { 300 sb.append("\nthrows "); for (int i = 0; i < exs.length; i++) { 302 appendType(eu, sb, exs[i], false, false); 303 if (i < exs.length - 1) 304 sb.append(", "); } 306 } 307 sb.append("</pre>"); return sb; 309 } 310 311 private CharSequence getFieldHeader(ElementUtilities eu, FieldDoc fdoc) { 312 StringBuilder sb = new StringBuilder (); 313 sb.append("<pre>"); sb.append(getAnnotations(eu, fdoc)); 315 int len = sb.length(); 316 sb.append(fdoc.modifiers()); 317 len = sb.length() - len; 318 if (len > 0) 319 sb.append(' '); appendType(eu, sb, fdoc.type(), false, false); 321 sb.append(" <b>").append(fdoc.name()).append("</b>"); sb.append("</pre>"); return sb; 324 } 325 326 private CharSequence getClassHeader(ElementUtilities eu, ClassDoc cdoc) { 327 StringBuilder sb = new StringBuilder (); 328 sb.append("<pre>"); sb.append(getAnnotations(eu, cdoc)); 330 int mods = cdoc.modifierSpecifier() & ~Modifier.INTERFACE; 331 if (cdoc.isEnum()) 332 mods &= ~Modifier.FINAL; 333 sb.append(Modifier.toString(mods)); 334 if (sb.length() > 0) 335 sb.append(' '); if (cdoc.isAnnotationType()) 337 sb.append("@interface "); else if (cdoc.isEnum()) 339 sb.append("enum "); else if (cdoc.isInterface()) 341 sb.append("interface "); else 343 sb.append("class "); sb.append("<b>").append(cdoc.name()); TypeVariable[] tvars = cdoc.typeParameters(); 346 if (tvars.length > 0) { 347 sb.append("<"); for (int i = 0; i < tvars.length; i++) { 349 appendType(eu, sb, tvars[i], false, true); 350 if (i < tvars.length - 1) 351 sb.append(","); } 353 sb.append(">"); } 355 sb.append("</b>"); if (!cdoc.isAnnotationType()) { 357 if (cdoc.isClass()) { 358 Type supercls = cdoc.superclassType(); 359 if (supercls != null) { 360 sb.append("\nextends "); appendType(eu, sb, supercls, false, false); 362 } 363 364 } 365 Type[] ifaces = cdoc.interfaceTypes(); 366 if (ifaces.length > 0) { 367 sb.append(cdoc.isInterface() ? "\nextends " : "\nimplements "); for (int i = 0; i < ifaces.length; i++) { 369 appendType(eu, sb, ifaces[i], false, false); 370 if (i < ifaces.length - 1) 371 sb.append(", "); } 373 } 374 } 375 sb.append("</pre>"); return sb; 377 } 378 379 private CharSequence getAnnotations(ElementUtilities eu, ProgramElementDoc peDoc) { 380 StringBuilder sb = new StringBuilder (); 381 for (AnnotationDesc annotationDesc : peDoc.annotations()) { 382 AnnotationTypeDoc annotationType = annotationDesc.annotationType(); 383 if (annotationType != null) { 384 appendType(eu, sb, annotationType, false, false); 385 ElementValuePair[] pairs = annotationDesc.elementValues(); 386 if (pairs.length > 0) { 387 sb.append('('); for (int i = 0; i < pairs.length; i++) { 389 AnnotationTypeElementDoc ated = pairs[i].element(); 390 createLink(sb, eu.elementFor(ated), ated.name()); 391 sb.append('='); appendAnnotationValue(eu, sb, pairs[i].value()); 393 if (i < pairs.length - 1) 394 sb.append(","); } 396 sb.append(')'); } 398 sb.append('\n'); } 400 } 401 return sb; 402 } 403 404 private void appendAnnotationValue(ElementUtilities eu, StringBuilder sb, AnnotationValue av) { 405 Object value = av.value(); 406 if (value instanceof AnnotationValue[]) { 407 int length = ((AnnotationValue[])value).length; 408 if (length > 1) 409 sb.append('{'); for(int i = 0; i < ((AnnotationValue[])value).length; i++) { 411 appendAnnotationValue(eu, sb, ((AnnotationValue[])value)[i]); 412 if (i < ((AnnotationValue[])value).length - 1) 413 sb.append(","); } 415 if (length > 1) 416 sb.append('}'); } else if (value instanceof Doc) { 418 createLink(sb, eu.elementFor((Doc)value), ((Doc)value).name()); 419 } else { 420 sb.append(value.toString()); 421 } 422 } 423 424 private CharSequence getTags(ElementUtilities eu, Doc doc) { 425 StringBuilder see = new StringBuilder (); 426 StringBuilder par = new StringBuilder (); 427 StringBuilder thr = new StringBuilder (); 428 StringBuilder ret = new StringBuilder (); 429 String since = null; 430 for (Tag tag : doc.tags()) { 431 if (PARAM_TAG.equals(tag.kind())) { 432 par.append("<code>").append(((ParamTag)tag).parameterName()).append("</code>"); Tag[] its = tag.inlineTags(); 434 if (its.length > 0) { 435 par.append(" - "); par.append(inlineTags(eu, doc, its)); 437 } 438 par.append("<br>"); } else if (THROWS_TAG.equals(tag.kind())) { 440 thr.append("<code>"); Type exType = ((ThrowsTag)tag).exceptionType(); 442 if (exType != null) 443 createLink(thr, eu.elementFor(exType.asClassDoc()), exType.simpleTypeName()); 444 else 445 thr.append(((ThrowsTag)tag).exceptionName()); 446 thr.append("</code>"); Tag[] its = tag.inlineTags(); 448 if (its.length > 0) { 449 thr.append(" - "); thr.append(inlineTags(eu, doc, its)); 451 } 452 thr.append("<br>"); } else if (RETURN_TAG.equals(tag.kind())) { 454 ret.append(inlineTags(eu, doc, tag.inlineTags())); 455 ret.append("<br>"); } else if (SEE_TAG.equals(tag.kind())) { 457 SeeTag stag = (SeeTag)tag; 458 ClassDoc refClass = stag.referencedClass(); 459 String className = stag.referencedClassName(); 460 String memberName = stag.referencedMemberName(); 461 String label = stag.label(); 462 if (memberName != null) { 463 if (refClass != null) { 464 createLink(see, eu.elementFor(stag.referencedMember()), "<code>" + (label != null && label.length() > 0 ? label : (refClass.simpleTypeName() + "." + memberName)) + "</code>"); } else { 466 see.append(className); 467 see.append('.'); see.append(memberName); 469 } 470 see.append(", "); } else if (className != null) { 472 if (refClass != null) { 473 createLink(see, eu.elementFor(refClass), "<code>" + (label != null && label.length() > 0 ? label : refClass.simpleTypeName()) + "</code>"); } else { 475 see.append(className); 476 } 477 see.append(", "); } else { 479 see.append(stag.text()).append(", "); } 481 } else if (SINCE_TAG.equals(tag.kind())) { 482 since = tag.text(); 483 } 484 } 485 StringBuilder sb = new StringBuilder (); 486 if (par.length() > 0) { 487 sb.append("<b>").append(NbBundle.getMessage(JavaCompletionDoc.class, "JCD-params")).append("</b><blockquote>").append(par).append("</blockquote>"); } 489 if (ret.length() > 0) { 490 sb.append("<b>").append(NbBundle.getMessage(JavaCompletionDoc.class, "JCD-returns")).append("</b><blockquote>").append(ret).append("</blockquote>"); } 492 if (thr.length() > 0) { 493 sb.append("<b>").append(NbBundle.getMessage(JavaCompletionDoc.class, "JCD-throws")).append("</b><blockquote>").append(thr).append("</blockquote>"); } 495 if (since != null) { 496 sb.append("<b>").append(NbBundle.getMessage(JavaCompletionDoc.class, "JCD-since")).append("</b><blockquote>").append(since).append("</blockquote>"); } 498 int length = see.length(); 499 if (length > 0) { 500 sb.append("<b>").append(NbBundle.getMessage(JavaCompletionDoc.class, "JCD-see")).append("</b><blockquote>").append(see.delete(length - 2, length)).append("</blockquote>"); } 502 return sb; 503 } 504 505 private CharSequence getDeprecatedTag(ElementUtilities eu, Doc doc) { 506 StringBuilder sb = new StringBuilder (); 507 for (Tag tag : doc.tags()) { 508 if (DEPRECATED_TAG.equals(tag.kind())) 509 sb.append("<b>").append(NbBundle.getMessage(JavaCompletionDoc.class, "JCD-deprecated")).append("</b> <i>").append(tag.text()).append("</i></p><p>"); } 511 return sb; 512 } 513 514 private CharSequence inlineTags(ElementUtilities eu, Doc doc, Tag[] tags) { 515 StringBuilder sb = new StringBuilder (); 516 for (Tag tag : tags) { 517 if (SEE_TAG.equals(tag.kind())) { 518 SeeTag stag = (SeeTag)tag; 519 ClassDoc refClass = stag.referencedClass(); 520 String memberName = stag.referencedMemberName(); 521 String label = stag.label(); 522 boolean plain = LINKPLAIN_TAG.equals(stag.name()); 523 if (memberName != null) { 524 if (refClass != null) { 525 createLink(sb, eu.elementFor(stag.referencedMember()), (plain ? "" : "<code>") + (label != null && label.length() > 0 ? label : (refClass.simpleTypeName() + "." + memberName)) + (plain ? "" : "</code>")); } else { 527 sb.append(stag.referencedClassName()); 528 sb.append('.'); sb.append(memberName); 530 } 531 } else { 532 if (refClass != null) { 533 createLink(sb, eu.elementFor(refClass), (plain ? "" : "<code>") + (label != null && label.length() > 0 ? label : refClass.simpleTypeName()) + (plain ? "" : "</code>")); } else { 535 sb.append(stag.referencedClassName()); 536 } 537 } 538 } else if (INHERIT_DOC_TAG.equals(tag.kind())) { 539 if (doc.isMethod()) { 540 MethodDoc mdoc = ((MethodDoc)doc).overriddenMethod(); 541 if (mdoc != null) 542 sb.append(inlineTags(eu, mdoc, mdoc.inlineTags())); 543 } else if (doc.isClass() || doc.isInterface()) { 544 ClassDoc cdoc = ((ClassDoc)doc).superclass(); 545 if (cdoc != null) 546 sb.append(inlineTags(eu, cdoc, cdoc.inlineTags())); 547 } 548 } else if (CODE_TAG.equals(tag.kind())) { 549 sb.append("<code>"); sb.append(tag.text()); 551 sb.append("</code>"); } else { 553 sb.append(tag.text()); 554 } 555 } 556 return sb; 557 } 558 559 private CharSequence getFragment(Element e) { 560 StringBuilder sb = new StringBuilder (); 561 if (!e.getKind().isClass() && !e.getKind().isInterface()) { 562 if (e.getKind() == ElementKind.CONSTRUCTOR) { 563 sb.append(e.getEnclosingElement().getSimpleName()); 564 } else { 565 sb.append(e.getSimpleName()); 566 } 567 if (e.getKind() == ElementKind.METHOD || e.getKind() == ElementKind.CONSTRUCTOR) { 568 ExecutableElement ee = (ExecutableElement)e; 569 sb.append('('); for (Iterator <? extends VariableElement> it = ee.getParameters().iterator(); it.hasNext();) { 571 VariableElement param = it.next(); 572 appendType(sb, param.asType(), ee.isVarArgs() && !it.hasNext()); 573 if (it.hasNext()) 574 sb.append(", "); 575 } 576 sb.append(')'); } 578 } 579 return sb; 580 } 581 582 private void appendType(StringBuilder sb, TypeMirror type, boolean varArg) { 583 switch (type.getKind()) { 584 case ARRAY: 585 appendType(sb, ((ArrayType)type).getComponentType(), false); 586 sb.append(varArg ? "..." : "[]"); break; 588 case DECLARED: 589 sb.append(((TypeElement)((DeclaredType)type).asElement()).getQualifiedName()); 590 break; 591 default: 592 sb.append(type); 593 } 594 } 595 596 private void appendSpace(StringBuilder sb, int length) { 597 while (length-- >= 0) 598 sb.append(' '); } 600 601 private int appendType(ElementUtilities eu, StringBuilder sb, Type type, boolean varArg, boolean typeVar) { 602 int len = 0; 603 WildcardType wt = type.asWildcardType(); 604 if (wt != null) { 605 sb.append('?'); len++; 607 Type[] bounds = wt.extendsBounds(); 608 if (bounds != null && bounds.length > 0) { 609 sb.append(" extends "); len += 9; 611 len += appendType(eu, sb, bounds[0], false, false); 612 } 613 bounds = wt.superBounds(); 614 if (bounds != null && bounds.length > 0) { 615 sb.append(" super "); len += 7; 617 len += appendType(eu, sb, bounds[0], false, false); 618 } 619 } else { 620 TypeVariable tv = type.asTypeVariable(); 621 if (tv != null) { 622 len += createLink(sb, null, tv.simpleTypeName()); 623 Type[] bounds = tv.bounds(); 624 if (typeVar && bounds != null && bounds.length > 0) { 625 sb.append(" extends "); len += 9; 627 for (int i = 0; i < bounds.length; i++) { 628 len += appendType(eu, sb, bounds[i], false, false); 629 if (i < bounds.length - 1) { 630 sb.append(" & "); len += 3; 632 } 633 } 634 } 635 } else { 636 String tName = type.simpleTypeName(); 637 ClassDoc cd = type.asClassDoc(); 638 if (cd != null && cd.isAnnotationType()) 639 tName = "@" + tName; len += createLink(sb, eu.elementFor(type.asClassDoc()), tName); 641 ParameterizedType pt = type.asParameterizedType(); 642 if (pt != null) { 643 Type[] targs = pt.typeArguments(); 644 if (targs.length > 0) { 645 sb.append("<"); for (int j = 0; j < targs.length; j++) { 647 len += appendType(eu, sb, targs[j], false, false); 648 if (j < targs.length - 1) { 649 sb.append(","); len++; 651 } 652 } 653 sb.append(">"); len += 2; 655 } 656 } 657 } 658 } 659 String dim = type.dimension(); 660 if (dim.length() > 0) { 661 if (varArg) 662 dim = dim.substring(2) + "..."; sb.append(dim); 664 len += dim.length(); 665 } 666 return len; 667 } 668 669 private int createLink(StringBuilder sb, Element e, String text) { 670 if (e != null && e.asType().getKind() != TypeKind.ERROR) { 671 String link = "*" + linkCounter++; links.put(link, ElementHandle.create(e)); 673 sb.append("<a HREF='").append(link).append("'>"); } 675 sb.append(text); 676 if (e != null) 677 sb.append("</a>"); return text.length(); 679 } 680 } 681 | Popular Tags |