<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;"># Copyright (C) 2002-09  Stephane Galland &lt;galland@arakhne.org&gt;
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING.  If not, write to
# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.

=pod

=head1 NAME

Bib2HTML::Generator::Theme::DynaTheme - A theme for the HTML generator

=head1 SYNOPSYS

use Bib2HTML::Generator::Theme::DynaTheme ;

my $gen = Bib2HTML::Generator::Theme::DynaTheme-&gt;new( bib2html,
                                                         target,
                                                         title,
                                                         phpgen,
                                                         webgen ) ;

=head1 DESCRIPTION

Bib2HTML::Generator::Theme::DynaTheme is a Perl module, which proposes
a documentation theme for the HTML generator of bib2html. This theme generates
something like javadoc.

=head1 GETTING STARTED

=head2 Initialization

To start a generator script, say something like this:

    use Bib2HTML::Generator::Theme::DynaTheme;

    my $gen = Bib2HTML::Generator::Theme::DynaTheme-&gt;new( { 'VERSION' =&gt; '0.11' },
								 "./phpdoc",
								 "Title",
								 1, 1 ) ;

...or something similar. Acceptable parameters to the constructor are:

=over

=item * bib2html (hash)

contains some data about bib2html.

=item * target (string)

The directory in which the documentation must be put.

=item * title (string)

is the title of the documentation.

=item * phpgen (boolean)

indicates if the PHP doc was generated

=item * webgen (boolean)

indicates if the WEB doc was generated

=item * lang (object ref)

is a reference to the language object.

=back

=head1 METHOD DESCRIPTIONS

This section contains only the methods in Html.pm itself.

=over

=cut

package Bib2HTML::Generator::Theme::Dyna;

@ISA = ('Bib2HTML::Generator::Theme');
@EXPORT = qw();
@EXPORT_OK = qw();

use strict;
use vars qw(@ISA @EXPORT @EXPORT_OK $VERSION);
use Exporter;

use Carp ;

use Bib2HTML::Generator::Theme ;
use Bib2HTML::General::Verbose ;
use Bib2HTML::General::Error ;
use Bib2HTML::General::HTML ;
use Bib2HTML::General::Misc ;

#------------------------------------------------------
#
# Global vars
#
#------------------------------------------------------

# Version number of Dyna theme
my $VERSION = "4.0" ;

#------------------------------------------------------
#
# Constructor
#
#------------------------------------------------------

sub new($$$$$$$) {
  my $proto = shift;
  my $class = ref($proto) || $proto;
  my $self = $class-&gt;SUPER::new( @_ ) ;

  $self-&gt;{'COPY_FILES'} = [ 'stylesheet.css',
			    'minus.gif',
			    'plus.gif',
			    'child.gif',
			    'lastchild.gif',
			    'samechild.gif',
			    'emptychild.gif',
			  ] ;

  $self-&gt;{'FRAME_TREE_ID_COUNT'} = 0 ;
  $self-&gt;{'TREE_ID_COUNT'} = 0 ;

  bless( $self, $class );

  return $self;
}

#------------------------------------------------------
#
# Validation
#
#------------------------------------------------------

=pod

=item * getMyValidHTML()

Replies the list of W3C protocols for which this theme
was validated. You must override this method.

=cut
sub getMyValidHTML() {
  my $self = shift ;
  return ( 'html', 'css' ) ;
}

#------------------------------------------------------
#
# Main structure
#
#------------------------------------------------------

=pod

=item * get_html_header()

Replies the HTML header of each page.
Takes 1 arg:

=over

=item * rootdir (string)

is the path to the root directory

=back

=cut
sub get_html_header($) : method {
  my $self = shift ;
  my $rootdir = $_[0] || confess( 'you must supply the root directory' ) ;
  return join( '',
               "&lt;link REL ='stylesheet' TYPE='text/css' HREF='",
               htmlcatfile($rootdir,"stylesheet.css"),
               "' TITLE='Style'&gt;\n",

               # JavaScript
               "&lt;script language='JavaScript1.2' type=\"text/javascript\"&gt;\n&lt;!--\n",
               "function swaptreecontent(elID) {\n",
	       "  b = document.getElementById(elID).innerHTML;\n",
	       "  a = document.getElementById(elID + \"off__\").innerHTML;\n",
	       "  if (a.length == 0) {",
	       "    document.getElementById(elID).innerHTML = \"\";\n",
               "  } else {\n",
	       "    document.getElementById(elID).innerHTML = a;\n",
               "  }\n",
	       "  document.getElementById(elID + \"off__\").innerHTML = b;\n",
	       "}\n\n",
               "function swaptreeicon(elID) {\n",
               "  a = document.getElementById(elID + \"plusminus\").src;\n",
	       "  if (a.indexOf(\"minus.gif\") != -1) a = \"",
               htmlcatfile($rootdir,"plus.gif"),
               "\";\n",
	       "  else a = \"",
               htmlcatfile($rootdir,"minus.gif"),
               "\";\n",
	       "  document.getElementById(elID + \"plusminus\").src = a;\n",
	       "}\n\n",
               "function swaptree(elID) {\n",
	       "  swaptreecontent(elID);\n",
	       "  swaptreeicon(elID);\n",
               "}\n\n",
               "function swaptree2(elID1,elID2) {\n",
	       "  swaptreecontent(elID1);\n",
	       "  swaptreecontent(elID2);\n",
	       "  swaptreeicon(elID1);\n",
               "}\n",
               "//--&gt;\n&lt;/script&gt;\n" ) ;
}


