1 /*
   2  * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package jdk.javadoc.internal.doclets.formats.html;
  27 
  28 import java.util.*;
  29 import java.util.stream.Collectors;
  30 
  31 import javax.lang.model.element.Element;
  32 import javax.lang.model.element.ExecutableElement;
  33 import javax.lang.model.element.Modifier;
  34 import javax.lang.model.element.TypeElement;
  35 import javax.lang.model.element.TypeParameterElement;
  36 import javax.lang.model.element.VariableElement;
  37 import javax.lang.model.type.TypeMirror;
  38 import javax.lang.model.util.SimpleElementVisitor9;
  39 
  40 import com.sun.source.doctree.DocTree;
  41 import com.sun.tools.javac.util.DefinedBy;
  42 import com.sun.tools.javac.util.DefinedBy.Api;
  43 
  44 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlAttr;
  45 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants;
  46 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
  47 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
  48 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
  49 import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
  50 import jdk.javadoc.internal.doclets.toolkit.Content;
  51 import jdk.javadoc.internal.doclets.toolkit.taglets.DeprecatedTaglet;
  52 import jdk.javadoc.internal.doclets.toolkit.util.MethodTypes;
  53 import jdk.javadoc.internal.doclets.toolkit.util.Utils;
  54 import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap;
  55 
  56 import static javax.lang.model.element.Modifier.*;
  57 
  58 /**
  59  * The base class for member writers.
  60  *
  61  *  <p><b>This is NOT part of any supported API.
  62  *  If you write code that depends on this, you do so at your own risk.
  63  *  This code and its internal interfaces are subject to change or
  64  *  deletion without notice.</b>
  65  *
  66  * @author Robert Field
  67  * @author Atul M Dambalkar
  68  * @author Jamie Ho (Re-write)
  69  * @author Bhavesh Patel (Modified)
  70  */
  71 public abstract class AbstractMemberWriter {
  72 
  73     protected final ConfigurationImpl configuration;
  74     protected final Utils utils;
  75     protected final SubWriterHolderWriter writer;
  76     protected final TypeElement typeElement;
  77     protected Map<String, Integer> typeMap = new LinkedHashMap<>();
  78     protected Set<MethodTypes> methodTypes = EnumSet.noneOf(MethodTypes.class);
  79     private int methodTypesOr = 0;
  80     public final boolean nodepr;
  81 
  82     protected boolean printedSummaryHeader = false;
  83 
  84     public AbstractMemberWriter(SubWriterHolderWriter writer, TypeElement typeElement) {
  85         this.configuration = writer.configuration;
  86         this.writer = writer;
  87         this.nodepr = configuration.nodeprecated;
  88         this.typeElement = typeElement;
  89         this.utils = writer.configuration.utils;
  90     }
  91 
  92     public AbstractMemberWriter(SubWriterHolderWriter writer) {
  93         this(writer, null);
  94     }
  95 
  96     /*** abstracts ***/
  97 
  98     /**
  99      * Add the summary label for the member.
 100      *
 101      * @param memberTree the content tree to which the label will be added
 102      */
 103     public abstract void addSummaryLabel(Content memberTree);
 104 
 105     /**
 106      * Get the summary for the member summary table.
 107      *
 108      * @return a string for the table summary
 109      */
 110     public abstract String getTableSummary();
 111 
 112     /**
 113      * Get the caption for the member summary table.
 114      *
 115      * @return a string for the table caption
 116      */
 117     public abstract Content getCaption();
 118 
 119     /**
 120      * Get the summary table header for the member.
 121      *
 122      * @param member the member to be documented
 123      * @return the summary table header
 124      */
 125     public abstract List<String> getSummaryTableHeader(Element member);
 126 
 127     /**
 128      * Add inherited summary label for the member.
 129      *
 130      * @param typeElement the TypeElement to which to link to
 131      * @param inheritedTree the content tree to which the inherited summary label will be added
 132      */
 133     public abstract void addInheritedSummaryLabel(TypeElement typeElement, Content inheritedTree);
 134 
 135     /**
 136      * Add the anchor for the summary section of the member.
 137      *
 138      * @param typeElement the TypeElement to be documented
 139      * @param memberTree the content tree to which the summary anchor will be added
 140      */
 141     public abstract void addSummaryAnchor(TypeElement typeElement, Content memberTree);
 142 
 143     /**
 144      * Add the anchor for the inherited summary section of the member.
 145      *
 146      * @param typeElement the TypeElement to be documented
 147      * @param inheritedTree the content tree to which the inherited summary anchor will be added
 148      */
 149     public abstract void addInheritedSummaryAnchor(TypeElement typeElement, Content inheritedTree);
 150 
 151     /**
 152      * Add the summary type for the member.
 153      *
 154      * @param member the member to be documented
 155      * @param tdSummaryType the content tree to which the type will be added
 156      */
 157     protected abstract void addSummaryType(Element member, Content tdSummaryType);
 158 
 159     /**
 160      * Add the summary link for the member.
 161      *
 162      * @param typeElement the TypeElement to be documented
 163      * @param member the member to be documented
 164      * @param tdSummary the content tree to which the link will be added
 165      */
 166     protected void addSummaryLink(TypeElement typeElement, Element member, Content tdSummary) {
 167         addSummaryLink(LinkInfoImpl.Kind.MEMBER, typeElement, member, tdSummary);
 168     }
 169 
 170     /**
 171      * Add the summary link for the member.
 172      *
 173      * @param context the id of the context where the link will be printed
 174      * @param typeElement the TypeElement to be documented
 175      * @param member the member to be documented
 176      * @param tdSummary the content tree to which the summary link will be added
 177      */
 178     protected abstract void addSummaryLink(LinkInfoImpl.Kind context,
 179             TypeElement typeElement, Element member, Content tdSummary);
 180 
 181     /**
 182      * Add the inherited summary link for the member.
 183      *
 184      * @param typeElement the TypeElement to be documented
 185      * @param member the member to be documented
 186      * @param linksTree the content tree to which the inherited summary link will be added
 187      */
 188     protected abstract void addInheritedSummaryLink(TypeElement typeElement,
 189             Element member, Content linksTree);
 190 
 191     /**
 192      * Get the deprecated link.
 193      *
 194      * @param member the member being linked to
 195      * @return a content tree representing the link
 196      */
 197     protected abstract Content getDeprecatedLink(Element member);
 198 
 199     /**
 200      * Get the navigation summary link.
 201      *
 202      * @param typeElement the TypeElement to be documented
 203      * @param link true if its a link else the label to be printed
 204      * @return a content tree for the navigation summary link.
 205      */
 206     protected abstract Content getNavSummaryLink(TypeElement typeElement, boolean link);
 207 
 208     /**
 209      * Add the navigation detail link.
 210      *
 211      * @param link true if its a link else the label to be printed
 212      * @param liNav the content tree to which the navigation detail link will be added
 213      */
 214     protected abstract void addNavDetailLink(boolean link, Content liNav);
 215 
 216     /**
 217      * Add the member name to the content tree.
 218      *
 219      * @param name the member name to be added to the content tree.
 220      * @param htmltree the content tree to which the name will be added.
 221      */
 222     protected void addName(String name, Content htmltree) {
 223         htmltree.addContent(name);
 224     }
 225 
 226     protected String typeString(Element member) {
 227         return new SimpleElementVisitor9<String, Void>() {
 228 
 229             @Override @DefinedBy(Api.LANGUAGE_MODEL)
 230             public String visitExecutable(ExecutableElement e, Void p) {
 231                return utils.isMethod(e) ? e.getReturnType().toString() : "";
 232             }
 233 
 234             @Override @DefinedBy(Api.LANGUAGE_MODEL)
 235             public String visitVariable(VariableElement e, Void p) {
 236                 return e.toString();
 237             }
 238 
 239             @Override @DefinedBy(Api.LANGUAGE_MODEL)
 240             protected String defaultAction(Element e, Void p) {
 241                 return "";
 242             }
 243         }.visit(member);
 244     }
 245 
 246     /**
 247      * Add the modifier for the member. The modifiers are ordered as specified
 248      * by <em>The Java Language Specification</em>.
 249      *
 250      * @param member the member for which teh modifier will be added.
 251      * @param htmltree the content tree to which the modifier information will be added.
 252      */
 253     protected void addModifiers(Element member, Content htmltree) {
 254         Set<Modifier> set = new TreeSet<>(member.getModifiers());
 255 
 256         // remove the ones we really don't need
 257         set.remove(NATIVE);
 258         set.remove(SYNCHRONIZED);
 259         set.remove(STRICTFP);
 260 
 261         // According to JLS, we should not be showing public modifier for
 262         // interface methods.
 263         if ((utils.isField(member) || utils.isMethod(member))
 264             && ((writer instanceof ClassWriterImpl
 265                  && utils.isInterface(((ClassWriterImpl) writer).getTypeElement())  ||
 266                  writer instanceof AnnotationTypeWriterImpl) )) {
 267             // Remove the implicit abstract and public modifiers
 268             if (utils.isMethod(member) &&
 269                 (utils.isInterface(member.getEnclosingElement()) ||
 270                  utils.isAnnotationType(member.getEnclosingElement()))) {
 271                 set.remove(ABSTRACT);
 272                 set.remove(PUBLIC);
 273             }
 274             if (!utils.isMethod(member)) {
 275                 set.remove(PUBLIC);
 276             }
 277         }
 278         if (!set.isEmpty()) {
 279             String mods = set.stream().map(m -> m.toString()).collect(Collectors.joining(" "));
 280             htmltree.addContent(mods);
 281             htmltree.addContent(writer.getSpace());
 282         }
 283     }
 284 
 285     protected String makeSpace(int len) {
 286         if (len <= 0) {
 287             return "";
 288         }
 289         StringBuilder sb = new StringBuilder(len);
 290         for (int i = 0; i < len; i++) {
 291             sb.append(' ');
 292         }
 293         return sb.toString();
 294     }
 295 
 296     /**
 297      * Add the modifier and type for the member in the member summary.
 298      *
 299      * @param member the member to add the type for
 300      * @param type the type to add
 301      * @param tdSummaryType the content tree to which the modified and type will be added
 302      */
 303     protected void addModifierAndType(Element member, TypeMirror type,
 304             Content tdSummaryType) {
 305         HtmlTree code = new HtmlTree(HtmlTag.CODE);
 306         addModifier(member, code);
 307         if (type == null) {
 308             code.addContent(utils.isClass(member) ? "class" : "interface");
 309             code.addContent(writer.getSpace());
 310         } else {
 311             List<? extends TypeParameterElement> list = utils.isExecutableElement(member)
 312                     ? ((ExecutableElement)member).getTypeParameters()
 313                     : null;
 314             if (list != null && !list.isEmpty()) {
 315                 Content typeParameters = ((AbstractExecutableMemberWriter) this)
 316                         .getTypeParameters((ExecutableElement)member);
 317                     code.addContent(typeParameters);
 318                 //Code to avoid ugly wrapping in member summary table.
 319                 if (typeParameters.charCount() > 10) {
 320                     code.addContent(new HtmlTree(HtmlTag.BR));
 321                 } else {
 322                     code.addContent(writer.getSpace());
 323                 }
 324                 code.addContent(
 325                         writer.getLink(new LinkInfoImpl(configuration,
 326                         LinkInfoImpl.Kind.SUMMARY_RETURN_TYPE, type)));
 327             } else {
 328                 code.addContent(
 329                         writer.getLink(new LinkInfoImpl(configuration,
 330                         LinkInfoImpl.Kind.SUMMARY_RETURN_TYPE, type)));
 331             }
 332 
 333         }
 334         tdSummaryType.addContent(code);
 335     }
 336 
 337     /**
 338      * Add the modifier for the member.
 339      *
 340      * @param member the member to add the type for
 341      * @param code the content tree to which the modified will be added
 342      */
 343     private void addModifier(Element member, Content code) {
 344         if (utils.isProtected(member)) {
 345             code.addContent("protected ");
 346         } else if (utils.isPrivate(member)) {
 347             code.addContent("private ");
 348         } else if (!utils.isPublic(member)) { // Package private
 349             code.addContent(configuration.getText("doclet.Package_private"));
 350             code.addContent(" ");
 351         }
 352         boolean isAnnotatedTypeElement = utils.isAnnotationType(member.getEnclosingElement());
 353         if (!isAnnotatedTypeElement && utils.isMethod(member)) {
 354             if (!utils.isInterface(member.getEnclosingElement()) && utils.isAbstract(member)) {
 355                 code.addContent("abstract ");
 356             }
 357             if (utils.isDefault(member)) {
 358                 code.addContent("default ");
 359             }
 360         }
 361         if (utils.isStatic(member)) {
 362             code.addContent("static ");
 363         }
 364     }
 365 
 366     /**
 367      * Add the deprecated information for the given member.
 368      *
 369      * @param member the member being documented.
 370      * @param contentTree the content tree to which the deprecated information will be added.
 371      */
 372     protected void addDeprecatedInfo(Element member, Content contentTree) {
 373         Content output = (new DeprecatedTaglet()).getTagletOutput(member,
 374             writer.getTagletWriterInstance(false));
 375         if (!output.isEmpty()) {
 376             Content deprecatedContent = output;
 377             Content div = HtmlTree.DIV(HtmlStyle.block, deprecatedContent);
 378             contentTree.addContent(div);
 379         }
 380     }
 381 
 382     /**
 383      * Add the comment for the given member.
 384      *
 385      * @param member the member being documented.
 386      * @param htmltree the content tree to which the comment will be added.
 387      */
 388     protected void addComment(Element member, Content htmltree) {
 389         if (!utils.getBody(member).isEmpty()) {
 390             writer.addInlineComment(member, htmltree);
 391         }
 392     }
 393 
 394     protected String name(Element member) {
 395         return utils.getSimpleName(member);
 396     }
 397 
 398     /**
 399      * Get the header for the section.
 400      *
 401      * @param member the member being documented.
 402      * @return a header content for the section.
 403      */
 404     protected Content getHead(Element member) {
 405         Content memberContent = new StringContent(name(member));
 406         Content heading = HtmlTree.HEADING(HtmlConstants.MEMBER_HEADING, memberContent);
 407         return heading;
 408     }
 409 
 410     /**
 411     * Return true if the given <code>ProgramElement</code> is inherited
 412     * by the class that is being documented.
 413     *
 414     * @param ped The <code>ProgramElement</code> being checked.
 415     * return true if the <code>ProgramElement</code> is being inherited and
 416     * false otherwise.
 417     */
 418     protected boolean isInherited(Element ped){
 419         return (!utils.isPrivate(ped) &&
 420                 (!utils.isPackagePrivate(ped) ||
 421                     ped.getEnclosingElement().equals(ped.getEnclosingElement())));
 422     }
 423 
 424     /**
 425      * Add deprecated information to the documentation tree
 426      *
 427      * @param deprmembers list of deprecated members
 428      * @param headingKey the caption for the deprecated members table
 429      * @param tableSummary the summary for the deprecated members table
 430      * @param tableHeader table headers for the deprecated members table
 431      * @param contentTree the content tree to which the deprecated members table will be added
 432      */
 433     protected void addDeprecatedAPI(Collection<Element> deprmembers, String headingKey,
 434             String tableSummary, List<String> tableHeader, Content contentTree) {
 435         if (deprmembers.size() > 0) {
 436             Content caption = writer.getTableCaption(configuration.getResource(headingKey));
 437             Content table = (configuration.isOutputHtml5())
 438                     ? HtmlTree.TABLE(HtmlStyle.deprecatedSummary, caption)
 439                     : HtmlTree.TABLE(HtmlStyle.deprecatedSummary, tableSummary, caption);
 440             table.addContent(writer.getSummaryTableHeader(tableHeader, "col"));
 441             Content tbody = new HtmlTree(HtmlTag.TBODY);
 442             boolean altColor = true;
 443             for (Element member : deprmembers) {
 444                 HtmlTree td = HtmlTree.TD(HtmlStyle.colOne, getDeprecatedLink(member));
 445                 List<? extends DocTree> deprTrees = utils.getBlockTags(member, DocTree.Kind.DEPRECATED);
 446                 if (!deprTrees.isEmpty()) {
 447                     writer.addInlineDeprecatedComment(member, deprTrees.get(0), td);
 448                 }
 449                 HtmlTree tr = HtmlTree.TR(td);
 450                 tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor);
 451                 altColor = !altColor;
 452                 tbody.addContent(tr);
 453             }
 454             table.addContent(tbody);
 455             Content li = HtmlTree.LI(HtmlStyle.blockList, table);
 456             Content ul = HtmlTree.UL(HtmlStyle.blockList, li);
 457             contentTree.addContent(ul);
 458         }
 459     }
 460 
 461     /**
 462      * Add use information to the documentation tree.
 463      *
 464      * @param mems list of program elements for which the use information will be added
 465      * @param heading the section heading
 466      * @param tableSummary the summary for the use table
 467      * @param contentTree the content tree to which the use information will be added
 468      */
 469     protected void addUseInfo(List<? extends Element> mems,
 470             Content heading, String tableSummary, Content contentTree) {
 471         if (mems == null || mems.isEmpty()) {
 472             return;
 473         }
 474         List<? extends Element> members = mems;
 475         boolean printedUseTableHeader = false;
 476         if (members.size() > 0) {
 477             Content caption = writer.getTableCaption(heading);
 478             Content table = (configuration.isOutputHtml5())
 479                     ? HtmlTree.TABLE(HtmlStyle.useSummary, caption)
 480                     : HtmlTree.TABLE(HtmlStyle.useSummary, tableSummary, caption);
 481             Content tbody = new HtmlTree(HtmlTag.TBODY);
 482             boolean altColor = true;
 483             for (Element element : members) {
 484                 TypeElement te = utils.getEnclosingTypeElement(element);
 485                 if (!printedUseTableHeader) {
 486                     table.addContent(writer.getSummaryTableHeader(
 487                             this.getSummaryTableHeader(element), "col"));
 488                     printedUseTableHeader = true;
 489                 }
 490                 HtmlTree tr = new HtmlTree(HtmlTag.TR);
 491                 tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor);
 492                 altColor = !altColor;
 493                 HtmlTree tdFirst = new HtmlTree(HtmlTag.TD);
 494                 tdFirst.addStyle(HtmlStyle.colFirst);
 495                 writer.addSummaryType(this, element, tdFirst);
 496                 tr.addContent(tdFirst);
 497                 HtmlTree tdLast = new HtmlTree(HtmlTag.TD);
 498                 tdLast.addStyle(HtmlStyle.colLast);
 499                 if (te != null
 500                         && !utils.isConstructor(element)
 501                         && !utils.isClass(element)
 502                         && !utils.isInterface(element)
 503                         && !utils.isAnnotationType(element)) {
 504                     HtmlTree name = new HtmlTree(HtmlTag.SPAN);
 505                     name.addStyle(HtmlStyle.typeNameLabel);
 506                     name.addContent(name(te) + ".");
 507                     tdLast.addContent(name);
 508                 }
 509                 addSummaryLink(utils.isClass(element) || utils.isInterface(element)
 510                         ? LinkInfoImpl.Kind.CLASS_USE
 511                         : LinkInfoImpl.Kind.MEMBER,
 512                     te, element, tdLast);
 513                 writer.addSummaryLinkComment(this, element, tdLast);
 514                 tr.addContent(tdLast);
 515                 tbody.addContent(tr);
 516             }
 517             table.addContent(tbody);
 518             contentTree.addContent(table);
 519         }
 520     }
 521 
 522     /**
 523      * Add the navigation detail link.
 524      *
 525      * @param members the members to be linked
 526      * @param liNav the content tree to which the navigation detail link will be added
 527      */
 528     protected void addNavDetailLink(SortedSet<Element> members, Content liNav) {
 529         addNavDetailLink(!members.isEmpty(), liNav);
 530     }
 531 
 532     /**
 533      * Add the navigation summary link.
 534      *
 535      * @param members members to be linked
 536      * @param visibleMemberMap the visible inherited members map
 537      * @param liNav the content tree to which the navigation summary link will be added
 538      */
 539     protected void addNavSummaryLink(SortedSet<? extends Element> members,
 540             VisibleMemberMap visibleMemberMap, Content liNav) {
 541         if (!members.isEmpty()) {
 542             liNav.addContent(getNavSummaryLink(null, true));
 543             return;
 544         }
 545 
 546         TypeElement superClass = utils.getSuperClass(typeElement);
 547         while (superClass != null) {
 548             if (visibleMemberMap.hasMembersFor(superClass)) {
 549                 liNav.addContent(getNavSummaryLink(superClass, true));
 550                 return;
 551             }
 552             superClass = utils.getSuperClass(superClass);
 553         }
 554         liNav.addContent(getNavSummaryLink(null, false));
 555     }
 556 
 557     protected void serialWarning(Element e, String key, String a1, String a2) {
 558         if (configuration.serialwarn) {
 559             configuration.getDocletSpecificMsg().warning(e, key, a1, a2);
 560         }
 561     }
 562 
 563     /**
 564      * Add the member summary for the given class.
 565      *
 566      * @param tElement the class that is being documented
 567      * @param member the member being documented
 568      * @param firstSentenceTags the first sentence tags to be added to the summary
 569      * @param tableContents the list of contents to which the documentation will be added
 570      * @param counter the counter for determining id and style for the table row
 571      */
 572     public void addMemberSummary(TypeElement tElement, Element member,
 573             List<? extends DocTree> firstSentenceTags, List<Content> tableContents, int counter) {
 574         HtmlTree tdSummaryType = new HtmlTree(HtmlTag.TD);
 575         tdSummaryType.addStyle(HtmlStyle.colFirst);
 576         writer.addSummaryType(this, member, tdSummaryType);
 577         HtmlTree tdSummary = new HtmlTree(HtmlTag.TD);
 578         setSummaryColumnStyle(tdSummary);
 579         addSummaryLink(tElement, member, tdSummary);
 580         writer.addSummaryLinkComment(this, member, firstSentenceTags, tdSummary);
 581         HtmlTree tr = HtmlTree.TR(tdSummaryType);
 582         tr.addContent(tdSummary);
 583         if (utils.isMethod(member) && !utils.isAnnotationType(member)) {
 584             int methodType = utils.isStatic(member) ? MethodTypes.STATIC.value() :
 585                     MethodTypes.INSTANCE.value();
 586             if (utils.isInterface(member.getEnclosingElement())) {
 587                 methodType = utils.isAbstract(member)
 588                         ? methodType | MethodTypes.ABSTRACT.value()
 589                         : methodType | MethodTypes.DEFAULT.value();
 590             } else {
 591                 methodType = utils.isAbstract(member)
 592                         ? methodType | MethodTypes.ABSTRACT.value()
 593                         : methodType | MethodTypes.CONCRETE.value();
 594             }
 595             if (utils.isDeprecated(member) || utils.isDeprecated(typeElement)) {
 596                 methodType = methodType | MethodTypes.DEPRECATED.value();
 597             }
 598             methodTypesOr = methodTypesOr | methodType;
 599             String tableId = "i" + counter;
 600             typeMap.put(tableId, methodType);
 601             tr.addAttr(HtmlAttr.ID, tableId);
 602         }
 603         if (counter%2 == 0)
 604             tr.addStyle(HtmlStyle.altColor);
 605         else
 606             tr.addStyle(HtmlStyle.rowColor);
 607         tableContents.add(tr);
 608     }
 609 
 610     /**
 611      * Generate the method types set and return true if the method summary table
 612      * needs to show tabs.
 613      *
 614      * @return true if the table should show tabs
 615      */
 616     public boolean showTabs() {
 617         int value;
 618         for (MethodTypes type : EnumSet.allOf(MethodTypes.class)) {
 619             value = type.value();
 620             if ((value & methodTypesOr) == value) {
 621                 methodTypes.add(type);
 622             }
 623         }
 624         boolean showTabs = methodTypes.size() > 1;
 625         if (showTabs) {
 626             methodTypes.add(MethodTypes.ALL);
 627         }
 628         return showTabs;
 629     }
 630 
 631     /**
 632      * Set the style for the summary column.
 633      *
 634      * @param tdTree the column for which the style will be set
 635      */
 636     public void setSummaryColumnStyle(HtmlTree tdTree) {
 637         tdTree.addStyle(HtmlStyle.colLast);
 638     }
 639 
 640     /**
 641      * Add inherited member summary for the given class and member.
 642      *
 643      * @param tElement the class the inherited member belongs to
 644      * @param nestedClass the inherited member that is summarized
 645      * @param isFirst true if this is the first member in the list
 646      * @param isLast true if this is the last member in the list
 647      * @param linksTree the content tree to which the summary will be added
 648      */
 649     public void addInheritedMemberSummary(TypeElement tElement,
 650             Element nestedClass, boolean isFirst, boolean isLast,
 651             Content linksTree) {
 652         writer.addInheritedMemberSummary(this, tElement, nestedClass, isFirst,
 653                 linksTree);
 654     }
 655 
 656     /**
 657      * Get the inherited summary header for the given class.
 658      *
 659      * @param tElement the class the inherited member belongs to
 660      * @return a content tree for the inherited summary header
 661      */
 662     public Content getInheritedSummaryHeader(TypeElement tElement) {
 663         Content inheritedTree = writer.getMemberTreeHeader();
 664         writer.addInheritedSummaryHeader(this, tElement, inheritedTree);
 665         return inheritedTree;
 666     }
 667 
 668     /**
 669      * Get the inherited summary links tree.
 670      *
 671      * @return a content tree for the inherited summary links
 672      */
 673     public Content getInheritedSummaryLinksTree() {
 674         return new HtmlTree(HtmlTag.CODE);
 675     }
 676 
 677     /**
 678      * Get the summary table tree for the given class.
 679      *
 680      * @param tElement the class for which the summary table is generated
 681      * @param tableContents list of contents to be displayed in the summary table
 682      * @return a content tree for the summary table
 683      */
 684     public Content getSummaryTableTree(TypeElement tElement, List<Content> tableContents) {
 685         return writer.getSummaryTableTree(this, tElement, tableContents, showTabs());
 686     }
 687 
 688     /**
 689      * Get the member tree to be documented.
 690      *
 691      * @param memberTree the content tree of member to be documented
 692      * @return a content tree that will be added to the class documentation
 693      */
 694     public Content getMemberTree(Content memberTree) {
 695         return writer.getMemberTree(memberTree);
 696     }
 697 
 698     /**
 699      * Get the member tree to be documented.
 700      *
 701      * @param memberTree the content tree of member to be documented
 702      * @param isLastContent true if the content to be added is the last content
 703      * @return a content tree that will be added to the class documentation
 704      */
 705     public Content getMemberTree(Content memberTree, boolean isLastContent) {
 706         if (isLastContent)
 707             return HtmlTree.UL(HtmlStyle.blockListLast, memberTree);
 708         else
 709             return HtmlTree.UL(HtmlStyle.blockList, memberTree);
 710     }
 711 }