001package Torello.JavaDoc;
002
003import Torello.HTML.*;
004import Torello.HTML.NodeSearch.*;
005
006import Torello.Java.StrPrint;
007import static Torello.Java.C.*;
008
009import Torello.JDUInternal.GeneralPurpose.Messager;
010
011import java.util.Vector;
012
013/**
014 * Encapsulates the HTML placed both the top and the bottom of a JavaDoc Web-Page, including the
015 * Navigation-Bar HTML, the Package-Name, Type-Signature and other Banner-Labesl.
016 * 
017 * <EMBED CLASS='external-html' DATA-FILE-ID=PROG_MOD_HTML>
018 * <EMBED CLASS='external-html' DATA-FILE-ID=HEADER_FOOTER>
019 */
020@JDHeaderBackgroundImg(EmbedTagFileID="REFLECTION_HTML_CLASS")
021public class HeaderFooterHTML
022{
023    /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUID> */
024    protected static final long serialVersionUID = 1;
025
026
027    // ********************************************************************************************
028    // ********************************************************************************************
029    // Some Private Constants
030    // ********************************************************************************************
031    // ********************************************************************************************
032
033
034    private static final String MARKER_NOT_FOUND_MESSAGE =
035        "Could not Find Marker: === START OF CLASS DATA === on a Java Doc Page";
036
037    private static final String PAGE_TOP_STR = "CIET Page Top-Description";
038
039
040    // ********************************************************************************************
041    // ********************************************************************************************
042    // Private Replaceable-HTML Fields
043    // ********************************************************************************************
044    // ********************************************************************************************
045
046
047    private final SubSection head;
048    private final SubSection topNavBar;
049    private final SubSection packageInfo;
050    private final SubSection title;
051    private final SubSection inheritance;
052    private final Replaceable defListsAboveSig;
053    private final SubSection signature;
054    private final Replaceable description;
055    private final Replaceable defListsBelowDesc;
056    private final SubSection bottomNavBar;
057
058
059    // ********************************************************************************************
060    // ********************************************************************************************
061    // Public Accessor Methods
062    // ********************************************************************************************
063    // ********************************************************************************************
064
065
066    /**
067     * Retrieve the HTML {@code <HEAD>}.
068     * 
069     * @return An HTML-{@code Vector} containing all elements between the opening-{@code <HEAD>}
070     * and closing-{@code </HEAD>} tags.  This method shall never return null, nor will it return
071     * an empty-{@code Vector}
072     */
073    public Vector<HTMLNode> head()
074    { return this.head.html; }
075
076    /**
077     * Retrieve the Navigation-Bar HTML at the top of a Java Doc Page.
078     * 
079     * @return An HTML-{@code Vector} containing all elements in the Top Navigation-Bar.  If there
080     * is no Navigation-Bar at the top, <I>then this method shall return null.</I>
081     */
082    public Vector<HTMLNode> topNavBar()
083    { return (this.topNavBar != null) ? this.topNavBar.html : null; }
084
085    /**
086     * Retrieve the Type's Package-Information, as an HTML-{@code Vector}.
087     * 
088     * @return An HTML-{@code Vector} containing all elements in the package label at the top of a
089     * Java-Doc Page.  This method shall never return null, nor will it return an
090     * empty-{@code Vector}
091     */
092    public Vector<HTMLNode> packageInfo()
093    { return this.packageInfo.html; }
094
095    /**
096     * Retrieve the title of the page, as an HTML-{@code Vector}
097     * 
098     * @return An HTML-{@code Vector} containing all elements in the title.  This method shall
099     * never return null, nor will it return an empty-{@code Vector}
100     */
101    public Vector<HTMLNode> title()
102    { return this.title.html; }
103
104    /**
105     * Get the HTML for the Type's inheritance {@code <UL>'s}-List.
106     * 
107     * @return An HTML-{@code Vector} containing all elements in the Type Inheritance List.  If
108     * the Type is an {@code Interface} that does not have any inheriting-types, or an
109     * {@code @Annotation}, <I>then this method shall return null.</I>
110     */
111    public Vector<HTMLNode> inheritance()
112    { return (this.inheritance != null) ? this.inheritance.html : null; }
113
114    /**
115     * Get any Definition-Lists that occur above the Type's Signature, which is at the top.
116     * 
117     * @return An HTML-{@code Vector} containing all elements in the definition {@code <DL>} lists
118     * below the Yellow-Box Description.  This method shall <I>never return null</I>.  If there are
119     * no such lists, then an empty HTML-{@code Vector} is returned.
120     * 
121     * <BR /><BR />It is perfectly acceptable to add HTML-Content to an empty-list.  Here, it would
122     * place such content directly above the Type-Signature {@code <PRE>} box that is located at
123     * the top of the page.
124     */
125    public Vector<HTMLNode> defListsAboveSig()
126    { return this.defListsAboveSig.currentNodes(); }
127
128    /**
129     * Retrieve the signature HTML from the top of the page.
130     * 
131     * @return An HTML-{@code Vector} containing all elements in the Type-Signature {@code <PRE>}
132     * Element.  This is located at the top of the class, and is box with a shadow border.  This
133     * method shall never return null, nor will it return an empty-{@code Vector}
134     */
135    public Vector<HTMLNode> signature()
136    { return this.signature.html; }
137
138    /**
139     * Retrieve the description from the top of the page, as HTML.
140     * 
141     * @return An HTML-{@code Vector} containing all elements in the description, which is a
142     * Yellow box at the top of the page.  This method shall <I>never return null</I>.  If there
143     * is no such HTML divider, then an empty HTML-{@code Vector} is returned.
144     * 
145     * <BR /><BR />It is perfectly acceptable to add HTML-Content to an empty-list.  Here, it would
146     * place such content directly below the Yellow-Description box that is located at the top of
147     * the page.
148     */
149    public Vector<HTMLNode> description()
150    { return this.description.currentNodes(); }
151
152    /**
153     * Get any Definition-Lists that occur below the Yellow-Box Signature.
154     * 
155     * @return An HTML-{@code Vector} containing all elements in the definition {@code <DL>} lists
156     * below the Yellow-Box Description.  This method shall <I>never return null</I>.  If there are
157     * no such lists, then an empty HTML-{@code Vector} is returned.
158     * 
159     * <BR /><BR />It is perfectly acceptable to add HTML-Content to an empty-list.  Here, it would
160     * place such content directly below the Yellow-Description box that is located at the top of
161     * the page.
162     */
163    public Vector<HTMLNode> defListsBelowDesc()
164    { return this.defListsBelowDesc.currentNodes(); }
165
166    /**
167     * Retrieve the Navigation-Bar HTML at the bottom of a Java Doc Page.
168     * 
169     * @return An HTML-{@code Vector} containing all elements in the Bottom Navigation-Bar.  If
170     * there is no Navigation-Bar at the top, <I>then this method shall return null.</I>
171     */
172    public Vector<HTMLNode> bottomNavBar()
173    { return (this.bottomNavBar != null) ? this.bottomNavBar.html : null; }
174
175
176    // ********************************************************************************************
177    // ********************************************************************************************
178    // The Constructor (This class version of a Main-Method)
179    // ********************************************************************************************
180    // ********************************************************************************************
181
182
183    // MESSAGER
184    //  1) INVOKES:     assertFailHTML
185    //  2) INVOKED-BY:  JavaDocHTMLFile
186    //  3) RETURNS:     NOTHING, this is a constructor
187    //  4) THROWS:      JavaDocHTMLParseException (assertFailHTML)
188
189    HeaderFooterHTML(Vector<HTMLNode> page, CIET ciet)
190    {
191        // Temporary-Variables that are used over and over again.
192        int             sPos, ePos, pos;
193        DotPair         dp;
194        SubSection      ss;
195        Vector<DotPair> dps;
196
197
198        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
199        // EPOS (used over and over)  Everything **EXCEPT** bottomNavBar is **BEFORE** EPOS
200        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
201
202        // This is the actual 'ePos' that is used many times.  The temporary ePos is only used
203        // once or twice in the code below.  This makes sure not to start searching past the
204        // end of the page-header HTML.  The BEGINNING of the <DIV CLASS='summary'> is **EXACTLY**
205        // the **END** of the Page-Header HTML.
206
207        final int EPOS = InnerTagFind.first(page, "div", "class", s -> s.equals("summary"));
208
209        // These asserts are kind of important.  If for some odd reason a javadoc version was
210        // outputting different HTML, it is better to get an error-message and fail than to start
211        // outputting garbage-HTML.
212
213        if (EPOS == -1) Messager.assertFailHTML
214            ("There Java Doc Page doesn't have a <DIV CLASS='summary'> Element", PAGE_TOP_STR);
215
216
217        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
218        // HTML <HEAD>...</HEAD>
219        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
220
221        this.head = TagNodePeekInclusive.first(page, "head");
222
223        if (this.head == null) Messager.assertFailHTML(
224            "This page does not appear to have a <HEAD>...</HEAD> Element",
225            PAGE_TOP_STR
226        );
227
228
229        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
230        // The Top Navigation-Bar, There may be pages which do not have a NavBar
231        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
232        //
233        // NOTE: I just noticed that the Navigation-Bar is a series of <DIV>'s, and there is no
234        //       surrounding HTML divider.  We have to find the first open-<DIV>, and the last
235        //       closing </DIV>
236
237        sPos = CommentNodeFind.first
238            (page, head.location.end, EPOS, s -> s.contains("=== START OF TOP NAVBAR ==="));
239
240        if (sPos == -1) this.topNavBar = null;
241
242        else
243        {
244            ePos = CommentNodeFind.first
245                (page, sPos, EPOS, s -> s.contains("=== END OF TOP NAVBAR ==="));
246
247            sPos = TagNodeFind.first(page, sPos, ePos, TC.OpeningTags, "div");
248            ePos = TagNodeFind.last(page, sPos, ePos, TC.ClosingTags, "div");
249
250            dp = new DotPair(sPos, ePos);
251
252            this.topNavBar = new SubSection(dp, Util.cloneRange(page, dp));
253        }
254
255
256        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
257        // Package-Name Information is the First Item after the Navigation-Bar
258        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
259
260        // It's after the NavBar, if there was no NavBar, skip the first 20 nodes...
261        // (a nice round number)
262
263        sPos = (topNavBar != null) ? (this.topNavBar.location.end + 1) : 20;
264
265        sPos = CommentNodeFind.first
266            (page, sPos, EPOS, TextComparitor.CN, "=== START OF CLASS DATA ===");
267
268        if (sPos == -1) Messager.assertFailHTML(MARKER_NOT_FOUND_MESSAGE, PAGE_TOP_STR);
269
270        // NOTE: The +4 is skipping past the comment, and some stuff.  
271        this.packageInfo = InnerTagPeekInclusive.first
272            (page, sPos + 4, EPOS, "div", "class", TextComparitor.C, "subTitle");
273
274        if (this.packageInfo == null) Messager.assertFailHTML(
275            "Java-Package Information <DIV CLASS='subTitle'> element, not located on the page",
276            PAGE_TOP_STR
277        );
278
279
280        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
281        // Name of the CIET/Type (The Class-Name, Interface-Name, Enum-Name, Annotation-Name...)
282        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
283
284        sPos = this.packageInfo.location.end + 1;
285
286        this.title = InnerTagPeekInclusive.first
287            (page, sPos, EPOS, "h2", "class", TextComparitor.C, "title");
288
289        if (this.title == null) Messager.assertFailHTML(
290            "Java CIET-Title <H2 CLASS='title'> element was not located on the page",
291            PAGE_TOP_STR
292        );
293
294
295        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
296        // The Inheritance-Tree
297        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
298
299        sPos = this.title.location.end + 1;
300
301        if (ciet == CIET.ANNOTATION) this.inheritance = null;
302
303        else
304        {
305            this.inheritance = InnerTagPeekInclusive.first
306                (page, sPos, EPOS, "ul", "class", TextComparitor.C, "inheritance");
307
308            if ((this.inheritance == null) && (ciet != CIET.INTERFACE)) Messager.assertFailHTML(
309                "CIET is a(n) " + ciet.toString() + ", but no Inheritance-Tree "+
310                "<UL CLASS='inheritance'> element was located on the page", PAGE_TOP_STR
311            );
312        }
313
314
315        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
316        // Defintion-Lists (<DL> <DT>...</DT> <DD>...</DD> </DL>) **ABOVE** the signature
317        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
318        //
319        // These Include: All Implemented Interfaces, Direct Known Sub-Classes, Type-Parameters,
320        // All Known Implementing Classes, Functional-Interface, etc...
321
322        if (this.inheritance != null) sPos = this.inheritance.location.end + 1;
323
324        ePos = TagNodeFind.first(page, sPos, EPOS, TC.OpeningTags, "hr");
325
326        if (ePos == -1) Messager.assertFailHTML
327            ("There was not <HR> element in the Page Header", PAGE_TOP_STR);
328
329        dps = TagNodeFindInclusive.all(page, sPos, ePos, "dl");
330
331        if (dps.size() > 0)
332        {
333            dp = new DotPair(
334                dps.elementAt(0).start,
335                dps.elementAt(dps.size() - 1).end
336            );
337
338            this.defListsAboveSig = new SubSection(dp, Util.cloneRange(page, dp));
339        }
340
341        else this.defListsAboveSig = Replaceable.empty((this.inheritance != null)
342            ? (this.inheritance.location.end + 1)
343            : (this.title.location.end + 1)
344        );
345
346
347
348        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
349        // The CIET Signature
350        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
351
352        sPos = this.defListsAboveSig.originalLocationEnd() + 1;
353
354        this.signature = TagNodePeekInclusive.first(page, sPos, EPOS, "pre");
355
356        if (this.signature == null) Messager.assertFailHTML
357            ("There Signature HTML <PRE> element was not located on the page", PAGE_TOP_STR);
358
359
360        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
361        // Description
362        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
363
364        sPos = signature.location.end + 1; // This is white-space
365
366        ss = InnerTagPeekInclusive.first
367            (page, sPos, EPOS, "div", "class", TextComparitor.C, "block");
368
369        // The user may wish to add stuff anyway.  Primarily the @JDHeaderBackgroundImg needs an
370        // insertion point NO MATTER WHAT...  Therefore this cannot be a null SubSection, it has
371        // to be an empty-Replaceable if it was not found...
372
373        this.description = (ss != null) ? ss : Replaceable.empty(sPos);
374
375
376        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
377        // Defintion-Lists (<DL> <DT>...</DT> <DD>...</DD> </DL>) **BELOW** the description
378        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
379        //
380        // These include: See Also, Since , etc...
381
382        sPos = this.description.originalLocationEnd() + 1;
383            // This will be the next node after the <PRE> if the description is just an empty
384            // Replaceable, but that is ok, because the insertion-point is still after the
385            // description's insertion-pont NO MATTER WHAT.
386
387        pos = InnerTagFind.first
388            (page, sPos, EPOS, "span", "class", TextComparitor.C_OR, "seeLabel", "simpleTagLabel");
389
390        // In order to insert "HiLitedSrcCode Links", there needs to be an insertion-point
391        // This is now implemented as a "Replaceable.empty" if there are no <DL>'s below the
392        // description or signature
393
394        if (pos == -1) this.defListsBelowDesc = Replaceable.empty(sPos);
395
396        else
397        {
398            dp = Surrounding.first(page, pos, "dl");
399
400            if (dp == null) Messager.assertFailHTML(
401                "Header <SPAN CLASS=Label> Element Found, but no Surrounding <DL> identified",
402                PAGE_TOP_STR
403            );
404
405            this.defListsBelowDesc = new SubSection(dp, Util.cloneRange(page, dp));
406        }
407
408
409        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
410        // The Bottom Navigation-Bar, There may be pages which do not have a NavBar
411        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
412        //
413        // Searching through "CommentNode" instances is much faster since the
414        // if (HTMLNode.isCommentNode()) is the fastest of the search-specifies...  There aren't
415        // many comment's in a javadc page (much fewer than the number of TagNode's & TextNode's)
416        //
417        // REMEMBER, Here *DO NOT* use 'EPOS', that is the position of the beginning of the 
418        // summaries-section.
419        //
420        // ALSO: as explained in the "Top Navigation-Bar" getter-section (way above this part),
421        //       The Bottom and Top Bar's are a series of "sibling" <DIV> Tags, and you have to
422        //       get the first opening-<DIV> and the last closing-</DIV>
423
424        sPos = CommentNodeFind.first(page, s -> s.contains("== START OF BOTTOM NAVBAR =="));
425
426        if (sPos == -1) this.bottomNavBar = null;
427
428        else
429        {
430            ePos = CommentNodeFind.first
431                (page, sPos, -1, s -> s.contains("=== END OF BOTTOM NAVBAR ==="));
432
433            if (ePos == -1) Messager.assertFailHTML("BOTTOM NAVBAR End-Marker not found", null);
434
435            sPos = TagNodeFind.first(page, sPos, ePos, TC.OpeningTags, "div");
436            ePos = TagNodeFind.last(page, sPos, ePos, TC.ClosingTags, "div");
437    
438            dp = new DotPair(sPos, ePos);
439    
440            this.bottomNavBar = new SubSection(dp, Util.cloneRange(page, dp));
441        }
442    }
443
444
445    // ********************************************************************************************
446    // ********************************************************************************************
447    // DEBUG-PRINTING
448    // ********************************************************************************************
449    // ********************************************************************************************
450
451
452    private static final String STARS =
453        BYELLOW + "\n*****************************************\n" + RESET;
454
455    /**
456     * Prints an abbreviated-version of the contents of this instance, to a user-provided
457     * {@code Appendable}.  If the HTML requires more than four lines of text, only the first four
458     * lines are printed.
459     * 
460     * @param a This may be any Java Appendable.  If an {@code IOException} is thrown while writing
461     * to this {@code Appendable}, it will be caught an wrapped in an
462     * {@code IllegalArgumentException}, with the {@code IOException} set as the {@code cause}.
463     * 
464     * @throws IllegalArgumentException If {@code 'a'} throws an {@code IOException}
465     * @see StrPrint#firstNLines(String, int)
466     * @see Util#pageToString(Vector)
467     */
468    public void debugPrint(Appendable a)
469    {
470        try 
471        {
472            a.append(
473                STARS + BCYAN + "this.head" + RESET + ':' + STARS +
474                StrPrint.firstNLines(Util.pageToString(head.html), 4) +
475                '\n'
476            );
477
478            if (topNavBar != null) a.append(
479                STARS + BCYAN + "this.topNavBar" + RESET + ':' + STARS +
480                StrPrint.firstNLines(Util.pageToString(topNavBar.html), 4) +
481                '\n'
482            );
483            else a.append(STARS + BRED + "this.topNavBar is null" + RESET + STARS);
484
485            a.append(
486                STARS + BCYAN + "this.packageInfo" + RESET + ':' + STARS +
487                StrPrint.firstNLines(Util.pageToString(packageInfo.html), 4) +
488                '\n'
489            );
490
491            a.append(
492                STARS + BCYAN + "this.title" + RESET + ':' + STARS +
493                StrPrint.firstNLines(Util.pageToString(title.html), 4) +
494                '\n'
495            );
496
497            if (inheritance != null) a.append(
498                STARS + BCYAN + "this.inheritance" + RESET + ':' + STARS +
499                StrPrint.firstNLines(Util.pageToString(inheritance.html), 4) +
500                '\n'
501            );
502            else a.append(STARS + BRED + "this.inheritance is null" + RESET + STARS);
503
504            if (defListsAboveSig.currentSize() > 0) a.append(
505                STARS + BCYAN + "this.defListsAboveSig" + RESET + ':' + STARS +
506                StrPrint.firstNLines(Util.pageToString(defListsAboveSig.currentNodes()), 4) +
507                '\n'
508            );
509            else a.append(STARS + BRED + "this.defListsAboveSig is empty" + RESET + STARS);
510
511            a.append(
512                STARS + BCYAN + "this.signature" + RESET + ':' + STARS +
513                StrPrint.firstNLines(Util.pageToString(signature.html), 4) +
514                '\n'
515            );
516
517            if (description.currentSize() > 0) a.append(
518                STARS + BCYAN + "this.description" + RESET + ':' + STARS +
519                StrPrint.firstNLines(Util.pageToString(description.currentNodes()), 4) +
520                '\n'
521            );
522            else a.append(STARS + BRED + "this.description is empty" + RESET + STARS);
523
524            if (defListsBelowDesc.currentSize() > 0) a.append(
525                STARS + BCYAN + "this.defListsBelowDesc" + RESET + ':' + STARS +
526                StrPrint.firstNLines(Util.pageToString(defListsBelowDesc.currentNodes()), 4) +
527                '\n'
528            );
529            else a.append(STARS + BRED + "this.defListsBelowDesc is empty" + RESET + STARS);
530
531            if (bottomNavBar != null) a.append(
532                STARS + BCYAN + "this.bottomNavBar" + RESET + ':' + STARS +
533                StrPrint.firstNLines(Util.pageToString(bottomNavBar.html), 4) +
534                '\n'
535            );
536            else a.append(STARS + BRED + "this.bottomNavBar is null" + RESET + STARS);
537        }
538        catch (java.io.IOException ioe)
539        {
540            throw new IllegalArgumentException(
541                "Your Appendable instance has caused an IOException to throw.  See getCause() " +
542                "for details", ioe
543            );
544        }
545    }
546
547
548    // ********************************************************************************************
549    // ********************************************************************************************
550    // At the end of the processing of a JavaDoc Web-Page, this gets all the changes that were made
551    // ********************************************************************************************
552    // ********************************************************************************************
553
554
555    Vector<Replaceable> allReplaceables()
556    {
557        Vector<Replaceable> ret = new Vector<>();
558
559        ret.add(head);              // Required, always present
560
561        if (topNavBar != null) ret.add(topNavBar);
562
563        ret.add(packageInfo);       // Required, always present
564        ret.add(title);             // Required, always present
565
566        if (inheritance != null) ret.add(inheritance);
567
568        ret.add(defListsAboveSig);  // A "Replaceable" is never null.
569        ret.add(signature);         // Required, always present
570        ret.add(description);       // A "Replaceable" is never null.
571        ret.add(defListsBelowDesc); // A "Replaceable" is never null.
572
573        if (bottomNavBar != null) ret.add(bottomNavBar);
574
575        return ret;
576    }
577
578
579    // ********************************************************************************************
580    // ********************************************************************************************
581    // THE NEW-THING: Garbage-Collector Helper?
582    // ********************************************************************************************
583    // ********************************************************************************************
584    // 
585    // Does this help?  Is this "good" for the Garbage-Collect?  Is this going to speed it up,
586    // or slow it down?  This is just a "C-Styled" FREE or DESTORY method...
587    // It isn't publicly visible anyway...
588
589    void clear()
590    {
591        // private final SubSection head;
592        // Guaranteed: Never Null, or Messager.assertFailHTML
593
594        head.html.clear();
595        head.html = null;
596
597        // private final SubSection topNavBar;
598        // Maybe they don't have one
599
600        if (topNavBar != null)
601        {
602            topNavBar.html.clear();
603            topNavBar.html = null;
604        }
605
606        // private final SubSection packageInfo;
607        // Guaranteed: Never Null, or Messager.assertFailHTML
608        // NOTE: This may one day change...
609
610        if (packageInfo != null)
611        {
612            packageInfo.html.clear();
613            packageInfo.html = null;
614        }
615
616        // private final SubSection title;
617        // Guaranteed: Never Null, or Messager.assertFailHTML
618
619        title.html.clear();
620        title.html = null;
621
622        // private final SubSection inheritance;
623        // Maybe they don't have one
624
625        if (inheritance != null)
626        {
627            inheritance.html.clear();
628            inheritance.html = null;
629        }
630
631        // private final Replaceable defListsAboveSig;
632        // THIS IS A REPLACEABLE: It won't be null, but it may be empty
633
634        if (SubSection.class.isAssignableFrom(defListsAboveSig.getClass()))
635        {
636            ((SubSection) defListsAboveSig).html.clear();
637            ((SubSection) defListsAboveSig).html = null;
638        }
639        else if (defListsAboveSig.currentSize() > 0) defListsAboveSig.clearHTML();
640
641        // private final SubSection signature;
642        // Guaranteed: Never Null, or Messager.assertFailHTML
643
644        signature.html.clear();
645        signature.html = null;
646
647        // private final Replaceable description;
648        // THIS IS A REPLACEABLE: It won't be null, but it may be empty
649
650        if (SubSection.class.isAssignableFrom(description.getClass()))
651        {
652            ((SubSection) description).html.clear();
653            ((SubSection) description).html = null;
654        }
655        else if (description.currentSize() > 0) description.clearHTML();
656
657        // private final Replaceable defListsBelowDesc;
658        // THIS IS A REPLACEABLE: It won't be null, but it may be empty
659
660        if (SubSection.class.isAssignableFrom(defListsBelowDesc.getClass()))
661        {
662            ((SubSection) defListsBelowDesc).html.clear();
663            ((SubSection) defListsBelowDesc).html = null;
664        }
665        else if (defListsBelowDesc.currentSize() > 0) defListsBelowDesc.clearHTML();
666
667        // private final SubSection bottomNavBar;
668        // Maybe they don't have one
669
670        if (bottomNavBar != null)
671        {
672            bottomNavBar.html.clear();
673            bottomNavBar.html = null;
674        }
675    }
676}