#------------------------------------------------------
#
# Structural element API
#
#------------------------------------------------------

=pod

=item * get_tree_node()

Replues the HTML string for the specified tree.
a list.
Takes 2 args:

=over

=item * node (string)

is the string that is the root of the tree.

=item * subs (string)

is an HTML string that describes the children.

=item * rootdir (string)

is the path to the root directory.

=back

=cut
sub get_tree_node($$$) {
  my $self = shift ;
  my $text = $_[0] || '' ;
  $text =~ s/[ \t\n\r]+/&amp;nbsp;/g ;
  return $self-&gt;SUPER::get_tree_node($text,$_[1],$_[2]) ;
}

=pod

=item * get_tree_leaf()

Replies a line of a tree which will be displayed inside
a list.
Takes 1 args:

=over

=item * node (string)

is the string that is the root of the tree.

=item * rootdir (string)

is the path to the root directory.

=back

=cut
sub get_tree_leaf($$) {
  my $self = shift ;
  my $text = $_[0] || '' ;
  $text =~ s/[ \t\n\r]+/&amp;nbsp;/g ;
  return $self-&gt;SUPER::get_tree_leaf($text,$_[1]) ;
}

=pod

=item * get_tree()

Creates a tree.
Takes 2 or 3 args:

=over

=item * tree (hash)

is the tree

=item * rootdir (string)

is the path to the root directory

=item * root label (optional string)

is the label of the root node

=back

=cut
sub get_tree($$;$) : method {
  my $self = shift ;
  my $tree = $_[0] || confess( "you must supply the tree" ) ;
  my $rootdir = $_[1] || confess( 'you must supply the root directory' ) ;
  my $defaultRootLabel = $self-&gt;{'LANG'}-&gt;get('I18N_LANG_THEME_TREE_ROOT');
  my $rootlabel = $_[2] || $defaultRootLabel;
  $tree = { $rootlabel =&gt; $tree } ;
  return $self-&gt;__get_dyna_tree__( $tree, $rootdir ) ;
}

sub __get_dyna_tree__($$) {
  my $self = shift ;
  my $rootdir = $_[1] || confess( 'you must supply the root directory' ) ;
  my ($prevs,$lines,$max) = $self-&gt;__get_dyna_tree_rec__(@_) ;

  my $content = '' ;
  foreach my $prev (@{$prevs}) {
    $content .= join( '',
		      "&lt;DIV id=\"",
		      $prev,
		      "off__\" style=\"visibility : hidden; position: absolute\"&gt;&lt;/DIV&gt;\n" ) ;
  }

  my $tblheader = "&lt;TABLE border='0' cellspacing='0' cellpadding='0' width='100%'&gt;\n" ;
  my $tblfooter = "&lt;/TABLE&gt;\n" ;

  my $tablecontent = "" ;
  foreach my $line (@{$lines}) {
    my $iddata = pop @{$line} ;
    my $count = $max ;
    my $linecontent = '' ;

    while (@{$line}) {
      my $cell = shift @{$line} ;

      if (($cell)&amp;&amp;("$cell" eq "[-]")) {
	# Add a collapse button
 	confess( 'empty id when collapsable node' ) unless $iddata-&gt;{'open'} ;
 	$count -- ;
 	$linecontent .= join( '',
			      "&lt;TD valign='middle' align='left' width='11' height='17'&gt;",
			      $self-&gt;href( "javascript:swaptree('".$iddata-&gt;{'open'}."')",
					   "&lt;img src=\"".
					   htmlcatfile($rootdir,"minus.gif").
					   "\" alt=\"-\" ".
					   "id=\"".$iddata-&gt;{'open'}."plusminus\" width=\"11\" ".
					   "height=\"11\" border=\"0\"&gt;" ),
			      "&lt;/TD&gt;" ) ;
      }
      elsif (($cell)&amp;&amp;($cell eq '[ ]')) {
	# Add a white space
 	$count -- ;
 	$linecontent .= join( '',
			      "&lt;TD valign='top' align='left' width='11' height='17'&gt;",
			      "&lt;IMG src=\"",
			      htmlcatfile($rootdir,"emptychild.gif"),
			      "\" alt=\" \" width=\"11\" ",
			      "height=\"17\" border=\"0\"&gt;",
			      "&lt;/TD&gt;" ) ;
      }
      elsif (($cell)&amp;&amp;($cell eq '[+]')) {
	# Add a tee
 	$count -- ;
 	$linecontent .= join( '',
			      "&lt;TD valign='top' align='left' width='11' height='17'&gt;",
			      "&lt;IMG src=\"",
			      htmlcatfile($rootdir,"child.gif"),
			      "\" alt=\"+\" width=\"11\" ",
			      "height=\"17\" border=\"0\"&gt;",
			      "&lt;/TD&gt;" ) ;
      }
      elsif (($cell)&amp;&amp;($cell eq '[|]')) {
	# Add a vertical bar
 	$count -- ;
 	$linecontent .= join( '',
			      "&lt;TD valign='top' align='left' height='17'&gt;",
			      "&lt;IMG src=\"",
			      htmlcatfile($rootdir,"samechild.gif"),
			      "\" alt=\"|\" width=\"11\" ",
			      "height=\"17\" border=\"0\"&gt;",
			      "&lt;/TD&gt;" ) ;
       }
       elsif (($cell)&amp;&amp;($cell eq '[\\]')) {
	 # Add a corner
	 $count -- ;
	 $linecontent .= join( '',
			       "&lt;TD valign='top' align='left' width='11' height='17'&gt;",
			       "&lt;IMG src=\"",
			       htmlcatfile($rootdir,"lastchild.gif"),
			       "\" alt=\"\\\" width=\"11\" ",
			       "height=\"17\" border=\"0\"&gt;",
			       "&lt;/TD&gt;" ) ;
       }
      elsif (($cell)&amp;&amp;($count&gt;0)) {
	# Add a text
 	$linecontent .= join( '',
			      "&lt;TD colspan='$count' width='100%' valign='middle' align='left' class='TreeText' height='17'&gt;",
			      $cell,
			      "&lt;/TD&gt;" ) ;
	$count = 0 ;
      }

    }

    # Add the line
    if ($linecontent !~ /^\s*$/m) {

      # Test if a table header was needed
      $tablecontent = "$tblheader" unless ($tablecontent) ;

      # Add the line
      $tablecontent .= "&lt;TR&gt;$linecontent&lt;/TR&gt;" ;

      # Close the table if on a block bound
      if ((!isemptyarray($iddata-&gt;{'closes'}))||
	  ($iddata-&gt;{'open'})) {
	$content .= "$tablecontent$tblfooter" ;
	$tablecontent = "" ;
      }

      # Put the block's open/close actions
      if (!isemptyarray($iddata-&gt;{'closes'})) {
	for(my $i=0; $i&lt;@{$iddata-&gt;{'closes'}}; $i++) {
	  $content .= "&lt;/DIV&gt;" ;
	}
      }
      if ( $iddata-&gt;{'open'} ) {
	$content .= "&lt;DIV id=\"".$iddata-&gt;{'open'}."\"&gt;" ;
      }

    }

  }

  if ($tablecontent) {
    $content .= "$tablecontent$tblfooter" ;
  }

  return $content ;
}

