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