line
stmt
bran
cond
sub
pod
time
code
1
package Autodia::Diagram;
2
1
1
23625
use strict;
1
2
1
43
3
4
=head1 NAME
5
6
Autodia::Diagram - Class to hold a collection of objects representing parts of a Dia Diagram.
7
8
=head1 SYNOPSIS
9
10
use Autodia::Diagram;
11
12
my $Diagram = Autodia::Diagram->new;
13
14
=head2 Description
15
16
Diagram is an object that contains a collection of diagram elements and the logic to generate the diagram layout as well as to output the diagram itself in Dia's XML format using template toolkit.
17
18
=cut
19
20
1
1
3834
use Template;
1
99369
1
40
21
1
1
3490
use Data::Dumper;
1
11736
1
230
22
23
$Data::Dumper::Maxdepth = 2;
24
25
1
1
732
use Autodia::Diagram::Class;
1
4
1
53
26
1
1
758
use Autodia::Diagram::Component;
1
2
1
51
27
1
1
705
use Autodia::Diagram::Superclass;
1
3
1
45
28
1
1
551
use Autodia::Diagram::Dependancy;
1
2
1
43
29
1
1
643
use Autodia::Diagram::Inheritance;
1
2
1
48
30
1
1
687
use Autodia::Diagram::Relation;
1
2
1
42
31
1
1
861
use Autodia::Diagram::Realization;
1
3
1
14397
32
33
my %dot_filetypes = (
34
gif => 'as_gif',
35
png => 'as_png',
36
jpg => 'as_jpeg',
37
jpeg => 'as_jpeg',
38
dot => 'as_canon',
39
svg => 'as_svg',
40
fig => 'as_fig',
41
);
42
43
my %vcg_filetypes = (
44
ps => 'as_ps',
45
pbm => 'as_pbm',
46
ppm => 'as_ppm',
47
vcg => 'as_vcg',
48
plainvcg => 'as_plainvcg',
49
);
50
51
#----------------------------------------------------------------
52
# Constructor Methods
53
54
55
=head1 METHODS
56
57
=head2 Class Methods
58
59
=over 4
60
61
=item new - constructor method
62
63
creates and returns an unpopulated diagram object.
64
65
=back
66
67
=cut
68
69
sub new
70
{
71
0
0
1
my $class = shift;
72
73
0
my $config_ref = shift;
74
0
my $Diagram = {};
75
0
0
bless ($Diagram, ref($class) || $class);
76
0
$Diagram->directed(1);
77
0
$Diagram->_initialise($config_ref);
78
0
return $Diagram;
79
}
80
81
=head2 Object methods
82
83
To get a collection of a objects of a certain type you use the method of the same name. ie $Diagram->Classes() returns an array of 'class' objects.
84
85
The methods available are Classes(), Components(), Superclasses(), Inheritances(), Relations(), and Dependancies(); These are all called in the template to get the collections of objects to loop through.
86
87
To add an object to the diagram. You call the add_ method, for example $Diagram->add_class($class_name), passing the name of the object in the case of Class, Superclass and Component but not Inheritance or Dependancy which have their names generated automagically.
88
89
Objects are not removed, they can only be superceded by another object; Component can be superceded by Superclass which can superceded by Class. This is handled by the object itself rather than the diagram.
90
91
=head2 Accessing and manipulating the Diagram
92
93
Elements are added to the Diagram through the add_ method (ie add_classes() ).
94
95
Collections of elements are retrieved through the method (ie Classes() ).
96
97
The diagram is laid out and output to a file using the export_xml() method.
98
99
=cut
100
101
################
102
# Access Methods
103
104
sub directed {
105
0
0
0
my $self = shift;
106
0
my $value = shift;
107
0
0
$self->{directed} = $value if (defined $value);
108
0
0
$self->{directed} ||= 0;
109
0
return $self->{directed};
110
}
111
112
sub add_inputfile {
113
0
0
0
my $self = shift;
114
0
my $inputfile = shift;
115
0
$self->{input_files}{$inputfile} = 1;
116
0
return;
117
}
118
119
sub is_inputfile {
120
0
0
0
my $self = shift;
121
0
my $name = shift;
122
0
return $self->{input_files}{$name};
123
}
124
125
126
sub add_dependancy
127
{
128
0
0
0
my $self = shift;
129
0
my $dependancy = shift;
130
131
0
$self->_package_add($dependancy);
132
0
$dependancy->Set_Id($self->_object_count);
133
134
0
return 1;
135
}
136
137
sub add_realization {
138
0
0
0
my $self = shift;
139
0
my $realization = shift;
140
141
0
$self->_package_add($realization);
142
0
$realization->Set_Id( $self->_object_count );
143
144
0
return 1;
145
}
146
147
sub add_inheritance {
148
0
0
0
my $self = shift;
149
0
my $inheritance = shift;
150
151
0
$self->_package_add($inheritance);
152
0
$inheritance->Set_Id($self->_object_count);
153
154
0
return 1;
155
}
156
157
sub add_relation {
158
0
0
0
my $self = shift;
159
0
my $relation = shift;
160
161
0
$self->_package_add($relation);
162
0
$relation->Set_Id($self->_object_count);
163
164
0
return 1;
165
}
166
167
sub add_component
168
{
169
0
0
0
my $self = shift;
170
0
my $component = shift;
171
0
my $return = 0;
172
173
# check to see if package of this name already exists
174
0
my $exists = $self->_package_exists($component);
175
176
0
0
if (ref($exists))
177
{
178
0
0
if ($exists->Type eq "Component")
179
{
180
# replace self with already present component
181
0
$component->Redundant($exists);
182
0
$return = $exists;
183
}
184
}
185
else
186
{
187
# component is new and unique
188
0
$self->_package_add($component);
189
0
$component->Set_Id($self->_object_count);
190
}
191
192
0
return $return;
193
}
194
195
sub add_superclass
196
{
197
0
0
0
my $self = shift;
198
0
my $superclass = shift;
199
0
my $return = 0;
200
201
# check to see if package of this name already exists
202
0
my $exists = $self->_package_exists($superclass);
203
204
0
0
if (ref($exists))
205
{
206
0
0
if ($exists->Type eq "superclass")
207
0
{ $return = $exists;}
208
0
else { print STDERR "eek!! wrong type of object returned by _package_exists\n"; }
209
}
210
else
211
{
212
0
$self->_package_add($superclass);
213
0
$superclass->Set_Id($self->_object_count);
214
}
215
0
return $return;
216
}
217
218
sub add_class
219
{
220
0
0
0
my $self = shift;
221
0
my $class = shift;
222
223
# some perl modules such as CGI.pm do things by redeclaring packages - eek!
224
# this is a nasty hack to get around that nasty hack. ie class is not added
225
# to diagram and so everything is discarded until next new package declared
226
0
0
if (defined $self->{"packages"}{"class"}{$class->Name})
227
{
228
0
print STDERR "Diagram.pm : add_class : ignoring duplicate class",
229
$class->Name, "\n";
230
# warn Dumper (original_class=>$self->{"packages"}{"class"}{$class->Name});
231
0
return $self->{"packages"}{"class"}{$class->Name};
232
}
233
# note : when running benchmark.pl this seems to appear which I guess is a
234
# scoping issue when calling autodial multiple times - odd, beware if using
235
# mod_perl or something similar, not that it breaks anything but you never know
236
237
0
$class->Set_Id($self->_object_count);
238
0
$self->_package_add($class);
239
240
0
return $class;
241
}
242
243
sub remove_duplicates
244
{
245
0
0
0
my $self = shift;
246
247
0
0
if (defined $self->{"packages"}{"superclass"})
248
{
249
0
my @superclasses = @{$self->Superclasses};
0
250
0
foreach my $superclass (@superclasses)
251
{
252
# if a component exists with the same name as the superclass
253
0
0
if (defined $self->{"packages"}{"Component"}{$superclass->Name})
254
{
255
0
my $component = $self->{"packages"}{"Component"}{$superclass->Name};
256
# mark component redundant
257
0
$component->Redundant;
258
# remove component
259
0
$self->_package_remove($component);
260
# kill its dependancies
261
0
foreach my $dependancy ($component->Dependancies)
262
{
263
# remove dependancy
264
0
$self->_package_remove($dependancy);
265
}
266
}
267
}
268
}
269
270
0
0
if (defined $self->{"packages"}{"class"})
271
{
272
0
my @classes = @{$self->Classes};
0
273
0
foreach my $class (@classes)
274
{
275
# if a superclass exists with the same name as the class
276
0
0
if (defined $self->{"packages"}{"superclass"}{$class->Name})
277
{
278
# mark as redundant, remove and steal its children
279
0
my $superclass = $self->{"packages"}{"superclass"}{$class->Name};
280
0
$superclass->Redundant;
281
0
$self->_package_remove($superclass);
282
0
foreach my $inheritance ($superclass->Inheritances) {
283
0
0
if (ref($inheritance)) {
284
0
$inheritance->Parent($class->Id);
285
} else {
286
0
warn "problem with inheritance : $inheritance - class : ",$class->Name,"\n";
287
}
288
}
289
0
$class->has_child(scalar $superclass->Inheritances);
290
291
0
foreach my $relation ($superclass->Relations) {
292
0
$relation->Right($class);
293
}
294
295
}
296
297
# if a component exists with the same name as the class
298
0
0
if (defined $self->{"packages"}{"Component"}{$class->Name})
299
{
300
# mark as redundant, remove and steal its children
301
0
my $component = $self->{"packages"}{"Component"}{$class->Name};
302
0
$component->Redundant;
303
0
$self->_package_remove($component);
304
0
foreach my $dependancy ($component->Dependancies)
305
0
{ $dependancy->Parent($class->Id); }
306
}
307
308
}
309
}
310
0
return 1;
311
}
312
313
###
314
315
sub Classes
316
{
317
0
0
0
my $self = shift;
318
319
0
my ($cp, $cf, $cl) = caller;
320
321
0
my %config = %{$self->{_config}};
0
322
0
0
unless (defined $self->{packages}{class})
323
{
324
0
print STDERR "Diagram.pm : Classes : no Classes to be printed\n";
325
0
return 0;
326
}
327
0
my @classes;
328
0
my %classes = %{$self->{"packages"}{"class"}};
0
329
0
my @keys = keys %classes;
330
0
my $i = 0;
331
332
0
foreach my $key (@keys)
333
0
{ $classes[$i++] = $classes{$key}; }
334
335
0
my $return = \@classes;
336
337
0
0
0
if (($config{sort}) && ($cp ne "Diagram"))
338
0
{ $return = $self->_sort(\@classes); }
339
340
341
0
return $return;
342
}
343
344
345
sub InputFiles {
346
0
0
0
my $self = shift;
347
0
return $self->{input_files};
348
}
349
350
sub Components
351
{
352
0
0
0
my $self = shift;
353
0
0
unless (defined $self->{"packages"}{"Component"})
354
{
355
0
print STDERR "Diagram.pm : Components : no Components to be printed\n";
356
0
return 0;
357
}
358
0
my @components;
359
0
my %components = %{$self->{"packages"}{"Component"}};
0
360
0
my @keys = keys %components;
361
0
my $i = 0;
362
363
0
foreach my $key (@keys)
364
0
{ $components[$i++] = $components{$key}; }
365
366
0
return \@components;
367
}
368
369
sub Superclasses
370
{
371
0
0
0
my $self = shift;
372
0
0
unless (defined $self->{"packages"}{"superclass"})
373
{
374
0
print STDERR "Diagram.pm : Superclasses : no superclasses to be printed\n";
375
0
return 0;
376
}
377
0
my @superclasses;
378
0
my %superclasses = %{$self->{"packages"}{"superclass"}};
0
379
0
my @keys = keys %superclasses;
380
0
my $i = 0;
381
382
0
foreach my $key (@keys)
383
{
384
0
$superclasses[$i++] = $superclasses{$key};
385
}
386
0
return \@superclasses;
387
}
388
389
sub Inheritances
390
{
391
0
0
0
my $self = shift;
392
0
0
unless (defined $self->{"packages"}{"inheritance"})
393
{
394
0
print STDERR "Diagram.pm : Inheritances : no Inheritances to be printed - ignoring..\n";
395
0
return 0;
396
}
397
0
my @inheritances;
398
0
my %inheritances = %{$self->{"packages"}{"inheritance"}};
0
399
0
my @keys = keys %inheritances;
400
0
my $i = 0;
401
402
0
foreach my $key (@keys)
403
{
404
0
$inheritances[$i++] = $inheritances{$key};
405
}
406
407
0
return \@inheritances;
408
}
409
410
sub Relations {
411
0
0
0
my $self = shift;
412
413
0
0
unless (defined $self->{"packages"}{"relation"}) {
414
0
print STDERR "Diagram.pm : Relations : no Relations to be printed - ignoring..\n";
415
0
return 0;
416
}
417
418
0
my @relations;
419
0
my %relations = %{$self->{"packages"}{"relation"}};
0
420
0
my @keys = keys %relations;
421
422
423
0
my $i = 0;
424
0
foreach my $key (@keys) {
425
0
$relations[$i++] = $relations{$key};
426
}
427
428
0
return \@relations;
429
}
430
431
sub Realizations {
432
0
0
0
my $self = shift;
433
434
0
0
unless( defined $self->{"packages"}{"realization"} ) {
435
0
print STDERR "Realizations Diagram.pm : none to be printed - ignoring..\n
436
";
437
0
return 0;
438
}
439
440
0
my @realizations;
441
0
my %realizations = %{ $self->{"packages"}{"realization"} };
0
442
0
my @keys = keys %realizations;
443
0
my $i = 0;
444
445
0
foreach my $key (@keys) {
446
0
$realizations[ $i++ ] = $realizations{$key};
447
}
448
449
0
return \@realizations;
450
}
451
452
sub Dependancies
453
{
454
0
0
0
my $self = shift;
455
0
0
unless (defined $self->{"packages"}{"dependancy"})
456
{
457
0
print STDERR "Diagram.pm : Dependancies : no dependancies to be printed - ignoring..\n";
458
0
return 0;
459
}
460
0
my @dependancies;
461
0
my %dependancies = %{$self->{"packages"}{"dependancy"}};
0
462
0
my @keys = keys %dependancies;
463
0
my $i = 0;
464
465
0
foreach my $key (@keys)
466
{
467
0
$dependancies[$i++] = $dependancies{$key};
468
}
469
470
0
return \@dependancies;
471
}
472
473
##########################################################
474
# export_graphviz - output to file via GraphViz.pm and dot
475
476
sub export_graphviz
477
{
478
0
0
0
my $self = shift;
479
0
require GraphViz;
480
0
require Data::Dumper;
481
482
0
my %config = %{$self->{_config}};
0
483
484
0
my $output_filename = $config{outputfile};
485
486
0
my ($extension) = reverse (split(/\./,$output_filename));
487
488
0
0
$extension = "gif" unless ($dot_filetypes{$extension});
489
490
0
$output_filename =~ s/\.[^\.]+$/.$extension/;
491
492
0
my %args = (directed => $self->directed, ratio => 'expand', concentrate => 1, splines=>'false', lines=>1);
493
# $args{layout} = 'fdp' unless ($self->directed);
494
# $args{overlap} = 'false' unless ($self->directed);
495
0
my $g = GraphViz->new( %args );
496
497
0
my %nodes = ();
498
499
0
my $classes = $self->Classes;
500
0
0
if (ref $classes) {
501
0
foreach my $Class (@$classes) {
502
503
0
my $node = '{'.$Class->Name."|";
504
505
0
0
if ($config{methods}) {
506
0
my @method_strings = ();
507
0
my ($methods) = ($Class->Operations);
508
0
foreach my $method (@$methods) {
509
0
0
0
next if ($method->{visibility} == 1 && $config{public});
510
0
0
my $method_string = ($method->{visibility} == 0) ? '+ ' : '- ';
511
0
$method_string .= $method->{name}."(";
512
0
0
if (ref $method->{"Params"} ) {
513
0
my @args = ();
514
0
foreach my $argument ( @{$method->{"Params"}} ) {
0
515
0
0
push (@args, ((defined ($argument->{Type}) )? $argument->{Type} . " " . $argument->{Name} : $argument->{Name}));
516
}
517
0
0
$method_string .= join (", ",@args) if (scalar @args);
518
}
519
0
0
$method_string .= " ) : ". (defined $method->{type} ? $method->{type} : '');
520
0
push (@method_strings,$method_string);
521
}
522
0
foreach my $method_string ( @method_strings ) {
523
0
$node .= "$method_string".'\l';
524
}
525
}
526
0
$node .= "|";
527
0
0
if ($config{attributes}) {
528
0
my ($attributes) = ($Class->Attributes);
529
0
foreach my $attribute (@$attributes) {
530
0
0
0
next if ($attribute->{visibility} == 1 && $config{public});
531
0
0
$node .= ($attribute->{visibility} == 0) ? '+ ' : '- ';
532
0
$node .= $attribute->{name};
533
534
# Check if $attribute->{type} is defined.
535
# Otherwise we get warnings like:
536
0
0
if (defined $attribute->{type}) {
537
0
$node .= " : ".$attribute->{type}.'\l';
538
} else {
539
0
$node .= '\l';
540
}
541
}
542
}
543
544
0
$node .= '}';
545
546
0
$nodes{$Class->Id} = $node;
547
548
0
$g->add_node($node,shape=>'record');
549
550
}
551
} else {
552
0
return 0;
553
}
554
555
0
0
unless ($config{skip_superclasses}) {
556
0
my $superclasses = $self->Superclasses;
557
0
0
if (ref $superclasses) {
558
0
foreach my $Superclass (@$superclasses) {
559
# warn "superclass name :", $Superclass->Name, " id :", $Superclass->Id, "\n";
560
0
my $node = $Superclass->Name;
561
0
$node=~ s/[\{\}]//g;
562
0
$node = '{'.$node."|\n}";
563
# warn "node : $node\n";
564
0
$nodes{$Superclass->Id} = $node;
565
0
$g->add_node($node,shape=>'record');
566
}
567
}
568
}
569
570
571
0
my $inheritances = $self->Inheritances;
572
0
0
if (ref $inheritances) {
573
0
foreach my $Inheritance (@$inheritances) {
574
0
0
next unless ($nodes{$Inheritance->Parent});
575
# warn "inheritance parent :", $Inheritance->Parent, " child :", $Inheritance->Child, "\n";
576
0
$g->add_edge($nodes{$Inheritance->Parent} => $nodes{$Inheritance->Child}, dir => 'back');
577
}
578
}
579
580
0
my $relations = $self->Relations;
581
0
0
if (ref $relations) {
582
0
foreach my $Relation (@$relations) {
583
0
0
next unless ($nodes{$Relation->Left});
584
0
my %edge_args = (dir => 'none', weight => 1.2 );
585
0
$g->add_edge($nodes{$Relation->Left} => $nodes{$Relation->Right}, %edge_args);
586
}
587
}
588
589
0
0
unless ($config{skip_packages}) {
590
0
my $components = $self->Components;
591
0
0
if (ref $components) {
592
0
foreach my $Component (@$components) {
593
# warn "component name :", $Component->Name, " id :", $Component->Id, "\n";
594
0
my $node = '{'.$Component->Name.'}';
595
# warn "node : $node\n";
596
0
$nodes{$Component->Id} = $node;
597
0
$g->add_node($node, shape=>'record');
598
}
599
}
600
}
601
602
0
my $dependancies = $self->Dependancies;
603
0
0
if (ref $dependancies) {
604
0
foreach my $Dependancy (@$dependancies) {
605
# warn "dependancy parent ", $Dependancy->Parent, " child :", $Dependancy->Child, "\n";
606
0
0
next unless ($nodes{$Dependancy->Parent});
607
0
$g->add_edge($nodes{$Dependancy->Parent}=>$nodes{$Dependancy->Child}, dir => 'back', style=>'dashed');
608
}
609
}
610
611
0
0
open (FILE,">$output_filename") or die "couldn't open $output_filename file for output : $!\n";
612
0
binmode FILE;
613
0
eval 'print FILE $g->'. $dot_filetypes{$extension};
614
615
0
close FILE;
616
617
0
return 1;
618
}
619
620
sub Warn {
621
0
0
0
my ($self,$warning) = @_;
622
0
warn "warning : $warning\n";
623
0
return;
624
}
625
626
627
########################################################
628
# export_springgraph - output to file via SpringGraph.pm
629
630
sub export_springgraph
631
{
632
0
0
0
my $self = shift;
633
0
my %config = %{$self->{_config}};
0
634
635
0
require SpringGraph;
636
0
require Data::Dumper;
637
638
0
my $output_filename = $config{outputfile};
639
0
my ($extension) = reverse (split(/\./,$output_filename));
640
0
0
$extension = "gif" unless ($dot_filetypes{$extension});
641
0
$output_filename =~ s/\.[^\.]+$/.$extension/;
642
643
0
my $g = new SpringGraph;
644
645
0
my %nodes = ();
646
0
my $classes = $self->Classes;
647
0
0
if (ref $classes) {
648
0
foreach my $Class (@$classes) {
649
650
0
my $node = $Class->Name."|";
651
652
0
0
if ($config{methods}) {
653
0
my @method_strings = ();
654
0
my ($methods) = ($Class->Operations);
655
0
foreach my $method (@$methods) {
656
0
0
0
next if ($method->{visibility} == 1 && $config{public});
657
0
0
my $method_string = ($method->{visibility} == 0) ? '+ ' : '- ';
658
0
$method_string .= $method->{name}."(";
659
0
0
if (ref $method->{"Params"} ) {
660
0
my @args = ();
661
0
foreach my $argument ( @{$method->{"Params"}} ) {
0
662
0
0
push (@args, ((defined ($argument->{Type}) )? $argument->{Type} . " " . $argument->{Name} : $argument->{Name}));
663
}
664
0
0
$method_string .= join (", ",@args) if (scalar @args);
665
}
666
0
0
$method_string .= " ) : ". (defined $method->{type} ? $method->{type} : '');
667
0
push (@method_strings,$method_string);
668
}
669
0
foreach my $method_string ( @method_strings ) {
670
0
$node .= "$method_string\n";
671
}
672
}
673
0
$node .= "|";
674
0
0
if ($config{attributes}) {
675
0
my ($attributes) = ($Class->Attributes);
676
0
foreach my $attribute (@$attributes) {
677
0
0
0
next if ($attribute->{visibility} == 1 && $config{public});
678
0
0
$node .= "\n" . ($attribute->{visibility} == 0) ? '+ ' : '- ';
679
0
$node .= $attribute->{name};
680
0
0
$node .= " : ".$attribute->{type} if (defined $attribute->{type});
681
0
$node .= "\n";
682
}
683
}
684
685
0
$nodes{$Class->Id} = $Class->Name;
686
687
0
$g->add_node($Class->Name, label=>$node,shape=>'record');
688
689
}
690
} else {
691
0
return 0;
692
}
693
0
0
unless ($config{skip_superclasses}) {
694
0
my $superclasses = $self->Superclasses;
695
0
0
if (ref $superclasses) {
696
0
foreach my $Superclass (@$superclasses) {
697
# warn "superclass name :", $Superclass->Name, " id :", $Superclass->Id, "\n";
698
0
my $node = $Superclass->Name;
699
0
$node=~ s/[\{\}]//g;
700
0
$node .= "|\n";
701
# warn "node : $node\n";
702
0
$nodes{$Superclass->Id} = $node;
703
0
$g->add_node($node,label=>$node,shape=>'record');
704
}
705
}
706
}
707
0
my $inheritances = $self->Inheritances;
708
0
0
if (ref $inheritances) {
709
0
foreach my $Inheritance (@$inheritances) {
710
0
0
next unless ($nodes{$Inheritance->Parent});
711
# warn "inheritance parent :", $Inheritance->Parent, " child :", $Inheritance->Child, "\n";
712
0
$g->add_edge(
713
$nodes{$Inheritance->Parent}=>$nodes{$Inheritance->Child},
714
dir=>'1',
715
);
716
}
717
}
718
719
0
my $relations = $self->Relations;
720
0
0
if (ref $relations) {
721
0
foreach my $Relation (@$relations) {
722
0
0
next unless ($nodes{$Relation->Left});
723
# warn "relation left :", $Relation->Left, " right :", $Relation->Right, "\n";
724
0
my %edge_args = ($nodes{$Relation->Left} => $nodes{$Relation->Right}, style => 'dotted');
725
0
$g->add_edge(%edge_args);
726
}
727
}
728
729
0
0
unless ($config{skip_packages}) {
730
0
my $components = $self->Components;
731
0
0
if (ref $components) {
732
0
foreach my $Component (@$components) {
733
# warn "component name :", $Component->Name, " id :", $Component->Id, "\n";
734
0
my $node = $Component->Name;
735
# warn "node : $node\n";
736
0
$nodes{$Component->Id} = $node;
737
0
$g->add_node($node,label=>$node, shape=>'record');
738
}
739
}
740
}
741
742
0
my $dependancies = $self->Dependancies;
743
0
0
if (ref $dependancies) {
744
0
foreach my $Dependancy (@$dependancies) {
745
0
0
next unless ($nodes{$Dependancy->Parent});
746
# warn "dependancy parent ", $Dependancy->Parent, " child :", $Dependancy->Child, "\n";
747
0
$g->add_edge( $nodes{$Dependancy->Parent}=>$nodes{$Dependancy->Child}, style=>'dashed',dir=>1);
748
}
749
}
750
751
0
$g->as_png($output_filename);
752
753
0
return 1;
754
}
755
756
####################################################
757
# export_vcg - output to file via VCG.pm and xvcg
758
759
sub export_vcg {
760
0
0
0
my $self = shift;
761
0
require VCG;
762
0
require Data::Dumper;
763
764
0
my %config = %{$self->{_config}};
0
765
0
my $output_filename = $config{outputfile};
766
0
my ($extension) = reverse (split(/\./,$output_filename));
767
0
0
$extension = "pbm" unless ($vcg_filetypes{$extension});
768
769
0
$output_filename =~ s/\.[^\.]+$/.$extension/;
770
771
0
my $vcg = VCG->new(scale=>100,);
772
0
my %nodes = ();
773
0
my $classes = $self->Classes;
774
775
0
0
if (ref $classes) {
776
0
foreach my $Class (@$classes) {
777
# warn "class name : ", $Class->Name , " id :", $Class->Id, "\n";
778
0
my $node = $Class->Name."\n----------------\n";
779
780
0
0
if ($config{methods}) {
781
0
my @method_strings = ();
782
0
my ($methods) = ($Class->Operations);
783
0
foreach my $method (@$methods) {
784
0
0
0
next if ($method->{visibility} == 1 && $config{public});
785
0
0
my $method_string = ($method->{visibility} == 0) ? '+ ' : '- ';
786
0
$method_string .= $method->{name}."(";
787
0
0
if (ref $method->{"Params"} ) {
788
0
my @args = ();
789
0
foreach my $argument ( @{$method->{"Params"}} ) {
0
790
0
push (@args, $argument->{Type} . " " . $argument->{Name});
791
}
792
0
$method_string .= join (", ",@args);
793
}
794
0
$method_string .= " ) : ". $method->{type};
795
0
push (@method_strings,$method_string);
796
}
797
0
foreach my $method_string ( @method_strings ) {
798
0
$node .= "$method_string\n";
799
}
800
}
801
0
$node .= "----------------\n";
802
0
0
if ($config{attributes}) {
803
0
my ($attributes) = ($Class->Attributes);
804
0
foreach my $attribute (@$attributes) {
805
0
0
0
next if ($attribute->{visibility} == 1 && $config{public});
806
0
0
$node .= ($attribute->{visibility} == 0) ? '+ ' : '- ';
807
0
$node .= $attribute->{name};
808
0
$node .= " : $attribute->{type} \n";
809
}
810
}
811
812
0
$nodes{$Class->Id} = $node;
813
814
0
$vcg->add_node(label=>$node, title=>$node);
815
816
}
817
} else {
818
0
return 0;
819
}
820
821
0
0
unless ($config{skip_superclasses}) {
822
0
my $superclasses = $self->Superclasses;
823
824
0
0
if (ref $superclasses) {
825
0
foreach my $Superclass (@$superclasses) {
826
# warn "superclass name :", $Superclass->Name, " id :", $Superclass->Id, "\n";
827
0
my $node = $Superclass->Name()."\n----------------\n";
828
0
$nodes{$Superclass->Id} = $node;
829
0
$vcg->add_node(title=>$node, label=> $node);
830
}
831
}
832
}
833
834
0
my $inheritances = $self->Inheritances;
835
0
0
if (ref $inheritances) {
836
0
foreach my $Inheritance (@$inheritances) {
837
0
0
next unless ($nodes{$Inheritance->Parent});
838
# warn "inheritance parent :", $Inheritance->Parent, " child :", $Inheritance->Child, "\n";
839
0
$vcg->add_edge(
840
source=>$nodes{$Inheritance->Parent}, target=>$nodes{$Inheritance->Child},
841
);
842
}
843
}
844
845
0
my $relations = $self->Relations;
846
0
0
if (ref $relations) {
847
0
foreach my $Relation (@$relations) {
848
0
0
next unless ($nodes{$Relation->Left});
849
# warn "relation left :", $Relation->Left, " right :", $Relation->Right, "\n";
850
0
my %edge_args = (source => $nodes{$Relation->Left}, target => $nodes{$Relation->Right});
851
0
$vcg->add_edge(%edge_args);
852
}
853
}
854
855
856
0
0
unless ($config{skip_packages}) {
857
0
my $components = $self->Components;
858
0
0
if (ref $components) {
859
0
foreach my $Component (@$components) {
860
# warn "component name :", $Component->Name, " id :", $Component->Id, "\n";
861
0
my $node = $Component->Name;
862
0
$nodes{$Component->Id} = $node;
863
0
$vcg->add_node(label=>$node, title=>$node);
864
}
865
}
866
}
867
868
0
my $dependancies = $self->Dependancies;
869
0
0
if (ref $dependancies) {
870
0
foreach my $Dependancy (@$dependancies) {
871
0
0
next unless ($nodes{$Dependancy->Parent});
872
# warn "dependancy parent ", $Dependancy->Parent, " child :", $Dependancy->Child, "\n";
873
0
$vcg->add_edge(
874
source=>$nodes{$Dependancy->Parent}, target=>$nodes{$Dependancy->Child},
875
);
876
}
877
}
878
879
0
0
open (FILE,">$output_filename") or die "couldn't open $output_filename file for output : $!\n";
880
0
binmode FILE;
881
0
0
eval 'print FILE $vcg->'. $vcg_filetypes{$extension} or die "can't eval : $! \n";;
882
883
0
close FILE;
884
885
0
return 1;
886
}
887
888
889
####################################################
890
# export_xml - output to file via template toolkit
891
892
893
sub export_xml
894
{
895
0
0
0
my $self = shift;
896
897
0
my %config = %{$self->{_config}};
0
898
899
0
my $output_filename = $config{outputfile};
900
0
0
my $template_file = $config{templatefile} || get_template(%config);
901
902
0
0
if ($config{no_deps})
903
0
{ $self->_no_deps; }
904
905
0
my $success = $self->_layout_dia_new;
906
0
0
return 0 unless $success;
907
908
0
0
if (ref $self->Classes) {
909
0
foreach my $Class ( @{$self->Classes} ) {
0
910
911
# warn "handling $Class->{name}\n";
912
913
0
my ($methods) = ($Class->Operations);
914
0
foreach my $method (@$methods) {
915
0
$method->{name}=xml_escape($method->{name});
916
0
0
if (ref $method->{"Params"} ) {
917
0
foreach my $argument ( @{$method->{"Params"}} ) {
0
918
0
0
$argument->{Type} = xml_escape($argument->{Type}) if (defined $argument->{Type});
919
0
$argument->{Name} = xml_escape($argument->{Name});
920
0
0
$argument->{Kind} = xml_escape($argument->{Kind}) if (defined $argument->{Kind});
921
}
922
}
923
}
924
925
0
my ($attributes) = ($Class->Attributes);
926
0
foreach my $attribute (@$attributes) {
927
0
$attribute->{name} = xml_escape($attribute->{name});
928
}
929
}
930
}
931
932
0
0
print "\n\n" if ($config{use_stdout});
933
934
# use a template for xml output.
935
0
my $template_conf = {
936
POST_CHOMP => 1,
937
# EVAL_PERL => 1, # debug
938
# INTERPOLATE =>1, # debug
939
# LOAD_PERL => 1, # debug
940
ABSOLUTE => 1,
941
OUTPUT_PATH => '.',
942
}; # cleanup whitespace and allow absolute paths
943
0
my $template = Template->new($template_conf);
944
0
my $template_variables = { "diagram" => $self, config => $self->{_config}};
945
946
0
my @template_args = ($template_file,$template_variables);
947
0
0
push (@template_args, $output_filename)
948
unless ( $config{use_stdout} );
949
950
0
0
$template->process(@template_args)
951
|| die $template->error();
952
953
0
return 1;
954
}
955
956
#---------------------------------------------------------------------------------
957
# Internal Methods
958
959
sub _no_deps
960
{
961
0
0
my $self = shift;
962
0
print STDERR "skipping dependancies..\n";
963
0
undef $self->{packages}{dependancy};
964
0
undef $self->{packages}{Component};
965
0
return;
966
}
967
968
sub _initialise
969
{
970
0
0
my $self = shift;
971
0
$self->{_config} = shift; # ref to %conf
972
0
$self->{"_object_count"} = 0; # keeps count of objects
973
0
$self->{_nodes} = {};
974
0
return;
975
}
976
977
sub _package_exists # check to see if a package already exists
978
{
979
0
0
my $self = shift;
980
0
my $object = shift;
981
0
my $return = 0;
982
983
# check type of object, and only check for relevent packages.
984
SWITCH:
985
{
986
0
0
if ($object->Type eq "class")
0
987
{
988
0
last SWITCH;
989
}
990
0
0
if ($object->Type eq "superclass")
991
{
992
993
0
0
if ($self->{"packages"}{"superclass"}{$object->Name})
994
{
995
0
$return = $self->{"packages"}{"superclass"}{$object->Name};
996
0
bless ($return, "Autodia::Diagram::Superclass");
997
}
998
0
last SWITCH;
999
}
1000
0
0
if ($object->Type eq "Component")
1001
{
1002
0
0
if ($self->{"packages"}{"Component"}{$object->Name})
1003
{
1004
0
$return = $self->{"packages"}{"Component"}{$object->Name};
1005
0
bless ($return, "Autodia::Diagram::Component");
1006
}
1007
0
last SWITCH;
1008
}
1009
}
1010
0
return $return;
1011
}
1012
1013
sub _object_count
1014
{
1015
0
0
my $self = shift;
1016
0
my $id = $self->{"_object_count"};
1017
0
$self->{"_object_count"}++;
1018
0
return $id;
1019
}
1020
1021
sub _package_add
1022
{
1023
0
0
my $self = shift;
1024
0
my $new_package = shift;
1025
0
my @packages;
1026
1027
0
0
if (defined $self->{$new_package->Type})
1028
0
{ @packages = @{$self->{$new_package->Type}}; }
0
1029
1030
0
push(@packages, $self->{"_object_count"});
1031
1032
0
$self->{$new_package->Type} = \@packages;
1033
0
$new_package->LocalId(scalar @packages);
1034
0
$self->{"packages"}{$new_package->Type}{$new_package->Name} = $new_package;
1035
0
0
0
if (defined $new_package->Type && defined $new_package->Id) {
1036
0
$self->{"package_types"}{$new_package->Type}{$new_package->Id} = 1;
1037
}
1038
1039
0
return 1;
1040
}
1041
1042
sub _package_remove
1043
{
1044
0
0
my $self = shift;
1045
0
my $package = shift;
1046
1047
0
my @packages = @{$self->{$package->Type}};
0
1048
0
$packages[$package->LocalId] = "removed";
1049
1050
0
$self->{$package->Type} = \@packages;
1051
0
delete $self->{"packages"}{$package->Type}{$package->Name};
1052
1053
0
return 1;
1054
}
1055
1056
1057
sub _get_childless_classes
1058
{
1059
0
0
my $self = shift;
1060
0
my @classes;
1061
1062
0
my $childless = $self->Classes;
1063
0
0
if (ref $childless)
1064
{
1065
0
foreach my $class (@$childless)
1066
{
1067
0
0
unless ($class->has_child)
1068
0
{ push (@classes, $class); }
1069
}
1070
}
1071
0
else { warn "Diagram.pm : _get_childless_classes : no classes!\n"; }
1072
0
return @classes;
1073
}
1074
1075
sub _get_parent_classes
1076
{
1077
0
0
my $self = shift;
1078
0
my @classes;
1079
1080
0
my $parents = $self->Classes;
1081
0
0
if (ref $parents)
1082
{
1083
0
foreach my $class (@$parents)
1084
{
1085
0
0
if ($class->has_child)
1086
0
{ push (@classes, $class); }
1087
}
1088
}
1089
0
else { warn "Diagram.pm : _get_parent_classes : no classes !\n"; }
1090
0
return @classes;
1091
}
1092
1093
sub _sort
1094
{
1095
0
0
my $self = shift;
1096
0
my @classes = @{shift()};
0
1097
1098
0
0
print "sorting classes alphabetically\n" unless ( $self->{config}->{silent} );
1099
0
my @sorted_classes = sort {$a->Name cmp $b->Name} @classes;
0
1100
1101
return \@sorted_classes
1102
0
}
1103
1104
1105
# now returns 0 if no classes found
1106
1107
sub _layout_dia_new {
1108
0
0
my $self = shift;
1109
0
my %config = %{$self->{_config}};
0
1110
# build table of nodes and relationships
1111
0
my %nodes = ();
1112
0
my @edges = ();
1113
0
my @rows = ();
1114
0
my @row_heights = ();
1115
0
my @row_widths = ();
1116
# - add classes nodes
1117
0
my $classes = $self->Classes;
1118
0
0
if (ref $classes) {
1119
0
foreach my $Class (@$classes) {
1120
# count methods and attributes to give height
1121
0
my $height = 23;
1122
0
my $width = 3 + ( (length ($Class->Name) - 3) * 0.75 );
1123
0
my ($methods) = ($Class->Operations);
1124
0
0
if (uc(ref $methods) eq 'SCALAR') {
1125
0
$height += scalar @$methods;
1126
}
1127
0
0
if ($config{attributes}) {
1128
0
my ($attributes) = ($Class->Attributes);
1129
0
0
if (uc(ref $attributes) eq 'SCALAR') {
1130
0
$height += (scalar @$attributes * 3.2);
1131
}
1132
}
1133
# warn "creating node for class : ", $Class->Id, "\n";
1134
0
$nodes{$Class->Id} = {parents=>[], weight=>0, center=>[], height=>$height,
1135
children=>[], entity=>$Class, width=>$width};
1136
}
1137
}
1138
# - add superclasses nodes
1139
0
my $superclasses = $self->Superclasses;
1140
0
0
if (ref $superclasses) {
1141
0
foreach my $Superclass (@$superclasses) {
1142
0
my $width = 3 + ( (length ($Superclass->Name) - 3) * 0.75 );
1143
# warn "creating node for class : ", $Superclass->Id, "\n";
1144
0
$nodes{$Superclass->Id} = {parents=>[], weight=>0, center=>[], height=>15,
1145
children=>[], entity=>$Superclass, width=>$width};
1146
}
1147
}
1148
# - add package nodes
1149
0
my $components = $self->Components;
1150
0
0
if (ref $components) {
1151
0
foreach my $Component (@$components) {
1152
# warn "creating node for class : ", $Component->Id, "\n";
1153
0
my $width = 3 + ( (length ($Component->Name) - 3) * 0.55 );
1154
0
$nodes{$Component->Id} = {parents=>[], weight=>0, center=>[], height=>15,
1155
children=>[], entity=>$Component, width=>$width};
1156
}
1157
}
1158
# - add inheritance edges
1159
0
my $inheritances = $self->Inheritances;
1160
0
0
if (ref $inheritances) {
1161
0
foreach my $Inheritance (@$inheritances) {
1162
0
push (@edges, { to => $Inheritance->Child, from => $Inheritance->Parent });
1163
}
1164
}
1165
# - add dependancy edges
1166
0
my $dependancies = $self->Dependancies;
1167
0
0
if (ref $dependancies) {
1168
0
foreach my $Dependancy (@$dependancies) {
1169
0
push (@edges, { to => $Dependancy->Child, from => $Dependancy->Parent });
1170
}
1171
}
1172
1173
# add realization edges
1174
0
my $realizations = $self->Realizations;
1175
0
0
if( ref $realizations ) {
1176
0
foreach my $Realization (@$realizations) {
1177
0
push( @edges,
1178
{ to => $Realization->Child, from => $Realization->Parent } );
1179
}
1180
}
1181
1182
1183
# add relation edges
1184
0
my $relations = $self->Relations;
1185
0
0
if (ref $relations) {
1186
0
foreach my $Relation (@$relations) {
1187
0
push (@edges, { to => $Relation->Left, from => $Relation->Right });
1188
}
1189
}
1190
1191
# first pass (build network of edges to and from each node)
1192
0
foreach my $edge (@edges) {
1193
# warn Dumper (edge=>$edge) unless ($edge->{from} && $edge->{to});
1194
0
my ($from,$to) = ($edge->{from},$edge->{to});
1195
0
push(@{$nodes{$to}{parents}},$from);
0
1196
0
push(@{$nodes{$from}{children}},$to);
0
1197
}
1198
1199
# second pass (establish depth ( ie verticle placement of each node )
1200
0
foreach my $node (keys %nodes) {
1201
0
my $depth = 0;
1202
0
foreach my $parent (@{$nodes{$node}{parents}}) {
0
1203
0
my $newdepth = get_depth($parent,$node,\%nodes);
1204
0
0
$depth = $newdepth if ($depth < $newdepth);
1205
}
1206
0
$nodes{$node}{depth} = $depth;
1207
0
push(@{$rows[$depth]},$node)
0
1208
}
1209
1210
# calculate height and width of diagram in discrete steps
1211
0
my $i = 0;
1212
0
my $widest_row = 0;
1213
0
my $total_height = 0;
1214
0
my $total_width = 0;
1215
0
foreach my $row (@rows) {
1216
0
0
unless (ref $row) { $row = []; next }
0
0
1217
0
my $tallest_node_height = 0;
1218
0
my $widest_node_width = 0;
1219
0
0
$widest_row = scalar @$row if ( scalar @$row > $widest_row );
1220
0
my @newrow = ();
1221
0
foreach my $node (@$row) {
1222
# warn Dumper(node=>$node);
1223
0
0
0
unless (defined $node && defined $nodes{$node}) { warn "warning : empty class/package encountered, skipping"; Dumper(empty_node=>$nodes{$node}); next;}
0
0
0
1224
0
0
$tallest_node_height = $nodes{$node}{height}
1225
if ($nodes{$node}{height} > $tallest_node_height);
1226
0
0
$widest_node_width = $nodes{$node}{width}
1227
if ($nodes{$node}{width} > $widest_node_width);
1228
0
push (@newrow,$node);
1229
}
1230
0
$row = \@newrow;
1231
0
$row_heights[$i] = $tallest_node_height + 0.5;
1232
0
$row_widths[$i] = $widest_node_width;
1233
0
$total_height += $tallest_node_height + 0.5 ;
1234
0
$total_width += $widest_node_width;
1235
0
$i++;
1236
}
1237
1238
# prepare table of available positions
1239
0
my @positions;
1240
0
foreach (@rows) {
1241
0
my %available;
1242
0
@available{(0 .. ($widest_row + 1))} = 1 x ($widest_row + 1);
1243
0
push (@positions,\%available);
1244
}
1245
1246
0
my %done = ();
1247
0
$self->{_dia_done} = \%done;
1248
0
$self->{_dia_nodes} = \%nodes;
1249
0
$self->{_dia_positions} = \@positions;
1250
0
$self->{_dia_rows} = \@rows;
1251
0
$self->{_dia_row_heights} = \@row_heights;
1252
0
$self->{_dia_row_widths} = \@row_widths;
1253
0
$self->{_dia_total_height} = $total_height;
1254
0
$self->{_dia_total_width} = $total_width;
1255
0
$self->{_dia_widest_row} = $widest_row;
1256
1257
#
1258
# plot (relative) position of nodes (left to right, follow branch)
1259
0
my $side;
1260
0
0
return 0 unless (ref $rows[0]);
1261
0
my @toprow = sort {$nodes{$b}{weight} <=> $nodes{$a}{weight} } @{$rows[0]};
0
0
1262
0
0
unshift (@toprow, pop(@toprow)) unless (scalar @toprow < 3);
1263
0
my $increment = $widest_row / ( scalar @toprow + 1 );
1264
0
my $pos = $increment;
1265
0
my $y = 0 - ( ( $self->{_dia_total_height} / 2) - 5 );
1266
0
my $done2ndrow = 0;
1267
0
foreach my $node ( @toprow ) {
1268
0
my $x = 0 - ( $self->{_dia_row_widths}[0] * $self->{_dia_widest_row} / 2)
1269
+ ($pos * $self->{_dia_row_widths}[0]);
1270
0
$nodes{$node}{xx} = $x;
1271
0
$nodes{$node}{yy} = $y;
1272
0
$nodes{$node}{entity}->set_location($x,$y);
1273
# if (scalar @{$nodes{$node}{children}} && ( scalar @{$rows[1]} > 0)) {
1274
0
0
0
if (defined $nodes{$node}{children} && defined $rows[1]) {
1275
0
0
0
if (scalar @{$nodes{$node}{children}} && scalar(@rows) && ( scalar @{$rows[1]} > 0)) {
0
0
0
0
0
0
0
1276
1277
0
my @sorted_children = sort {
1278
0
$nodes{$b}{weight} <=> $nodes{$a}{weight}
1279
0
} @{$nodes{$node}{children}};
1280
0
unshift (@sorted_children, pop(@sorted_children));
1281
0
my $child_increment = $widest_row / (scalar @{$rows[1]});
0
1282
0
my $childpos = $child_increment;
1283
# foreach my $child (@{$nodes{$node}{children}}) {
1284
0
foreach my $child (@sorted_children) {
1285
0
my $side;
1286
0
0
if ($childpos <= ( $widest_row * 0.385 ) ) {
0
1287
0
$side = 'left';
1288
} elsif ( $childpos <= ($widest_row * 0.615 ) ) {
1289
0
$side = 'center';
1290
} else {
1291
0
$side = 'right';
1292
}
1293
0
plot_branch($self,$nodes{$child},$childpos,$side);
1294
0
$childpos += $child_increment;
1295
}
1296
} elsif ( defined $rows[1] && scalar @{$rows[1]} && $done2ndrow == 0) {
1297
0
$done2ndrow = 1;
1298
0
foreach my $node ( @{$rows[1]} ) {
0
1299
# warn "handling node in next row\n";
1300
# warn Dumper(node=>$node{$node});
1301
0
my $x = 0 - ( $self->{_dia_row_widths}[1] * $self->{_dia_widest_row} / 2)
1302
+ ($pos * $self->{_dia_row_widths}[1]);
1303
0
$nodes{$node}{x} = $x;
1304
0
$nodes{$node}{'y'} = $y;
1305
0
0
0
if (scalar @{$nodes{$node}{children}} && scalar @{$rows[2]}) {
0
0
1306
0
my @sorted_children = sort {
1307
0
$nodes{$b}{weight} <=> $nodes{$a}{weight}
1308
0
} @{$nodes{$node}{children}};
1309
0
unshift (@sorted_children, pop(@sorted_children));
1310
0
my $child_increment = $widest_row / (scalar @{$rows[2]});
0
1311
0
my $childpos = $child_increment;
1312
# foreach my $child (@{$nodes{$node}{children}}) {
1313
0
foreach my $child (@sorted_children) {
1314
# warn "child : $child\n";
1315
0
0
next unless ($child);
1316
0
my $side;
1317
0
0
if ($childpos <= ( $widest_row * 0.385 ) ) {
0
1318
0
$side = 'left';
1319
} elsif ( $childpos <= ($widest_row * 0.615 ) ) {
1320
0
$side = 'center';
1321
} else {
1322
0
$side = 'right';
1323
}
1324
0
plot_branch($self,$nodes{$child},$childpos,$side);
1325
0
$childpos += $child_increment;
1326
}
1327
}
1328
}
1329
}
1330
}
1331
1332
0
$nodes{$node}{pos} = $pos;
1333
1334
0
$pos += $increment;
1335
0
$done{$node} = 1;
1336
}
1337
1338
0
my @relationships = ();
1339
1340
0
0
if (ref $self->Dependancies)
1341
0
{ push(@relationships, @{$self->Dependancies}); }
0
1342
1343
0
0
if( ref $self->Realizations ) {
1344
0
push( @relationships, @{ $self->Realizations } );}
0
1345
1346
0
0
if (ref $self->Inheritances)
1347
0
{ push(@relationships, @{$self->Inheritances}); }
0
1348
1349
0
0
if (ref $self->Relations)
1350
0
{ push(@relationships, @{$self->Relations}); }
0
1351
1352
1353
0
foreach my $relationship (@relationships)
1354
0
{ $relationship->Reposition; }
1355
1356
0
$self->{_nodes} = \%nodes;
1357
1358
0
return 1;
1359
}
1360
1361
sub object_from_id {
1362
0
0
0
my ($self, $id) = @_;
1363
0
my $object;
1364
0
0
if (ref $self->{_nodes}) {
1365
0
$object = $self->{_nodes}{$id}{entity};
1366
};
1367
0
return $object;
1368
}
1369
1370
#
1371
## Functions used by _layout_dia_new method
1372
#
1373
1374
# recursively calculate the depth of a node by following edges to its parents
1375
sub get_depth {
1376
0
0
0
my ($node,$child,$nodes) = @_;
1377
0
my $depth = 0;
1378
0
$nodes->{$node}{weight}++;
1379
0
0
if (exists $nodes->{$node}{depth}) {
1380
0
$depth = $nodes->{$node}{depth} + 1;
1381
} else {
1382
0
$nodes->{$node}{depth} = 1;
1383
0
my @parents = @{$nodes->{$node}{parents}};
0
1384
0
0
if (scalar @parents > 0) {
1385
0
foreach my $parent (@parents) {
1386
0
my $newdepth = get_depth($parent,$node,$nodes);
1387
0
0
$depth = $newdepth if ($depth < $newdepth);
1388
}
1389
0
$depth++;
1390
} else {
1391
0
$depth = 1;
1392
0
$nodes->{$node}{depth} = 0;
1393
}
1394
}
1395
0
return $depth;
1396
}
1397
1398
# recursively plot the branches of a tree
1399
sub plot_branch {
1400
0
0
0
my ($self,$node,$pos,$side) = @_;
1401
# warn "plotting branch : ", $node->{entity}->Name," , $pos, $side\n";
1402
1403
0
my $depth = $node->{depth};
1404
0
my $offset = 0.8;
1405
0
my $h = 0;
1406
0
while ( $h < $depth ) {
1407
0
$offset += $self->{_dia_row_heights}[$h++] + 0.1;
1408
}
1409
1410
# warn Dumper(node=>$node);
1411
0
my (@parents,@children) = ($node->{parents},$node->{children});
1412
0
0
0
if ( $self->{_dia_done}{$node->{entity}->Id} && (scalar @children < 1) ) {
0
1413
0
0
if (scalar @parents > 1 ) {
1414
0
$self->{_dia_done}{$node}++;
1415
0
my $sum = 0;
1416
0
foreach my $parent (@parents) {
1417
0
0
return 0 unless (exists $self->{_dia_nodes}{$parent->{entity}->Id}{pos});
1418
0
$sum += $self->{_dia_nodes}{$parent->{entity}->Id}{pos};
1419
}
1420
0
$self->{_dia_positions}[$depth]{int($pos)} = 1;
1421
0
my $newpos = ( $sum / scalar @parents );
1422
0
0
unless (exists $self->{_dia_positions}[$depth]{int($newpos)}) {
1423
# use wherever is free if position already taken
1424
0
my $best_available = $pos;
1425
0
0
my $diff = ($best_available > $newpos )
1426
? $best_available - $newpos : $newpos - $best_available ;
1427
0
foreach my $available (keys %{$self->{_dia_positions}[$depth]}) {
0
1428
0
0
my $newdiff = ($available > $newpos ) ? $available - $newpos : $newpos - $available ;
1429
0
0
if ($newdiff < $diff) {
1430
0
$best_available = $available;
1431
0
$diff = $newdiff;
1432
}
1433
}
1434
0
$pos = $best_available;
1435
} else {
1436
0
$pos = $newpos;
1437
}
1438
}
1439
0
my $y = 0 - ( ( $self->{_dia_total_height} / 2) - 4 ) + $offset;
1440
0
print "y : $y\n";
1441
0
my $x = 0 - ( $self->{_dia_row_widths}[$depth] * $self->{_dia_widest_row} / 2)
1442
+ ($pos * $self->{_dia_row_widths}[$depth]);
1443
# my $x = 0 - ( $self->{_dia_widest_row} / 2) + ($pos * $self->{_dia_row_widths}[$depth]);
1444
0
$node->{xx} = int($x);
1445
0
$node->{yy} = int($y);
1446
0
$node->{entity}->set_location($x,$y);
1447
0
$node->{pos} = $pos;
1448
0
delete $self->{_dia_positions}[$depth]{int($pos)};
1449
# warn "node ", $node->{entity}->Name(), " : $pos xx : ", $node->{xx} ," yy : ",$node->{yy} ,"\n";
1450
0
return 0;
1451
} elsif ($self->{_dia_done}{$node}) {
1452
# warn "node ", $node->{entity}->Name(), " : $node->{pos}\n";
1453
0
return 0;
1454
}
1455
1456
0
0
unless (exists $self->{_dia_positions}[$depth]{int($pos)}) {
1457
0
my $best_available;
1458
0
my $diff = $self->{_dia_widest_row} + 5;
1459
0
foreach my $available (keys %{$self->{_dia_positions}[$depth]}) {
0
1460
0
0
$best_available ||= $available;
1461
0
0
my $newdiff = ($available > $pos ) ? $available - $pos : $pos - $available ;
1462
0
0
if ($newdiff < $diff) {
1463
0
$best_available = $available;
1464
0
$diff = $newdiff;
1465
}
1466
}
1467
0
$pos = $best_available;
1468
}
1469
1470
0
delete $self->{_dia_positions}[$depth]{int($pos)};
1471
1472
0
my $y = 0 - ( ( $self->{_dia_total_height} / 2) - 1 ) + $offset;
1473
0
my $x = 0 - ( $self->{_dia_row_widths}[0] * $self->{_dia_widest_row} / 2)
1474
+ ($pos * $self->{_dia_row_widths}[0]);
1475
# my $x = 0 - ( $self->{_dia_widest_row} / 2) + ($pos * $self->{_dia_row_widths}[$depth]);
1476
# my $x = 0 - ( ( $pos * $self->{_dia_row_widths}[0] ) / 2);
1477
0
$node->{xx} = int($x);
1478
0
$node->{yy} = int($y);
1479
0
$node->{entity}->set_location($x,$y);
1480
1481
0
$self->{_dia_done}{$node} = 1;
1482
0
$node->{pos} = $pos;
1483
1484
0
0
if (scalar @{$node->{children}}) {
0
0
1485
0
my @sorted_children = sort {
1486
0
$self->{_dia_nodes}{$b}{weight} <=> $self->{_dia_nodes}{$a}{weight}
1487
0
} @{$node->{children}};
1488
0
unshift (@sorted_children, pop(@sorted_children));
1489
0
0
0
my $child_increment = (ref $self->{_dia_rows}[$depth + 1]) ? $self->{_dia_widest_row} / (scalar @{$self->{_dia_rows}[$depth + 1]} || 1) : 0 ;
1490
0
my $childpos = 0;
1491
0
0
if ( $side eq 'left' ) {
0
1492
0
$childpos = 0
1493
} elsif ( $side eq 'center' ) {
1494
0
$childpos = $pos;
1495
} else {
1496
0
$childpos = $pos + $child_increment;
1497
}
1498
0
foreach my $child (@{$node->{children}}) {
0
1499
0
0
$childpos += $child_increment if (plot_branch($self,$self->{_dia_nodes}{$child},$childpos,$side));
1500
}
1501
} elsif ( scalar @parents == 1 ) {
1502
0
my $y = 0 - ( ( $self->{_dia_total_height} / 2) - 1 ) + $offset;
1503
0
my $x = 0 - ( $self->{_dia_row_widths}[0] * $self->{_dia_widest_row} / 2)
1504
+ ($pos * $self->{_dia_row_widths}[0]);
1505
# my $x = 0 - ( $self->{_dia_widest_row} / 2) + ($pos * $self->{_dia_row_widths}[$depth]);
1506
# my $x = 0 - ( ( $pos * $self->{_dia_row_widths}[0] ) / 2);
1507
0
$node->{xx} = int($x);
1508
0
$node->{yy} = int($y);
1509
0
$node->{entity}->set_location($x,$y);
1510
}
1511
# warn "node ", $node->{entity}->Name(), " : $pos xx : ", $node->{xx} ," yy : ",$node->{yy} ,"\n";
1512
0
return 1;
1513
}
1514
1515
#
1516
########################################
1517
#
1518
1519
sub _layout {
1520
0
0
my $self = shift;
1521
0
my @columns;
1522
my @orphan_classes;
1523
0
my $column_count=0;
1524
1525
# populate a grid to be used for laying out the diagram.
1526
1527
# put each parent class in a column
1528
0
my @parent_classes = $self->_get_parent_classes;
1529
0
my %parent_class;
1530
0
foreach my $class (@parent_classes) {
1531
0
$parent_class{$class->Id} = $column_count;
1532
0
0
if (defined $columns[$column_count][2][0]) {
1533
0
push (@{$columns[$column_count][2]},$class);
0
1534
} else {
1535
0
$columns[$column_count][2][0] = $class;
1536
}
1537
0
$column_count++;
1538
}
1539
1540
0
$column_count = 0;
1541
1542
0
my @childless_classes = $self->_get_childless_classes;
1543
# put each child class in its parent column
1544
0
foreach my $class (@childless_classes) {
1545
0
0
if (defined $class->Inheritances) {
1546
0
my ($inheritance) = $class->Inheritances;
1547
0
0
my $parents_column = $parent_class{$inheritance->Parent} || 0;
1548
0
push (@{$columns[$parents_column][3]},$class);
0
1549
} else {
1550
0
push (@orphan_classes,$class);
1551
}
1552
}
1553
1554
0
$column_count++;
1555
1556
0
foreach my $orphan (@orphan_classes) {
1557
0
push (@{$columns[$column_count][3]}, $orphan);
0
1558
}
1559
1560
# put components in columns with the most of their kids
1561
0
0
if (ref $self->Components) {
1562
0
my @components = @{$self->Components};
0
1563
0
foreach my $component (@components) {
1564
0
my $i =0;
1565
0
my $current_column = 0;
1566
0
my $current_children = 0;
1567
# find column with most children
1568
1569
0
my %child_ids = ();
1570
0
my @children = $component->Dependancies;
1571
0
foreach my $child (@children) {
1572
0
$child_ids{$child->Child} = 1;
1573
}
1574
1575
0
foreach my $column (@columns) {
1576
0
0
if (ref $column) {
1577
0
my @column = @$column;
1578
0
0
next unless (defined $column);
1579
0
my $children = 0;
1580
0
foreach my $subcolumn (@column) {
1581
0
foreach my $child (@$subcolumn) {
1582
0
0
if (defined $child_ids{$child->Id}) {
1583
0
$children++;
1584
}
1585
}
1586
}
1587
0
0
if ($children > $current_children) {
1588
0
$current_column = $i; $current_children = $children;
0
1589
}
1590
0
$i++;
1591
} else {
1592
0
print STDERR "Diagram.pm : _layout() : empty column .. skipping\n";
1593
}
1594
}
1595
0
push(@{$columns[$current_column][0]},$component);
0
1596
}
1597
} else {
1598
0
print STDERR "Diagram.pm : _layout() : no components / dependancies\n";
1599
}
1600
1601
0
0
if (ref $self->Superclasses) {
1602
0
my @superclasses = @{$self->Superclasses};
0
1603
# put superclasses in columns with most of their kids
1604
0
foreach my $superclass (@superclasses) {
1605
0
my $i=0;
1606
0
my $current_column = 0;
1607
0
my $current_children = 0;
1608
# find column with most children
1609
1610
0
my %child_ids = ();
1611
0
my @children = $superclass->Inheritances;
1612
0
foreach my $child (@children) {
1613
0
$child_ids{$child->Child} = 1;
1614
}
1615
1616
0
foreach my $column (@columns) {
1617
0
0
if (ref $column) {
1618
0
my @column = @$column;
1619
0
my $children = 0;
1620
0
foreach my $subcolumn (@column) {
1621
0
foreach my $child (@$subcolumn) {
1622
0
0
if (defined $child_ids{$child->Id}) {
1623
0
$children++;
1624
}
1625
}
1626
}
1627
0
0
if ($children > $current_children) {
1628
0
$current_column = $i; $current_children = $children;
0
1629
}
1630
0
$i++;
1631
} else {
1632
0
print STDERR "Diagram.pm : _layout() : empty column .. skipping\n";
1633
}
1634
}
1635
0
push(@{$columns[$current_column][1]},$superclass);
0
1636
}
1637
} else {
1638
0
print STDERR "Diagram.pm : _layout() : no superclasses / inheritances\n";
1639
}
1640
1641
# grid now created - Components in top row, superclasses in second,
1642
# classes with subclasses in 3rd row, childless & orphan classes in 4th row.
1643
1644
# now we position the contents of the grid.
1645
0
my $next_row_y = 0;
1646
0
my $next_col_x = 0;
1647
0
my ($colspace, $rowspace) = (1.5 , 0.5);
1648
1649
0
foreach my $column (@columns) {
1650
0
my $x = $next_col_x;
1651
0
foreach my $subcolumn (@$column) {
1652
0
my $count = 0;
1653
0
my $y = $next_row_y;
1654
0
$next_row_y += 3;
1655
0
foreach my $entity (@$subcolumn)
1656
{
1657
0
my $next_xy = $entity->set_location($x,$y);
1658
0
($x,$y) = @$next_xy;
1659
0
$x-=3;
1660
0
$y-=(2+($entity->Height/5));
1661
0
0
if ($count >= 4) {
1662
0
$next_row_y = 0;
1663
0
$y = 0;
1664
0
$x += $colspace;
1665
0
$count = 0;
1666
}
1667
0
$count++;
1668
}
1669
0
$y += $rowspace;
1670
}
1671
0
$x += $colspace;
1672
0
$next_col_x = $x;
1673
}
1674
1675
0
my @relationships = ();
1676
1677
0
0
if (ref $self->Dependancies)
1678
0
{ push(@relationships, @{$self->Dependancies}); }
0
1679
1680
0
0
if( ref $self->Realizations ) {
1681
0
push( @relationships, @{ $self->Realizations } );}
0
1682
1683
0
0
if (ref $self->Inheritances)
1684
0
{ push(@relationships, @{$self->Inheritances}); }
0
1685
1686
0
foreach my $relationship (@relationships)
1687
0
{ $relationship->Reposition; }
1688
1689
0
return 1;
1690
}
1691
1692
sub xml_escape {
1693
0
0
0
my $retval = shift;
1694
0
0
return '' unless $retval;
1695
1696
0
$retval =~ s/\&/\&/;
1697
0
$retval =~ s/\'/\"/;
1698
0
$retval =~ s/\"/\"/;
1699
0
$retval =~ s/\\</;
1700
0
$retval =~ s/\>/\>/;
1701
1702
0
return $retval;
1703
}
1704
1705
1706
sub get_template {
1707
0
0
0
my %config = @_;
1708
# warn "get_template called : outfile -- $config{outputfile}\n";
1709
0
my $template;
1710
TEMPLATE_SWITCH: {
1711
0
0
if ($config{outputfile} =~ /\.xmi$/) {
0
1712
0
$template = get_umbrello_template($config{outputfile});
1713
0
last TEMPLATE_SWITCH;
1714
}
1715
0
$template = get_default_template($config{outputfile});
1716
} # end of TEMPLATE_SWITCH
1717
# warn "template : ", $template, "\n";
1718
# NOTE: $template should always be a ref to a string
1719
0
return $template;
1720
}
1721
1722
sub get_umbrello_template {
1723
0
0
0
my $outfile = shift;
1724
0
warn "using umbrello template for $outfile\n";
1725
0
my $pwd = $ENV{PWD};
1726
0
my $template =<
1727
1728
1729
1730
1731
umbrello uml modeller http://uml.sf.net
1732
1.1
1733
1734
1735
1736
1737
1738
1739
1740
1746
[%# -------------------------------------------- %]
1747
[% classes = diagram.Classes %]
1748
[% xmictr = 1 %]
1749
[% FOREACH class = classes %]
1750
[% xmictr = xmictr + 1 %]
1751
1752
1753
[% FOREACH at = class.Attributes %]
1754
1755
[% END %]
1756
[% FOREACH op = class.Operations %]
1757
1758
1759
[% FOREACH par = op.Params %]
1760
1761
[% END %]
1762
1763
1764
[% END %]
1765
1766
1767
[% END %]
1768
[% SET superclasses = diagram.Superclasses %]
1769
[% FOREACH superclass = superclasses %]
1770
1771
1772
[% END %]
1773
[% SET components = diagram.Components %]
1774
[% FOREACH component = components %]
1775
1776
[% FOREACH at = class.Attributes %]
1777
[% xmictr = xmictr + 1 %]
1778
1779
documentation="" name="[% at.name FILTER html %]" static="0" scope="200" />
1780
[% END %]
1781
[% FOREACH op = class.Operations %]
1782
[% xmictr = xmictr + 1 %]
1783
1784
[% FOREACH par = op.Params %]
1785
[% xmictr = xmictr + 1 %]
1786
1787
[% END %]
1788
1789
[% END %]
1790
1791
[% END %]
1792
[% SET inheritances = diagram.Inheritances %]
1793
[% FOREACH inheritance = inheritances %]
1794
[%- IF inheritance.Parent >0 AND inheritance.Child >0 -%]
1795
1803
1804
[%- END %]
1805
[% END %]
1806
[% SET dependencies = diagram.Dependancies %]
1807
[% FOREACH dependency = dependencies %]
1808
1809
[% END %]
1810
1811
1812
1813
1814
1815
1816
1817
xmi.id="2" documentation="" type="402" showops="1" showpackage="0" name="class diagram" localid="30000"
1818
showstereotype="0" showscope="1" snapcsgrid="0" font="Sans,10,-1,5,50,0,0,0,0,0" linecolor="#ff0000" canvasheight="632" >
1819
1820
1821
1822
[%# -------------------------------------------- %]
1823
[% classes = diagram.Classes %]
1824
[% FOREACH class = classes %]
1825
1826
x="[% class.left_x %]" linecolour="#ff0000" y="[% class.top_y %]" showopsigs="601" linewidth="none" usesdiagramlinewidth="1" usesdiagramlinecolour="0"
1827
fillcolour="#ffffc0" height="[% class.Height %]" usefillcolor="1" showpubliconly="0" showattributes="1" isinstance="0" xmi.id="[% class.Id %]"
1828
showoperations="1" showpackage="0" showscope="1" showstereotype="0" font="Sans,10,-1,5,50,0,0,0,0,0" />
1829
[% END %]
1830
[% SET superclasses = diagram.Superclasses %]
1831
[% FOREACH class = superclasses %]
1832
[% xmictr = xmictr + 1 %]
1833
1834
x="[% class.left_x %]" linecolour="#ff0000" y="[% class.top_y %]" showopsigs="601" usesdiagramlinecolour="0"
1835
fillcolour="#ffffc0" height="[% class.Height %]" usefillcolor="1" showattributes="1" xmi.id="[% xmictr %]"
1836
showoperations="1" showpackage="0" showscope="1" showstereotype="0" font="Sans,10,-1,5,50,0,0,0,0,0" />
1837
1838
[% END %]
1839
1840
1841
1842
[% SET inheritances = diagram.Inheritances %]
1843
[% FOREACH inheritance = inheritances %]
1844
[%- IF inheritance.Parent >0 AND inheritance.Child >0 -%]
1845
1846
1847
1848
1849
1850
1851
[%- END %]
1852
[% END %]
1853
[% SET dependencies = diagram.Dependancies %]
1854
[% FOREACH dependency = dependencies %]
1855
[%- IF dependency.Parent >0 AND dependency.Child >0 -%]
1856
1857
1858
1859
1860
1861
1862
[%- END %]
1863
[% END %]
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
END_UMBRELLO_TEMPLATE
1880
0
return \$template;
1881
}
1882
1883
sub get_default_template {
1884
0
0
0
warn "using default (dia) template\n";
1885
0
my $template = <<'END_TEMPLATE';
1886
1887
[%# #################################################### %]
1888
[%# Autodia Template for Dia XML. (c)Copyright 2001-2004 %]
1889
[%# #################################################### %]
1890
1891
1892
1893
1894
1895
1896
1897
1898
#A4#
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
[%# -------------------------------------------- %]
1948
[% classes = diagram.Classes %]
1949
[% FOREACH class = classes %]
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
#[% class.Name | html %]#
1968
1969
1970
[% IF class.Parent %]
1971
#[% class.Parent | html %]#
1972
[% ELSE %]
1973
1974
[% END %]
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
[% IF class.Attributes %]
1999
2000
[% FOREACH at = class.Attributes %]
2001
2002
2003
#[% at.name FILTER html %]#
2004
2005
2006
#[% at.type FILTER html %]#
2007
2008
2009
[% at.value | html %]
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
[% END %]
2022
2023
[% ELSE %]
2024
2025
[% END %]
2026
[% IF class.Operations %]
2027
2028
[% FOREACH op = class.Operations %]
2029
2030
2031
#[% op.name FILTER html %]#
2032
2033
2034
[% IF op.type %]
2035
#[% op.type FILTER html %]#
2036
[% ELSE %]
2037
2038
[% END %]
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
[% IF op.Params.0 %]
2050
2051
[% FOREACH par = op.Params %]
2052
2053
2054
#[% par.Name FILTER html %]#
2055
2056
2057
#[% par.Type FILTER html %]#
2058
2059
2060
[% IF par.Value %]
2061
2062
[% ELSE %]
2063
2064
[% END %]
2065
2066
2067
[% IF par.Kind %]
2068
2069
[% ELSE %]
2070
2071
[% END %]
2072
2073
2074
[% END %]
2075
2076
[% ELSE %]
2077
2078
[% END %]
2079
2080
[% END %]
2081
2082
[% ELSE %]
2083
2084
[% END %]
2085
2086
2087
2088
2089
2090
[% END %]
2091
[%#%]
2092
[% UNLESS config.skip_packages %]
2093
[% SET components = diagram.Components %]
2094
[%#%]
2095
[% FOREACH component = components %]
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
#[% component.Name | html %]#
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
[% END %]
2136
[% # %]
2137
[% SET realizations = diagram.Realizations %]
2138
[% # %]
2139
[% FOREACH realization = realizations %]
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
[% END %]
2173
[% # %]
2174
[% SET dependancies = diagram.Dependancies %]
2175
[% # %]
2176
[% FOREACH dependancy = dependancies %]
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
[% END %]
2210
[% END %]
2211
[% # %]
2212
[% UNLESS config.skip_superclasses %]
2213
[% SET superclasses = diagram.Superclasses %]
2214
[% # %]
2215
[% FOREACH superclass = superclasses %]
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
#[% superclass.Name %]#
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
[% END %]
2261
[% END %]
2262
[% #### %]
2263
[% SET inheritances = diagram.Inheritances %]
2264
[% FOREACH inheritance = inheritances %]
2265
[% IF config.skip_superclasses %]
2266
[% SET parent = inheritance.Parent %]
2267
[% UNLESS diagram.package_types.class.$parent %] [% NEXT %] [% END %]
2268
[% END %]
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
[% END %]
2302
2303
[% SET relations = diagram.Relations %]
2304
[% FOREACH relation = relations %]
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
##
2328
2329
2330
2331
2332
2333
2334
2335
##
2336
2337
2338
##
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
##
2353
2354
2355
##
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
[% END %]
2374
2375
2376
2377
END_TEMPLATE
2378
2379
0
return \$template;
2380
}
2381
2382
1;
2383
2384
##################################################################
2385
2386
=head2 See Also
2387
2388
Autodia
2389
2390
Autodia::Diagram::Object
2391
2392
Autodia::Diagram::Class
2393
2394
Autodia::Diagram::Superclass
2395
2396
Autodia::Diagram::Component
2397
2398
Autodia::Diagram::Inheritance
2399
2400
Autodia::Diagram::Relation
2401
2402
Autodia::Diagram::Dependancy
2403
2404
=head1 AUTHOR
2405
2406
Aaron Trevena, Eaaron.trevena@gmail.comE
2407
2408
=head1 COPYRIGHT AND LICENSE
2409
2410
Copyright (C) 2004 by Aaron Trevena
2411
2412
This library is free software; you can redistribute it and/or modify
2413
it under the same terms as Perl itself, either Perl version 5.8.1 or,
2414
at your option, any later version of Perl 5 you may have available.
2415
2416
2417
=cut
2418
2419
########################################################################
2420
2421
2422
2423
2424
2425