1package Visio; 2 3 4#PLEASE SEE MSPATENTLICENSE 5# "This product may incorporate intellectual property owned by 6# Microsoft Corporation. The terms and conditions upon which Microsoft 7# is licensing such intellectual property may be found at 8# http://msdn.microsoft.com/library/en-us/odcXMLRef/html/odcXMLRefLegalNotice.asp" 9 10# Copyright 2005 Aamer Akhter. All rights reserved. 11 12# Redistribution and use in source and binary forms, with or without 13# modification, are permitted provided that the following conditions are 14# met: 15 16# 1. Redistributions of source code must retain the above copyright 17# notice, this list of conditions and the following disclaimer. 18 19# 2. Redistributions in binary form must reproduce the above copyright 20# notice, this list of conditions and the following disclaimer in the 21# documentation and/or other materials provided with the distribution. 22 23# THIS SOFTWARE IS PROVIDED BY THE LICENSOR(S) ``AS IS'' AND ANY EXPRESS 24# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26# DISCLAIMED. IN NO EVENT SHALL THE LICENSOR(S) OR OTHER CONTRIBUTORS BE 27# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 30# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 31# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 32# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 33# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 35# The views and conclusions contained in the software and documentation 36# are those of the authors and should not be interpreted as representing 37# official policies, either expressed or implied, of the Licensor(s). 38 39# The software may be subject to additional license restrictions 40# provided by the Licensor(s). 41 42 43 44 45use 5.008; 46use strict; 47use strict; 48use warnings; 49use Log::Log4perl qw(get_logger); 50use XML::LibXML; 51use Carp; 52use Data::Dumper; 53use vars qw($VERSION); 54 55use Visio::Page; 56use Visio::Master; 57 58$VERSION = sprintf "%d.%03d", q$Revision: 1.10 $ =~ /: (\d+)\.(\d+)/; 59 60Log::Log4perl->init_once(\ qq{ 61 log4perl.logger = DEBUG, Screen 62 log4perl.appender.Screen = Log::Log4perl::Appender::ScreenColoredLevels 63 log4perl.appender.Screen.layout = PatternLayout 64 log4perl.appender.Screen.layout.ConversionPattern=[%d] [%c] [%F{1}:%L] [%p] %m%n 65}); 66my $log = get_logger('visio'); 67my $vNS = 'visio'; 68my $vNSURI = 'http://schemas.microsoft.com/visio/2003/core'; 69 70our $xmlParser = XML::LibXML->new(); 71 72# Preloaded methods go here. 73 74sub new { 75 my $class = shift; 76 my $opts = shift; 77 my $fileName = $$opts{fromFile}; 78 my $self = {}; 79 $self->{xmlparser} = $Visio::xmlParser; 80 81 if (defined $fileName) { 82 $self->{xmldoc} = $self->{xmlparser}->parse_file($fileName); 83 $log->debug("visio object created from $fileName"); 84 $self->{xmlroot} = $self->{xmldoc}->documentElement(); 85 bless($self,$class); 86 } else { 87 $self->{xmldoc} = $self->{xmlparser}->parse_string(<<'EOT'); 88 <VisioDocument xmlns='http://schemas.microsoft.com/visio/2003/core'> 89 </VisioDocument> 90EOT 91$self->{xmlroot} = $self->{xmldoc}->documentElement(); 92 bless($self,$class); 93 $log->debug("visio xml object created"); 94 } 95 $self->{vNSURI} = $self->{xmlroot}->namespaceURI; 96 #add the visio ns as a prefix 97 $self->{xmlroot}->setNamespace 98 ( 99 ($self->{vNSURI}), 100 $vNS, 101 0 102 ); 103 return $self; 104} 105 106sub addpage { 107 my $self = shift; 108 my $pagesN; 109 110#if pages nodes does not exist, create it; 111 $pagesN = generic_create_node($self->{xmlroot}, 112 'Pages' 113 ); 114 115 if (defined $self->{maxpageid}) { 116 $self->{maxpageid} = $self->{maxpageid} + 1; 117 } else { 118 $self->{maxpageid} = 0; 119 } 120 my $page = new Visio::Page($pagesN,$self->{maxpageid}); 121 return $page; 122} 123 124sub toFile { 125 my $self = shift; 126 my $filename = shift; 127 $self->{xmldoc}->toFile($filename,1); 128} 129 130sub toString { 131 my $self = shift; 132 $self->{xmldoc}->toString(2); 133} 134 135sub toXmlDoc { 136 my $self = shift; 137 return $self->{xmldoc}; 138} 139 140sub set_docprop_node { 141 my $self = shift; 142 my $nodeType = shift; 143 my $text = shift; 144 my $dpt = $self->create_docprop_node($nodeType); 145 my $textNode = $self->{xmldoc}->createTextNode($text); 146 $dpt->removeChildNodes(); 147 $log->debug("doc $nodeType set"); 148 $dpt->appendChild($textNode); 149} 150 151sub set_docprop_timenode { 152 my $self = shift; 153 my $nodeType = shift; 154 my $text = shift; 155 $text = visio_timeformat() if (!defined $text); 156 $self->set_docprop_node($nodeType,$text); 157} 158 159sub visio_timeformat { 160 my $time = shift; 161 if (!defined $time) {$time = time()}; 162 my @gmTime = gmtime($time); 163 $gmTime[4]++; # perl months are from 0..11 164 $gmTime[5] += 1900; # perl years 165 return sprintf("%4d-%02d-%02dT%02d:%02d:%02d", 166 $gmTime[5], 167 $gmTime[3], 168 $gmTime[4], 169 $gmTime[2], 170 $gmTime[1], 171 $gmTime[0] 172 ); 173} 174 175sub set_timeSaved { 176 my $self = shift; 177 my $text = shift; 178 $self->set_docprop_timenode('TimeSaved',$text); 179} 180 181sub set_timeCreated { 182 my $self = shift; 183 my $text = shift; 184 $self->set_docprop_timenode('TimeCreated',$text); 185} 186 187 188sub set_title { 189 my $self = shift; 190 my $text = shift; 191 $self->set_docprop_node('Title',$text); 192} 193 194sub set_subject { 195 my $self = shift; 196 my $text = shift; 197 $self->set_docprop_node('Subject',$text); 198} 199 200sub set_manager { 201 my $self = shift; 202 my $text = shift; 203 $self->set_docprop_node('Manager',$text); 204} 205 206sub set_company { 207 my $self = shift; 208 my $text = shift; 209 $self->set_docprop_node('Company',$text); 210} 211 212sub set_desc { 213 my $self = shift; 214 my $text = shift; 215 $self->set_docprop_node('Desc',$text); 216} 217 218sub set_creator { 219 my $self = shift; 220 my $text = shift; 221 $self->set_docprop_node('Creator',$text); 222} 223 224sub find_master_dom { 225 my $self = shift; 226 my $opts = shift; 227 my $nname = $opts->{'name'}; 228 my $xp = "/$vNS:VisioDocument/$vNS:Masters/$vNS:Master"; 229 my $xpSel = ""; 230 if (defined $nname) { 231 $xpSel .= "\@Name = '$nname'"; 232 } 233 $xp .= "[$xpSel]"; 234 $log->debug("searching with $xp"); 235 return $self->{xmlroot}->findnodes($xp); 236} 237 238 239sub create_master { 240 my $self = shift; 241 my $opts = shift; 242 my $fromDom = $$opts{'fromDom'}; 243 my $master; 244 my $mastersNode = generic_create_node($self->{xmlroot}, 245 'Masters' 246 ); 247 if (defined $self->{maxMasterid}) { 248 $self->{maxMasterid} = $self->{maxMasterid} + 1; 249 } else { 250 $self->{maxMasterid} = 0; 251 } 252 if (defined $fromDom) { 253 $master = new Visio::Master($mastersNode, 254 $self->{maxMasterid}, 255 {fromDom=>$fromDom} 256 ); 257 } 258 return $master; 259} 260 261 262 263 264#================ PRIIVATE FUNCTIONS 265 266 267sub create_docprop_node { 268 my $self = shift; 269 my $node = shift; 270 my $dp = $self->create_docprop(); 271 return generic_create_node($dp, $node); 272} 273 274sub create_docprop { 275 my $self = shift; 276 #see of DocumentProperties already exists, if not crate it 277 my $docpropNL = $self->{xmlroot}->findnodes("DocumentProperties"); 278 return $docpropNL->pop if ($docpropNL->size() > 0); 279 $log->debug('creating DocumentProperties node'); 280 my $docpropN = $self->{xmldoc}->createElement("DocumentProperties"); 281 $self->{xmlroot}->insertBefore( 282 $docpropN, 283 $self->{xmlroot}->firstChild 284 ); 285} 286 287sub generic_create_node { 288 my $parent = shift; 289 my $node = shift; 290 my $nodeNL = $parent->findnodes("$node"); 291 return $nodeNL->pop if ($nodeNL->size() > 0); 292 $log->debug("creating $parent/$node node"); 293 my $uri = $parent->namespaceURI; 294 if (!defined $uri) { 295 $uri = $vNSURI; 296 } 297 my $nodeN = $parent->ownerDocument->createElement("$node"); 298 $parent->appendChild($nodeN); 299 return $nodeN; 300} 301 302sub generic_settext { 303 my $node = shift; 304 my $text = shift; 305 my $textNode = $node->ownerDocument->createTextNode($text); 306 $node->removeChildNodes(); 307 $log->debug("doc $node text set"); 308 $node->appendChild($textNode); 309} 310 311 3121; 313__END__ 314# Below is stub documentation for your module. You'd better edit it! 315 316=head1 NAME 317 318Visio - Perl extension mainpulating XML based Visio files 319 320=head1 SYNOPSIS 321 322To create a viso vdx file, create multiple pages, reorient one of the pages: 323 324 my $v = new Visio(); 325 $v->set_title('wabla wabla'); 326 $v->set_timeCreated(); 327 $v->set_timeSaved() 328 329 my $page = $v->addpage(); 330 $page->set_name('my page'); 331 $page->set_heightWidth(8,11); 332 333 my $page2 = $v->addpage(); 334 $page2->set_name('my page2'); 335 336 $v->toFile('myvisofile.vdx'); 337 338=head1 ABSTRACT 339 340 Visio is an alpha stage library to create and manipulate Microsoft Visio 341 drawings. 342 343=head1 DESCRIPTION 344 345 Visio is an alpha stage library to create and manipulate Microsoft Visio 346 drawings. 347 348 Currently it can only create drawings from scratch, and can not 349 create a usable object model from a pre-existing file. 350 351 The Visio module is however able to extract stencils from pre-existing 352 files and insert them into your new drawings. This is helpfull as 353 it is fairly difficult to make a nice drawing on your own via the 354 current Visio perl module API. 355 356 This is my first public Perl module, and I'm sure there are tons of 357 mistakes. Please feel free to communicate any design flaws or reworking 358 you may feel would make Visio more usable and approachable. 359 360=head1 Document Methods 361 362=head2 new() 363 364A new Visio document is created using the new method: 365 366 my $vDoc = new Visio(); 367 368By default the document is completely empty and the document creator is set to 'perl-visio'. This can be overwritten by use of the set_creator method. 369 370=head2 toString() 371 372Visio document is returned as an XML string. 373 374 my $vString = $vDoc->toString; 375 376=head2 toFile($filename) 377 378Visio doc is written out to an XML file. 379 380 $vDoc->toFile('myfile.vdx'); 381 382=head2 toXmlDoc() 383 384libxml2 doc element is returned 385 386 $vDoc->toXmlDoc(); 387 388=head2 set_title($title) 389 390Sets Document title 391 392 $vDoc->set_title('my title'); 393 394=head2 set_subject($subject) 395 396Sets Document subject 397 398 $vDoc->set_subject('my subject'); 399 400=head2 set_manager($manager) 401 402Sets Document manager field 403 404 $vDoc->set_manager('my manager'); 405 406=head2 set_company($company) 407 408Sets company filed in document. 409 410 $vDoc->set_company('my company'); 411 412=head2 set_desc($desc) 413 414Sets Document description. 415 416 $vDoc->set_desc('my really good description'); 417 418=head2 set_creator($creator) 419 420Sets Document creator field. 421 422 $vDoc->set_creator('just me'); 423 424=head2 set_timeCreated($visoTimeString) 425 426Set's document time created information. If time is not passed, the current time (UTC) is set. 427 428 $vDoc->set_timeCreated(); 429 430=head2 set_timeSaved($visioTimeString) 431 432Set's document time saved information. If time is not passed, the current time (UTC) is set. 433 434 $vDoc->set_timeSaved(); 435 436=head2 visio_timeformat($time) 437 438Takes in argument of $time, which is in the format of the perl time() function. Returns a $visioTimeString formatted string. 439 440 $vDoc->set_timeCreated(Visio::visio_timeformat(time())); 441 442 is equivilent to: 443 444 $vDoc->set_timeCreated(); 445 446=head2 find_master_dom() 447 448searches the visio masters (stencils). filters can be specifed: 449 450 $vDoc->find_master_dom({name=>'myrectangle'}) 451 452returns a libxml nodelist object of all stencils that had name 'myractangle'. Not specifying filters returns all stencils. 453 454filters avaliable: 455 456name 457 458 459 460=head1 Page Methods 461 462=head2 addpage() 463 464A new Visio page is created in a Visio document. 465 466 my $vPage1 = $vDoc->addpage(); 467 468By default the document is completely empty and the document creator is set to 'perl-visio'. This can be overwritten by use of the set_creator method. 469 470=head2 set_name($name) 471 472Sets the name of the page 473 474 $vPage->set_name('mypage'); 475 476=head2 set_heightWidth($height,$width) 477 478Sets a page's height and width. In inches by default: 479 480 $vPage->setheightWidth(8,11); 481 482=head2 create_pageSheet(); 483 484creates a pageSheet method if needed under this page 485 486 my $pageSheet = $vPage->create_pageSheet(); 487 488=head1 PageSheet methods 489 490For the most part one shouldn't need to directly use these methods 491 492=head2 new($parentNode) 493 494new creates (if one does not already exist) a new child PageSheet element node under $parentNode, which is a libxml2 object. 495 496=head2 get_node 497 498returns the PageSheet libxml2 node 499 500 my $pageSheetNode = $pageSheet->getnode(); 501 502=head2 create_pageProps 503 504creates a PageProps object and element under the current PageSheet 505 506=head1 PageProps methods 507 508For the most part one shouldn't need to directly use these methods 509 510=head2 new($parentNode) 511 512new creates (if one does not already exist) a new child PageProps element node under $parentNode, which is a libxml2 object. 513 514 515=head2 get_node 516 517returns the PageProps libxml2 node 518 519 my $pagePropsNode = $pageProps->getnode(); 520 521=head2 set_PageWidth($width) 522 523sets the page width of this PageProps node. Default unit is in inches. 524 525 $pageProps->set_PageWidth($width); 526 527=head2 set_PageHeight($height) 528 529sets the page height of this PageProps node. Default unit is in inches. 530 531 $pageProps->set_PageHeight($height); 532 533 534 535=head2 EXPORT 536 537None by default. 538 539 540 541=head1 SEE ALSO 542 543 544If you have a mailing list set up for your module, mention it here. 545 546 547=head1 AUTHOR 548 549Aamer Akhter, E<lt>aakhter@cisco.comE<gt> E<lt>aakhter@gmail.comE<gt> 550 551=head1 COPYRIGHT AND LICENSE 552 553Copyright 2005 by Aamer Akhter 554 555This library is free software; you can redistribute it and/or modify 556it under the same terms as in LICENSE and MSPATENTLICENSE files. 557 558 "This product may incorporate intellectual property owned by 559 Microsoft Corporation. The terms and conditions upon which Microsoft 560 is licensing such intellectual property may be found at 561 http://msdn.microsoft.com/library/en-us/odcXMLRef/html/odcXMLRefLegalNotice.asp" 562 563=cut 564