#=============================================================================
#
# Copyright (c) 2010 Ars Aperta, Itaapy, Pierlis, Talend.
# Copyright (c) 2011 Jean-Marie Gouarné.
# Author: Jean-Marie Gouarné <jean.marie.gouarne@online.fr>
#
#=============================================================================
use 5.010_000;
use strict;
#=============================================================================
# Style handling package
#=============================================================================
package ODF::lpOD::Style;
use base 'ODF::lpOD::Element';
our $VERSION = '1.006';
use constant PACKAGE_DATE => '2012-02-02T20:43:40';
use ODF::lpOD::Common;
#-----------------------------------------------------------------------------
BEGIN {
*insert = *register;
}
#-----------------------------------------------------------------------------
our %STYLE_DEF =
(
'text' =>
{
tag => 'style:style',
name => 'name',
class => odf_text_style
},
'paragraph' =>
{
tag => 'style:style',
name => 'name',
class => odf_paragraph_style
},
'list' =>
{
tag => 'text:list-style',
name => 'style:name',
class => odf_list_style
},
'outline' =>
{
tag => 'text:outline-style',
name => undef,
class => odf_outline_style
},
'table' =>
{
tag => 'style:style',
name => 'name',
class => odf_table_style
},
'table column' =>
{
tag => 'style:style',
name => 'name',
class => odf_column_style
},
'table row' =>
{
tag => 'style:style',
name => 'name',
class => odf_row_style
},
'table cell' =>
{
tag => 'style:style',
name => 'name',
class => odf_cell_style
},
'master page' =>
{
tag => 'style:master-page',
name => 'name',
class => odf_master_page
},
'header footer' =>
{
class => odf_page_end_style
},
'page layout' =>
{
tag => 'style:page-layout',
name => 'name',
class => odf_page_layout
},
'presentation page layout' =>
{
tag => 'style:presentation-page-layout',
name => 'name',
class => odf_presentation_page_layout
},
'graphic' =>
{
tag => 'style:style',
name => 'name',
class => odf_graphic_style
},
'gradient' =>
{
tag => 'draw:gradient',
name => 'name',
class => odf_gradient
},
'presentation' =>
{
tag => 'style:style',
name => 'name',
class => odf_graphic_style
},
'drawing page' =>
{
tag => 'style:style',
name => 'name',
class => odf_drawing_page_style
}
);
#-----------------------------------------------------------------------------
sub set_class
{
my $self = shift;
my $family = shift || $self->get_family;
my $class;
unless ($family)
{
my $tag = $self->get_tag;
if ($tag =~ /^number:.*-style$/)
{
$class = odf_data_style;
}
}
else
{
my $desc = $STYLE_DEF{$family};
$class = $desc->{class} if $desc;
}
return $class ? bless($self, $class) : undef;
}
sub get_family_path
{
my $self = shift;
my $family = shift;
my $desc = $STYLE_DEF{$family};
unless ($desc)
{
alert "Unknown style family"; return FALSE;
}
return $desc->{class}->context_path;
}
sub required_tag
{
my $self = shift;
my $family = $self->get_family() or return undef;
return $STYLE_DEF{$family}->{tag};
}
sub set_name
{
my $self = shift;
my $name = shift;
return undef unless defined $name;
return $self->set_tag($name) if (caller() eq 'XML::Twig::Elt');
my $family = $self->get_family;
my $attr;
if ($family)
{
my $desc = $STYLE_DEF{$family};
$attr = $desc->{'name'} if $desc;
}
return $attr ?
$self->set_attribute($attr => $name) :
$self->SUPER::set_name($name);
}
sub get_name
{
my $self = shift;
return $self->get_attribute('style:name');
}
sub set_display_name
{
my $self = shift;
$self->set_attribute('style:display-name' => shift);
}
sub get_display_name
{
my $self = shift;
return $self->get_attribute('style:display-name' => shift);
}
sub set_family
{
my $self = shift;
my $tag = $self->get_tag;
return undef unless ($tag eq 'style:style');
my $family = shift; $family =~ s/ /-/g;
return $self->set_attribute(family => $family);
}
sub set_parent_style
{
my $self = shift;
my $style = shift;
if (ref $style)
{
unless ($style->isa('ODF::lpOD::Style'))
{
alert "Wrong style reference"; return undef;
}
$style = $style->get_name;
}
return $self->set_attribute('parent style name' => $style);
}
sub get_parent_style
{
my $self = shift;
return $self->get_attribute('parent style name');
}
sub get_parent_styles
{
my $self = shift;
my $doc = $self->document;
unless ($doc)
{
alert "Non attached style"; return undef;
}
my $family = $self->get_family;
my $name;
my @styles;
my $s = $self;
while ($s && ($name = $s->get_parent_style))
{
$s = $doc->get_style($family, $name);
push @styles, $s if $s;
}
return @styles;
}
sub set_style_class
{
my $self = shift;
return $self->set_attribute(class => shift);
}
sub is_default
{
my $self = shift;
my $tag = $self->get_tag or return undef;
return $tag eq 'style:default-style' ? TRUE : FALSE;
}
sub could_be_default
{
my $self = shift;
my $tag = $self->get_tag or return undef;
return $tag eq 'style:style' ? TRUE : FALSE;
}
sub make_default
{
my $self = shift;
return $self if $self->is_default;
if ($self->could_be_default)
{
my $ds = $self->clone; $self->delete;
my $f = $ds->get_family;
$ds->del_attributes;
$ds->_set_tag('style:default-style');
$ds->set_attribute('style:family' => $f);
return $ds;
}
else
{
alert "Wrong default style";
return FALSE;
}
}
#-----------------------------------------------------------------------------
sub _create { ODF::lpOD::Style->create(@_) }
#-----------------------------------------------------------------------------
sub create
{
my $caller = shift;
my $family = shift;
my $desc = $STYLE_DEF{$family};
unless ($desc)
{
alert "Missing or not supported style family"; return FALSE;
}
my %opt = process_options(@_);
my $tag = $opt{'tag'} || $desc->{tag}; delete $opt{tag};
my $style;
if ($opt{clone})
{
$style = $opt{clone}->clone;
unless ($style)
{
alert "Style cloning error"; return undef;
}
my $f = $style->get_family;
unless (($f eq $family) || ($style->convert($family)))
{
alert "Family mismatch";
$style->delete;
return undef;
}
delete $opt{clone};
}
else
{
$style = ODF::lpOD::Element->create($tag);
}
$style->set_family($family);
bless $style, $desc->{class};
$style->set_name($opt{name});
$style->set_display_name($opt{display_name});
$style->set_parent_style($opt{parent});
$style->register($opt{register}) if $opt{register};
delete @opt{qw(register name display_name parent)};
$style->initialize(%opt);
return $style;
}
sub initialize
{
my $self = shift;
return ($self->set_properties(@_) || undef);
}
sub register
{
my $self = shift;
my $document = shift or return undef;
return $document->register_style($self, @_);
}
#-----------------------------------------------------------------------------
sub get_family
{
my $self = shift;
my $family = $self->get_attribute('family');
$family =~ s/-/ /g if $family;
return $family;
}
#-----------------------------------------------------------------------------
sub properties_tag {}
sub attribute_name { my $self = shift; return shift; }
sub set_properties_context
{
my $self = shift;
my $pt = $self->properties_tag;
unless ($pt)
{
my $area = shift || $self->get_family;
$area =~ s/[ _]/-/g;
$pt = $self->ns_prefix() . ':' . $area . '-properties';
}
return $self->set_child($pt);
}
sub set_properties
{
my $self = shift;
my %opt = @_;
my $area = $opt{area} || $self->get_family; delete $opt{area};
return $self->ODF::lpOD::TextStyle::set_properties(%opt)
if $area eq 'text';
my $f = $area; $f =~ s/[ _]/-/g;
my $pt = $self->properties_tag() || ('style:' . $f . '-properties');
my $pr = $self->first_child($pt);
if ($opt{clone})
{
my $proto = $opt{clone}->first_child($pt) or return undef;
$pr->delete() if $pr;
$proto->clone->paste_last_child($self);
}
else
{
$pr //= $self->insert_element($pt);
foreach my $k (keys %opt)
{
my $att = $STYLE_DEF{$area}
->{class}
->attribute_name($k);
$pr->set_attribute($att => $opt{$k});
}
}
return $self->get_properties(area => $area);
}
sub get_properties
{
my $self = shift;
my $pt = $self->properties_tag;
unless ($pt)
{
my %opt = @_;
my $area = $opt{area} || $self->get_family;
$area =~ s/[ _]/-/g;
$pt = $self->ns_prefix() . ':' . $area . '-properties';
}
my $pr = $self->get_child($pt);
return $pr ? $pr->get_attributes() : undef;
}
#-----------------------------------------------------------------------------
sub set_background
{
my $self = shift;
my %opt = @_;
$opt{url} //= $opt{image};
delete $opt{image};
if (exists $opt{color})
{
$self->set_properties
(
area => $opt{area},
'fo:background-color' => $opt{color}
);
}
if (exists $opt{url})
{
my $pr = $self->set_properties_context($opt{area});
my $im = $pr->get_child('style:background-image');
$im->delete if $im;
if (defined $opt{url})
{
$im = $pr->insert_element('style:background-image');
$im->set_attribute('xlink:href' => $opt{url});
$im->set_attribute('draw:opacity' => $opt{opacity});
$im->set_attribute('filter name' => $opt{filter});
delete @opt{qw(area url opacity filter color)};
$im->set_attributes(%opt);
}
}
}
#=============================================================================
package ODF::lpOD::TextStyle;
use base 'ODF::lpOD::Style';
our $VERSION = '1.003';
use constant PACKAGE_DATE => '2011-05-27T09:05:45';
use ODF::lpOD::Common;
#-----------------------------------------------------------------------------
our %ATTR =
(
font => 'style:font-name',
size => 'fo:font-size',
weight => 'fo:font-weight',
style => 'fo:font-style',
variant => 'fo:font-variant',
color => 'fo:color',
country => 'fo:country',
language => 'fo:language',
underline => 'style:text-underline-style',
background_color => 'fo:background-color',
display => 'text:display'
);
sub initialize
{
my $self = shift;
my %opt =
(
class => 'text',
@_
);
$self->set_style_class($opt{class}); delete $opt{class};
my $result = $self->set_properties(%opt);
return $result ? $self : undef;
}
#-----------------------------------------------------------------------------
sub properties_tag { 'style:text-properties' }
sub set_properties
{
my $self = shift;
my %opt = @_;
delete $opt{area};
my $pt = 'style:text-properties';
my $pr = $self->first_child($pt);
if ($opt{clone})
{
my $proto = $opt{clone}->first_child($pt) or return undef;
$pr->delete() if $pr;
$proto->clone->paste_last_child($self);
}
else
{
$pr //= $self->insert_element($pt);
foreach my $k (keys %opt)
{
if ($k =~ /^underline./)
{
my $a = 'text-' . $k;
my $v = $opt{$k};
$v = 'skip-white-space'
if (($k =~ /mode$/) && ($v =~ /^word/));
$pr->set_attribute($a => $v);
}
if ($k eq 'display')
{
my $v;
given ($opt{$k})
{
when (TRUE) { $v = 'true'; }
when (FALSE) { $v = 'none'; }
default { $v = $opt{$k}; }
}
$pr->set_attribute('text:display' => $v);
}
else
{
my $att = $ATTR{$k} // $k;
$pr->set_attribute($att => $opt{$k});
}
}
}
return $self->get_properties(area => 'text');
}
sub set_background
{
my $self = shift;
my %opt = @_;
$self->set_properties('fo:background-color' => $opt{color});
}
#=============================================================================
package ODF::lpOD::ParagraphStyle;
use base 'ODF::lpOD::Style';
our $VERSION = '1.000';
use constant PACKAGE_DATE => '2011-05-27T09:06:14';
use ODF::lpOD::Common;
#-----------------------------------------------------------------------------
our %ATTR =
(
line_spacing => 'style:line-spacing',
line_height_at_least => 'style:line-height-at-least',
font_independent_line_spacing => 'style:font-independent-line-spacing',
together => 'fo:keep-together',
auto_text_indent => 'style:auto-text-indent',
shadow => 'style:shadow'
);
sub attribute_name
{
my $self = shift;
my $property = shift // return undef;
my $attribute = undef;
if ($property =~ /:/)
{
$attribute = $property;
}
else
{
if ($ATTR{$property})
{
$attribute = $ATTR{$property};
}
else
{
$attribute = ($property =~ /^align|^indent/) ?
'text-' . $property : $property;
my $prefix = ($property =~ /^tab|register/) ?
'style' : 'fo';
$attribute = $prefix . ':' . $attribute;
}
}
return $attribute;
}
#-----------------------------------------------------------------------------
sub initialize
{
my $self = shift;
my %opt =
(
class => 'text',
@_
);
$self->set_style_class($opt{class});
$self->set_master_page($opt{master_page});
delete @opt{qw(class master_page)};
my $result = $self->set_properties(area => 'paragraph', %opt);
return $result ? $self : undef;
}
sub set_master_page
{
my $self = shift;
return $self->set_attribute('master page name' => shift);
}
sub get_master_page
{
my $self = shift;
return $self->get_attribute('master page name');
}
#=============================================================================
package ODF::lpOD::ListStyle;
use base 'ODF::lpOD::Style';
our $VERSION = '1.001';
use constant PACKAGE_DATE => '2010-12-31T11:53:23';
use ODF::lpOD::Common;
#-----------------------------------------------------------------------------
sub get_family { 'list' }
sub get_properties {}
sub set_properties {}
sub set_background
{
alert("Background properties not supported for this object");
return FALSE;
}
#-----------------------------------------------------------------------------
sub level_style_tag
{
my $self = shift;
my $type = shift;
unless ($type)
{
alert "Missing item mark type"; return FALSE;
}
return ('text:list-level-style-' . $type);
}
sub convert
{
my $self = shift;
my $family = shift;
return FALSE unless ($family && ($family eq 'outline'));
$self->set_name(undef);
$self->set_tag($STYLE_DEF{outline}->{tag});
foreach my $ls ($self->get_children(qr'level-style'))
{
$ls->set_tag($self->level_style_tag);
}
return $self;
}
#-----------------------------------------------------------------------------
sub get_level_style
{
my $self = shift;
my $level = shift;
return $self->get_xpath('.//*[@text:level="' . $level . '"]', 0);
}
sub set_level_style
{
my $self = shift;
my $level = shift;
unless (defined $level && $level > 0)
{
alert "Missing or wrong level"; return FALSE;
}
my %opt = process_options(@_);
my $e;
if (defined $opt{clone})
{
$e = $opt{clone}->clone;
my $old = $self->get_level_style($level);
$old && $old->delete;
$e->set_attribute(level => $level);
return $self->append_element($e);
}
my $type = $opt{type} || 'number';
$e = ODF::lpOD::ListLevelStyle->create($type) or return FALSE;
given ($type)
{
when ('number')
{
$e->set_attributes
(
'style:num-format' => $opt{format},
'style:num-prefix' => $opt{prefix},
'style:num-suffix' => $opt{suffix},
'start value' => $opt{start_value},
'display levels' => $opt{display_levels}
);
}
when ('bullet')
{
$e->set_attribute('bullet char' => $opt{character});
}
when ('image')
{
$e->set_url($opt{url} // $opt{uri});
}
default
{
$e->delete; undef $e;
alert "Unknown item mark type"; return FALSE;
}
}
$e->set_attribute(level => $level);
$e->set_style($opt{style});
my $old = $self->get_level_style($level); $old && $old->delete;
return $self->append_element($e);
}
#=============================================================================
package ODF::lpOD::ListLevelStyle;
use base 'ODF::lpOD::Element';
our $VERSION = '1.001';
use constant PACKAGE_DATE => '2010-12-29T23:13:48';
use ODF::lpOD::Common;
#-----------------------------------------------------------------------------
our %ATTR =
(
align => 'fo:text-align',
font => 'style:font-name',
width => 'fo:width',
height => 'fo:height'
);
our %PROP = reverse %ATTR;
#-----------------------------------------------------------------------------
sub _create { ODF::lpOD::ListLevelStyle->create(@_) }
#-----------------------------------------------------------------------------
sub create
{
my $caller = shift;
my $type = shift;
my $tag;
given ($type)
{
when (undef)
{
alert "Missing list level type";
}
when (['bullet', 'number', 'image'])
{
$tag = 'text:list-level-style-' . $type;
}
default
{
alert "Wrong list level type";
}
}
return $tag ? ODF::lpOD::Element->create($tag) : undef;
}
sub get_type
{
my $self = shift;
my $t = $self->get_tag;
$t =~ /([a-z])$/;
return $t;
}
sub get_properties
{
my $self = shift;
my $pr = $self->first_child('style:list-level-properties')
or return undef;
my %prop;
my %att = $pr->get_attributes;
foreach my $k (keys %att)
{
my $p = $PROP{$k};
unless ($p)
{
$p = $k;
$p =~ s/^.*://; $p =~ s/-/_/g;
}
$prop{$p} = $att{$k};
}
return wantarray ? %prop : { %prop };
}
sub set_properties
{
my $self = shift;
my %opt = process_options(@_);
my $pr = $self->set_child('style:list-level-properties');
foreach my $k (keys %opt)
{
my $att;
if ($k =~ /:/)
{
$att = $k;
}
else
{
$att = $ATTR{$k};
unless ($att)
{
$att = 'text:' . $k;
}
}
$pr->set_attribute($att => $opt{$k});
}
return $pr;
}
#=============================================================================
package ODF::lpOD::OutlineStyle;
use base 'ODF::lpOD::ListStyle';
our $VERSION = '1.000';
use constant PACKAGE_DATE => '2010-12-24T13:46:31';
use ODF::lpOD::Common;
#-----------------------------------------------------------------------------
sub get_family { 'outline' }
sub context_path { STYLES, '//office:styles' }
sub get_display_name {}
sub set_display_name {}
sub get_properties {}
sub set_properties {}
#-----------------------------------------------------------------------------
sub initialize { return shift; }
sub level_style_tag { 'text:outline-level-style' }
sub convert
{
my $self = shift;
my $family = shift;
return FALSE unless ($family && ($family eq 'list'));
$self->set_tag($STYLE_DEF{list}->{tag});
foreach my $ls ($self->get_children(qr'level-style'))
{
$ls->set_tag($self->level_style_tag('number'));
}
return $self;
}
#-----------------------------------------------------------------------------
sub set_level_style
{
my $self = shift;
my $level = shift;
my %opt = @_;
$opt{type} = 'number';
return $self->SUPER::set_level_style($level, %opt);
}
#=============================================================================
package ODF::lpOD::AreaStyle;
use base 'ODF::lpOD::Style';
use strict;
our $VERSION = '1.000';
use constant PACKAGE_DATE => '2012-02-01T16:17:09';
use ODF::lpOD::Common;
#-----------------------------------------------------------------------------
BEGIN {
*set_frame_sides = *set_area_sides;
*set_margin = *set_margins;
*set_border = *set_borders;
}
#-----------------------------------------------------------------------------
sub set_area_sides
{
my $self = shift;
my %opt =
(
prefix => 'fo:',
option => 'border',
area => undef,
value => undef,
@_
);
my %attr;
$attr{area} = $opt{area};
$attr{$opt{prefix} . $opt{option} . '_' . $_} = $opt{value}
for ('left', 'right', 'top', 'bottom');
$self->set_properties(%attr);
}
sub set_borders
{
my $self = shift;
return $self->set_area_sides
(option => 'border', value => shift, @_);
}
sub set_padding
{
my $self = shift;
return $self->set_area_sides
(option => 'padding', value => shift, @_);
}
sub set_margins
{
my $self = shift;
return $self->set_area_sides
(option => 'margin', value => shift, @_);
}
#-----------------------------------------------------------------------------
sub fill
{
my $self = shift;
my $mode = shift or return undef;
my $value = shift;
my $attr = undef;
given ($mode)
{
when (['color', 'solid'])
{
$mode = 'solid';
$attr = 'draw:fill-color';
}
when (['bitmap', 'hatch'])
{
$attr = 'draw:fill-' . $mode . '-name';
}
when (['none', 'empty'])
{
$mode = 'none';
}
default
{
alert "Unknown shape fill mode";
return undef;
}
}
$self->set_properties
(
area => 'graphic',
'draw:fill' => $mode,
$attr => $value
);
}
#=============================================================================
package ODF::lpOD::TableStyle;
use base 'ODF::lpOD::AreaStyle';
use strict;
our $VERSION = '1.000';
use constant PACKAGE_DATE => '2011-05-27T09:08:16';
use ODF::lpOD::Common;
#-----------------------------------------------------------------------------
sub initialize
{
my $self = shift;
my %opt = @_;
if ($opt{name}) { $self->set_name($opt{name}); delete $opt{name}; }
$self->set_properties(%opt);
return $self;
}
#-----------------------------------------------------------------------------
sub properties_tag
{
my $self = shift;
my $f = $self->get_family;
$f =~ s/[ _]/-/g;
return ('style:' . $f . '-properties');
}
#-----------------------------------------------------------------------------
sub set_properties
{
my $self = shift;
my %opt = @_;
if ($opt{area} && ($opt{area} eq 'text'))
{
alert "Text properties are not allowed for this object";
return undef;
}
delete $opt{name};
my $pt = $self->properties_tag;
my $pr = $self->first_child($pt);
if ($opt{clone})
{
my $proto = $opt{clone}->first_child($pt) or return undef;
$pr->delete() if $pr;
$proto->clone->paste_last_child($self);
}
else
{
my $a;
$pr //= $self->insert_element($pt);
OPT: foreach my $k (keys %opt)
{
if ($k eq 'margin')
{
my $v = $opt{$k};
$pr->set_attributes
(
'fo:margin-left' => $v,
'fo:margin-right' => $v,
'fo:margin-bottom' => $v,
'fo:margin-top' => $v
);
next OPT;
}
elsif ($k eq 'width')
{
my $v = $opt{$k};
$v =~ s/\s*//g; $v =~ s/\*/%/g;
my ($v1, $v2) = split(/,/, $v);
for ($v1, $v2)
{
next unless defined $_;
if ($_ =~ /%/)
{
$pr->set_attribute
('rel width' => $_)
}
else {
$pr->set_attribute
('width' => $_)
}
}
next OPT;
}
elsif ($k eq 'together')
{
next OPT unless defined $opt{$k};
my $v = odf_boolean(is_false($opt{$k}));
$pr->set_attribute
('may break between rows' => $v);
next OPT;
}
given ($k)
{
when (/:/)
{
$a = $k;
}
when (/(color|margin|break|keep)/)
{
$a = 'fo:' . $k;
}
when (['align', 'display'])
{
$a = 'table:' . $k;
}
default
{
$a = $k;
}
}
$pr->set_attribute($a => $opt{$k});
}
}
return $self->get_properties();
}
sub set_shadow
{
my $self = shift;
my %opt =
(
type => 'visible',
offset => ['3mm', '3mm'],
color => '#000000',
@_
);
my $t = $opt{type};
my ($x, $y) = input_2d_value($opt{offset});
my $c = color_code($opt{color});
$self->set_properties(shadow => "$c $x $y");
}
#=============================================================================
package ODF::lpOD::ColumnStyle;
use base 'ODF::lpOD::TableStyle';
our $VERSION = '1.000';
use constant PACKAGE_DATE => '2010-12-24T13:47:03';
use ODF::lpOD::Common;
#-----------------------------------------------------------------------------
sub width_values
{
my $arg = shift or return undef;
$arg =~ s/\s*//g; $arg =~ s/%/*/g;
my ($v1, $v2) = split(/,/, $arg);
my ($av, $rv);
for ($v1, $v2)
{
next unless defined $_;
if ($_ =~ /\*/) { $rv = $_ }
else { $av = $_ }
}
return ($av, $rv);
}
sub set_properties
{
my $self = shift;
my %opt = process_options(@_);
if ($opt{width})
{
($opt{'column width'}, $opt{'rel column width'}) =
width_values($opt{width});
delete $opt{width};
}
if ($opt{optimal_width})
{
$opt{'style:use-optimal-column-width'} =
odf_boolean($opt{optimal_width});
delete $opt{optimal_width};
}
return $self->SUPER::set_properties(%opt);
}
#=============================================================================
package ODF::lpOD::RowStyle;
use base 'ODF::lpOD::TableStyle';
our $VERSION = '1.000';
use constant PACKAGE_DATE => '2010-12-24T13:47:18';
use ODF::lpOD::Common;
#-----------------------------------------------------------------------------
sub set_properties
{
my $self = shift;
my %opt = process_options(@_);
if ($opt{height})
{
$opt{'row height'} = $opt{height}; delete $opt{height};
}
return $self->SUPER::set_properties(%opt);
}
#=============================================================================
package ODF::lpOD::CellStyle;
use base 'ODF::lpOD::TableStyle';
our $VERSION = '1.003';
use constant PACKAGE_DATE => '2012-02-02T08:15:46';
use ODF::lpOD::Common;
#-----------------------------------------------------------------------------
BEGIN {
*set_text_properties = *ODF::lpOD::TextStyle::set_properties;
*p_attribute_name = *ODF::lpOD::ParagraphStyle::attribute_name;
*g_attribute_name = *ODF::lpOD::GraphicStyle::attribute_name;
}
#-----------------------------------------------------------------------------
sub attribute_name
{
my $self = shift;
my $property = shift // return undef;
my $attribute = undef;
if ($property =~ /:/)
{
$attribute = $property;
}
else
{
my $prefix = '';
if ($property =~ /^border|wrap|padding|color/)
{
$prefix = 'fo';
}
$attribute = $prefix ? $prefix . ':' . $property : $property;
}
return $attribute;
}
#-----------------------------------------------------------------------------
sub initialize
{
my $self = shift;
my %opt = @_;
if ($opt{data_style})
{
$self->set_data_style($opt{data_style});
delete $opt{data_style};
}
$self->set_properties(area => 'table cell', %opt);
return $self;
}
sub set_properties
{
my $self = shift;
my %opt = process_options(@_);
my $area = $opt{area} // $self->get_family;
delete $opt{area};
given ($area)
{
when ('table cell')
{
return $self->set_cell_properties(%opt);
}
when ('text')
{
return $self->set_text_properties(%opt);
}
when ('paragraph')
{
return $self->set_paragraph_properties(%opt);
}
when ('graphic')
{
return $self->set_graphic_properties(%opt);
}
}
return undef;
}
sub set_cell_properties
{
my $self = shift;
my %opt = @_;
delete $opt{name};
my $pt = $self->properties_tag;
my $pr = $self->set_child($pt);
if ($opt{clone})
{
my $proto = $opt{clone}->first_child($pt) or return undef;
$pr->delete() if $pr;
$proto->clone->paste_last_child($self);
}
else
{
foreach my $k (keys %opt)
{
my $a = $self->attribute_name($k);
$pr->set_attribute($a => $opt{$k});
}
}
}
sub set_paragraph_properties
{
my $self = shift;
my %opt = @_;
my $pt = 'style:paragraph-properties';
my $pr = $self->set_child($pt);
if ($opt{clone})
{
my $proto = $opt{clone}->first_child($pt) or return undef;
$pr->delete() if $pr;
$proto->clone->paste_last_child($self);
}
else
{
foreach my $k (keys %opt)
{
my $a = $self->p_attribute_name($k);
$pr->set_attribute($a => $opt{$k});
}
}
}
sub set_graphic_properties
{
my $self = shift;
my %opt = @_;
my $pt = 'style:graphic-properties';
my $pr = $self->set_child($pt);
if ($opt{clone})
{
my $proto = $opt{clone}->first_child($pt) or return undef;
$pr->delete() if $pr;
$proto->clone->paste_last_child($self);
}
else
{
foreach my $k (keys %opt)
{
my $a = $self->g_attribute_name($k);
$pr->set_attribute($a => $opt{$k});
}
}
}
sub get_data_style
{
my $self = shift;
return $self->get_attribute('style:data-style-name');
}
sub set_data_style
{
my $self = shift;
return $self->set_attribute('style:data-style-name' => shift);
}
sub set_background
{
my $self = shift;
my $doctype = $self->document_type;
if ($doctype && $doctype eq 'presentation')
{
return $self->fill(@_);
}
return $self->SUPER::set_background(@_);
}
#=============================================================================
package ODF::lpOD::DataStyle;
use base 'ODF::lpOD::Style';
our $VERSION = '1.001';
use constant PACKAGE_DATE => '2011-05-27T09:10:55';
use ODF::lpOD::Common;
#-----------------------------------------------------------------------------
sub create
{
my $caller = shift;
my $ds = ODF::lpOD::Element->create(@_);
return bless $ds, __PACKAGE__;
}
#-----------------------------------------------------------------------------
our @FAMILIES =
(
"number", "percentage", "currency",
"date", "time", "boolean", "text"
);
sub get_family
{
my $self = shift;
my $tag = $self->get_tag;
my $f;
if ($tag =~ /^number:(.*)-style$/)
{
$f = $1;
}
return $f;
}
sub classify
{
my $arg = shift;
if (ref $arg)
{
my $f = $arg->ODF::lpOD::DataStyle::get_family;
if ($f)
{
bless $arg, __PACKAGE__;
}
return $arg;
}
else
{
if ($arg =~ /^number:(.*)-style$/)
{
my $family = $1;
if ($family ~~ [@FAMILIES])
{
return __PACKAGE__;
}
}
}
return undef;
}
sub set_name
{
my $self = shift;
return $self->set_attribute('style:name' => shift);
}
sub get_name
{
my $self = shift;
return $self->get_attribute('style:name');
}
sub set_title
{
my $self = shift;
return $self->set_attribute('title' => shift);
}
sub get_title
{
my $self = shift;
return $self->get_attribute('title');
}
sub set_properties {}
sub get_properties {}
#-----------------------------------------------------------------------------
sub families
{
my $self = shift;
return wantarray ? @FAMILIES : [ @FAMILIES ];
}
#=============================================================================
package ODF::lpOD::MasterPage;
use base 'ODF::lpOD::Style';
our $VERSION = '1.000';
use constant PACKAGE_DATE => '2011-05-27T09:11:14';
use ODF::lpOD::Common;
#-----------------------------------------------------------------------------
sub get_family { 'master page' }
sub context_path { STYLES, '//office:master-styles' }
sub get_properties {}
sub set_properties {}
sub set_background
{
alert("Background properties not supported for this object");
return FALSE;
}
#-----------------------------------------------------------------------------
sub initialize
{
my $self = shift;
my %opt = @_;
$self->set_layout($opt{layout});
$self->set_next($opt{next});
return $self;
}
#-----------------------------------------------------------------------------
sub get_header
{
my $self = shift;
return $self->get_child('style:header');
}
sub set_header
{
my $self = shift;
return $self->replace_child('style:header');
}
sub delete_header
{
my $self = shift;
return $self->delete_child('style:header');
}
sub get_footer
{
my $self = shift;
return $self->get_child('style:footer');
}
sub set_footer
{
my $self = shift;
return $self->replace_child('style:footer');
}
sub delete_footer
{
my $self = shift;
return $self->delete_child('style:footer');
}
sub get_layout
{
my $self = shift;
return $self->get_attribute('page layout name');
}
sub set_layout
{
my $self = shift;
return $self->set_attribute('page layout name' => shift);
}
sub get_next
{
my $self = shift;
return $self->get_attribute('next style name');
}
sub set_next
{
my $self = shift;
return $self->set_attribute('next style name');
}
#=============================================================================
package ODF::lpOD::PageEndStyle;
use base 'ODF::lpOD::Style';
our $VERSION = '1.000';
use constant PACKAGE_DATE => '2011-05-27T09:13:35';
use ODF::lpOD::Common;
#-----------------------------------------------------------------------------
sub get_family { 'header footer' };
sub get_display_name {}
sub set_display_name {}
sub properties_tag { 'style:header-footer-properties' }
#-----------------------------------------------------------------------------
sub set_properties
{
my $self = shift;
my %opt = @_;
my $pr = $self->set_child($self->properties_tag);
foreach my $k (keys %opt)
{
my $a;
given ($k)
{
when (/:/)
{
$a = $k;
}
when ('height')
{
$a = 'fo:min-height';
}
when (/(margin|border|padding|background)/)
{
$a = 'fo:' . $k;
}
default
{
$a = $k;
}
}
$pr->set_attribute($a => $opt{$k});
}
return $pr->get_attributes;
}
#=============================================================================
package ODF::lpOD::PageLayout;
use base 'ODF::lpOD::Style';
our $VERSION = '1.001';
use constant PACKAGE_DATE => '2011-05-27T09:14:03';
use ODF::lpOD::Common;
#-----------------------------------------------------------------------------
sub get_family { 'page layout' }
sub context_path { STYLES, '//office:automatic-styles' }
sub get_display_name {}
sub set_display_name {}
sub properties_tag { 'style:page-layout-properties' }
#-----------------------------------------------------------------------------
sub set_properties
{
my $self = shift;
my %opt = @_;
my $pr = $self->set_child('page layout properties');
foreach my $k (keys %opt)
{
my $a;
my $v = $opt{$k};
given ($k)
{
when ('size')
{
$self->set_size($v);
next;
}
when (['height', 'width'])
{
$a = 'fo:page-' . $k;
}
when (['margin', 'margins'])
{
$pr->set_attributes
(
'fo:margin-top' => $v,
'fo:margin-right' => $v,
'fo:margin-bottom' => $v,
'fo:margin-left' => $v
);
next;
}
when (['border', 'borders'])
{
$pr->set_attributes
(
'fo:border-top' => $v,
'fo:border-right' => $v,
'fo:border-bottom' => $v,
'fo:border-left' => $v
);
next;
}
when (/(margin|border|padding|background)/)
{
$a = 'fo:' . $k;
}
when (/number/)
{
$a = $k; $a =~ s/ber//;
}
when ('footnote height')
{
$a = 'footnote max height';
}
when ('orientation')
{
$a = 'print orientation';
}
when ('paper tray')
{
$a = 'paper tray name';
}
default
{
$a = $k;
}
}
$pr->set_attribute($a => $v);
}
return $pr->get_attributes;
}
sub get_header
{
my $self = shift;
return $self->get_child('header style');
}
sub set_header
{
my $self = shift;
return $self->replace_child('header style');
}
sub delete_header
{
my $self = shift;
return $self->delete_child('header style');
}
sub get_footer
{
my $self = shift;
return $self->get_child('footer style');
}
sub set_footer
{
my $self = shift;
return $self->replace_child('footer style');
}
sub delete_footer
{
my $self = shift;
return $self->delete_child('footer style');
}
sub get_column_count
{
my $self = shift;
my $pr = $self->get_child('page layout properties')
or return undef;
my $co = $pr->get_child('columns') or return undef;
return $co->get_attribute('fo:column-count');
}
sub set_columns
{
my $self = shift;
my $number = shift;
unless (defined $number)
{
alert "Missing number of columns"; return FALSE;
}
my $pr = $self->set_child('page layout properties');
my $co = $pr->get_child('columns');
if ($number < 2)
{
$co && $co->delete;
}
else
{
my %opt = @_;
$co = $pr->replace_child
(
'columns', undef,
'fo:column-count' => $number,
'fo:column-gap' => $opt{gap}
);
}
return $self->get_column_count;
}
#-----------------------------------------------------------------------------
sub get_size
{
my $self = shift;
my $sep = shift // ', ';
my %p = $self->get_properties;
my $w = $p{'fo:page-width'};
my $h = $p{'fo:page-height'};
return wantarray ? ($w, $h) : join $sep, ($w // ""), ($h // "");
}
sub set_size
{
my $self = shift;
my ($w, $h) = input_2d_value(@_);
$self->set_properties(width => $w, height => $h);
return $self->get_size;
}
#=============================================================================
package ODF::lpOD::PresentationPageLayout;
use base 'ODF::lpOD::Style';
our $VERSION = '1.000';
use constant PACKAGE_DATE => '2011-05-27T09:16:39';
use ODF::lpOD::Common;
#-----------------------------------------------------------------------------
sub get_family { 'presentation page layout' }
sub context_path { STYLES, '//office:styles' }
sub initialize { return shift; }
sub get_properties {}
sub set_properties {}
sub set_background
{
alert("Background properties not supported for this object");
return FALSE;
}
#-----------------------------------------------------------------------------
sub set_placeholder
{
my $self = shift;
my $shape = shift;
unless ($shape)
{
alert "Missing object class"; return FALSE;
}
my $ph = ref $shape ?
$shape :
ODF::lpOD::Element->create('presentation:placeholder');
$ph->set_attribute(object => $shape);
my %opt = @_;
$ph->set_size($opt{size});
$ph->set_position($opt{position});
return $self->append_element($ph);
}
sub get_placeholders
{
my $self = shift;
return $self->get_children('presentation:placeholder');
}
#=============================================================================
package ODF::lpOD::DrawingPageStyle;
use base 'ODF::lpOD::Style';
our $VERSION = '1.001';
use constant PACKAGE_DATE => '2011-02-20T00:41:54';
use ODF::lpOD::Common;
#-----------------------------------------------------------------------------
sub set_background
{
alert("Background properties not supported for this object");
return FALSE;
}
sub attribute_name
{
my $self = shift;
my $p = shift // return undef;
my $prefix;
given ($p)
{
when (/:/)
{ return $p }
when (/display|visible|transition/)
{ $prefix = 'presentation' }
default
{ $prefix = 'draw' }
}
return $prefix . ':' . $p;
}
#=============================================================================
package ODF::lpOD::GraphicStyle;
use base 'ODF::lpOD::AreaStyle';
our $VERSION = '1.004';
use constant PACKAGE_DATE => '2012-02-01T16:18:58';
use ODF::lpOD::Common;
#-----------------------------------------------------------------------------
BEGIN {
*set_borders = *set_stroke;
*set_border = *set_stroke;
*set_background = *ODF::lpOD::AreaStyle::fill;
}
#-----------------------------------------------------------------------------
sub initialize
{
my $self = shift;
my %opt =
(
'clip' => 'rect(0cm 0cm 0cm 0cm)',
'style:vertical-rel' => 'paragraph',
'style:horizontal-rel' => 'paragraph',
'style:vertical-pos' => 'from-top',
'style:horizontal-pos' => 'from-left',
'color-mode' => 'standard',
@_
);
if ($opt{page})
{
$opt{'style:vertical-rel'} //= 'page-content';
$opt{'style:horizontal-rel'} //= 'page-content';
}
foreach my $k (keys %opt)
{
given ($k)
{
when (/^background.*color/)
{
$self->set_background(color => $opt{$k});
delete $opt{$k};
}
when (['border', 'borders', 'stroke'])
{
my ($w, $t, $c) = split / +/, $opt{$k};
$self->set_borders
(
type => $t,
width => $w,
color => $c
);
delete $opt{$k};
}
}
}
$opt{area} = 'graphic';
$self->set_properties(%opt);
return $self;
}
#-----------------------------------------------------------------------------
sub attribute_name
{
my $self = shift;
my $p = shift;
my $prefix;
given ($p)
{
when (undef)
{ return $p }
when (/:/)
{ return $p }
when (/^(fill|shadow)/)
{ $prefix = 'draw' }
when (/(pos$|rel$|wrap$|run|shadow)/)
{ $prefix = 'style' }
when (/^stroke[ -_]/)
{ $prefix = 'svg' }
when (/border|color|height|width|padding|margin|clip/)
{ $prefix = 'fo' }
default
{ $prefix = 'draw' }
}
return $prefix . ':' . $p;
}
#-----------------------------------------------------------------------------
sub set_stroke
{
my $self = shift;
my %opt =
(
'type' => 'solid',
'width' => '1pt',
'color' => '#000000',
@_
);
$self->set_properties
(
'draw:stroke' => $opt{type} // 'solid',
'svg:stroke-width' => $opt{width} // '1pt',
'svg:stroke-color' => $opt{color} // '#000000'
);
}
sub set_shadow
{
my $self = shift;
my %opt =
(
type => 'visible',
offset => ['3mm', '3mm'],
color => '#000000',
@_
);
my $t = $opt{type};
my ($x, $y) = input_2d_value($opt{offset});
my $c = $opt{color};
delete @opt{qw(type offset color)};
$self->set_properties
(
'draw:shadow' => $t,
'draw:shadow-offset-x' => $x,
'draw:shadow-offset-y' => $y,
'draw:shadow-color' => $c,
%opt
);
}
#=============================================================================
package ODF::lpOD::Gradient;
use base 'ODF::lpOD::Style';
our $VERSION = '1.000';
use constant PACKAGE_DATE => '2011-05-27T09:18:59';
use ODF::lpOD::Common;
#-----------------------------------------------------------------------------
sub get_family { 'gradient'}
sub context_path { STYLES, '//office:styles' }
sub get_properties {}
sub set_properties {}
sub get_name
{
my $self = shift;
return $self->get_attribute('name');
}
#-----------------------------------------------------------------------------
sub attribute_name
{
my $self = shift;
my $p = shift;
given ($p)
{
when (undef)
{ return $p }
when (/:/)
{ return $p }
when ('style')
{ return 'draw:style' }
default
{ return $p }
}
}
sub initialize
{
my $self = shift;
my %opt = @_;
foreach my $k (keys %opt)
{
my $a = $self->attribute_name($k);
$self->set_attribute($a => $opt{$k});
}
return $self;
}
sub set_display_name
{
my $self = shift;
$self->set_attribute('draw:display-name' => shift);
}
sub get_display_name
{
my $self = shift;
return $self->get_attribute('draw:display-name' => shift);
}
#=============================================================================
package ODF::lpOD::FontDeclaration;
use base 'ODF::lpOD::Element';
our $VERSION = '1.001';
use constant PACKAGE_DATE => '2010-12-29T23:17:13';
use ODF::lpOD::Common;
#-----------------------------------------------------------------------------
sub _create { ODF::lpOD::FontDeclaration->create(@_) }
#-----------------------------------------------------------------------------
sub create
{
my $caller = shift;
my $name = shift;
my %opt =
(
family => $name,
@_
);
unless ($name)
{
alert "Missing font name"; return FALSE;
}
my $fd = ODF::lpOD::Element->create('style:font-face');
$fd->set_name($name);
$fd->set_attribute('svg:font-family' => $opt{family});
delete $opt{family};
foreach my $k (keys %opt)
{
my $att = $k =~ /:/ ? $k : 'style:font-' . $k;
$fd->set_attribute($att => $opt{$k});
}
return $fd;
}
#=============================================================================
1;