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