line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
############################################################################# |
2
|
|
|
|
|
|
|
# Output an Graph::Easy object as textual description |
3
|
|
|
|
|
|
|
# |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
package Graph::Easy::As_txt; |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
$VERSION = '0.75'; |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
############################################################################# |
10
|
|
|
|
|
|
|
############################################################################# |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
package Graph::Easy; |
13
|
|
|
|
|
|
|
|
14
|
16
|
|
|
16
|
|
21630
|
use strict; |
|
16
|
|
|
|
|
40
|
|
|
16
|
|
|
|
|
781
|
|
15
|
16
|
|
|
16
|
|
97
|
use warnings; |
|
16
|
|
|
|
|
35
|
|
|
16
|
|
|
|
|
15200
|
|
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
sub _as_txt |
18
|
|
|
|
|
|
|
{ |
19
|
211
|
|
|
211
|
|
716
|
my ($self) = @_; |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
# Convert the graph to a textual representation - does not need layout(). |
22
|
211
|
|
|
|
|
1936
|
$self->_assign_ranks(); |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
# generate the class attributes first |
25
|
211
|
|
|
|
|
716
|
my $txt = ''; |
26
|
211
|
|
|
|
|
604
|
my $att = $self->{att}; |
27
|
211
|
|
|
|
|
1330
|
for my $class (sort keys %$att) |
28
|
|
|
|
|
|
|
{ |
29
|
|
|
|
|
|
|
|
30
|
544
|
|
|
|
|
3287
|
my $out = $self->_remap_attributes( |
31
|
|
|
|
|
|
|
$class, $att->{$class}, {}, 'noquote', 'encode' ); |
32
|
|
|
|
|
|
|
|
33
|
544
|
|
|
|
|
1467
|
my $att = ''; |
34
|
544
|
|
|
|
|
2266
|
for my $atr (sort keys %$out) |
35
|
|
|
|
|
|
|
{ |
36
|
|
|
|
|
|
|
# border is handled special below |
37
|
302
|
100
|
|
|
|
792
|
next if $atr =~ /^border/; |
38
|
287
|
|
|
|
|
1319
|
$att .= " $atr: $out->{$atr};\n"; |
39
|
|
|
|
|
|
|
} |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
# edges do not have a border |
42
|
544
|
100
|
|
|
|
2731
|
if ($class !~ /^edge/) |
43
|
|
|
|
|
|
|
{ |
44
|
437
|
|
50
|
|
|
1911
|
my $border = $self->border_attribute($class) || ''; |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
# 'solid 1px #000000' =~ /^solid/; |
47
|
|
|
|
|
|
|
# 'solid 1px #000000' =~ /^solid 1px #000000/; |
48
|
437
|
100
|
|
|
|
4626
|
$border = '' if $self->default_attribute($class,'border') =~ /^$border/; |
49
|
|
|
|
|
|
|
|
50
|
437
|
100
|
|
|
|
1853
|
$att .= " border: $border;\n" if $border ne ''; |
51
|
|
|
|
|
|
|
} |
52
|
|
|
|
|
|
|
|
53
|
544
|
100
|
|
|
|
2926
|
if ($att ne '') |
54
|
|
|
|
|
|
|
{ |
55
|
|
|
|
|
|
|
# the following makes short, single definitions to fit on one line |
56
|
170
|
100
|
66
|
|
|
1682
|
if ($att !~ /\n.*\n/ && length($att) < 40) |
57
|
|
|
|
|
|
|
{ |
58
|
109
|
|
|
|
|
525
|
$att =~ s/\n/ /; $att =~ s/^ / /; |
|
109
|
|
|
|
|
571
|
|
59
|
|
|
|
|
|
|
} |
60
|
|
|
|
|
|
|
else |
61
|
|
|
|
|
|
|
{ |
62
|
61
|
|
|
|
|
192
|
$att = "\n$att"; |
63
|
|
|
|
|
|
|
} |
64
|
170
|
|
|
|
|
1185
|
$txt .= "$class {$att}\n"; |
65
|
|
|
|
|
|
|
} |
66
|
|
|
|
|
|
|
} |
67
|
|
|
|
|
|
|
|
68
|
211
|
100
|
|
|
|
908
|
$txt .= "\n" if $txt ne ''; # insert newline |
69
|
|
|
|
|
|
|
|
70
|
211
|
|
|
|
|
1190
|
my @nodes = $self->sorted_nodes('name','id'); |
71
|
|
|
|
|
|
|
|
72
|
211
|
|
|
|
|
839
|
my $count = 0; |
73
|
|
|
|
|
|
|
# output nodes with attributes first, sorted by their name |
74
|
211
|
|
|
|
|
717
|
foreach my $n (@nodes) |
75
|
|
|
|
|
|
|
{ |
76
|
860
|
|
|
|
|
3057
|
$n->{_p} = undef; # mark as not yet processed |
77
|
860
|
|
|
|
|
3110
|
my $att = $n->attributes_as_txt(); |
78
|
860
|
100
|
|
|
|
3365
|
if ($att ne '') |
79
|
|
|
|
|
|
|
{ |
80
|
250
|
|
|
|
|
601
|
$n->{_p} = 1; # mark as processed |
81
|
250
|
|
|
|
|
481
|
$count++; |
82
|
250
|
|
|
|
|
1083
|
$txt .= $n->as_pure_txt() . $att . "\n"; |
83
|
|
|
|
|
|
|
} |
84
|
|
|
|
|
|
|
} |
85
|
|
|
|
|
|
|
|
86
|
211
|
100
|
|
|
|
835
|
$txt .= "\n" if $count > 0; # insert a newline |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
# output groups first, with their nodes |
89
|
211
|
|
|
|
|
374
|
foreach my $gn (sort keys %{$self->{groups}}) |
|
211
|
|
|
|
|
1038
|
|
90
|
|
|
|
|
|
|
{ |
91
|
42
|
|
|
|
|
144
|
my $group = $self->{groups}->{$gn}; |
92
|
42
|
|
|
|
|
223
|
$txt .= $group->as_txt(); # marks nodes as processed if nec. |
93
|
42
|
|
|
|
|
129
|
$count++; |
94
|
|
|
|
|
|
|
} |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
# XXX TODO: |
97
|
|
|
|
|
|
|
# Output all nodes with rank=0 first, and also follow their successors |
98
|
|
|
|
|
|
|
# What is left will then be done next, with rank=1 etc. |
99
|
|
|
|
|
|
|
# This output order let's us output node chains in compact form as: |
100
|
|
|
|
|
|
|
# [A]->[B]->[C]->[D] |
101
|
|
|
|
|
|
|
# [B]->[E] |
102
|
|
|
|
|
|
|
# instead of having: |
103
|
|
|
|
|
|
|
# [A]->[B] |
104
|
|
|
|
|
|
|
# [B]->[E] |
105
|
|
|
|
|
|
|
# [B]->[C] etc |
106
|
|
|
|
|
|
|
|
107
|
211
|
|
|
|
|
1635
|
@nodes = $self->sorted_nodes('rank','name'); |
108
|
211
|
|
|
|
|
791
|
foreach my $n (@nodes) |
109
|
|
|
|
|
|
|
{ |
110
|
860
|
|
|
|
|
4407
|
my @out = $n->sorted_successors(); |
111
|
860
|
|
|
|
|
2440
|
my $first = $n->as_pure_txt(); # [ A | B ] |
112
|
860
|
100
|
100
|
|
|
12219
|
if ( defined $n->{autosplit} || ((@out == 0) && ( (scalar $n->predecessors() || 0) == 0))) |
|
|
|
100
|
|
|
|
|
|
|
|
66
|
|
|
|
|
113
|
|
|
|
|
|
|
{ |
114
|
|
|
|
|
|
|
# single node without any connections (unless already output) |
115
|
134
|
100
|
100
|
|
|
780
|
next if exists $n->{autosplit} && !defined $n->{autosplit}; |
116
|
75
|
100
|
|
|
|
287
|
$txt .= $first . "\n" unless defined $n->{_p}; |
117
|
|
|
|
|
|
|
} |
118
|
|
|
|
|
|
|
|
119
|
801
|
|
|
|
|
2656
|
$first = $n->_as_part_txt(); # [ A.0 ] |
120
|
|
|
|
|
|
|
# for all outgoing connections |
121
|
801
|
|
|
|
|
2405
|
foreach my $other (@out) |
122
|
|
|
|
|
|
|
{ |
123
|
|
|
|
|
|
|
# in case there exists more than one edge from $n --> $other |
124
|
576
|
|
|
|
|
2586
|
my @edges = $n->edges_to($other); |
125
|
576
|
|
|
|
|
4964
|
for my $edge (sort { $a->{id} <=> $b->{id} } @edges) |
|
43
|
|
|
|
|
143
|
|
126
|
|
|
|
|
|
|
{ |
127
|
612
|
|
|
|
|
3017
|
$txt .= $first . $edge->as_txt() . $other->_as_part_txt() . "\n"; |
128
|
|
|
|
|
|
|
} |
129
|
|
|
|
|
|
|
} |
130
|
|
|
|
|
|
|
} |
131
|
|
|
|
|
|
|
|
132
|
211
|
|
|
|
|
1724
|
foreach my $n (@nodes) |
133
|
|
|
|
|
|
|
{ |
134
|
860
|
|
|
|
|
3246
|
delete $n->{_p}; # clean up |
135
|
|
|
|
|
|
|
} |
136
|
|
|
|
|
|
|
|
137
|
211
|
|
|
|
|
2755
|
$txt; |
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
############################################################################# |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
package Graph::Easy::Group; |
143
|
|
|
|
|
|
|
|
144
|
16
|
|
|
16
|
|
206
|
use strict; |
|
16
|
|
|
|
|
173
|
|
|
16
|
|
|
|
|
7300
|
|
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
sub as_txt |
147
|
|
|
|
|
|
|
{ |
148
|
45
|
|
|
45
|
1
|
1164
|
my $self = shift; |
149
|
|
|
|
|
|
|
|
150
|
45
|
|
|
|
|
87
|
my $n = ''; |
151
|
45
|
100
|
|
|
|
593
|
if (!$self->isa('Graph::Easy::Group::Anon')) |
152
|
|
|
|
|
|
|
{ |
153
|
40
|
|
|
|
|
118
|
$n = $self->{name}; |
154
|
|
|
|
|
|
|
# quote special chars in name |
155
|
40
|
|
|
|
|
133
|
$n =~ s/([\[\]\(\)\{\}\#])/\\$1/g; |
156
|
40
|
|
|
|
|
113
|
$n = ' ' . $n; |
157
|
|
|
|
|
|
|
} |
158
|
|
|
|
|
|
|
|
159
|
45
|
|
|
|
|
333
|
my $txt = "($n"; |
160
|
|
|
|
|
|
|
|
161
|
45
|
|
|
|
|
131
|
$n = $self->{nodes}; |
162
|
|
|
|
|
|
|
|
163
|
45
|
100
|
|
|
|
219
|
$txt .= (keys %$n > 0 ? "\n" : ' '); |
164
|
45
|
|
|
|
|
10113
|
for my $name ( sort keys %$n ) |
165
|
|
|
|
|
|
|
{ |
166
|
87
|
|
|
|
|
267
|
$n->{$name}->{_p} = 1; # mark as processed |
167
|
87
|
|
|
|
|
342
|
$txt .= ' ' . $n->{$name}->as_pure_txt() . "\n"; |
168
|
|
|
|
|
|
|
} |
169
|
45
|
|
|
|
|
280
|
$txt .= ")" . $self->attributes_as_txt() . "\n\n"; |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
# insert all the edges of the group |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
# |
174
|
45
|
|
|
|
|
241
|
$txt; |
175
|
|
|
|
|
|
|
} |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
############################################################################# |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
package Graph::Easy::Node; |
180
|
|
|
|
|
|
|
|
181
|
16
|
|
|
16
|
|
112
|
use strict; |
|
16
|
|
|
|
|
237
|
|
|
16
|
|
|
|
|
32688
|
|
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
sub attributes_as_txt |
184
|
|
|
|
|
|
|
{ |
185
|
|
|
|
|
|
|
# return the attributes of this node as text description |
186
|
1553
|
|
|
1553
|
1
|
3457
|
my ($self, $remap) = @_; |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
# nodes that were autosplit |
189
|
1553
|
100
|
|
|
|
5280
|
if (exists $self->{autosplit}) |
190
|
|
|
|
|
|
|
{ |
191
|
|
|
|
|
|
|
# other nodes are invisible in as_txt: |
192
|
128
|
100
|
|
|
|
475
|
return '' unless defined $self->{autosplit}; |
193
|
|
|
|
|
|
|
# the first one might have had a label set |
194
|
|
|
|
|
|
|
} |
195
|
|
|
|
|
|
|
|
196
|
1470
|
|
|
|
|
2174
|
my $att = ''; |
197
|
1470
|
|
|
|
|
8074
|
my $class = $self->class(); |
198
|
1470
|
|
|
|
|
3243
|
my $g = $self->{graph}; |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
# XXX TODO: remove atttributes that are simple the default attributes |
201
|
|
|
|
|
|
|
|
202
|
1470
|
|
|
|
|
2653
|
my $attributes = $self->{att}; |
203
|
1470
|
100
|
|
|
|
6131
|
if (exists $self->{autosplit}) |
204
|
|
|
|
|
|
|
{ |
205
|
|
|
|
|
|
|
# for the first node in a row of autosplit nodes, we need to create |
206
|
|
|
|
|
|
|
# the correct attributes, e.g. "silver|red|" instead of just silver: |
207
|
45
|
|
|
|
|
132
|
my $basename = $self->{autosplit_basename}; |
208
|
45
|
|
|
|
|
85
|
$attributes = { }; |
209
|
|
|
|
|
|
|
|
210
|
45
|
|
|
|
|
326
|
my $parts = $self->{autosplit_parts}; |
211
|
|
|
|
|
|
|
# gather all possible attribute names, otherwise an attribute set |
212
|
|
|
|
|
|
|
# on only one part (like via "color: |red;" would not show up: |
213
|
45
|
|
|
|
|
81
|
my $names = {}; |
214
|
45
|
|
|
|
|
1023
|
for my $child ($self, @$parts) |
215
|
|
|
|
|
|
|
{ |
216
|
128
|
|
|
|
|
179
|
for my $k (sort keys %{$child->{att}}) |
|
128
|
|
|
|
|
516
|
|
217
|
|
|
|
|
|
|
{ |
218
|
40
|
|
|
|
|
144
|
$names->{$k} = undef; |
219
|
|
|
|
|
|
|
} |
220
|
|
|
|
|
|
|
} |
221
|
|
|
|
|
|
|
|
222
|
45
|
|
|
|
|
165
|
for my $k (sort keys %$names) |
223
|
|
|
|
|
|
|
{ |
224
|
32
|
100
|
|
|
|
115
|
next if $k eq 'basename'; |
225
|
14
|
|
|
|
|
39
|
my $val = $self->{att}->{$k}; |
226
|
14
|
100
|
|
|
|
35
|
$val = '' unless defined $val; |
227
|
14
|
|
|
|
|
20
|
my $first = $val; my $not_equal = 0; |
|
14
|
|
|
|
|
18
|
|
228
|
14
|
|
|
|
|
28
|
$val .= '|'; |
229
|
14
|
|
|
|
|
28
|
for my $child (@$parts) |
230
|
|
|
|
|
|
|
{ |
231
|
|
|
|
|
|
|
# only consider our own autosplit parts (check should not be nec.) |
232
|
|
|
|
|
|
|
# next if !exists $child->{autosplit_basename} || |
233
|
|
|
|
|
|
|
# $child->{autosplit_basename} ne $basename; |
234
|
|
|
|
|
|
|
|
235
|
21
|
100
|
|
|
|
46
|
my $v = $child->{att}->{$k}; $v = '' if !defined $v; |
|
21
|
|
|
|
|
291
|
|
236
|
21
|
100
|
|
|
|
51
|
$not_equal ++ if $v ne $first; |
237
|
21
|
|
|
|
|
62
|
$val .= $v . '|'; |
238
|
|
|
|
|
|
|
} |
239
|
|
|
|
|
|
|
# all parts equal, so do "red|red|red" => "red" |
240
|
14
|
100
|
|
|
|
89
|
$val = $first if $not_equal == 0; |
241
|
|
|
|
|
|
|
|
242
|
14
|
|
|
|
|
71
|
$val =~ s/\|+\z/\|/; # "silver|||" => "silver|" |
243
|
14
|
100
|
|
|
|
67
|
$val =~ s/\|\z// if $val =~ /\|.*\|/; # "silver|" => "silver|" |
244
|
|
|
|
|
|
|
# but "red|blue|" => "red|blue" |
245
|
14
|
50
|
|
|
|
66
|
$attributes->{$k} = $val unless $val eq '|'; # skip '|' |
246
|
|
|
|
|
|
|
} |
247
|
45
|
100
|
|
|
|
452
|
$attributes->{basename} = $self->{att}->{basename} if defined $self->{att}->{basename}; |
248
|
|
|
|
|
|
|
} |
249
|
|
|
|
|
|
|
|
250
|
1470
|
|
|
|
|
9345
|
my $new = $g->_remap_attributes( $self, $attributes, $remap, 'noquote', 'encode' ); |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
# For nodes, we do not output their group attribute, since they simple appear |
253
|
|
|
|
|
|
|
# at the right place in the txt: |
254
|
1470
|
|
|
|
|
3468
|
delete $new->{group}; |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
# for groups inside groups, insert their group attribute |
257
|
1470
|
100
|
100
|
|
|
17172
|
$new->{group} = $self->{group}->{name} |
258
|
|
|
|
|
|
|
if $self->isa('Graph::Easy::Group') && exists $self->{group}; |
259
|
|
|
|
|
|
|
|
260
|
1470
|
100
|
|
|
|
5291
|
if (defined $self->{origin}) |
261
|
|
|
|
|
|
|
{ |
262
|
69
|
|
|
|
|
228
|
$new->{origin} = $self->{origin}->{name}; |
263
|
69
|
|
|
|
|
380
|
$new->{offset} = join(',', $self->offset()); |
264
|
|
|
|
|
|
|
} |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
# shorten output for multi-celled nodes |
267
|
|
|
|
|
|
|
# for "rows: 2;" still output "rows: 2;", because it is shorter |
268
|
1470
|
100
|
|
|
|
4895
|
if (exists $new->{columns}) |
269
|
|
|
|
|
|
|
{ |
270
|
18
|
|
50
|
|
|
165
|
$new->{size} = ($new->{columns}||1) . ',' . ($new->{rows}||1); |
|
|
|
100
|
|
|
|
|
271
|
18
|
|
|
|
|
233
|
delete $new->{rows}; |
272
|
18
|
|
|
|
|
39
|
delete $new->{columns}; |
273
|
|
|
|
|
|
|
# don't output the default size |
274
|
18
|
100
|
|
|
|
62
|
delete $new->{size} if $new->{size} eq '1,1'; |
275
|
|
|
|
|
|
|
} |
276
|
|
|
|
|
|
|
|
277
|
1470
|
|
|
|
|
5368
|
for my $atr (sort keys %$new) |
278
|
|
|
|
|
|
|
{ |
279
|
542
|
100
|
|
|
|
1976
|
next if $atr =~ /^border/; # handled special |
280
|
|
|
|
|
|
|
|
281
|
491
|
|
|
|
|
2399
|
$att .= "$atr: $new->{$atr}; "; |
282
|
|
|
|
|
|
|
} |
283
|
|
|
|
|
|
|
|
284
|
1470
|
100
|
|
|
|
6943
|
if (!$self->isa_cell()) |
285
|
|
|
|
|
|
|
{ |
286
|
848
|
|
|
|
|
1445
|
my $border; |
287
|
848
|
100
|
|
|
|
2124
|
if (!exists $self->{autosplit}) |
288
|
|
|
|
|
|
|
{ |
289
|
803
|
|
|
|
|
4562
|
$border = $self->border_attribute(); |
290
|
|
|
|
|
|
|
} |
291
|
|
|
|
|
|
|
else |
292
|
|
|
|
|
|
|
{ |
293
|
45
|
|
100
|
|
|
890
|
$border = Graph::Easy::_border_attribute( |
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
294
|
|
|
|
|
|
|
$attributes->{borderstyle}||'', |
295
|
|
|
|
|
|
|
$attributes->{borderwidth}||'', |
296
|
|
|
|
|
|
|
$attributes->{bordercolor}||''); |
297
|
|
|
|
|
|
|
} |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
# XXX TODO: should do this for all attributes, not only for border |
300
|
|
|
|
|
|
|
# XXX TODO: this seems wrong anyway |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
# don't include default border |
303
|
848
|
100
|
66
|
|
|
5263
|
$border = '' if ref $g && $g->attribute($class,'border') eq $border; |
304
|
848
|
100
|
|
|
|
2599
|
$att .= "border: $border; " if $border ne ''; |
305
|
|
|
|
|
|
|
} |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
# if we have a subclass, we probably need to include it |
308
|
1470
|
|
|
|
|
2501
|
my $c = ''; |
309
|
1470
|
100
|
|
|
|
6105
|
$c = $1 if $class =~ /\.(\w+)/; |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
# but we do not need to include it if our group has a nodeclass attribute |
312
|
1470
|
100
|
100
|
|
|
6520
|
$c = '' if ref($self->{group}) && $self->{group}->attribute('nodeclass') eq $c; |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
# include our subclass as attribute |
315
|
1470
|
100
|
100
|
|
|
5316
|
$att .= "class: $c; " if $c ne '' && $c ne 'anon'; |
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
# generate attribute text if nec. |
318
|
1470
|
100
|
|
|
|
4804
|
$att = ' { ' . $att . '}' if $att ne ''; |
319
|
|
|
|
|
|
|
|
320
|
1470
|
|
|
|
|
8047
|
$att; |
321
|
|
|
|
|
|
|
} |
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
sub _as_part_txt |
324
|
|
|
|
|
|
|
{ |
325
|
|
|
|
|
|
|
# for edges, we need the name of the part of the first part, not the entire |
326
|
|
|
|
|
|
|
# autosplit text |
327
|
1403
|
|
|
1403
|
|
2200
|
my $self = shift; |
328
|
|
|
|
|
|
|
|
329
|
1403
|
|
|
|
|
3126
|
my $name = $self->{name}; |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
# quote special chars in name |
332
|
1403
|
|
|
|
|
12565
|
$name =~ s/([\[\]\|\{\}\#])/\\$1/g; |
333
|
|
|
|
|
|
|
|
334
|
1403
|
|
|
|
|
7640
|
'[ ' . $name . ' ]'; |
335
|
|
|
|
|
|
|
} |
336
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
sub as_pure_txt |
338
|
|
|
|
|
|
|
{ |
339
|
1194
|
|
|
1194
|
1
|
1829
|
my $self = shift; |
340
|
|
|
|
|
|
|
|
341
|
1194
|
100
|
100
|
|
|
4959
|
if (exists $self->{autosplit} && defined $self->{autosplit}) |
342
|
|
|
|
|
|
|
{ |
343
|
74
|
|
|
|
|
148
|
my $name = $self->{autosplit}; |
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
# quote special chars in name (but not |) |
346
|
74
|
|
|
|
|
190
|
$name =~ s/([\[\]\{\}\#])/\\$1/g; |
347
|
|
|
|
|
|
|
|
348
|
74
|
|
|
|
|
347
|
return '[ '. $name .' ]' |
349
|
|
|
|
|
|
|
} |
350
|
|
|
|
|
|
|
|
351
|
1120
|
|
|
|
|
2910
|
my $name = $self->{name}; |
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
# quote special chars in name |
354
|
1120
|
|
|
|
|
3367
|
$name =~ s/([\[\]\|\{\}\#])/\\$1/g; |
355
|
|
|
|
|
|
|
|
356
|
1120
|
|
|
|
|
4919
|
'[ ' . $name . ' ]'; |
357
|
|
|
|
|
|
|
} |
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
sub as_txt |
360
|
|
|
|
|
|
|
{ |
361
|
23
|
|
|
23
|
1
|
919
|
my $self = shift; |
362
|
|
|
|
|
|
|
|
363
|
23
|
50
|
|
|
|
98
|
if (exists $self->{autosplit}) |
364
|
|
|
|
|
|
|
{ |
365
|
0
|
0
|
|
|
|
0
|
return '' unless defined $self->{autosplit}; |
366
|
0
|
|
|
|
|
0
|
my $name = $self->{autosplit}; |
367
|
|
|
|
|
|
|
# quote special chars in name (but not |) |
368
|
0
|
|
|
|
|
0
|
$name =~ s/([\[\]\{\}\#])/\\$1/g; |
369
|
0
|
|
|
|
|
0
|
return '[ ' . $name . ' ]' |
370
|
|
|
|
|
|
|
} |
371
|
|
|
|
|
|
|
|
372
|
23
|
|
|
|
|
62
|
my $name = $self->{name}; |
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
# quote special chars in name |
375
|
23
|
|
|
|
|
230
|
$name =~ s/([\[\]\|\{\}\#])/\\$1/g; |
376
|
|
|
|
|
|
|
|
377
|
23
|
|
|
|
|
97
|
'[ ' . $name . ' ]' . $self->attributes_as_txt(); |
378
|
|
|
|
|
|
|
} |
379
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
############################################################################# |
381
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
package Graph::Easy::Edge; |
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
my $styles = { |
385
|
|
|
|
|
|
|
solid => '--', |
386
|
|
|
|
|
|
|
dotted => '..', |
387
|
|
|
|
|
|
|
double => '==', |
388
|
|
|
|
|
|
|
'double-dash' => '= ', |
389
|
|
|
|
|
|
|
dashed => '- ', |
390
|
|
|
|
|
|
|
'dot-dash' => '.-', |
391
|
|
|
|
|
|
|
'dot-dot-dash' => '..-', |
392
|
|
|
|
|
|
|
wave => '~~', |
393
|
|
|
|
|
|
|
}; |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
sub _as_txt |
396
|
|
|
|
|
|
|
{ |
397
|
622
|
|
|
622
|
|
929
|
my $self = shift; |
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
# '- Name ' or '' |
400
|
622
|
100
|
|
|
|
1849
|
my $n = $self->{att}->{label}; $n = '' unless defined $n; |
|
622
|
|
|
|
|
1834
|
|
401
|
|
|
|
|
|
|
|
402
|
622
|
100
|
|
|
|
902
|
my $left = ' '; $left = ' <' if $self->{bidirectional}; |
|
622
|
|
|
|
|
2086
|
|
403
|
622
|
100
|
|
|
|
889
|
my $right = '> '; $right = ' ' if $self->{undirected}; |
|
622
|
|
|
|
|
2188
|
|
404
|
|
|
|
|
|
|
|
405
|
622
|
|
50
|
|
|
2806
|
my $s = $self->style() || 'solid'; |
406
|
|
|
|
|
|
|
|
407
|
622
|
|
|
|
|
985
|
my $style = '--'; |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
# suppress border on edges |
410
|
622
|
|
|
|
|
3145
|
my $suppress = { all => { label => undef } }; |
411
|
622
|
100
|
|
|
|
3102
|
if ($s =~ /^(bold|bold-dash|broad|wide|invisible)\z/) |
412
|
|
|
|
|
|
|
{ |
413
|
|
|
|
|
|
|
# output "--> { style: XXX; }" |
414
|
15
|
|
|
|
|
33
|
$style = '--'; |
415
|
|
|
|
|
|
|
} |
416
|
|
|
|
|
|
|
else |
417
|
|
|
|
|
|
|
{ |
418
|
|
|
|
|
|
|
# output "-->" or "..>" etc |
419
|
607
|
|
|
|
|
1318
|
$suppress->{all}->{style} = undef; |
420
|
|
|
|
|
|
|
|
421
|
607
|
|
|
|
|
1410
|
$style = $styles->{ $s }; |
422
|
607
|
50
|
|
|
|
1530
|
if (!defined $style) |
423
|
|
|
|
|
|
|
{ |
424
|
0
|
|
|
|
|
0
|
require Carp; |
425
|
0
|
|
|
|
|
0
|
Carp::confess ("Unknown edge style '$s'\n"); |
426
|
|
|
|
|
|
|
} |
427
|
|
|
|
|
|
|
} |
428
|
|
|
|
|
|
|
|
429
|
622
|
100
|
|
|
|
1576
|
$n = $style . " $n " if $n ne ''; |
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
# make " - " into " - - " |
432
|
622
|
50
|
66
|
|
|
2334
|
$style = $style . $style if $self->{undirected} && substr($style,1,1) eq ' '; |
433
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
# ' - Name -->' or ' --> ' or ' -- ' |
435
|
622
|
|
|
|
|
2005
|
my $a = $self->attributes_as_txt($suppress) . ' '; $a =~ s/^\s//; |
|
622
|
|
|
|
|
2572
|
|
436
|
622
|
|
|
|
|
4706
|
$left . $n . $style . $right . $a; |
437
|
|
|
|
|
|
|
} |
438
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
1; |
440
|
|
|
|
|
|
|
__END__ |