File Coverage

blib/lib/Ftree/FamilyTreeGraphics.pm
Criterion Covered Total %
statement 39 341 11.4
branch 0 86 0.0
condition 0 27 0.0
subroutine 13 47 27.6
pod 0 24 0.0
total 52 525 9.9


line stmt bran cond sub pod time code
1             #######################################################DWidth
2             #
3             # Family Tree generation program, v2.0
4             # Written by Ferenc Bodon and Simon Ward, March 2000 (simonward.com)
5             # Copyright (C) 2000 Ferenc Bodon, Simon K Ward
6             #
7             # This program is free software; you can redistribute it and/or
8             # modify it under the terms of the GNU General Public License
9             # as published by the Free Software Foundation; either version 2
10             # of the License, or (at your option) any later version.
11             #
12             # This program is distributed in the hope that it will be useful,
13             # but WITHOUT ANY WARRANTY; without even the implied warranty of
14             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15             # GNU General Public License for more details.
16             #
17             # For a copy of the GNU General Public License, visit
18             # http://www.gnu.org or write to the Free Software Foundation, Inc.,
19             # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20             #
21             #######################################################
22              
23              
24             package Ftree::FamilyTreeGraphics;
25 1     1   22518 use strict;
  1         3  
  1         35  
26 1     1   6 use warnings;
  1         4  
  1         43  
27              
28 1     1   731 use version; our $VERSION = qv('2.3.31');
  1         4189  
  1         7  
29              
30 1     1   710 use Ftree::FamilyTreeBase;
  1         4  
  1         7  
31              
32 1     1   201 use Params::Validate qw(:all);
  1         2  
  1         213  
33 1     1   5 use List::Util qw(first max);
  1         2  
  1         98  
34 1     1   6 use List::MoreUtils qw(first_index);
  1         2  
  1         12  
35 1     1   547 use CGI::Carp qw(fatalsToBrowser warningsToBrowser);
  1         1  
  1         9  
36 1     1   96 use Sub::Exporter -setup => { exports => [ qw(new main) ] };
  1         2  
  1         9  
37 1     1   383 use utf8;
  1         2  
  1         4  
38 1     1   31 use Encode qw(decode_utf8);
  1         2  
  1         34  
39 1     1   550 use Ftree::Picture;
  1         2  
  1         75  
40              
41              
42              
43             #######################################################
44             #
45             # The HTML output table is generated in three parts:
46             # - the Ancestor tree (ATree)
47             # - the peer level (peers)
48             # - the Descendant tree (DTree)
49             #
50             #
51             #######################################################
52              
53 1     1   6 use base 'Ftree::FamilyTreeBase';
  1         2  
  1         5051  
