1#=============================================================================
2#
3#       Copyright (c) 2010 Ars Aperta, Itaapy, Pierlis, Talend.
4#       Copyright (c) 2014 Jean-Marie Gouarné.
5#       Author: Jean-Marie Gouarné <jean.marie.gouarne@online.fr>
6#
7#=============================================================================
8use     5.010_001;
9use     strict;
10use     experimental    'smartmatch';
11#=============================================================================
12#       Structured containers : Sections, lists, draw pages, frames, shapes...
13#-----------------------------------------------------------------------------
14package ODF::lpOD::StructuredContainer;
15use base 'ODF::lpOD::Element';
16our $VERSION    = '1.001';
17use constant PACKAGE_DATE => '2011-11-15T19:52:49';
18use ODF::lpOD::Common;
19#=============================================================================
20package ODF::lpOD::Section;
21use base 'ODF::lpOD::StructuredContainer';
22our $VERSION    = '1.003';
23use constant PACKAGE_DATE => '2011-11-15T19:52:49';
24use ODF::lpOD::Common;
25#=============================================================================
26
27BEGIN   {
28        *set_hyperlink          = *set_source;
29        *get_hyperlink          = *get_source;
30        *set_url                = *set_source;
31        *get_url                = *get_source;
32        }
33
34#-----------------------------------------------------------------------------
35
36sub     _create  { ODF::lpOD::Section->create(@_) }
37
38#-----------------------------------------------------------------------------
39
40sub     create
41        {
42        my $caller      = shift;
43        my $name        = shift;
44        unless ($name)
45                {
46                alert "Missing section name";
47                return FALSE;
48                }
49
50        my %opt =
51                (
52                style           => undef,
53                url             => undef,
54                display         => undef,
55                condition       => undef,
56                protected       => undef,
57                key             => undef,
58                @_
59                );
60
61        my $s = ODF::lpOD::StructuredContainer->create('text:section');
62        if (defined $opt{url} or defined $opt{source})
63                {
64                my $link = $opt{url} || $opt{source};
65                $s->set_source($link);
66                $opt{protected} = TRUE;
67                }
68        $s->set_protected($opt{protected});
69        $s->set_name($name);
70        $s->set_style($opt{style});
71        $s->set_attribute('protection key', $opt{key});
72        $s->set_display($opt{display});
73        $s->set_attribute('condition', $opt{condition});
74
75        return $s;
76        }
77
78#-----------------------------------------------------------------------------
79
80sub     set_display
81        {
82        my $self        = shift;
83        my $value       = shift // 'true';
84        unless ($value ~~ ['true', 'none', 'condition'])
85                {
86                if ($value == TRUE)
87                        {
88                        $value = 'true';
89                        }
90                elsif ($value == FALSE)
91                        {
92                        $value = 'none';
93                        }
94                else
95                        {
96                        alert "Wrong display parameter"; return undef;
97                        }
98                }
99        $self->set_attribute('display' => $value);
100        }
101
102sub     get_display
103        {
104        my $self        = shift;
105        my $value = $self->get_attribute('display');
106        given ($value)
107                {
108                when (undef)        { return TRUE   }
109                when ('true')       { return TRUE   }
110                when ('none')       { return FALSE  }
111                default             { return $value }
112                }
113        }
114
115sub     set_source
116        {
117        my $self        = shift;
118        my $url         = shift;
119        my %attr        = @_;
120
121        my $source = $self->insert_element('section source');
122        $source->set_attribute('xlink:href', $url);
123        $source->set_attributes({%attr});
124        $self->set_protected(TRUE);
125        return $source;
126        }
127
128sub     get_source
129        {
130        my $self        = shift;
131        my $source = $self->get_element('section source') or return undef;
132        return wantarray ?
133                $source->get_attributes()               :
134                $source->get_attribute('xlink:href');
135        }
136
137#=============================================================================
138package ODF::lpOD::List;
139use base 'ODF::lpOD::StructuredContainer';
140our $VERSION    = '1.003';
141use constant PACKAGE_DATE => '2012-05-02T09:09:28';
142use ODF::lpOD::Common;
143#-----------------------------------------------------------------------------
144
145sub     _create  { ODF::lpOD::List->create(@_) }
146
147#-----------------------------------------------------------------------------
148
149sub     create
150        {
151        my $caller      = shift;
152        my %opt         = process_options(@_);
153        my $list = ODF::lpOD::StructuredContainer->create('text:list');
154        $list->set_style($opt{style});
155        $list->set_id($opt{id});
156        return $list;
157        }
158
159#-----------------------------------------------------------------------------
160
161sub     get_id
162        {
163        my $self        = shift;
164        return $self->get_attribute('xml:id');
165        }
166
167sub     set_id
168        {
169        my $self        = shift;
170        return $self->set_attribute('xml:id', shift);
171        }
172
173sub     get_item
174        {
175        my $self        = shift;
176        my $p           = shift;
177        if (is_numeric($p))
178                {
179                return $self->get_element('text:list-item', position => $p);
180                }
181        push @_, $p;
182        return $self->get_element('text:list-item', @_);
183        }
184
185sub     get_item_list
186        {
187        my $self        = shift;
188        return $self->get_element_list('text:list-item', @_);
189        }
190
191sub     add_item
192        {
193        my $self        = shift;
194        my %opt         = process_options
195                (
196                number          => 1,
197                @_
198                );
199        my $ref_elt     = $opt{after} || $opt{before};
200        my $position    = undef;
201        if ($ref_elt)
202                {
203                if ($opt{before} && $opt{after})
204                        {
205                        alert "'before' and 'after' are mutually exclusive";
206                        return FALSE;
207                        }
208                $position = $opt{before} ? 'before' : 'after';
209                $ref_elt = $self->get_item($ref_elt) unless ref $ref_elt;
210                unless  (
211                        $ref_elt->is('text:list-item')
212                                &&
213                        $ref_elt->parent() == $self
214                        )
215                        {
216                        alert "Wrong list item $position reference";
217                        return FALSE;
218                        }
219                }
220        my $number = $opt{number};
221        my $text = $opt{text};
222        my $style = $opt{style};
223        my $start = $opt{start_value};
224        delete @opt{qw(number before after text style start_value)};
225        return undef unless $number && ($number > 0);
226        my $elt;
227        if ($ref_elt)
228                {
229                $elt = $ref_elt->clone;
230                $elt->cut_children;
231                }
232        else
233                {
234                $elt = ODF::lpOD::Element->create('text:list-item');
235                }
236        if (defined $text || defined $style)
237                {
238                my $p = ODF::lpOD::Paragraph->create
239                                (text => $text, style => $style);
240                $p->paste_last_child($elt);
241                }
242        if ($ref_elt)
243                {
244                $elt->paste($position, $ref_elt);
245                }
246        else
247                {
248                $elt->paste_last_child($self);
249                }
250        my @items = ();
251        push @items, $elt;
252        if ($number)
253                {
254                while ($number > 1)
255                        {
256                        my $cp = $elt->clone;
257                        $cp->paste_after($elt);
258                        push @items, $cp;
259                        $number--;
260                        }
261                }
262        $elt->set_attribute('start value', $start) if defined $start;
263        return  wantarray ? @items : $elt;
264        }
265
266sub     set_header
267        {
268        my $self        = shift;
269        my $h = $self->get_element('text:list-header');
270        $h->delete if $h;
271        $h = ODF::lpOD::Element->create('text:list-header');
272        $h->paste_first_child($self);
273        while (@_)
274                {
275                my $c = shift;
276                my $elt = ref $c ?
277                        $c : ODF::lpOD::Paragraph->create(text => $c);
278                $elt->paste_last_child($h);
279                }
280        return $h;
281        }
282
283#=============================================================================
284package ODF::lpOD::DrawPage;
285use base 'ODF::lpOD::StructuredContainer';
286our $VERSION    = '1.004';
287use constant PACKAGE_DATE => '2011-11-15T19:52:49';
288use ODF::lpOD::Common;
289#-----------------------------------------------------------------------------
290
291sub     _create  { ODF::lpOD::DrawPage->create(@_) }
292
293#-----------------------------------------------------------------------------
294
295sub     create
296        {
297        my $caller      = shift;
298        my $id          = shift;
299        unless ($id)
300                {
301                alert "Missing draw page identifier"; return FALSE;
302                }
303        my %opt         = @_;
304        my $dp = ODF::lpOD::StructuredContainer->create('draw:page');
305        $dp->set_id($id);
306        $dp->set_name($opt{'name'});
307        $dp->set_style($opt{style});
308        $dp->set_master($opt{master});
309        $dp->set_layout($opt{layout} );
310        return $dp;
311        }
312
313#-----------------------------------------------------------------------------
314
315sub     get_master
316        {
317        my $self        = shift;
318        return $self->get_attribute('master page name');
319        }
320
321sub     set_master
322        {
323        my $self        = shift;
324        return $self->set_attribute('master page name', shift);
325        }
326
327sub     get_layout
328        {
329        my $self        = shift;
330        return $self->get_attribute
331                ('presentation:presentation-page-layout-name');
332        }
333
334sub     set_layout
335        {
336        my $self        = shift;
337        return $self->set_attribute
338                ('presentation:presentation-page-layout-name', shift);
339        }
340
341sub     get_title_frame
342        {
343        my $self        = shift;
344        return $self->get_element
345                (
346                'draw:frame',
347                attribute       => 'presentation:class',
348                value           => 'title'
349                );
350        }
351
352sub     get_title
353        {
354        my $self        = shift;
355        my $frame = $self->get_title_frame      or return undef;
356        my $p = $frame->get_paragraph           or return undef;
357        return $p->get_text;
358        }
359
360#=============================================================================
361package ODF::lpOD::Shape;
362use base 'ODF::lpOD::StructuredContainer';
363our $VERSION    = '1.003';
364use constant PACKAGE_DATE => '2011-11-15T19:52:49';
365use ODF::lpOD::Common;
366#-----------------------------------------------------------------------------
367
368sub     _create  { ODF::lpOD::Shape->create(@_) }
369
370#-----------------------------------------------------------------------------
371
372sub     create
373        {
374        my $caller      = shift;
375        my %opt         = process_options(@_);
376        my $tag = $opt{tag}; $tag = 'draw:' . $tag unless $tag =~ /:/;
377        my $f = ODF::lpOD::StructuredContainer->create($tag);
378        $f->set_attribute('name' => $opt{name});
379        $f->set_style($opt{style});
380        $f->set_text_style($opt{text_style});
381        $f->set_position($opt{position});
382        if (defined $opt{page})
383                {
384                $f->set_anchor_page($opt{page});
385                }
386        else
387                {
388                $f->set_attribute('text:anchor-type' => $opt{anchor_type});
389                }
390        $f->set_title($opt{title});
391        $f->set_description($opt{description});
392        delete @opt
393                {qw(
394                        tag name style size position page
395                        anchor_type title description
396                )};
397        foreach my $a (keys %opt)
398                {
399                $f->set_attribute($a => $opt{$a});
400                }
401        return $f;
402        }
403
404#-----------------------------------------------------------------------------
405
406sub     input_2d
407        {
408        my $self        = shift;
409        return input_2d_value(@_);
410        }
411
412sub     set_anchor_page
413        {
414        my $self        = shift;
415        my $number      = shift;
416        $self->set_attribute('text:anchor-page-number' => $number);
417        $self->set_attribute('text:anchor-type' => 'page');
418        return $number;
419        }
420
421sub     get_anchor_page
422        {
423        my $self        = shift;
424        return $self->get_attribute('text:anchor-page-number');
425        }
426
427sub     set_title
428        {
429        my $self        = shift;
430        my $t = $self->set_last_child('svg:title', shift);
431        return $t;
432        }
433
434sub     get_title
435        {
436        my $self        = shift;
437        my $t = $self->get_element('svg:title') or return undef;
438        return $t->get_text;
439        }
440
441sub     set_description
442        {
443        my $self        = shift;
444        my $t = $self->set_last_child('svg:desc', shift);
445        return $t;
446        }
447
448sub     get_description
449        {
450        my $self        = shift;
451        my $t = $self->get_element('svg:desc') or return undef;
452        return $t->get_text;
453        }
454
455sub     set_text_style
456        {
457        my $self        = shift;
458        return $self->set_attribute('text style name' => shift);
459        }
460
461sub     get_text_style
462        {
463        my $self        = shift;
464        return $self->get_attribute('text style name');
465        }
466
467#=============================================================================
468package ODF::lpOD::Area;
469use base 'ODF::lpOD::Shape';
470our $VERSION    = '1.002';
471use constant PACKAGE_DATE => '2011-02-19T19:54:55';
472use ODF::lpOD::Common;
473#-----------------------------------------------------------------------------
474
475sub     _create  { ODF::lpOD::Area->create(@_) }
476
477#-----------------------------------------------------------------------------
478
479sub     create
480        {
481        my $caller      = shift;
482        my %opt         = @_;
483        my $size        = $opt{size};
484        delete @opt {qw(start end size)};
485        my $a = ODF::lpOD::Shape->create(%opt) or return undef;
486        $a->set_size($size);
487        return $a;
488        }
489
490#=============================================================================
491package ODF::lpOD::Rectangle;
492use base 'ODF::lpOD::Area';
493our $VERSION    = '1.001';
494use constant PACKAGE_DATE => '2010-12-29T22:55:59';
495use ODF::lpOD::Common;
496#-----------------------------------------------------------------------------
497
498sub     _create  { ODF::lpOD::Rectangle->create(@_) }
499
500#-----------------------------------------------------------------------------
501
502sub     create
503        {
504        my $caller      = shift;
505        my $r = ODF::lpOD::Area->create(tag => 'rect', @_);
506        }
507
508#=============================================================================
509package ODF::lpOD::Ellipse;
510use base 'ODF::lpOD::Area';
511our $VERSION    = '1.001';
512use constant PACKAGE_DATE => '2010-12-29T22:56:09';
513use ODF::lpOD::Common;
514#-----------------------------------------------------------------------------
515
516sub     _create  { ODF::lpOD::Ellipse->create(@_) }
517
518#-----------------------------------------------------------------------------
519
520sub     create
521        {
522        my $caller      = shift;
523        return ODF::lpOD::Area->create(tag => 'ellipse', @_);
524        }
525
526#=============================================================================
527package ODF::lpOD::Vector;
528use base 'ODF::lpOD::Shape';
529our $VERSION    = '1.001';
530use constant PACKAGE_DATE => '2010-12-29T22:56:38';
531use ODF::lpOD::Common;
532#-----------------------------------------------------------------------------
533
534sub     _create  { ODF::lpOD::Vector->create(@_) }
535
536#-----------------------------------------------------------------------------
537
538sub     create
539        {
540        my $caller      = shift;
541        my %opt         = @_;
542        my $start       = $opt{start};
543        my $end         = $opt{end};
544        delete @opt {qw(start end position size)};
545        my $v = ODF::lpOD::Shape->create(%opt);
546        $v->set_start_position($start);
547        $v->set_end_position($end);
548        return $v;
549        }
550
551#-----------------------------------------------------------------------------
552
553sub     set_start_position
554        {
555        my $self        = shift;
556        my ($x, $y)     = input_2d_value(@_);
557        $self->set_attribute('svg:x1' => $x);
558        $self->set_attribute('svg:y1' => $y);
559        return ($x, $y);
560        }
561
562sub     set_end_position
563        {
564        my $self        = shift;
565        my ($x, $y)     = input_2d_value(@_);
566        $self->set_attribute('svg:x2' => $x);
567        $self->set_attribute('svg:y2' => $y);
568        return ($x, $y);
569        }
570
571sub     get_position
572        {
573        my $self        = shift;
574        my @p           =
575                (
576                $self->get_attribute('svg:x1'),
577                $self->get_attribute('svg:y1'),
578                $self->get_attribute('svg:x2'),
579                $self->get_attribute('svg:y2')
580                );
581        return wantarray ? @p : [ @p ];
582        }
583
584sub     set_position
585        {
586        my $self        = shift;
587        my $arg         = shift;
588        my ($x1, $y1, $x2, $y2);
589        if (ref $arg)
590                {
591                ($x1, $y1, $x2, $y2) = @{$arg};
592                }
593        else
594                {
595                ($x1, $y1, $x2, $y2) = ($arg, @_);
596                }
597        $self->set_attribute('svg:x1' => $x1);
598        $self->set_attribute('svg:y1' => $y1);
599        $self->set_attribute('svg:x2' => $x2);
600        $self->set_attribute('svg:y2' => $y2);
601        return wantarray ? ($x1, $y1, $x2, $y2) : [ ($x1, $y1, $x2, $y2) ];
602        }
603
604#=============================================================================
605package ODF::lpOD::Line;
606use base 'ODF::lpOD::Vector';
607our $VERSION    = '1.001';
608use constant PACKAGE_DATE => '2010-12-29T18:15:40';
609use ODF::lpOD::Common;
610#-----------------------------------------------------------------------------
611
612sub     _create  { ODF::lpOD::Line->create(@_) }
613
614#-----------------------------------------------------------------------------
615
616sub     create
617        {
618        my $caller      = shift;
619        return ODF::lpOD::Vector->create(tag => 'line', @_);
620        }
621
622#=============================================================================
623package ODF::lpOD::Connector;
624use base 'ODF::lpOD::Vector';
625our $VERSION    = '1.001';
626use constant PACKAGE_DATE => '2010-12-29T22:58:03';
627use ODF::lpOD::Common;
628#-----------------------------------------------------------------------------
629
630sub     _create  { ODF::lpOD::Connector->create(@_) }
631
632#-----------------------------------------------------------------------------
633
634sub     create
635        {
636        my $caller      = shift;
637        my %opt         = process_options(@_);
638        my $cs = $opt{connected_shapes};
639        my $gp = $opt{glue_points};
640        my $type = $opt{type};
641        delete @opt{qw(connected_shapes glue_points type)};
642        my $connector = ODF::lpOD::Vector->create(tag => 'connector', %opt);
643        $connector->set_connected_shapes($cs);
644        $connector->set_glue_points($gp);
645        $connector->set_type($type);
646        return $connector;
647        }
648
649#-----------------------------------------------------------------------------
650
651sub     set_connected_shapes
652        {
653        my $self        = shift;
654        my $arg         = shift;
655        my $ra = ref $arg       or return undef;
656        my ($start, $end);
657        if ($ra eq 'ARRAY')
658                {
659                ($start, $end) = @$arg;
660                }
661        else
662                {
663                ($start, $end) = ($arg, @_);
664                }
665        $self->set_attribute('start shape' => $start);
666        $self->set_attribute('end shape' => $end);
667        return wantarray ? ($start, $end) : [ ($start, $end) ];
668        }
669
670sub     get_connected_shapes
671        {
672        my $self        = shift;
673        my $start = $self->get_attribute('start shape');
674        my $end = $self->get_attribute('end shape');
675        return wantarray ? ($start, $end) : [ ($start, $end) ];
676        }
677
678sub     set_glue_points
679        {
680        my $self        = shift;
681        my $arg         = shift;
682        my ($sgp, $egp);
683        if (ref $arg)
684                {
685                ($sgp, $egp) = @$arg;
686                }
687        else
688                {
689                ($sgp, $egp) = ($arg, @_);
690                }
691        $self->set_attribute('start glue point' => $sgp);
692        $self->set_attribute('end glue point' => $egp);
693        return wantarray ? ($sgp, $egp) : [ ($sgp, $egp) ];
694        }
695
696sub     get_glue_points
697        {
698        my $self        = shift;
699        my $sgp = $self->get_attribute('start glue point');
700        my $egp = $self->get_attribute('end glue point');
701        return wantarray ? ($sgp, $egp) : [ ($sgp, $egp) ];
702        }
703
704sub     set_type
705        {
706        my $self        = shift;
707        my $type        = shift         or return undef;
708        unless ($type ~~ [ 'standard', 'lines', 'line', 'curve' ])
709                {
710                alert "Not allowed connector type $type";
711                return FALSE;
712                }
713        $self->set_attribute('type' => $type);
714        return $type;
715        }
716
717sub     get_type
718        {
719        my $self        = shift;
720        return $self->get_attribute('type');
721        }
722
723#=============================================================================
724package ODF::lpOD::Frame;
725use base 'ODF::lpOD::Area';
726our $VERSION    = '1.007';
727use constant PACKAGE_DATE => '2012-02-20T08:25:26';
728use ODF::lpOD::Common;
729#-----------------------------------------------------------------------------
730
731sub     _create  { ODF::lpOD::Frame->create(@_) }
732
733sub     _create_text
734        {
735        my $text        = shift;
736        return ODF::lpOD::Frame->create(text => $text, @_);
737        }
738
739sub     _create_image
740        {
741        my $link        = shift;
742        return ODF::lpOD::Frame->create(image => $link, @_);
743        }
744
745#-----------------------------------------------------------------------------
746
747sub     create
748        {
749        my $caller      = shift;
750        my %opt         = process_options(@_);
751        $opt{tag} = 'frame';
752        my $fr;
753        my $pc = $opt{class}; delete $opt{class};
754        if ($opt{image})
755                {
756                if ($opt{text})
757                        {
758                        alert   "image and text parameters "    .
759                                "are mutually exlusive";
760                        return undef;
761                        }
762                my $link = $opt{image}; delete $opt{image};
763                $fr = ODF::lpOD::Area->create(%opt) or return undef;
764                $link && $fr->set_image($link);
765                }
766        elsif ($opt{text})
767                {
768                my $text = $opt{text}; delete $opt{text};
769                $fr = ODF::lpOD::Area->create(%opt) or return undef;
770                $fr->set_text_box($text);
771                }
772        else
773                {
774                $fr = ODF::lpOD::Area->create(%opt);
775                }
776        $fr->set_attribute('presentation:class' => $pc) if $pc;
777        return $fr;
778        }
779
780#-----------------------------------------------------------------------------
781
782sub     get_image
783        {
784        my $self        = shift;
785        return $self->get_element('draw:image');
786        }
787
788sub     set_image
789        {
790        my $self        = shift;
791        my $source      = shift;
792        my $link;
793        if (ref $source)
794                {
795                if ($source->is('draw:image'))
796                        {
797                        $source->paste_last_child($self);
798                        return $source;
799                        }
800                else
801                        {
802                        alert "Non-valid image element";
803                        return FALSE;
804                        }
805                }
806        unless ($source)
807                {
808                alert "Missing image URL"; return FALSE;
809                }
810        my %opt = @_;
811        my ($w, $h) = $self->get_size;
812        my $sized = (defined $w && defined $h);
813        if (is_true($opt{load}))
814                {
815                my $doc = $self->document;
816                if ($doc && $doc->{container})
817                        {
818                        unless ($sized || defined $opt{size})
819                                {
820                                ($link, $opt{size}) =
821                                        $doc->add_image_file($source);
822                                }
823                        else
824                                {
825                                $link = $doc->add_image_file($source);
826                                }
827                        }
828                else
829                        {
830                        alert "Image loading not allowed out of a document";
831                        return FALSE;
832                        }
833                }
834        else
835                {
836                $link = $source;
837                }
838        my $image = $self->set_first_child('draw:image');
839        if (defined $opt{size})
840                {
841                $self->set_size($opt{size});
842                delete $opt{size};
843                }
844        else
845                {
846                unless ($sized)
847                        {
848                        my $doc;
849                        my $size;
850                        $doc = $self->get_document if $source =~ /^Pictures\//;
851                        if ($doc)
852                                {
853                                my $st = $doc->get_stored_part($source);
854                                if ($st->{data})
855                                        {
856                                        $size = is_true($st->{string}) ?
857                                                image_size(\$st->{data}) :
858                                                image_size($st->{data});
859                                        }
860                                else
861                                        {
862                                        $size = image_size
863                                                ($source, document => $doc);
864                                        }
865                                }
866                        else
867                                {
868                                $size = image_size($source);
869                                }
870                        $self->set_size($size);
871                        }
872                }
873        $image->set_attribute('xlink:href' => $link);
874        foreach my $o (keys %opt)
875                {
876                my $att = ($o =~ /:/) ? $o : 'xlink:' . $o;
877                $image->set_attribute($att => $opt{$o});
878                }
879        return $image;
880        }
881
882#-----------------------------------------------------------------------------
883
884sub     get_text_box
885        {
886        my $self        = shift;
887        return $self->get_element('draw:text-box');
888        }
889
890sub     set_text_box
891        {
892        my $self        = shift;
893        my $t = $self->set_first_child('draw:text-box');
894        my @list        = @_;
895        foreach my $e (@list)
896                {
897                if (ref $e)
898                        {
899                        $e->paste_last_child($t);
900                        }
901                else
902                        {
903                        ODF::lpOD::Paragraph->create(text => $e)
904                                                ->paste_last_child($t);
905                        }
906                }
907        return $t;
908        }
909
910sub     set_hyperlink
911        {
912        my $self        = shift;
913        unless ($self->parent)
914                {
915                alert "Not allowed with non-attached frames";
916                return FALSE;
917                }
918        my %opt         = process_options(@_);
919        unless ($opt{url})
920                {
921                alert("Missing URL"); return FALSE;
922                }
923        $opt{'xlink:href'}      = $opt{url};
924        $opt{'office:name'}     = $opt{name};
925        delete @opt{qw(url name)};
926        return $self->set_parent('draw:a', undef, %opt);
927        }
928
929sub     get_hyperlink
930        {
931        my $self        = shift;
932        my $parent = $self->parent;
933        return ($parent && $parent->is('draw:a')) ? $parent : undef;
934        }
935
936#=============================================================================
937package ODF::lpOD::Image;
938use base 'ODF::lpOD::StructuredContainer';
939our $VERSION    = '1.002';
940use constant PACKAGE_DATE => '2011-11-15T19:52:49';
941use ODF::lpOD::Common;
942#-----------------------------------------------------------------------------
943
944sub     _create  { ODF::lpOD::Image->create(@_) }
945
946#-----------------------------------------------------------------------------
947
948sub     create
949        {
950        my $caller      = shift;
951        my %opt         = @_;
952        my $image       = ODF::lpOD::StructuredContainer->create('draw:image');
953        my $uri         = $opt{url} || $opt{uri};
954        if ($uri)
955                {
956                $image->set_uri($uri);
957                }
958        elsif ($opt{content})
959                {
960                $image->set_content($opt{content});
961                }
962        else
963                {
964                alert "Missing image resource URI or content";
965                return FALSE;
966                }
967        return $image;
968        }
969
970#-----------------------------------------------------------------------------
971
972sub     set_uri
973        {
974        my $self        = shift;
975        my $uri         = shift;
976        $self->set_attribute('xlink:href' => $uri);
977        my $bin = $self->first_child('office:binary-data');
978        $bin->delete() if $bin;
979        return $uri;
980        }
981
982sub     get_uri
983        {
984        my $self        = shift;
985        return $self->get_attribute('xlink:href');
986        }
987
988sub     set_content
989        {
990        my $self        = shift;
991        my $bin =       $self->first_child('office:binary-data');
992        unless ($bin)
993                {
994                $bin = ODF::lpOD::Element->create('office:binary-data');
995                $bin->paste_last_child($self);
996                }
997        my $content = shift;
998        $bin->_set_text($content);
999        $self->del_attribute('xlink:href');
1000        return $content;
1001        }
1002
1003sub     get_content
1004        {
1005        my $self        = shift;
1006        my $bin = $self->first_child('office:binary-data') or return undef;
1007        return $bin->text;
1008        }
1009
1010#=============================================================================
1011package ODF::lpOD::TOC;
1012use base 'ODF::lpOD::StructuredContainer';
1013our $VERSION    = '1.003';
1014use constant PACKAGE_DATE => '2011-11-15T19:52:49';
1015use ODF::lpOD::Common;
1016#-----------------------------------------------------------------------------
1017
1018use constant TOC_SOURCE             => 'text:table-of-content-source';
1019use constant TOC_ENTRY_TEMPLATE     => 'text:table-of-content-entry-template';
1020use constant TOC_TITLE_TEMPLATE     => 'text:index-title-template';
1021use constant TOC_BODY               => 'text:index-body';
1022
1023#-----------------------------------------------------------------------------
1024
1025sub     _create  { ODF::lpOD::TOC->create(@_) }
1026
1027#-----------------------------------------------------------------------------
1028
1029sub     create
1030        {
1031        my $caller      = shift;
1032        my $name        = shift;
1033        my %opt         = process_options(@_);
1034        my $toc = ODF::lpOD::StructuredContainer->create
1035                ('text:table-of-content');
1036        $toc->set_name($name);
1037        $toc->set_style($opt{style});
1038        $toc->set_protected($opt{protected} // TRUE);
1039        $toc->set_outline_level($opt{outline_level} // 10);
1040        $toc->set_use_outline($opt{use_outline} // TRUE);
1041        $toc->set_use_index_marks($opt{use_index_marks} // FALSE);
1042        $toc->set_title($opt{title} // $name);
1043        return $toc;
1044        }
1045
1046#-----------------------------------------------------------------------------
1047
1048sub     get_source
1049        {
1050        my $self	= shift;
1051        return $self->first_child(TOC_SOURCE);
1052        }
1053
1054sub     set_source
1055        {
1056        my $self	= shift;
1057        return  $self->set_child(TOC_SOURCE);
1058        }
1059
1060sub     get_body
1061        {
1062        my $self	= shift;
1063        return $self->first_child(TOC_BODY);
1064        }
1065
1066sub     set_body
1067        {
1068        my $self	= shift;
1069        return $self->set_child(TOC_BODY);
1070        }
1071
1072sub     source_attribute
1073        {
1074        my $self        = shift;
1075        my $attr        = shift;
1076        my %opt         = @_;
1077        my ($source, $val);
1078        if (exists $opt{value})
1079                {
1080                $source = $self->set_source;
1081                $val = $opt{value};
1082                $val = odf_boolean($val) if $attr =~ /^use/;
1083                $source->set_attribute($attr => $val);
1084                }
1085        else
1086                {
1087                $source = $self->get_source;
1088                $val = $source ? $source->get_attribute($attr) : undef;
1089                $val = TRUE if (is_true($val) && $attr =~ /^use/);
1090                }
1091        return $val;
1092        }
1093
1094sub     get_title
1095        {
1096        my $self	= shift;
1097            my $title = $self->first_descendant(TOC_TITLE_TEMPLATE);
1098            return $title ? $title->get_text : undef;
1099        }
1100
1101sub     set_title
1102        {
1103        my $self	= shift;
1104            my $text        = shift;
1105            my %opt         = @_;
1106        my $source = $self->set_source;
1107            my $style = $opt{style}; delete $opt{style};
1108            return $source->set_child
1109                            (
1110                            TOC_TITLE_TEMPLATE,
1111                            $text,
1112                            'style name'    => $style,
1113                            @_
1114                            );
1115        }
1116
1117sub     get_outline_level
1118        {
1119        my $self	= shift;
1120            return $self->source_attribute('outline level');
1121        }
1122
1123sub     set_outline_level
1124        {
1125        my $self	= shift;
1126            my $level       = shift;
1127            my $source = $self->set_source;
1128            $source->set_attribute('outline level' => $level);
1129            foreach my $l (1..$level)
1130                    {
1131                    my $t = $source->get_element
1132                            (
1133                            TOC_ENTRY_TEMPLATE,
1134                            attribute       => 'outline level',
1135                            value           => $l
1136                            )
1137                            //
1138                    $source->append_element(TOC_ENTRY_TEMPLATE);
1139
1140                    $t->set_attribute ('outline level' => $l);
1141
1142                    $t->append_element('text:index-entry-chapter');
1143                    $t->append_element('text:index-entry-span')
1144                            ->set_text("  ");
1145                    $t->append_element('text:index-entry-text');
1146                    $t->append_element('text:index-entry-tab-stop')
1147                            ->set_attributes
1148                                    (
1149                                    'style:type'            => 'right',
1150                                    'style:leader-char'     => '.'
1151                                    );
1152                    $t->append_element('text:index-entry-page-number');
1153                    }
1154        return $level;
1155        }
1156
1157sub     get_protected
1158        {
1159        my $self	= shift;
1160        return is_true($self->get_attribute('protected'));
1161        }
1162
1163sub     set_protected
1164        {
1165        my $self	= shift;
1166        $self->set_attribute(protected => odf_boolean(shift));
1167            return $self->get_protected;
1168        }
1169
1170sub     get_use_index_marks
1171        {
1172        my $self	= shift;
1173        return $self->source_attribute('use index marks');
1174        }
1175
1176sub     set_use_index_marks
1177        {
1178        my $self	= shift;
1179        return $self->source_attribute('use index marks', value => shift);
1180        }
1181
1182sub     get_use_outline
1183        {
1184        my $self	= shift;
1185        return $self->source_attribute('use outline');
1186        }
1187
1188sub     set_use_outline
1189        {
1190        my $self        = shift;
1191        return $self->source_attribute('use outline', value => shift);
1192        }
1193
1194#-----------------------------------------------------------------------------
1195
1196sub     get_entry_template
1197        {
1198        my $self	= shift;
1199            my $level       = shift;
1200        my $source = $self->get_source;
1201            return $source->get_element
1202                    (
1203                    TOC_ENTRY_TEMPLATE,
1204                    attribute       => 'outline level',
1205                    value           => $level
1206                    );
1207        }
1208
1209#=============================================================================
12101;
1211