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             // Remove the implicit abstract and public modifiers
 267             if (utils.isMethod(member) && utils.isInterface(member.getEnclosingElement())) {
 268                 set.remove(ABSTRACT);
 269                 set.remove(PUBLIC);
 270             }
 271             if (!utils.isMethod(member)) {
 272                 set.remove(PUBLIC);
 273             }
 274         }
 275         if (!set.isEmpty()) {
 276             String mods = set.stream().map(m -> m.toString()).collect(Collectors.joining(" "));
 277             htmltree.addContent(mods);
 278             htmltree.addContent(writer.getSpace());
 279         }
 280     }
 281 
 282     protected String makeSpace(int len) {
 283         if (len <= 0) {
 284             return "";
 285         }
 286         StringBuilder sb = new StringBuilder(len);
 287         for (int i = 0; i < len; i++) {
 288             sb.append(' ');
 289         }
 290         return sb.toString();
 291     }
 292 
 293     /**
 294      * Add the modifier and type for the member in the member summary.
 295      *
 296      * @param member the member to add the type for
 297      * @param type the type to add
 298      * @param tdSummaryType the content tree to which the modified and type will be added
 299      */
 300     protected void addModifierAndType(Element member, TypeMirror type,
 301             Content tdSummaryType) {
 302         HtmlTree code = new HtmlTree(HtmlTag.CODE);
 303         addModifier(member, code);
 304         if (type == null) {
 305             code.addContent(utils.isClass(member) ? "class" : "interface");
 306             code.addContent(writer.getSpace());
 307         } else {
 308             List<? extends TypeParameterElement> list = utils.isExecutableElement(member)
 309                     ? ((ExecutableElement)member).getTypeParameters()
 310                     : null;
 311             if (list != null && !list.isEmpty()) {
 312                 Content typeParameters = ((AbstractExecutableMemberWriter) this)
 313                         .getTypeParameters((ExecutableElement)member);
 314                     code.addContent(typeParameters);
 315                 //Code to avoid ugly wrapping in member summary table.
 316                 if (typeParameters.charCount() > 10) {
 317                     code.addContent(new HtmlTree(HtmlTag.BR));
 318                 } else {
 319                     code.addContent(writer.getSpace());
 320                 }
 321                 code.addContent(
 322                         writer.getLink(new LinkInfoImpl(configuration,
 323                         LinkInfoImpl.Kind.SUMMARY_RETURN_TYPE, type)));
 324             } else {
 325                 code.addContent(
 326                         writer.getLink(new LinkInfoImpl(configuration,
 327                         LinkInfoImpl.Kind.SUMMARY_RETURN_TYPE, type)));
 328             }
 329 
 330         }
 331         tdSummaryType.addContent(code);
 332     }
 333 
 334     /**
 335      * Add the modifier for the member.
 336      *
 337      * @param member the member to add the type for
 338      * @param code the content tree to which the modified will be added
 339      */
 340     private void addModifier(Element member, Content code) {
 341         if (utils.isProtected(member)) {
 342             code.addContent("protected ");
 343         } else if (utils.isPrivate(member)) {
 344             code.addContent("private ");
 345         } else if (!utils.isPublic(member)) { // Package private
 346             code.addContent(configuration.getText("doclet.Package_private"));
 347             code.addContent(" ");
 348         }
 349         boolean isAnnotatedTypeElement = utils.isAnnotationType(member.getEnclosingElement());
 350         if (!isAnnotatedTypeElement && utils.isMethod(member)) {
 351             if (!utils.isInterface(member.getEnclosingElement()) && utils.isAbstract(member)) {
 352                 code.addContent("abstract ");
 353             }
 354             if (utils.isDefault(member)) {
 355                 code.addContent("default ");
 356             }
 357         }
 358         if (utils.isStatic(member)) {
 359             code.addContent("static ");
 360         }
 361     }
 362 
 363     /**
 364      * Add the deprecated information for the given member.
 365      *
 366      * @param member the member being documented.
 367      * @param contentTree the content tree to which the deprecated information will be added.
 368      */
 369     protected void addDeprecatedInfo(Element member, Content contentTree) {
 370         Content output = (new DeprecatedTaglet()).getTagletOutput(member,
 371             writer.getTagletWriterInstance(false));
 372         if (!output.isEmpty()) {
 373             Content deprecatedContent = output;
 374             Content div = HtmlTree.DIV(HtmlStyle.block, deprecatedContent);
 375             contentTree.addContent(div);
 376         }
 377     }
 378 
 379     /**
 380      * Add the comment for the given member.
 381      *
 382      * @param member the member being documented.
 383      * @param htmltree the content tree to which the comment will be added.
 384      */
 385     protected void addComment(Element member, Content htmltree) {
 386         if (!utils.getBody(member).isEmpty()) {
 387             writer.addInlineComment(member, htmltree);
 388         }
 389     }
 390 
 391     protected String name(Element member) {
 392         return utils.getSimpleName(member);
 393     }
 394 
 395     /**
 396      * Get the header for the section.
 397      *
 398      * @param member the member being documented.
 399      * @return a header content for the section.
 400      */
 401     protected Content getHead(Element member) {
 402         Content memberContent = new StringContent(name(member));
 403         Content heading = HtmlTree.HEADING(HtmlConstants.MEMBER_HEADING, memberContent);
 404         return heading;
 405     }
 406 
 407     /**
 408     * Return true if the given <code>ProgramElement</code> is inherited
 409     * by the class that is being documented.
 410     *
 411     * @param ped The <code>ProgramElement</code> being checked.
 412     * return true if the <code>ProgramElement</code> is being inherited and
 413     * false otherwise.
 414     */
 415     protected boolean isInherited(Element ped){
 416         return (!utils.isPrivate(ped) &&
 417                 (!utils.isPackagePrivate(ped) ||
 418                     ped.getEnclosingElement().equals(ped.getEnclosingElement())));
 419     }
 420 
 421     /**
 422      * Add deprecated information to the documentation tree
 423      *
 424      * @param deprmembers list of deprecated members
 425      * @param headingKey the caption for the deprecated members table
 426      * @param tableSummary the summary for the deprecated members table
 427      * @param tableHeader table headers for the deprecated members table
 428      * @param contentTree the content tree to which the deprecated members table will be added
 429      */
 430     protected void addDeprecatedAPI(Collection<Element> deprmembers, String headingKey,
 431             String tableSummary, List<String> tableHeader, Content contentTree) {
 432         if (deprmembers.size() > 0) {
 433             Content caption = writer.getTableCaption(configuration.getResource(headingKey));
 434             Content table = (configuration.isOutputHtml5())
 435                     ? HtmlTree.TABLE(HtmlStyle.deprecatedSummary, caption)
 436                     : HtmlTree.TABLE(HtmlStyle.deprecatedSummary, tableSummary, caption);
 437             table.addContent(writer.getSummaryTableHeader(tableHeader, "col"));
 438             Content tbody = new HtmlTree(HtmlTag.TBODY);
 439             boolean altColor = true;
 440             for (Element member : deprmembers) {
 441                 HtmlTree td = HtmlTree.TD(HtmlStyle.colOne, getDeprecatedLink(member));
 442                 List<? extends DocTree> deprTrees = utils.getBlockTags(member, DocTree.Kind.DEPRECATED);
 443                 if (!deprTrees.isEmpty()) {
 444                     writer.addInlineDeprecatedComment(member, deprTrees.get(0), td);
 445                 }
 446                 HtmlTree tr = HtmlTree.TR(td);
 447                 tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor);
 448                 altColor = !altColor;
 449                 tbody.addContent(tr);
 450             }
 451             table.addContent(tbody);
 452             Content li = HtmlTree.LI(HtmlStyle.blockList, table);
 453             Content ul = HtmlTree.UL(HtmlStyle.blockList, li);
 454             contentTree.addContent(ul);
 455         }
 456     }
 457 
 458     /**
 459      * Add use information to the documentation tree.
 460      *
 461      * @param mems list of program elements for which the use information will be added
 462      * @param heading the section heading
 463      * @param tableSummary the summary for the use table
 464      * @param contentTree the content tree to which the use information will be added
 465      */
 466     protected void addUseInfo(List<? extends Element> mems,
 467             Content heading, String tableSummary, Content contentTree) {
 468         if (mems == null || mems.isEmpty()) {
 469             return;
 470         }
 471         List<? extends Element> members = mems;
 472         boolean printedUseTableHeader = false;
 473         if (members.size() > 0) {
 474             Content caption = writer.getTableCaption(heading);
 475             Content table = (configuration.isOutputHtml5())
 476                     ? HtmlTree.TABLE(HtmlStyle.useSummary, caption)
 477                     : HtmlTree.TABLE(HtmlStyle.useSummary, tableSummary, caption);
 478             Content tbody = new HtmlTree(HtmlTag.TBODY);
 479             boolean altColor = true;
 480             for (Element element : members) {
 481                 TypeElement te = utils.getEnclosingTypeElement(element);
 482                 if (!printedUseTableHeader) {
 483                     table.addContent(writer.getSummaryTableHeader(
 484                             this.getSummaryTableHeader(element), "col"));
 485                     printedUseTableHeader = true;
 486                 }
 487                 HtmlTree tr = new HtmlTree(HtmlTag.TR);
 488                 tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor);
 489                 altColor = !altColor;
 490                 HtmlTree tdFirst = new HtmlTree(HtmlTag.TD);
 491                 tdFirst.addStyle(HtmlStyle.colFirst);
 492                 writer.addSummaryType(this, element, tdFirst);
 493                 tr.addContent(tdFirst);
 494                 HtmlTree tdLast = new HtmlTree(HtmlTag.TD);
 495                 tdLast.addStyle(HtmlStyle.colLast);
 496                 if (te != null
 497                         && !utils.isConstructor(element)
 498                         && !utils.isClass(element)
 499                         && !utils.isInterface(element)
 500                         && !utils.isAnnotationType(element)) {
 501                     HtmlTree name = new HtmlTree(HtmlTag.SPAN);
 502                     name.addStyle(HtmlStyle.typeNameLabel);
 503                     name.addContent(name(te) + ".");
 504                     tdLast.addContent(name);
 505                 }
 506                 addSummaryLink(utils.isClass(element) || utils.isInterface(element)
 507                         ? LinkInfoImpl.Kind.CLASS_USE
 508                         : LinkInfoImpl.Kind.MEMBER,
 509                     te, element, tdLast);
 510                 writer.addSummaryLinkComment(this, element, tdLast);
 511                 tr.addContent(tdLast);
 512                 tbody.addContent(tr);
 513             }
 514             table.addContent(tbody);
 515             contentTree.addContent(table);
 516         }
 517     }
 518 
 519     /**
 520      * Add the navigation detail link.
 521      *
 522      * @param members the members to be linked
 523      * @param liNav the content tree to which the navigation detail link will be added
 524      */
 525     protected void addNavDetailLink(SortedSet<Element> members, Content liNav) {
 526         addNavDetailLink(!members.isEmpty(), liNav);
 527     }
 528 
 529     /**
 530      * Add the navigation summary link.
 531      *
 532      * @param members members to be linked
 533      * @param visibleMemberMap the visible inherited members map
 534      * @param liNav the content tree to which the navigation summary link will be added
 535      */
 536     protected void addNavSummaryLink(SortedSet<? extends Element> members,
 537             VisibleMemberMap visibleMemberMap, Content liNav) {
 538         if (!members.isEmpty()) {
 539             liNav.addContent(getNavSummaryLink(null, true));
 540             return;
 541         }
 542 
 543         TypeElement superClass = utils.getSuperClass(typeElement);
 544         while (superClass != null) {
 545             if (visibleMemberMap.hasMembersFor(superClass)) {
 546                 liNav.addContent(getNavSummaryLink(superClass, true));
 547                 return;
 548             }
 549             superClass = utils.getSuperClass(superClass);
 550         }
 551         liNav.addContent(getNavSummaryLink(null, false));
 552     }
 553 
 554     protected void serialWarning(Element e, String key, String a1, String a2) {
 555         if (configuration.serialwarn) {
 556             configuration.getDocletSpecificMsg().warning(e, key, a1, a2);
 557         }
 558     }
 559 
 560     /**
 561      * Add the member summary for the given class.
 562      *
 563      * @param tElement the class that is being documented
 564      * @param member the member being documented
 565      * @param firstSentenceTags the first sentence tags to be added to the summary
 566      * @param tableContents the list of contents to which the documentation will be added
 567      * @param counter the counter for determining id and style for the table row
 568      */
 569     public void addMemberSummary(TypeElement tElement, Element member,
 570             List<? extends DocTree> firstSentenceTags, List<Content> tableContents, int counter) {
 571         HtmlTree tdSummaryType = new HtmlTree(HtmlTag.TD);
 572         tdSummaryType.addStyle(HtmlStyle.colFirst);
 573         writer.addSummaryType(this, member, tdSummaryType);
 574         HtmlTree tdSummary = new HtmlTree(HtmlTag.TD);
 575         setSummaryColumnStyle(tdSummary);
 576         addSummaryLink(tElement, member, tdSummary);
 577         writer.addSummaryLinkComment(this, member, firstSentenceTags, tdSummary);
 578         HtmlTree tr = HtmlTree.TR(tdSummaryType);
 579         tr.addContent(tdSummary);
 580         if (utils.isMethod(member) && !utils.isAnnotationType(member)) {
 581             int methodType = utils.isStatic(member) ? MethodTypes.STATIC.value() :
 582                     MethodTypes.INSTANCE.value();
 583             if (utils.isInterface(member.getEnclosingElement())) {
 584                 methodType = utils.isAbstract(member)
 585                         ? methodType | MethodTypes.ABSTRACT.value()
 586                         : methodType | MethodTypes.DEFAULT.value();
 587             } else {
 588                 methodType = utils.isAbstract(member)
 589                         ? methodType | MethodTypes.ABSTRACT.value()
 590                         : methodType | MethodTypes.CONCRETE.value();
 591             }
 592             if (utils.isDeprecated(member) || utils.isDeprecated(typeElement)) {
 593                 methodType = methodType | MethodTypes.DEPRECATED.value();
 594             }
 595             methodTypesOr = methodTypesOr | methodType;
 596             String tableId = "i" + counter;
 597             typeMap.put(tableId, methodType);
 598             tr.addAttr(HtmlAttr.ID, tableId);
 599         }
 600         if (counter%2 == 0)
 601             tr.addStyle(HtmlStyle.altColor);
 602         else
 603             tr.addStyle(HtmlStyle.rowColor);
 604         tableContents.add(tr);
 605     }
 606 
 607     /**
 608      * Generate the method types set and return true if the method summary table
 609      * needs to show tabs.
 610      *
 611      * @return true if the table should show tabs
 612      */
 613     public boolean showTabs() {
 614         int value;
 615         for (MethodTypes type : EnumSet.allOf(MethodTypes.class)) {
 616             value = type.value();
 617             if ((value & methodTypesOr) == value) {
 618                 methodTypes.add(type);
 619             }
 620         }
 621         boolean showTabs = methodTypes.size() > 1;
 622         if (showTabs) {
 623             methodTypes.add(MethodTypes.ALL);
 624         }
 625         return showTabs;
 626     }
 627 
 628     /**
 629      * Set the style for the summary column.
 630      *
 631      * @param tdTree the column for which the style will be set
 632      */
 633     public void setSummaryColumnStyle(HtmlTree tdTree) {
 634         tdTree.addStyle(HtmlStyle.colLast);
 635     }
 636 
 637     /**
 638      * Add inherited member summary for the given class and member.
 639      *
 640      * @param tElement the class the inherited member belongs to
 641      * @param nestedClass the inherited member that is summarized
 642      * @param isFirst true if this is the first member in the list
 643      * @param isLast true if this is the last member in the list
 644      * @param linksTree the content tree to which the summary will be added
 645      */
 646     public void addInheritedMemberSummary(TypeElement tElement,
 647             Element nestedClass, boolean isFirst, boolean isLast,
 648             Content linksTree) {
 649         writer.addInheritedMemberSummary(this, tElement, nestedClass, isFirst,
 650                 linksTree);
 651     }
 652 
 653     /**
 654      * Get the inherited summary header for the given class.
 655      *
 656      * @param tElement the class the inherited member belongs to
 657      * @return a content tree for the inherited summary header
 658      */
 659     public Content getInheritedSummaryHeader(TypeElement tElement) {
 660         Content inheritedTree = writer.getMemberTreeHeader();
 661         writer.addInheritedSummaryHeader(this, tElement, inheritedTree);
 662         return inheritedTree;
 663     }
 664 
 665     /**
 666      * Get the inherited summary links tree.
 667      *
 668      * @return a content tree for the inherited summary links
 669      */
 670     public Content getInheritedSummaryLinksTree() {
 671         return new HtmlTree(HtmlTag.CODE);
 672     }
 673 
 674     /**
 675      * Get the summary table tree for the given class.
 676      *
 677      * @param tElement the class for which the summary table is generated
 678      * @param tableContents list of contents to be displayed in the summary table
 679      * @return a content tree for the summary table
 680      */
 681     public Content getSummaryTableTree(TypeElement tElement, List<Content> tableContents) {
 682         return writer.getSummaryTableTree(this, tElement, tableContents, showTabs());
 683     }
 684 
 685     /**
 686      * Get the member tree to be documented.
 687      *
 688      * @param memberTree the content tree of member to be documented
 689      * @return a content tree that will be added to the class documentation
 690      */
 691     public Content getMemberTree(Content memberTree) {
 692         return writer.getMemberTree(memberTree);
 693     }
 694 
 695     /**
 696      * Get the member tree to be documented.
 697      *
 698      * @param memberTree the content tree of member to be documented
 699      * @param isLastContent true if the content to be added is the last content
 700      * @return a content tree that will be added to the class documentation
 701      */
 702     public Content getMemberTree(Content memberTree, boolean isLastContent) {
 703         if (isLastContent)
 704             return HtmlTree.UL(HtmlStyle.blockListLast, memberTree);
 705         else
 706             return HtmlTree.UL(HtmlStyle.blockList, memberTree);
 707     }
 708 }