########################################################################### # # ExpediteeFrameIO.pm -- # A component of the Greenstone digital library software # from the New Zealand Digital Library Project at the # University of Waikato, New Zealand. # # Copyright (C) 2009 New Zealand Digital Library Project # # This program is free software; you can redistr te 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; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # ########################################################################### package ExpediteeFrameIO; use strict; use CssStyleToExpAttr; sub new { my $class = shift(@_); my $output_dir = shift(@_); my $username = shift(@_) || "greenstone"; my $self = { 'items' => [], 'lines' => [], 'constraints' => [] }; $self->{'output_dir'} = $output_dir; $self->{'username'} = $username; return bless $self, $class; } sub getFormattedDate { my ($opt_mode) = @_; my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); my @mabbr = qw( Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec ); $year += 1900; my $fdate; if ((defined $opt_mode) && ($opt_mode eq "highPrecision")) { $fdate = sprintf("%02d%s%04d[%02d:%0d2.%02d]", $mday, $mabbr[$mon],$year,$hour,$min,$sec); } else { $fdate = sprintf("%02d%s%04d[%02d:%0d2]", $mday, $mabbr[$mon],$year,$hour,$min); } return $fdate; } sub convertStyleToAttr { my ($css_attr) = @_; my $exp_attr = {}; # load up some defaults for font information my $exp_font_family = "s"; # t my $exp_font_face = "r"; my $exp_font_size = "18"; # if (defined $css_attr->{'font-family'}) { # $font_family = $font_family_lookup->[$css_attr->{'font-family'}]; # } if (defined $css_attr->{'font-size'}) { my $css_font_size = $css_attr->{'font-size'}; $exp_font_size = CssStyleToExpAttr::convert_font_size($css_font_size); } if(defined $css_attr->{'font-family'}){ my $obtain_font_family = $css_attr->{'font-family'}; my $new_exp_font_family = CssStyleToExpAttr::convert_font_family($obtain_font_family); if(defined $new_exp_font_family){ $exp_font_family = $new_exp_font_family; } } my $css_font_style; my $css_font_face; if(defined $css_attr->{'font-style'}){ $css_font_style = $css_attr->{'font-style'}; $exp_font_face = CssStyleToExpAttr::convert_font_face($css_font_style); } if(defined $css_attr->{'font-weight'}){ $css_font_face = $css_attr->{'font-weight'}; $exp_font_face = CssStyleToExpAttr::convert_font_face($css_font_face); } if(defined $css_attr->{'font-style'} && defined $css_attr->{'font-weight'}){ my $font_face_param = $css_attr->{'font-weight'}.'-'.$css_attr->{'font-style'}; $exp_font_face = CssStyleToExpAttr::convert_font_face($font_face_param); } $exp_attr->{'f'} = $exp_font_family.$exp_font_face.$exp_font_size; # background color if (defined $css_attr->{'background-color'}) { my $css_color = $css_attr->{'background-color'}; my $exp_color = CssStyleToExpAttr::convert_color($css_color); $exp_attr->{'e'} = $exp_color; } return $exp_attr; } sub _nextFreeId { my $self = shift @_; my $items = $self->{'items'}; my $lines = $self->{'lines'}; my $constraints = $self->{'constraints'}; # Ids start at base of 1 return 1+(scalar(@$items) + scalar(@$lines) + scalar(@$constraints)); } sub _addItem { my $self = shift @_; my ($type,$attr) = @_; # By this point 'attr' is synonymous with being an item my $items = $self->{'items'}; my $next_free_id = $self->_nextFreeId(); $attr->{'_type'} = $type; $attr->{'_id'} = $next_free_id; push(@$items,$attr); return ($attr,$next_free_id); } sub _setBaseDefaultAttributes { my $self = shift @_; my ($attr) = @_; $attr->{'o'} = $self->{'username'}; $attr->{'s'} = getFormattedDate("highPrecision"); $attr->{'Q'} = "0"; # gradient $attr->{'v'} = "S"; # dot type } sub setPointDefaultAttributes { my $self = shift @_; my ($attr) = @_; $self->_setBaseDefaultAttributes($attr); } sub setTextDefaultAttributes { my $self = shift @_; my ($attr) = @_; $self->_setBaseDefaultAttributes($attr); if(defined $attr->{'d'}){ } else { $attr->{'d'} = "0 0 0"; # black color } } sub setRectPointDefaultAttributes { my $self = shift @_; my ($attr) = @_; $self->setPointDefaultAttributes($attr); if((defined $attr->{'d'}) && (defined $attr->{'h'})){ } else { $attr->{'d'} = "80 80 80"; # grey color for rect lines $attr->{'h'} = "1.0"; # line thickness } } sub addRectPoint { my $self = shift @_; my ($x, $y, $attr) = @_; my %attr_copy = %$attr; # make a private copy of 'attr' $self->setRectPointDefaultAttributes(\%attr_copy); my $items = $self->{'items'}; $attr_copy{'P'} = "$x $y"; return $self->_addItem("P",\%attr_copy); } sub addText { my $self = shift @_; my ($x,$y,$text,$w,$attr) = @_; my %attr_copy = %$attr; #make a private copy of 'attr' $self->setTextDefaultAttributes(\%attr_copy); my $items = $self->{'items'}; $attr_copy{'P'} = "$x $y"; $attr_copy{'T'} = $text; $attr_copy{'w'} = "-$w" if (defined $w); return $self->_addItem("T",\%attr_copy); } sub addLine { my $self = shift @_; my ($item_id1,$item_id2) = @_; my $lines = $self->{'lines'}; my $line_type = 1; my $next_free_id = $self->_nextFreeId(); my $attr = { 'L' => "$next_free_id $line_type" }; $attr->{'s'} = "$item_id1 $item_id2"; push(@$lines,$attr); return ($attr,$next_free_id); } sub addConstraint { my $self = shift @_; my ($orientation,$item_id1,$item_id2) = @_; my $constraints = $self->{'constraints'}; my $orientation_type = undef; if ($orientation eq "vertical") { $orientation_type = 2; } else { # assume horizontal for now $orientation_type = 3; } my $next_free_id = $self->_nextFreeId(); my $attr = { 'C' => "$next_free_id $orientation_type" }; $attr->{'s'} = "$item_id1 $item_id2"; push(@$constraints,$attr); return ($attr,$next_free_id); } sub addRect { my $self = shift @_; my ($xl, $yt, $xr, $yb, $attr) = @_; # do point in same order Expeditee puts them in my ($p_tr,$p_tr_id) = $self->addRectPoint($xr,$yt,$attr); my ($p_tl,$p_tl_id) = $self->addRectPoint($xl,$yt,$attr); my ($p_bl,$p_bl_id) = $self->addRectPoint($xl,$yb,$attr); my ($p_br,$p_br_id) = $self->addRectPoint($xr,$yb,$attr); my ($l_t,$l_t_id) = $self->addLine($p_tr_id,$p_tl_id); my ($l_l,$l_l_id) = $self->addLine($p_tl_id,$p_bl_id); my ($l_b,$l_b_id) = $self->addLine($p_bl_id,$p_br_id); my ($l_r,$l_r_id) = $self->addLine($p_br_id,$p_tr_id); my ($c_t,$c_t_id) = $self->addConstraint("horizontal",$p_tr_id,$p_tl_id); my ($c_l,$c_l_id) = $self->addConstraint("vertical" ,$p_tl_id,$p_bl_id); my ($c_b,$c_b_id) = $self->addConstraint("horizontal",$p_bl_id,$p_br_id); my ($c_r,$c_r_id) = $self->addConstraint("vertical" ,$p_br_id,$p_tr_id); $p_tr->{'l'} = "$l_t_id $l_r_id"; $p_tl->{'l'} = "$l_t_id $l_l_id"; $p_bl->{'l'} = "$l_l_id $l_b_id"; $p_br->{'l'} = "$l_b_id $l_r_id"; $p_tr->{'c'} = "$c_t_id $c_r_id"; $p_tl->{'c'} = "$c_t_id $c_l_id"; $p_bl->{'c'} = "$c_l_id $c_b_id"; $p_br->{'c'} = "$c_b_id $c_r_id"; } sub writeHeaderSection { my $self = shift @_; # Example header: # V 1 # p 4 # U davidb # D 09Jan2012[13:33] # M davidb # d 09Jan2012[13:33] # Z # # Legend: # V = version # p = permision level # U = username (owner) # M = last modified by # D, d = date information # Z => end of section my $username = $self->{'username'}; my $fdate = getFormattedDate(); print FOUT "V 1\n"; print FOUT "p 4\n"; print FOUT "U $username\n"; print FOUT "D $fdate\n"; print FOUT "M $username\n"; print FOUT "d $fdate\n"; print FOUT "Z\n\n"; } sub writeItemsSection { my $self = shift @_; my $items = $self->{'items'}; foreach my $item (@$items) { my $type = delete $item->{'_type'}; my $id = delete $item->{'_id'}; if(defined($type) && defined($id)) { print FOUT "S $type $id\n"; foreach my $a (keys %$item) { print FOUT "$a ", $item->{$a}, "\n"; } print FOUT "\n"; } } print FOUT "Z\n\n"; } sub writeLinesSection { my $self = shift @_; my $lines = $self->{'lines'}; foreach my $line (@$lines) { print FOUT "L ", $line->{'L'}, "\n"; print FOUT "s ", $line->{'s'}, "\n"; print FOUT "\n"; } print FOUT "Z\n\n"; } sub writeConstraintsSection { my $self = shift @_; my $constraints = $self->{'constraints'}; foreach my $constraint (@$constraints) { print FOUT "C ", $constraint->{'C'}, "\n"; print FOUT "s ", $constraint->{'s'}, "\n"; print FOUT "\n"; } print FOUT "Z\n\n"; } sub writeStatisticsSection { my $self = shift @_; # Currently do nothing } sub saveZeroFrame { my $self = shift @_; my $file = "0.exp"; my $filename = &util::filename_cat($self->{'output_dir'},$file); my $status = undef; my $username = $self->{'username'}; my $fdate = getFormattedDate(); if (open(FOUT,">$filename")) { binmode(FOUT,":utf8"); print FOUT <{'D'} = "gsdl.Metadata: assocfilepath"; $self->addText($x,$y,$text,undef,$attr); } sub saveFrame { my $self = shift @_; my ($file,$assoc) = @_; if ($file eq "1.exp") { $self->saveZeroFrame(); } my $filename = &util::filename_cat($self->{'output_dir'},$file); my $status = undef; if (open(FOUT,">$filename")) { binmode(FOUT,":utf8"); if(defined $assoc){ $self->writeAssocFilePath($assoc); #write assocfilepath out to frame. } $self->writeHeaderSection(); $self->writeItemsSection(); $self->writeLinesSection(); $self->writeConstraintsSection(); $self->writeStatisticsSection(); close(FOUT); $status = 1; } else { print STDERR "ExpediteeFrameIO::saveFrame() Failed to open $filename for output\n"; $status = 0; } return $status; } sub buildFrame { my $self = shift @_; my ($html_node) = @_; my $type = $html_node->{'type'}; if ($type eq "rect") { my $rect = $html_node->{'rect'}; my $xl = $rect->{'xl'}; my $xr = $rect->{'xr'}; my $yt = $rect->{'yt'}; my $yb = $rect->{'yb'}; my $attr = convertStyleToAttr($html_node->{'style'}); if (defined $html_node->{'attr'}) { # values provided in 'attr' explicitly overwrite any values # derived from CSS style my $direct_attr_str = $html_node->{'attr'}; my @direct_attr_array = split(/\s*;\s*/,$direct_attr_str); foreach my $da (@direct_attr_array) { my ($key,$val) = ($da =~ m/^(.)\s*(.*)$/); $attr->{$key} = $val; } } #don't want to add font information to non-text items! my $deleted = delete $attr->{'f'}; $self->addRect($xl,$yt,$xr,$yb,$attr); if (defined $html_node->{'img'}) { my $img_url = $html_node->{'img'}; $img_url =~ s/^http:\/\/(.*?)\/greenstone3(.*?)\///; if ($img_url =~ m/^interfaces\//) { $img_url = "greenstone3-svn/web/$img_url"; } elsif ($img_url =~ m/^sites\//) { # if ($img_url =~ m/^sites\//) { # $img_url =~ s/^sites\/(.*?)\//images\//; $img_url = "greenstone3-svn/web/$img_url"; } my $x = $xl; my $y = $yt; my $attr = {}; my $img_text = "\@i: $img_url"; $self->addText($x,$y,$img_text,undef,$attr); } } elsif ($type eq "text") { my $text = $html_node->{'text'}; my $x = $html_node->{'xl'}; my $y = $html_node->{'yt'}; my $w = $html_node->{'xr'} - $x +1; my $attr = convertStyleToAttr($html_node->{'style'}); # fudge factor for now (based on default font size used) $y += 16; # y-value of text item in Expeditee is it's base line $x += 4; my $data = $html_node->{'data'}; $attr->{'D'} = $data if defined $data; $self->addText($x,$y,$text,$w,$attr); } else { print STDERR "ExpediteeFrameIO::buildFrame(): Warning, unrecognized type '$type'\n"; } my $childNodes = $html_node->{'childNodes'}; foreach my $child_node (@$childNodes) { $self->buildFrame($child_node); } } sub saveLastFrameNumber { my $self = shift @_; my ($last_frame_number,$collect) = @_; my $filename = &util::filename_cat($self->{'output_dir'},"frame.inf"); my $status = undef; if (open(FNOUT,">$filename")) { binmode(FNOUT,":utf8"); #writes frameset name concatenated with last frame number in the set to the frame.inf file. # my $getFramesetName = $self->{'output_dir'}; #use collection name rather than the directory name where the frameset is stored, when saving the last frame name/number to the frame.inf file. print FNOUT "$collect"."$last_frame_number"; close(FNOUT); $status = 1; } else { print STDERR "ExpediteeFrameIO::saveLastFrameNumber() Failed to open $filename for output\n"; $status = 0; } return $status; } 1;