Coverage Report - org.apache.maven.doxia.macro.toc.TocMacro
 
Classes in this File Line Coverage Branch Coverage Complexity
TocMacro
92%
51/55
73%
22/30
8,333
 
 1  
 package org.apache.maven.doxia.macro.toc;
 2  
 
 3  
 /*
 4  
  * Licensed to the Apache Software Foundation (ASF) under one
 5  
  * or more contributor license agreements.  See the NOTICE file
 6  
  * distributed with this work for additional information
 7  
  * regarding copyright ownership.  The ASF licenses this file
 8  
  * to you under the Apache License, Version 2.0 (the
 9  
  * "License"); you may not use this file except in compliance
 10  
  * with the License.  You may obtain a copy of the License at
 11  
  *
 12  
  *   http://www.apache.org/licenses/LICENSE-2.0
 13  
  *
 14  
  * Unless required by applicable law or agreed to in writing,
 15  
  * software distributed under the License is distributed on an
 16  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 17  
  * KIND, either express or implied.  See the License for the
 18  
  * specific language governing permissions and limitations
 19  
  * under the License.
 20  
  */
 21  
 
 22  
 import java.io.StringReader;
 23  
 
 24  
 import org.apache.maven.doxia.index.IndexEntry;
 25  
 import org.apache.maven.doxia.index.IndexingSink;
 26  
 import org.apache.maven.doxia.macro.AbstractMacro;
 27  
 import org.apache.maven.doxia.macro.MacroExecutionException;
 28  
 import org.apache.maven.doxia.macro.MacroRequest;
 29  
 import org.apache.maven.doxia.util.HtmlTools;
 30  
 import org.apache.maven.doxia.parser.ParseException;
 31  
 import org.apache.maven.doxia.parser.Parser;
 32  
 import org.apache.maven.doxia.sink.Sink;
 33  
 
 34  
 import org.codehaus.plexus.util.StringUtils;
 35  
 
 36  
 /**
 37  
  * Macro to display a <code>Table Of Content</code> in a given <code>Sink</code>.
 38  
  * The input parameters for this macro are:
 39  
  * <dl>
 40  
  * <dt>section</dt>
 41  
  * <dd>Display a TOC for the specified section only, or all sections if 0.<br/>
 42  
  * Positive int, not mandatory, 0 by default.</dd>
 43  
  * <dt>fromDepth</dt>
 44  
  * <dd>Minimal depth of entries to display in the TOC.
 45  
  * Sections are depth 1, sub-sections depth 2, etc.<br/>
 46  
  * Positive int, not mandatory, 0 by default.</dd>
 47  
  * <dt>toDepth</dt>
 48  
  * <dd>Maximum depth of entries to display in the TOC.<br/>
 49  
  * Positive int, not mandatory, 5 by default.</dd>
 50  
  * </dl>
 51  
  * For instance, in an APT file, you could write:
 52  
  * <dl>
 53  
  * <dt>%{toc|section=2|fromDepth=2|toDepth=3}</dt>
 54  
  * <dd>Display a TOC for the second section in the document, including all
 55  
  * subsections (depth 2) and  sub-subsections (depth 3).</dd>
 56  
  * <dt>%{toc}</dt>
 57  
  * <dd>display a TOC with all section and subsections
 58  
  * (similar to %{toc|section=0} )</dd>
 59  
  * </dl>
 60  
  * Moreover, you need to write APT link for section to allow anchor,
 61  
  * for instance:
 62  
  * <pre>
 63  
  * * {SubSection 1}
 64  
  * </pre>
 65  
  *
 66  
  * Similarly, in an XDOC file, you could write:
 67  
  * <pre>
 68  
  * &lt;macro name="toc"&gt;
 69  
  *   &lt;param name="section" value="1" /&gt;
 70  
  *   &lt;param name="fromDepth" value="1" /&gt;
 71  
  *   &lt;param name="toDepth" value="2" /&gt;
 72  
  * &lt;/macro&gt;
 73  
  * </pre>
 74  
  *
 75  
  * @plexus.component role-hint="toc"
 76  
  *
 77  
  * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
 78  
  * @version $Id: TocMacro.java 1090706 2011-04-09 23:15:28Z hboutemy $
 79  
  */
 80  6
 public class TocMacro
 81  
     extends AbstractMacro
 82  
 {
 83  
     /** The section to display. */
 84  
     private int section;
 85  
 
 86  
     /** Start depth. */
 87  
     private int fromDepth;
 88  
 
 89  
     /** End depth. */
 90  
     private int toDepth;
 91  
 
 92  
     /** The default end depth. */
 93  
     private static final int DEFAULT_DEPTH = 5;
 94  
 
 95  
     /** {@inheritDoc} */
 96  
     public void execute( Sink sink, MacroRequest request )
 97  
         throws MacroExecutionException
 98  
     {
 99  6
         String source = (String) request.getParameter( "sourceContent" );
 100  6
         Parser parser = (Parser) request.getParameter( "parser" );
 101  
 
 102  6
         section = getInt( request, "section", 0 );
 103  6
         fromDepth = getInt( request, "fromDepth", 0 );
 104  6
         toDepth = getInt( request, "toDepth", DEFAULT_DEPTH );
 105  
 
 106  6
         if ( fromDepth > toDepth )
 107  
         {
 108  0
             return;
 109  
         }
 110  
 
 111  6
         IndexEntry index = new IndexEntry( "index" );
 112  6
         IndexingSink tocSink = new IndexingSink( index );
 113  
 
 114  
         try
 115  
         {
 116  6
             parser.parse( new StringReader( source ), tocSink );
 117  
         }
 118  0
         catch ( ParseException e )
 119  
         {
 120  0
             throw new MacroExecutionException( "ParseException: " + e.getMessage(), e );
 121  6
         }
 122  
 
 123  6
         if ( index.getChildEntries().size() > 0 )
 124  
         {
 125  6
             sink.list( getAttributesFromMap( request.getParameters() ) );
 126  
 
 127  6
             int i = 1;
 128  
 
 129  6
             for ( IndexEntry sectionIndex : index.getChildEntries() )
 130  
             {
 131  18
                 if ( ( i == section ) || ( section == 0 ) )
 132  
                 {
 133  14
                     writeSubSectionN( sink, sectionIndex, 1 );
 134  
                 }
 135  
 
 136  18
                 i++;
 137  
             }
 138  
 
 139  6
             sink.list_();
 140  
         }
 141  6
     }
 142  
 
 143  
     /**
 144  
      * @param sink The sink to write to.
 145  
      * @param sectionIndex The section index.
 146  
      * @param n The toc depth.
 147  
      */
 148  
     private void writeSubSectionN( Sink sink, IndexEntry sectionIndex, int n )
 149  
     {
 150  22
         if ( fromDepth <= n )
 151  
         {
 152  22
             sink.listItem();
 153  22
             sink.link( "#" + HtmlTools.encodeId( sectionIndex.getId() ) );
 154  22
             sink.text( sectionIndex.getTitle() );
 155  22
             sink.link_();
 156  
         }
 157  
 
 158  22
         if ( toDepth > n )
 159  
         {
 160  22
             if ( sectionIndex.getChildEntries().size() > 0 )
 161  
             {
 162  10
                 if ( fromDepth <= n )
 163  
                 {
 164  10
                     sink.list();
 165  
                 }
 166  
 
 167  10
                 for ( IndexEntry subsectionIndex : sectionIndex.getChildEntries() )
 168  
                 {
 169  10
                     if ( n == toDepth - 1 )
 170  
                     {
 171  2
                         sink.listItem();
 172  2
                         sink.link( "#" + HtmlTools.encodeId( subsectionIndex.getId() ) );
 173  2
                         sink.text( subsectionIndex.getTitle() );
 174  2
                         sink.link_();
 175  2
                         sink.listItem_();
 176  
                     }
 177  
                     else
 178  
                     {
 179  8
                         writeSubSectionN( sink, subsectionIndex, n + 1 );
 180  
                     }
 181  
                 }
 182  
 
 183  10
                 if ( fromDepth <= n )
 184  
                 {
 185  10
                     sink.list_();
 186  
                 }
 187  
             }
 188  
         }
 189  
 
 190  22
         if ( fromDepth <= n )
 191  
         {
 192  22
             sink.listItem_();
 193  
         }
 194  22
     }
 195  
 
 196  
     /**
 197  
      * @param request The MacroRequest.
 198  
      * @param parameter The parameter.
 199  
      * @param defaultValue the default value.
 200  
      * @return the int value of a parameter in the request.
 201  
      * @throws MacroExecutionException if something goes wrong.
 202  
      */
 203  
     private static int getInt( MacroRequest request, String parameter, int defaultValue )
 204  
         throws MacroExecutionException
 205  
     {
 206  18
         String value = (String) request.getParameter( parameter );
 207  
 
 208  18
         if ( StringUtils.isEmpty( value ) )
 209  
         {
 210  8
             return defaultValue;
 211  
         }
 212  
 
 213  
         int i;
 214  
 
 215  
         try
 216  
         {
 217  10
             i = Integer.parseInt( value );
 218  
         }
 219  4
         catch ( NumberFormatException e )
 220  
         {
 221  4
             return defaultValue;
 222  6
         }
 223  
 
 224  6
         if ( i < 0 )
 225  
         {
 226  0
             throw new MacroExecutionException( "The " + parameter + "=" + i + " should be positive." );
 227  
         }
 228  
 
 229  6
         return i;
 230  
     }
 231  
 }