54             sub new{
55 0     0 0   my $type = shift;
56 0           my $self = $type->SUPER::new(@_);
57 0           $self->{target_person} = undef;
58 0           $self->{DLevels} = 0; # nr of levels in DTree
59 0           $self->{cellwidth} = undef; # width of a cell
60 0           $self->{gridWidth} = undef; # width of the tree
61 0           $self->{fontsize} = undef;
62            
63 0           return $self;
64             }
65              
66             sub main{
67 0     0 0   my ($self) = validate_pos(@_, HASHREF);
68 0           $self->_process_parameters();
69            
70             $Person::unknown_male->set_default_picture(Picture->new(
71 0           {file_name => $self->{graphicsUrl} . '/nophoto_m.jpg',
72             comment => ""}));
73             $Person::unknown_female->set_default_picture(Picture->new(
74 0           {file_name => $self->{graphicsUrl} . '/nophoto_f.jpg',
75             comment => ""}));
76            
77 0           $self->_target_check();
78 0           $self->set_size();
79 0           $self->_password_check();
80            
81 0 0         if ( $self->{reqLevels} > 0 ) {
82 0           $self->_draw_familytree_page();
83             }
84             else {
85 0           my $address = $self->{cgi}->url(-relative=>0);
86 0           $address =~ s/$self->{treeScript}/$self->{personScript}/xm;
87             $address .= "?target=".$self->{target_person}->get_id()
88 0           .";lang=".$self->{lang};
89 0           print $self->{cgi}->redirect($address);
90             }
91            
92 0           return;
93             }
94              
95             #######################################################
96             # processing the parameters (type and passwd)
97             sub _process_parameters {
98 0     0     my ($self) = validate_pos(@_, HASHREF);
99 0           $self->SUPER::_process_parameters();
100 0           my $id = decode_utf8(CGI::param('target'));
101             my $family_tree_data =
102 0           Ftree::FamilyTreeDataFactory::getFamilyTree( $self->{settings}{data_source} );
103 0           $self->{target_person} = $family_tree_data->get_person($id);
104 0           $self->{reqLevels} = CGI::param('levels');
105 0 0         $self->{reqLevels} = 2 unless ( defined $self->{reqLevels} );
106            
107 0           return;
108             }
109              
110             #######################################################
111             # check if target person exists in database
112             sub _target_check {
113 0     0     my ($self) = validate_pos(@_, HASHREF);
114 0 0         if ( !defined $self->{target_person} ) {
115 0           my $title = $self->{textGenerator}->noDataAbout( CGI::param('target') );
116 0           $self->_toppage($title);
117 0           print $self->{cgi}->br, $title, $self->{cgi}->br, "\n";
118 0           $self->_endpage();
119 0           exit 1;
120             }
121              
122 0           return;
123             }
124              
125             #######################################################
126             # Size the output according to the no. levels being displayed
127             sub set_size {
128 0     0 0   my ($self) = validate_pos(@_, HASHREF);
129 0 0         if ( $self->{reqLevels} > 3 ) {
    0          
    0          
    0          
    0          
130 0           $self->{imgwidth} = 45;
131 0           $self->{fontsize} = 1;
132             }
133             elsif ( $self->{reqLevels} == 3 ) {
134 0           $self->{imgwidth} = 60;
135 0           $self->{fontsize} = 2;
136             }
137             elsif ( $self->{reqLevels} == 2 ) {
138 0           $self->{imgwidth} = 90;
139 0           $self->{fontsize} = 3;
140             }
141             elsif ( $self->{reqLevels} == 1 ) {
142 0           $self->{imgwidth} = 110;
143 0           $self->{fontsize} = 2;
144             }
145             elsif ( $self->{reqLevels} == 0 ) {
146 0           $self->{imgwidth} = 240;
147 0           $self->{fontsize} = 2;
148             }
149             else {
150 0           $self->{cellwidth} = 70;
151 0           $self->{imgwidth} = 60;
152 0           $self->{fontsize} = 2;
153             }
154 0           $self->{cellwidth} = "100%";
155 0           $self->{imgheight} = $self->{imgwidth} * 1.5;
156            
157 0           return;
158             }
159              
160             sub html_img {
161 0     0 0   my ( $self, $person ) = validate_pos(@_, HASHREF, SCALARREF);
162            
163 0           my $img = $self->SUPER::html_img($person);
164             return ($person == $self->{target_person} ||
165 0 0 0       $person == $Person::unknown_male ||
166             $person == $Person::unknown_female ) ? $img : $self->aref_tree($img, $person);
167             }
168              
169             sub img_graph {
170 0     0 0   my ( $self, $graphics ) = validate_pos(@_, HASHREF, SCALAR, 0);
171             return $self->{cgi}->img(
172             {
173             -width => $self->{cellwidth},
174 0           -height=> "26",
175             -src => "$self->{graphicsUrl}/".$graphics.".gif",
176             -alt => "",
177             } );
178             }
179             sub hone_img_graph {
180 0     0 0   my ( $self ) = validate_pos(@_, HASHREF, 0);
181 0           return $self->img_graph('hone');
182             }
183             sub getATreeWidth {
184 0     0 0   my ( $self, $levels ) = validate_pos(@_, HASHREF, SCALAR, 0);
185 0           return 2**( $levels );
186             }
187             #######################################################
188             # returns the width of tree below this person
189             # root_person: this person
190             # levels: no. of levels to descend in tree
191             sub getDTreeWidth {
192 0     0 0   my ( $self, $levels, $root_person ) = validate_pos(@_,
193             HASHREF, SCALAR, SCALARREF );
194              
195             # carp "called: getDTreeWidth with \$root_person = " . $root_person->get_name()->get_long_name() . ", \$levels = $levels";
196              
197 0 0         return 1 if ( 0 == $levels);
198 0 0 0       return 1 if ($root_person == $Person::unknown_male ||
199             $root_person == $Person::unknown_female);
200 0 0         return 1 unless defined $root_person->get_children();
201            
202 0           my $width = 0;
203             $width += $self->getDTreeWidth( $levels - 1, $_ )
204 0           for ( @{ $root_person->get_children() } );
  0            
205 0           return $width;
206             }
207              
208             #######################################################
209             # returns the no. levels available in Ancestor tree
210             # above this person
211             # root_person: this person
212             # anc_level: current level of ancestor tree (0=root_node)
213             # req_levels: no. levels requested
214             sub getATreeLevels {
215 0     0 0   my ( $self, $root_person, $anc_level, $req_levels ) = validate_pos(@_,
216             HASHREF, {type => SCALARREF|UNDEF}, SCALAR, SCALAR );
217              
218             # print "called: getATreeLevels (root_node=$root_person->get_name()->get_full_name(), anc_level=$anc_level, req_levels=$req_levels)\n";
219 0 0         return 0 if ( $req_levels == 0 );
220 0 0         return $anc_level unless defined $root_person;
221 0 0 0       return $anc_level unless ( defined $root_person->get_father() ||
222             defined $root_person->get_mother());
223 0 0         return $anc_level if($anc_level == $req_levels );
224            
225 0           my $p1_levels = $self->getATreeLevels( $root_person->get_father(),
226             $anc_level + 1, $req_levels );
227 0           my $p2_levels = $self->getATreeLevels( $root_person->get_mother(),
228             $anc_level + 1, $req_levels );
229 0           return List::Util::max($p1_levels, $p2_levels);
230             }
231              
232             #######################################################
233             # populate the Descendant Tree structure for all
234             # people below the person specified
235             # $root_person: this person
236             # dec_level: current level of descendant tree (0=root_node)
237             # req_levels: no. levels requested
238             sub fillDTree {
239 0     0 0   my ( $self, $root_person, $dec_level, $req_levels, $DTree_ref ) = validate_pos(@_,
240             HASHREF, SCALARREF, SCALAR, SCALAR, ARRAYREF );
241              
242             # print "called: fillDTree (root_node=$root_node_id, dec_level=$dec_level, req_levels=$req_levels)\n";
243 0           $dec_level++;
244              
245 0 0 0       if ( $root_person != $Person::unknown_male
      0        
246             && $root_person != $Person::unknown_female
247             && defined $root_person->get_children() ) {
248 0           push @{ $DTree_ref->[$dec_level] }, @{$root_person->get_children()};
  0            
  0            
249 0 0         $self->{DLevels} = $dec_level if ( $dec_level > $self->{DLevels} );
250             }
251             else {
252 0           push @{ $DTree_ref->[$dec_level] }, $Person::unknown_female;
  0            
253             }
254            
255 0 0         if ( $dec_level < $req_levels ) {
256 0 0         if(defined $root_person->get_children()) {
257             $self->fillDTree( $_, $dec_level, $req_levels, $DTree_ref )
258 0           for ( @{ $root_person->get_children() } );
  0            
259             }
260             else {
261 0           $self->fillDTree( $Person::unknown_female, $dec_level, $req_levels, $DTree_ref );
262             }
263             }
264            
265 0           return;
266             }
267              
268             sub putNTD {
269 0     0 0   my ( $self, $n, $data ) = validate_pos(@_,
270             HASHREF, SCALAR, {type => SCALAR, default => ""} );
271 0           print $self->{cgi}->td($data), "\n" for (1 .. $n);
272              
273 0           return;
274             }
275             sub drawRow {
276 0     0 0   my ( $self, $used_width, $people, $diff_levels, $this_level,
277             $left_fill, $emptyTDCond, $group_width_func, $display_func ) = validate_pos(@_,
278             HASHREF, SCALAR, ARRAYREF, {type => SCALAR|UNDEF},
279             {type => SCALAR|UNDEF}, SCALAR, CODEREF, CODEREF, CODEREF );
280 0           my $right_fill = $self->{gridWidth} - $used_width - $left_fill;
281 0           my $is_blank_line = 1;
282              
283 0           print $self->{cgi}->start_Tr, "\n";
284 0           $self->putNTD($left_fill);
285 0           foreach my $person (@{$people}) {
  0            
286 0           my $group_width = $group_width_func->($self, $diff_levels, $person);
287 0           my $left = int( ( $group_width - 1 ) / 2 );
288 0           my $right = $group_width - 1 - $left;
289            
290 0           $self->putNTD($left);
291 0 0         if ( $emptyTDCond->($self, $person, $this_level) ) {
292 0           print $self->{cgi}->td(), "\n";
293             }
294             else {
295 0           print $self->{cgi}->td( {-align => "center" },
296             $display_func->($self, $person) );
297 0           $is_blank_line = 0;
298             }
299 0           $self->putNTD($right);
300             }
301 0           $self->putNTD($right_fill);
302 0           print $self->{cgi}->end_Tr, "\n";
303            
304 0           return $is_blank_line;
305             }
306             sub unknownEquiCond {
307 0     0 0   my ( $self, $person ) = validate_pos(@_, HASHREF, SCALARREF, 0 );
308 0   0       return $person == $Person::unknown_male || $person == $Person::unknown_female;
309             }
310             sub unknownEquiNoChildrenCond {
311 0     0 0   my ( $self, $person, $this_level ) = validate_pos(@_,
312             HASHREF, SCALARREF, SCALAR );
313             return $person == $Person::unknown_female ||
314             $person == $Person::unknown_male ||
315             ! defined $person->get_children() ||
316 0   0       ( $this_level == $self->{reqLevels} );
317             }
318             sub falseCond {
319 0     0 0   return 0;
320             }
321             #######################################################
322             # generate a line of the D-tree graphics OVER the
323             # level specified
324             # this_level: level of grid to generate
325             # max_levels: max depth that will be shown
326             sub getDGridLineG {
327 0     0 0   my ( $self, $this_level, $max_levels, $DWidth, $DTree_ref ) = validate_pos(@_,
328             HASHREF, SCALAR, SCALAR, SCALAR, ARRAYREF );
329             # print "called: getDGridLineG (this_level = $this_level, max_levels = $max_levels)\n";
330              
331 0           my ( $left_fill, $branch, $right_fill );
332 0           my $lefto_fill = int( ( $self->{gridWidth} - $DWidth ) / 2 );
333 0           my $righto_fill = $self->{gridWidth} - $DWidth - $lefto_fill;
334              
335             # Spacers on LHS - fills gap between overall grid width and width of Dgrid
336 0           print $self->{cgi}->start_Tr, "\n";
337 0           $self->putNTD($lefto_fill);
338              
339 0 0         if ( @{ $DTree_ref->[$this_level] } == 0 ) {
  0            
340 0           printf '|;';
341             }
342             else {
343 0           foreach my $person (@{ $DTree_ref->[$this_level] }) {
  0            
344             # Find which parent is in the level above...
345 0           my $this_parent;
346              
347 0 0         if ( 1 == $this_level ) {
348 0           $this_parent = $self->{target_person};
349             } else {
350 0     0     $this_parent = List::Util::first {$_ == $person->get_father()}
351 0 0         @{ $DTree_ref->[$this_level - 1] }
  0            
352             if(defined $person->get_father());
353 0     0     $this_parent = List::Util::first {$_ == $person->get_mother()}
354 0 0         @{ $DTree_ref->[$this_level - 1] }
  0            
355             unless( defined $this_parent);
356             }
357              
358 0 0         if ( $person == $Person::unknown_female ) {
    0          
    0          
    0          
359             # This blank person
360 0           $left_fill = $branch = $right_fill = "";
361             }
362 0           elsif ( 1 == @{$this_parent->get_children() } )
363             {
364             # This person is an only child
365 0           $left_fill = $right_fill = "";
366 0           $branch = $self->img_graph('hone');
367             }
368             elsif ( $person == $this_parent->get_children()->[0] )
369             {
370             # Is this person the first child of this parent?
371 0           $left_fill = "";
372 0           $branch = $self->img_graph('hleft');
373 0           $right_fill = $self->img_graph('hblank');
374             }
375             elsif ( $person == $this_parent->get_children()->[-1] )
376             {
377             # Is this person the last child of this parent?
378 0           $left_fill = $self->img_graph('hblank');
379 0           $branch = $self->img_graph('hright');
380 0           $right_fill = "";
381             }
382             else {
383 0           $left_fill = $right_fill = $self->img_graph('hblank');
384 0           $branch = $self->img_graph('hbranch');
385             }
386            
387 0           my $group_width = $self->getDTreeWidth( $max_levels - $this_level, $person );
388 0           my $left = int( ( $group_width - 1 ) / 2 );
389 0           my $right = $group_width - 1 - $left;
390              
391 0           $self->putNTD( $left, $left_fill );
392 0           print $self->{cgi}->td($branch);
393 0           $self->putNTD( $right, $right_fill );
394             }
395             }
396              
397             # Spacers on RHS - fills gap between overall grid width and width of Dgrid
398 0           $self->putNTD($righto_fill);
399 0           print $self->{cgi}->end_Tr, "\n";
400            
401 0           return;
402             }
403              
404             #######################################################
405             # build A-tree for this person
406             # root_node: this person
407             # anc_level: current level of ancestor tree (0=root node)
408             # req_levels: no. levels requested
409             sub fillATree {
410 0     0 0   my ( $self, $root_person, $anc_level, $req_levels, $ATree_ref ) =
411             validate_pos(@_, HASHREF, {type => SCALARREF|UNDEF},
412             SCALAR, SCALAR, ARRAYREF );
413              
414 0 0         return unless $anc_level < $req_levels;
415             # print "called: fillATree (root_node = $root_person, anc_level = $anc_level, req_levels = $req_levels)\n";
416            
417 0 0         my $father = defined $root_person->get_father() ?
418             $root_person->get_father() : $Person::unknown_male;
419            
420 0 0         my $mother = defined $root_person->get_mother() ?
421             $root_person->get_mother() : $Person::unknown_female;
422            
423 0           push @{ $ATree_ref->[$anc_level] }, ($father, $mother);
  0            
424              
425 0           $anc_level++;
426 0           $self->fillATree( $father, $anc_level, $req_levels, $ATree_ref );
427 0           $self->fillATree( $mother, $anc_level, $req_levels, $ATree_ref );
428            
429 0           return;
430             }
431              
432             #######################################################
433             # draw the graphics UNDER the level specified
434             # this_level: level of grid to generate
435             # max_levels: max depth that will be shown
436             sub getAGridLineG {
437 0     0 0   my ( $self, $diff_levels, $AWidth, $aRow ) = validate_pos(@_,
438             HASHREF, SCALAR, SCALAR, ARRAYREF);
439              
440 0 0         return if ( 0 > $diff_levels );
441              
442 0           my $left_fill = int( ( $self->{gridWidth} - $AWidth + 1 ) / 2 );
443 0           my $right_fill = $self->{gridWidth} - $AWidth - $left_fill;
444              
445 0           print $self->{cgi}->start_Tr, "\n";
446 0           $self->putNTD($left_fill);
447            
448 0           my $node_width = 2**$diff_levels ;
449 0           my $nodel_fill = int( ( $node_width - 1 ) / 2 );
450 0           my $noder_fill = $node_width - 1 - $nodel_fill;
451            
452 0           for ( my $index = 0; $index < @$aRow; $index += 2 )
453             {
454 0           $self->putNTD($nodel_fill);
455 0           print $self->{cgi}->td( $self->img_graph("hleftup")),"\n";
456 0           $self->putNTD( $node_width - 1, $self->img_graph("hblankup") );
457 0           print $self->{cgi}->td( $self->img_graph("hrightup") ), "\n";
458 0           $self->putNTD($noder_fill);
459             }
460              
461 0           $self->putNTD($right_fill);
462 0           print $self->{cgi}->end_Tr, "\n";
463              
464 0           print $self->{cgi}->start_Tr, "\n";
465 0           $self->putNTD($left_fill);
466              
467 0           for ( my $index = 0 ; $index < @$aRow; $index += 2 )
468             {
469 0           $self->putNTD( $node_width - 1 );
470 0           print $self->{cgi}->td( $self->img_graph("hone") ), "\n";
471 0           $self->putNTD($node_width);
472             }
473            
474 0           $self->putNTD($right_fill);
475 0           print $self->{cgi}->end_Tr, "\n";
476            
477 0           return;
478             }
479              
480             #######################################################
481             sub buildDGrid {
482 0     0 0   my ($self, $DWidth, $DTree_ref) = validate_pos(@_, HASHREF, SCALAR, ARRAYREF);
483              
484 0           my $left_fill = int( ( $self->{gridWidth} - $DWidth ) / 2 );
485            
486 0           for my $this_level (1 .. $self->{DLevels}) {
487 0           $self->getDGridLineG( $this_level, $self->{reqLevels}, $DWidth, $DTree_ref );
488              
489 0           my $is_blank_line = $self->drawRow($DWidth, \@{ $DTree_ref->[$this_level] },
490 0           $self->{reqLevels} - $this_level, $this_level, $left_fill,
491             \&unknownEquiCond, \&getDTreeWidth, \&Ftree::FamilyTreeGraphics::html_img);
492            
493 0           $self->drawRow($DWidth, \@{ $DTree_ref->[$this_level] },
494 0           $self->{reqLevels} - $this_level, $this_level, $left_fill,
495             \&unknownEquiCond, \&getDTreeWidth, \&html_name);
496            
497 0           $self->drawRow($DWidth, \@{ $DTree_ref->[$this_level] },
498 0           $self->{reqLevels} - $this_level, $this_level, $left_fill,
499             \&unknownEquiNoChildrenCond, \&getDTreeWidth, \&hone_img_graph);
500            
501 0 0         $self->{DLevels} = $this_level - 1 if ( $is_blank_line );
502             }
503            
504 0           return;
505             }
506              
507             #######################################################
508             sub buildDestroyAGrid {
509 0     0 0   my ( $self, $ATree_ref ) = validate_pos(@_, {type => HASHREF}, ARRAYREF);
510             #printf "calling: getAGridLine \n";
511              
512 0           my $aLevel = @$ATree_ref;
513 0           my $AWidth = 2 ** $aLevel;
514 0           --$aLevel;
515 0           my $left_fill = int( ( $self->{gridWidth} - $AWidth + 1 ) / 2 );
516            
517 0           for ( my $this_level = $aLevel; $this_level >= 0 ; --$this_level ) {
518 0           my $aRow = pop @$ATree_ref;
519 0           $self->drawRow($AWidth, $aRow, $aLevel - $this_level, $this_level, $left_fill,
520             \&falseCond, \&getATreeWidth , \&Ftree::FamilyTreeGraphics::html_img);
521            
522 0           $self->drawRow($AWidth, $aRow, $aLevel - $this_level, $this_level, $left_fill,
523             \&falseCond, \&getATreeWidth, \&html_name);
524            
525 0           $self->getAGridLineG( $aLevel - $this_level, $AWidth, $aRow );
526             }
527              
528             #printf "buildAGrid returns";
529 0           return;
530             }
531              
532             #######################################################
533             sub buildPGrid {
534 0     0 0   my ($self, $PWidth) = validate_pos(@_, {type => HASHREF}, SCALAR);
535            
536 0           my @peers = $self->{target_person}->get_peers( );
537              
538 0     0     my $left_side = List::MoreUtils::first_index {$_ == $self->{target_person}} @peers;
  0            
539 0           my $left_fill = int(( $self->{gridWidth} - 1 ) / 2 ) - $left_side;
540 0           my $right_fill = $self->{gridWidth} - $PWidth - $left_fill;
541              
542              
543 0           print $self->{cgi}->start_Tr, "\n";
544 0           $self->putNTD($left_fill);
545              
546 0 0         if ( @peers > 1 ) {
547 0           print $self->{cgi}->td( $self->img_graph("hleft") ), "\n";
548 0           $self->putNTD($#peers - 1, $self->img_graph("hbranch"));
549 0           print $self->{cgi}->td( $self->img_graph("hright") ), "\n";
550             }
551             else {
552 0           print $self->{cgi}->td( $self->img_graph("hone") ), "\n";
553             }
554 0           $self->putNTD($right_fill);
555 0           print $self->{cgi}->end_Tr, "\n";
556              
557             $self->drawRow($PWidth, \@peers,
558             undef, undef, $left_fill,
559 0     0     \&falseCond, sub {return 1} , \&Ftree::FamilyTreeGraphics::html_img);
  0            
560            
561             $self->drawRow($PWidth, \@peers,
562             undef, undef, $left_fill,
563 0     0     \&falseCond, sub {return 1} , \&Ftree::FamilyTreeGraphics::html_name);
  0            
564              
565 0 0         if ( defined $self->{target_person}->get_children() ) {
566 0           print $self->{cgi}->start_Tr, "\n";
567 0           my $gridLeft = int( ( $self->{gridWidth} - 1 ) / 2 );
568 0           my $gridRight = $self->{gridWidth} - 1 - $gridLeft;
569 0           $self->putNTD($gridLeft);
570 0           print $self->{cgi}->td( $self->img_graph("hone") ), "\n";
571 0           $self->putNTD($gridRight);
572 0           print $self->{cgi}->end_Tr, "\n";
573             }
574              
575 0           return;
576             }
577              
578             #######################################################
579             # find the width of the peer line
580             # (allowing for the fact that it may be off-centre)
581             sub getPTreeWidth {
582 0     0 0   my ($self) = validate_pos(@_, {type => HASHREF});
583            
584 0           my @peers = $self->{target_person}->get_peers( );
585 0     0     my $node_pos = List::MoreUtils::first_index {$_ == $self->{target_person}} @peers;
  0            
586            
587 0           my $right_side = $#peers - $node_pos;
588 0           my $big_side = List::Util::max ($node_pos, $right_side );
589 0           return $big_side * 2 + 1;
590             }
591              
592             #######################################################
593             # generates the html for the name of this person
594             sub html_name {
595 0     0 0   my ( $self, $person ) = validate_pos(@_, {type => HASHREF}, {type => SCALARREF});
596             return $self->{cgi}->font({-size => $self->{fontsize}}, $self->{textGenerator}{Unknown})
597 0 0 0       if ( !defined $person || $person == $Person::unknown_male || $person == $Person::unknown_female );
      0        
598 0           my $show_name;
599 0 0         if(defined $person->get_name()) {
600 0 0         $show_name = ( $self->{reqLevels} > 1 ) ?
601             $person->get_name()->get_first_name() : $person->get_name()->get_short_name();
602             } else {
603 0           $show_name = $self->{textGenerator}{Unknown};
604             }
605 0 0         if ( $person == $self->{target_person} ) {
606 0           return $self->{cgi}->strong($self->{cgi}->font({-size => $self->{fontsize}}, $show_name));
607             }
608             else {
609 0           return $self->{cgi}->font({-size => $self->{fontsize}}, $self->aref_tree($show_name, $person));
610             }
611             }
612              
613              
614             sub print_zoom_buttons {
615 0     0 0   my ( $self, $aLevels ) = validate_pos(@_, {type => HASHREF}, SCALAR);
616 0           my $lev_minus1 = $self->{reqLevels} - 1;
617              
618             print $self->{cgi}->start_table(
619             { -border => "0", -cellpadding => "0", -cellspacing => "2" } ), "\n",
620 0           $self->{cgi}->start_Tr;
621 0 0         if ( $lev_minus1 >= 0 ) {
622             print $self->{cgi}->start_td({-align => "center"}), "\n",
623             $self->aref_tree($self->{cgi}->img( {
624             -src => "$self->{graphicsUrl}/zoomin.gif",
625             -alt => $self->{textGenerator}->ZoomIn($lev_minus1) }), $self->{target_person}, $lev_minus1),
626 0           $self->{cgi}->end_td, "\n";
627             }
628            
629 0 0         if( $self->{reqLevels} <= $aLevels ) {
630 0           my $lev_plus1 = $self->{reqLevels} + 1;
631             print $self->{cgi}->start_td({-align => "center"}), "\n",
632             $self->aref_tree($self->{cgi}->img( {
633             -src => "$self->{graphicsUrl}/zoomout.gif",
634             -alt => $self->{textGenerator}->ZoomOut($lev_plus1) }), $self->{target_person}, $lev_plus1),
635 0           $self->{cgi}->end_td;
636             }
637             print $self->{cgi}->end_Tr, "\n",
638 0           $self->{cgi}->end_table, $self->{cgi}->br, $self->{cgi}->br, "\n";
639            
640 0           return;
641             }
642             #########################################################
643             # OUTPUT SECTION #
644             #########################################################
645             sub _draw_start_page {
646 0     0     my ( $self, $aLevels ) = validate_pos(@_, {type => HASHREF}, SCALAR);
647              
648             # header html for page
649             my $title = $self->{textGenerator}->familyTreeFor(
650             defined $self->{target_person}->get_name() ? # He may have id but not any name
651             $self->{target_person}->get_name()->get_full_name():
652 0 0         $self->{textGenerator}->{Unknown});
653 0           $self->_toppage($title);
654              
655             # Zoom buttons
656 0           print $self->{cgi}->start_center, "\n";
657 0           $self->print_zoom_buttons($aLevels);
658              
659 0           return;
660             }
661              
662             sub _draw_familytree_page {
663 0     0     my ($self) = @_;
664              
665 0           my $aLevels = $self->getATreeLevels( $self->{target_person}, 0, $self->{reqLevels} );
666 0           my $AWidth = 2 ** $aLevels;
667 0           my $PWidth = $self->getPTreeWidth();
668 0           my $DWidth = $self->getDTreeWidth( $self->{reqLevels}, $self->{target_person} );
669              
670 0           $self->{gridWidth} = List::Util::max( $AWidth, $PWidth, $DWidth );
671              
672             # fill the grid
673 0           my @ATree;
674 0           $self->fillATree( $self->{target_person}, 0, $aLevels, \@ATree );
675 0           my @DTree;
676 0           $self->fillDTree( $self->{target_person}, 0, $self->{reqLevels}, \@DTree );
677              
678              
679 0           $self->_draw_start_page(List::Util::max($aLevels, $self->{DLevels}));
680              
681              
682             # Draw the grid
683             print $self->{cgi}->start_table(
684 0           { -border => "0", -cellpadding => "0", -cellspacing => "0" } ), "\n";
685 0           $self->buildDestroyAGrid(\@ATree);
686 0           $self->buildPGrid($PWidth);
687 0           $self->buildDGrid($DWidth, \@DTree);
688 0           print $self->{cgi}->end_table, "\n", $self->{cgi}->end_center, "\n";
689              
690              
691 0           $self->_endpage();
692 0           return;
693             }
694              
695             1;
696