sub __get_dyna_tree_rec__($$) {
  my $self = shift ;
  my $rootdir = $_[1] || confess( 'you must supply the root directory' ) ;
  my @content = () ;
  my @prev = () ;
  my $max = 0 ;

  if ( ! isemptyhash( $_[0] ) ) {

    my @keys = keys %{$_[0]};
    @keys = sortbyletters(@keys) ;

    for(my $i=0; $i&lt;=$#keys; $i++) {
      my $nodename = $keys[$i] ;
      my $oid = '' ;

      # Gets the children
      my ($child_prev,$child_content,$child_max) = $self-&gt;__get_dyna_tree_rec__( $_[0]-&gt;{$nodename}, $rootdir ) ;

      # Computes the collpasing icon
      my $collaps = '' ;
      if ( ! isemptyarray( $child_content ) ) {
	$collaps = '[-]' ;
	# Computes the tags just before the tree
	# This tag permits to undisplay the $id area
	$self-&gt;{'FRAME_TREE_ID_COUNT'} ++ ;
	$oid = "treeoverviewid".$self-&gt;{'FRAME_TREE_ID_COUNT'} ;
	push @prev, $oid ;
      }
      push @prev, @{$child_prev} ;

      # Adds this node to the array
      push @content, [ "$collaps", "&amp;nbsp;$nodename", { 'open' =&gt; $oid,
							'closes' =&gt; [] } ] ;
      $max = 2 ;

      # Adds the children
      my @subcontent = () ;
      my $found = 0 ;
      for(my $j=$#{$child_content}; $j&gt;=0; $j--) {
	my $next = $child_content-&gt;[$j][0] ;
	my $icon = '[ ]' ;
	if ( $found ) {
	  if ( ( ! $next ) || ( $next eq '[-]' ) ) {
	    $icon = '[+]' ;
	  }
	  else {
	    $icon = '[|]' ;
	  }
	}
	elsif ( ( ! $next ) || ( $next eq '[-]' ) ) {
	  $found = 1 ;
	  $icon = '[\\]' ;
	}
	unshift @subcontent, [ $icon, @{$child_content-&gt;[$j]} ] ;
	if ( $max &lt; (@{$child_content-&gt;[$j]}-1) ) {
	  $max = @{$child_content-&gt;[$j]}-1 ;
	}
      }
      push @content, @subcontent ;
      if ( $oid ) {
	push( @{$content[$#content]-&gt;[$#{$content[$#content]}]-&gt;{'closes'}},
	      $oid ) ;
      }
    }

  }

  return (\@prev,\@content,$max) ;
}

=pod

=item * build_linked_tree()

Creates a tree with links between nodes.
Takes 1 arg:

=over

=item * tree (array)

is the tree

=item * rootdir (string)

is the path to the root directory

=back

=cut
sub build_linked_tree($$) : method {
  my $self = shift ;
  my $tree = $_[0] || confess( "you must supply the tree" ) ;
  my $rootdir = $_[1] || confess( 'you must supply the root directory' ) ;
  my $content = "" ;
  if ( $#{$tree} &gt;= 0 ) {
    my $end = '' ;
    for(my $i=0; $i&lt;=$#{$tree}; $i++ ) {
      my $class = $tree-&gt;[$i] ;

      $self-&gt;{'FRAME_TREE_ID_COUNT'} ++ ;
      my $id1 = "classtreeid".$self-&gt;{'FRAME_TREE_ID_COUNT'} ;
      $self-&gt;{'FRAME_TREE_ID_COUNT'} ++ ;
      my $id2 = "classtreeid".$self-&gt;{'FRAME_TREE_ID_COUNT'} ;

      $content .= join( '',
			"&lt;DIV id=\"",
			$id1,
			"off__\" style=\"visibility : hidden; position: absolute\"&gt;&lt;/DIV&gt;\n",
			"&lt;DIV id=\"",
			$id2,
			"off__\" style=\"visibility : hidden; position: absolute\"&gt;&lt;/DIV&gt;\n",

			"&lt;TABLE border=0 cellspacing=2 cellpadding=0&gt;",
			"&lt;TR&gt;&lt;TD&gt;" ) ;

      if ( $i &lt; $#{$tree} ) {
	$content .= join( '',
			  $self-&gt;href( "javascript:swaptree2('".$id1."','".$id2."')",
				       "&lt;img src=\"".
				       htmlcatfile($rootdir,"minus.gif").
				       "\" alt=\"-\" ".
				       "id=\"".$id1."plusminus\" width=\"11\" ".
				       "height=\"11\" border=\"0\"&gt;" ),
			  "&lt;/TD&gt;&lt;TD&gt;&amp;nbsp;" ) ;
      }

      $content .= join( '',
			$class,
			"&lt;/TD&gt;&lt;/TR&gt;",
			"&lt;TR&gt;&lt;TD valign='top' align='right'&gt;" ) ;

      if ( $i &lt; $#{$tree} ) {
	$content .= join( '',
			  "&lt;DIV id=\"",
			  $id2,
			  "\"&gt;",
			  "&lt;IMG src=\"",
			  htmlcatfile($rootdir,"lastchild.gif"),
			  "\" alt=\"-\" width=\"11\" ",
			  "height=\"17\" border=\"0\"&gt;",
			  "&lt;/DIV&gt;" ) ;
      }

      $content .= join( '',
			"&lt;/TD&gt;&lt;TD class='TreeText' valign='middle' align='left'&gt;&lt;DIV id=\"",
			$id1,
			"\"&gt;") ;

      $end .= "&lt;/DIV&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TABLE&gt;" ;

    }

    $content .= $end ;

  }
  return $content ;
}

=pod

=item * build_detail_section_title()

Replies title of an detail section.
Takes 2 args:

=over

=item * title (string)

is the title of the section.

=item * label (string)

is the label of the title bar.

=back

=cut
sub build_detail_section_title($$) : method {
  my $self = shift ;
  return join( '',
	       "&lt;A NAME=\"",
               $_[1] || '',
               "\"&gt;&lt;/A&gt;",
	       "&lt;P&gt;&lt;/P&gt;&lt;TABLE BORDER='1' CELLPADDING='3' CELLSPACING='0' WIDTH='100%'&gt;",
               "&lt;THEAD&gt;&lt;TR&gt;&lt;TD CLASS='largetabletitle'&gt;",
               $_[0] || '',
               "&lt;/TD&gt;&lt;/TR&gt;&lt;/THEAD&gt;&lt;/TABLE&gt;&lt;BR&gt;\n" ) ;
}

=pod

=item * build_class_detail()

Replies the detail for a class.
Takes 3 args:

=over

=item * classname (string)

is the name of the class

=item * extends (string)

is the name of extended class.

=item * explanation (string)

is the description of the function.

=item * details (string)

contains some details on this function.

=back

=cut
sub build_class_detail($$$$) : method {
  my $self = shift ;
  my $classname = $_[0] || confess( 'you must supply the classname' ) ;
  my $extends = $_[1] || '' ;
  my $explanation = $_[2] || '' ;
  my $details = $_[3] || '' ;
  return join( '',
               "&lt;DL&gt;\n&lt;DT&gt;",
	       $self-&gt;{'LANG'}-&gt;get('I18N_LANG_CLASS'),
	       " &lt;B&gt;$classname&lt;/B&gt;",
               ( $extends ? "&lt;DT&gt;".
		 $self-&gt;{'LANG'}-&gt;get('I18N_LANG_EXTENDS').
		 " $extends&lt;/DL&gt;\n" : '' ),
	       "&lt;P&gt;",
               $explanation,
	       "&lt;/P&gt;\n",
               $details,
	       "&lt;/DL&gt;\n" ) ;
}

=pod

=item * build_function_detail()

Replies the detail for a function.
Takes 5 args:

=over

=item * key_name (string)

is the keyname of the function.

=item * name (string)

is the name of the function.

=item * signature (string)

is the signature of the function.

=item * explanation (string)

is the description of the function.

=item * details (string)

contains some details on this function.

=back

=cut
sub build_function_detail($$$$) : method {
  my $self = shift ;
  my $kname = $_[0] || confess( 'you must supply the keyname' ) ;
  my $name = $_[1] || confess( 'you must supply the name' ) ;
  my $signature = $_[2] || confess( 'you must supply the signature' ) ;
  my $explanation = $_[3] || confess( 'you must supply the explanation' ) ;
  my $details = $_[4] || '' ;
  return join( '',
	       "&lt;A NAME=\"",
               $kname,
               "\"&gt;&lt;/A&gt;&lt;H3&gt;",
               $name,
               "&lt;/H3&gt;\n&lt;PRE&gt;\n",
	       $signature,
	       "&lt;/PRE&gt;\n&lt;DL&gt;&lt;DD&gt;&lt;P&gt;",
               $explanation,
	       "&lt;/P&gt;\n",
	       $details,
	       "&lt;/DD&gt;&lt;/DL&gt;"
	     ) ;
}

=pod

=item * build_detail_part()

Replies a detail part.
Takes 3 args:

=over

=item * title (string)

is the title of the section.

=item * separator (string)

is the separator of the elements.

=item * elements (array ref)

is the whole of the elements.

=back

=cut
sub build_detail_part($$$) : method {
  my $self = shift ;
  if ( $#{$_[2]} &gt;= 0 ) {
    my $content = join( '',
			"&lt;DL&gt;&lt;DT&gt;&lt;B&gt;$_[0]:&lt;/B&gt;&lt;/DT&gt;&lt;DD&gt;"
		      ) ;
    my $i = 0 ;
    $content .= "&lt;UL&gt;" if ( $_[1] =~ /&lt;li&gt;/i ) ;
    foreach my $e (@{$_[2]}) {
      if ( $_[1] =~ /&lt;li&gt;/i ) {
        $content .= "&lt;LI&gt;" ;
      }
      elsif ( $i &gt; 0 ) {
	$content .= $_[1] ;
      }
      $content .= $e ;
      $content .= "&lt;/LI&gt;" if ( $_[1] =~ /&lt;li&gt;/i ) ;
      $i ++ ;
    }
    $content .= "&lt;/UL&gt;" if ( $_[1] =~ /&lt;li&gt;/i ) ;
    $content .= "&lt;/DD&gt;&lt;/DL&gt;\n" ;
    return $content ;
  }
  else {
    return "" ;
  }
}

#------------------------------------------------------
#
# Paragraph API
#
#------------------------------------------------------

=pod

=item * frame_subpart()

Replies a subpart of a frame
Takes 3 args:

=over

=item * title (string)

is the title of the part.

=item * text (array)

is the content of the frame.

=item * rootdir (string)

is the path to the root directory.

=back

=cut
sub frame_subpart($$$) : method {
  my $self = shift ;
  my $title = $_[0] || '' ;
  my $rootdir = $_[2] || confess( 'you must supply the root directory' ) ;
  $self-&gt;{'FRAME_TREE_ID_COUNT'} ++ ;
  my $id = "treeid".$self-&gt;{'FRAME_TREE_ID_COUNT'} ;

  my $content = "&lt;P&gt;&lt;/P&gt;&lt;DIV id=\"".$id."off__\" style=\"visibility : hidden; position: absolute\"&gt;&lt;/DIV&gt;\n" ;

  $content .= $self-&gt;href( "javascript:swaptree('".$id."')",
                           "&lt;img src=\"".
                           htmlcatfile($rootdir,"minus.gif").
                           "\" alt=\"-\" ".
                           "id=\"".$id."plusminus\" width=\"11\" ".
                           "height=\"11\" border=\"0\"&gt;" ) ;
  $content .= join( '',
                    ( $title ? '&amp;nbsp;'.html_add_unsecable_spaces($title)."&lt;BR&gt;\n" : '' ),
                    "&lt;div id=\"",
                    $id,
                    "\"&gt;" ) ;

  if ( ( isarray($_[1]) ) &amp;&amp; ( ! isemptyarray($_[1]) ) ) {
    for(my $i=0; $i&lt;=$#{$_[1]}; $i++) {
      my $item = html_add_unsecable_spaces( $_[1][$i] ) ;
      $content .= join( '',
                        "&lt;TABLE border=0 cellspacing=0 cellpadding=0&gt;",
                        "&lt;TR&gt;&lt;TD valign='top' align='right'&gt;&lt;img src=\"",
                        htmlcatfile($rootdir,
                                    ($i==$#{$_[1]}) ?
                                    "lastchild.gif" : "child.gif"),
                        "\" alt=\"-\" width=\"11\" ",
                        "height=\"17\" border=\"0\"&gt;&lt;/TD&gt;&lt;TD class='TreeText' valign='middle' align='left'&gt;&amp;nbsp;",
                        $item,
                        "&lt;/TD&gt;&lt;/TR&gt;&lt;/TABLE&gt;\n" ) ;
    }
  }
  $content .= "&lt;/DIV&gt;\n\n" ;
  return $content ;
}

=pod

=item * frame_window()

Replies a frame
Takes 2 args:

=over

=item * title (string)

is the title of the frame.

=item * text (string)

is the content of the frame.

=back

=cut
sub frame_window($$) : method {
  my $self = shift ;
  my $title = $_[0] || '' ;
  my $text = $_[1] || '' ;
  return join( '',
               ( $title ? "&lt;H2&gt;$title&lt;/H2&gt;\n\n" : '' ),
               $text ) ;
}

=pod

=item * small()

Replies a text with a small size.
Takes 1 arg:

=over

=item * text (string)

=back

=cut
sub small($) {
  my $self = shift ;
  my $text = $_[0] || '' ;
  return join( '',
	       "&lt;SPAN CLASS='small'&gt;",
	       $text,
	       "&lt;/SPAN&gt;\n" ) ;
}

=pod

=item * tiny()

Replies a text with a tiny size.
Takes 1 arg:

=over

=item * text (string)

=back

=cut
sub tiny($) {
  my $self = shift ;
  my $text = $_[0] || '' ;
  return join( '',
	       "&lt;SPAN CLASS='tiny'&gt;",
	       $text,
	       "&lt;/SPAN&gt;\n" ) ;
}

=pod

=item * section()

Replies a section
Takes 3 args:

=over

=item * title (string)

is the title of the new section.

=item * content (string)

is the content of the new section

=item * root (string)

is the root directory for the generated documentation.

=back

=cut
sub section($$$) : method {
  my $self = shift ;
  my $title = $_[0] || confess( 'you must specify the title' ) ;
  my $content = $_[1] || '' ;
  my $rootdir = $_[2] || confess( 'you must specify the root directory' ) ;
  return join( '',
	       "&lt;P&gt;&lt;/P&gt;",
	       "&lt;TABLE BORDER='0' WIDTH='100%' ",
	       "CELLPADDING='1' CELLSPACING='0'&gt;\n",
	       "&lt;TR&gt;&lt;TD CLASS='tabletitle'&gt;",
	       $title,
	       "&lt;/TD&gt;&lt;/TR&gt;\n",
	       "&lt;TR&gt;&lt;TD&gt;",
	       $content,
	       "&lt;/TD&gt;&lt;/TR&gt;&lt;/TABLE&gt;\n" ) ;
}

#------------------------------------------------------
#
# Array API
#
#------------------------------------------------------

=pod

=item * build_onecolumn_array()

Replies an one-column array.
Takes 2 args:

=over

=item * title (string)

is the title of the array

=item * cells (array ref)

is the content of the returned cells.

=back

=cut
sub build_onecolumn_array($$) : method {
  my $self = shift ;
  my $title = $_[0] || '' ;
  my $content = '' ;
  if ( ( isarray($_[1]) ) &amp;&amp; ( ! isemptyarray($_[1]) ) ) {
    foreach my $cell (@{$_[1]}) {
      $content .= join( '',
                        "&lt;TR&gt;&lt;TD&gt;",
                        $cell,
                        "&lt;/TD&gt;&lt;/TR&gt;\n" ) ;
    }
  }
  return join( '',
               "&lt;P&gt;&lt;/P&gt;&lt;TABLE BORDER='1' CELLPADDING='3' CELLSPACING='0' WIDTH='100%'&gt;",
               "&lt;THEAD&gt;",
               "&lt;TR&gt;&lt;TD CLASS='tabletitle'&gt;&lt;B&gt;",
               $title,
               "&lt;/B&gt;&lt;/TD&gt;&lt;/TR&gt;",
               "&lt;/THEAD&gt;\n&lt;TBODY&gt;",
               $content,
               "&lt;/TBODY&gt;\n&lt;/TABLE&gt;\n\n" ) ;
}

=pod

=item * build_twocolumn_array()

Replies an two-column array.
Takes 2 args:

=over

=item * title (string)

is the title of the array

=item * cells (array ref)

is the content of the returned cells.

=back

=cut
sub build_twocolumn_array($$) : method {
  my $self = shift ;
  my $title = $_[0] || '' ;
  my $content = '' ;
  if ( ( isarray($_[1]) ) &amp;&amp; ( ! isemptyarray($_[1]) ) ) {
    for(my $i=0; $i&lt;=$#{$_[1]}; $i++) {
      if ( ( ishash($_[1][$i]) ) &amp;&amp; ( ! isemptyhash($_[1][$i]) ) ) {
        $content .= join( '',
                          "&lt;TR&gt;&lt;TD valign='top' align='left' width='20%'&gt;",
                          $_[1][$i]-&gt;{'name'},
                          "&lt;/TD&gt;&lt;TD valign='top' align='left' width='80%'&gt;",
                          $_[1][$i]-&gt;{'explanation'},
                          "&lt;/TD&gt;&lt;/TR&gt;" ) ;
      }
    }
  }
  return join( '',
               "&lt;P&gt;&lt;/P&gt;&lt;TABLE BORDER='1' CELLPADDING='3' CELLSPACING='0' WIDTH='100%'&gt;",
               "&lt;THEAD&gt;",
               "&lt;TR&gt;&lt;TD CLASS='tabletitle' COLSPAN='2'&gt;&lt;B&gt;",
               $title,
               "&lt;/B&gt;&lt;/TD&gt;&lt;/TR&gt;",
               "&lt;/THEAD&gt;\n&lt;TBODY&gt;",
               $content,
               "&lt;/TBODY&gt;\n&lt;/TABLE&gt;\n\n" ) ;
}

=pod

=item * build_small_array()

Replies an small one-column array.
Takes 2 args:

=over

=item * title (string)

is the title of the array

=item * cells (array ref)

is the content of the returned cells.

=back

=cut
sub build_small_array($$) : method {
  my $self = shift ;
  my $title = $_[0] || '' ;
  my $content = '' ;
  if ( ( isarray($_[1]) ) &amp;&amp; ( ! isemptyarray($_[1]) ) ) {
    foreach my $cell (@{$_[1]}) {
      $content .= join( '',
                        "&lt;TR&gt;&lt;TD&gt;",
                        $cell,
                        "&lt;/TD&gt;&lt;/TR&gt;\n" ) ;
    }
  }
  return join( '',
               "&lt;P&gt;&lt;/P&gt;&lt;TABLE BORDER='1' CELLPADDING='3' CELLSPACING='0' WIDTH='100%'&gt;",
               "&lt;THEAD&gt;",
               "&lt;TR&gt;&lt;TD CLASS='smalltabletitle'&gt;&lt;B&gt;",
               $title,
               "&lt;/B&gt;&lt;/TD&gt;&lt;/TR&gt;",
               "&lt;/THEAD&gt;\n&lt;TBODY CLASS='smalltable'&gt;",
               $content,
               "&lt;/TBODY&gt;\n&lt;/TABLE&gt;\n\n" ) ;
}

=pod

=item * build_tiny_array()

Replies a tiny one-column array.
Takes 2 args:

=over

=item * title (string)

is the title of the array

=item * cells (array ref)

is the content of the returned cells.

=back

=cut
sub build_tiny_array($$) : method {
  my $self = shift ;
  my $title = $_[0] || '' ;
  my $content = '' ;
  if ( ( isarray($_[1]) ) &amp;&amp; ( ! isemptyarray($_[1]) ) ) {
    foreach my $cell (@{$_[1]}) {
      $content .= join( '',
                        "&lt;TR&gt;&lt;TD&gt;",
                        $cell,
                        "&lt;/TD&gt;&lt;/TR&gt;\n" ) ;
    }
  }
  return join( '',
               "&lt;P&gt;&lt;/P&gt;&lt;TABLE BORDER='1' CELLPADDING='3' CELLSPACING='0' WIDTH='100%'&gt;",
               "&lt;THEAD&gt;",
               "&lt;TR&gt;&lt;TD CLASS='tinytabletitle'&gt;&lt;B&gt;",
               $title,
               "&lt;/B&gt;&lt;/TD&gt;&lt;/TR&gt;",
               "&lt;/THEAD&gt;\n&lt;TBODY CLASS='tinytable'&gt;",
               $content,
               "&lt;/TBODY&gt;\n&lt;/TABLE&gt;\n\n" ) ;
}

=pod

=item * build_threecolumn_array()

Replies an two-column array.
Takes 3 args:

=over

=item * title (string)

is the title of the array

=item * cells (array ref)

is the content of the returned cells.

=item * anchor (string)

is the name of the anchor.

=back

=cut
sub build_threecolumn_array($$$) : method {
  my $self = shift ;
  my $title = $_[0] || '' ;
  my $content = '' ;
  if ( ( isarray($_[1]) ) &amp;&amp; ( ! isemptyarray($_[1]) ) ) {
    for(my $i=0; $i&lt;=$#{$_[1]}; $i++) {
      if ( ( ishash($_[1][$i]) ) &amp;&amp; ( ! isemptyhash($_[1][$i]) ) ) {
        $content .= join( '',
                          "&lt;TR&gt;&lt;TD valign='top' align='left'&gt;",
                          $_[1][$i]-&gt;{'type'},
                          "&lt;/TD&gt;&lt;TD WIDTH='100%' valign='top' align='left'&gt;",
                          $_[1][$i]-&gt;{'name'},
                          "&lt;BR&gt;\n",
                          $_[1][$i]-&gt;{'explanation'},
                          "&lt;/TD&gt;&lt;/TR&gt;" ) ;
      }
    }
  }
  return join( '',
               "&lt;P&gt;&lt;/P&gt;&lt;TABLE BORDER='1' CELLPADDING='3' CELLSPACING='0' WIDTH='100%'&gt;",
               "&lt;THEAD&gt;",
               "&lt;TR&gt;&lt;TD CLASS='tabletitle' COLSPAN='3'&gt;&lt;B&gt;",
               $title,
               "&lt;/B&gt;&lt;/TD&gt;&lt;/TR&gt;",
               "&lt;/THEAD&gt;\n&lt;TBODY&gt;",
               $content,
               "&lt;/TBODY&gt;\n&lt;/TABLE&gt;\n\n" ) ;
}

#------------------------------------------------------
#
# Navigation API
#
#------------------------------------------------------

=pod

=item * get_navigation_bar()

Replies the navigation bar.
Takes 3 args:

=over

=item * url (string)

is the url of the generated page.

=item * params (hash ref)

is a set of parameters used to generate the bar.

=item * root (string)

is the root directory for the generated documentation.

=back

=cut
sub get_navigation_bar($$$) : method {
  my $self = shift ;
  my $thispage = $_[0] || confess( 'the url must be provided' ) ;
  my $rootdir = $_[2] || confess( "the rootdir must be supplied" ) ;
  confess( 'params is not an associative aray' ) unless (ishash($_[1])) ;

  my $overview = "&lt;b&gt;".$self-&gt;{'LANG'}-&gt;get('I18N_LANG_OVERVIEW')."&lt;/b&gt;" ;
  my $tree = "&lt;b&gt;".$self-&gt;{'LANG'}-&gt;get('I18N_LANG_TREE')."&lt;/b&gt;" ;
  my $index = "&lt;b&gt;".$self-&gt;{'LANG'}-&gt;get('I18N_LANG_INDEX')."&lt;/b&gt;" ;
  my $newbuttons = '';

  my $prev = html_uc( $self-&gt;{'LANG'}-&gt;get('I18N_LANG_PREV') ) ;
  my $next = html_uc( $self-&gt;{'LANG'}-&gt;get('I18N_LANG_NEXT') ) ;

  if ( ! $_[1]{'overview'} ) {
    $overview = $self-&gt;ext_wt_href('overview-summary',$overview,$rootdir) ;
  }
  if ( ! $_[1]{'tree'} ) {
    $tree = $self-&gt;ext_wt_href('overview-tree',$tree,$rootdir) ;
  }
  if ( $_[1]{'index'} ) {
    $index = $self-&gt;href( htmlcatfile( $rootdir,
				       $self-&gt;filename('index',0) ),
			  $index,
			  $self-&gt;browserframe('index') ) ;
  }
  if ( $_[1]{'previous'} ) {
    $prev = $self-&gt;href($_[1]{'previous'},$prev) ;
  }
  if ( $_[1]{'next'} ) {
    $next = $self-&gt;href($_[1]{'next'},$next) ;
  }

  if ( $_[1]{'notree'} ) {
    $tree = "" ;
  }
  else {
    $tree = "&lt;td BGCOLOR=\"#EEEEFF\"&gt;&amp;nbsp;$tree&amp;nbsp;&lt;/td&gt;\n" ;
  }

  # new buttons
  if ( ( $_[1]{'userdef'} ) &amp;&amp;
       ( ! isemptyarray($_[1]-&gt;{'userdef'}) ) ) {
    foreach my $button (@{$_[1]-&gt;{'userdef'}}) {
      if ( ($button-&gt;{'url'}) &amp;&amp; ($button-&gt;{'label'}) ) {
	my $str = $self-&gt;href($button-&gt;{'url'},
			      $self-&gt;{'LANG'}-&gt;get($button-&gt;{'label'})) ;
	$newbuttons .= "&lt;td BGCOLOR=\"#EEEEFF\"&gt;&amp;nbsp;&lt;B&gt;$str&lt;/B&gt;&amp;nbsp;&lt;/td&gt;\n" ;
      }
    }
  }

  my $content = join( '',
		      "&lt;table BORDER=\"0\" WIDTH=\"100%\" ",
		      "CELLPADDING=\"1\" CELLSPACING=\"0\"&gt;\n",
		      "&lt;tr&gt;\n",
		      "&lt;td COLSPAN=2 BGCOLOR=\"#EEEEFF\"&gt;\n",
		      # First row
		      "&lt;table BORDER=\"0\" CELLPADDING=\"0\" ",
		      "CELLSPACING=\"3\"&gt;\n",
		      "&lt;tr ALIGN=\"center\" VALIGN=\"top\"&gt;\n",
		      "&lt;td BGCOLOR=\"#EEEEFF\"&gt;&amp;nbsp;$overview&amp;nbsp;&lt;/td&gt;\n",
		      $tree,
		      $newbuttons,
		      "&lt;td BGCOLOR=\"#EEEEFF\"&gt;&amp;nbsp;$index&amp;nbsp;&lt;/td&gt;\n",
		      "&lt;/tr&gt;\n&lt;/table&gt;\n",
		      "&lt;/td&gt;\n",
		      # Name of the doc
		      "&lt;td ALIGN=\"right\" VALIGN=\"top\" ROWSPAN=3&gt;&lt;em&gt;&lt;b&gt;",
		      $self-&gt;{'TITLE'},
		      "&lt;/b&gt;&lt;/em&gt;&lt;/td&gt;\n&lt;/tr&gt;\n",
		      # Second row
		      "&lt;tr&gt;\n",
		      "&lt;td BGCOLOR=\"white\"&gt;&lt;font SIZE=\"-2\"&gt;",
		      "$prev&amp;nbsp;&amp;nbsp;$next",
		      "&lt;/font&gt;&lt;/td&gt;\n",
		      "&lt;td BGCOLOR=\"white\"&gt;&lt;font SIZE=\"-2\"&gt;",
		      $self-&gt;ext_href('main_index',"&lt;b&gt;".
				      uc( $self-&gt;{'LANG'}-&gt;get('I18N_LANG_FRAMES') ).
				      "&lt;/b&gt;",$rootdir),
		      "&amp;nbsp;&amp;nbsp;",
		      $self-&gt;href($thispage,"&lt;b&gt;".
				  uc( $self-&gt;{'LANG'}-&gt;get('I18N_LANG_NO_FRAME') ).
				  "&lt;/b&gt;",
				  $self-&gt;browserframe('main_index')),
		      "&amp;nbsp;&lt;/font&gt;&lt;/td&gt;\n",
		      "&lt;/tr&gt;\n",
		      "&lt;/table&gt;\n"
		    ) ;
}

#------------------------------------------------------
#
# Filename API
#
#------------------------------------------------------

=pod

=item * copy_files()

Copies some files from the bib2html distribution directly inside the
HTML documentation tree.

=cut
sub copy_files() : method {
  my $self = shift ;
  $self-&gt;SUPER::copy_files() ;
  my @pack = File::Spec-&gt;splitdir( __FILE__ ) ;
  pop @pack ;
  push @pack, 'Dyna' ;
  foreach my $file (@{$self-&gt;{'COPY_FILES'}}) {
    Bib2HTML::General::Verbose::two( "Copying $file..." ) ;
    Bib2HTML::General::Verbose::three( "\tfrom ".File::Spec-&gt;catdir(@pack) ) ;
    Bib2HTML::General::Verbose::three( "\tto   ".$self-&gt;{'TARGET_DIR'} ) ;
    my $from = File::Spec-&gt;catfile(@pack, $file) ;
    filecopy( $from,
	      File::Spec-&gt;catfile($self-&gt;{'TARGET_DIR'},$file) )
      or Bib2HTML::General::Error::syserr( "$from: $!\n" );
  }
}

1;
__END__

=back

=head1 COPYRIGHT

(c) Copyright 2002-09 Stéphane Galland &lt;galland@arakhne.org&gt;, under GPL.

=head1 AUTHORS

=over

=item *

Conceived and initially developed by Stéphane Galland E&lt;lt&gt;galland@arakhne.orgE&lt;gt&gt;.

=back

=head1 SEE ALSO

bib2html.pl
</pre></body></html>