wolffd@0
|
1 #
|
wolffd@0
|
2 # dotty_edit: editing functions and data structures
|
wolffd@0
|
3 #
|
wolffd@0
|
4 dotty.protogt.getnodesbyattr = function (gt, key, val) {
|
wolffd@0
|
5 local nid, node, nlist;
|
wolffd@0
|
6
|
wolffd@0
|
7 nlist = [];
|
wolffd@0
|
8 for (nid in gt.graph.nodes) {
|
wolffd@0
|
9 node = gt.graph.nodes[nid];
|
wolffd@0
|
10 if (node.attr[key] == val)
|
wolffd@0
|
11 nlist[nid] = node;
|
wolffd@0
|
12 }
|
wolffd@0
|
13 return nlist;
|
wolffd@0
|
14 };
|
wolffd@0
|
15 dotty.protogt.reachablenodes = function (gt, node) {
|
wolffd@0
|
16 local nlist, stack, eid, edge, i;
|
wolffd@0
|
17
|
wolffd@0
|
18 stack[0] = node;
|
wolffd@0
|
19 i = 1;
|
wolffd@0
|
20 while (i > 0) {
|
wolffd@0
|
21 node = stack[i - 1];
|
wolffd@0
|
22 i = i - 1;
|
wolffd@0
|
23 nlist[node.nid] = node;
|
wolffd@0
|
24 for (eid in node.edges) {
|
wolffd@0
|
25 edge = node.edges[eid];
|
wolffd@0
|
26 if (~nlist[edge.head.nid]) {
|
wolffd@0
|
27 nlist[edge.head.nid] = edge.head;
|
wolffd@0
|
28 stack[i] = edge.head;
|
wolffd@0
|
29 i = i + 1;
|
wolffd@0
|
30 }
|
wolffd@0
|
31 }
|
wolffd@0
|
32 }
|
wolffd@0
|
33 return nlist;
|
wolffd@0
|
34 };
|
wolffd@0
|
35 dotty.protogt.mergegraph = function (gt, graph, show) {
|
wolffd@0
|
36 local nameid, onode, pos, size, eid, eid2, tnode, hnode, oedge;
|
wolffd@0
|
37
|
wolffd@0
|
38 if (~gt.noundo)
|
wolffd@0
|
39 gt.startadd2undo (gt);
|
wolffd@0
|
40 for (nameid in graph.nodedict) {
|
wolffd@0
|
41 pos = null;
|
wolffd@0
|
42 size = null;
|
wolffd@0
|
43 onode = graph.nodes[graph.nodedict[nameid]];
|
wolffd@0
|
44 if (onode.pos)
|
wolffd@0
|
45 pos = node.pos;
|
wolffd@0
|
46 if (onode.size)
|
wolffd@0
|
47 size = node.size;
|
wolffd@0
|
48 if (~(gt.graph.nodedict[nameid] >= 0)) {
|
wolffd@0
|
49 pos = null;
|
wolffd@0
|
50 size = null;
|
wolffd@0
|
51 if (onode.pos)
|
wolffd@0
|
52 pos = node.pos;
|
wolffd@0
|
53 if (onode.size)
|
wolffd@0
|
54 size = node.size;
|
wolffd@0
|
55 gt.insertnode (gt, pos, size, nameid, onode.attr, show);
|
wolffd@0
|
56 }
|
wolffd@0
|
57 }
|
wolffd@0
|
58 for (eid in graph.edges) {
|
wolffd@0
|
59 oedge = graph.edges[eid];
|
wolffd@0
|
60 tnode = gt.graph.nodes[gt.graph.nodedict[oedge.tail.name]];
|
wolffd@0
|
61 hnode = gt.graph.nodes[gt.graph.nodedict[oedge.head.name]];
|
wolffd@0
|
62 for (eid2 in tnode.edges)
|
wolffd@0
|
63 if (
|
wolffd@0
|
64 tnode.edges[eid2].tail == tnode &
|
wolffd@0
|
65 tnode.edges[eid2].head == hnode
|
wolffd@0
|
66 ) {
|
wolffd@0
|
67 oedge = null;
|
wolffd@0
|
68 break;
|
wolffd@0
|
69 }
|
wolffd@0
|
70 if (oedge)
|
wolffd@0
|
71 gt.insertedge (gt, tnode, null, hnode, null, oedge.attr, show);
|
wolffd@0
|
72 }
|
wolffd@0
|
73 if (~gt.noundo)
|
wolffd@0
|
74 gt.endadd2undo (gt);
|
wolffd@0
|
75 };
|
wolffd@0
|
76 dotty.protogt.insertsgraph = function (gt, name, attr, show) {
|
wolffd@0
|
77 local gid, sgraph, aid;
|
wolffd@0
|
78
|
wolffd@0
|
79 if (~gt)
|
wolffd@0
|
80 return null;
|
wolffd@0
|
81 gid = gt.graph.maxgid;
|
wolffd@0
|
82 if (~name) {
|
wolffd@0
|
83 while (gt.graph.graphdict[(name = concat ('g', gid))] >= 0)
|
wolffd@0
|
84 gid = gid + 1;
|
wolffd@0
|
85 } else if (gt.graph.graphdict[name]) {
|
wolffd@0
|
86 dotty.message (0, concat ('graph: ', name, ' exists'));
|
wolffd@0
|
87 return null;
|
wolffd@0
|
88 }
|
wolffd@0
|
89 gt.graph.graphdict[name] = gid;
|
wolffd@0
|
90 gt.graph.maxgid = gid + 1;
|
wolffd@0
|
91 gt.graph.graphs[gid] = [
|
wolffd@0
|
92 dotty.keys.gid = gid;
|
wolffd@0
|
93 dotty.keys.name = name;
|
wolffd@0
|
94 dotty.keys.gattr = copy (gt.graph.graphattr);
|
wolffd@0
|
95 dotty.keys.nattr = copy (gt.graph.nodeattr);
|
wolffd@0
|
96 dotty.keys.eattr = copy (gt.graph.edgeattr);
|
wolffd@0
|
97 ];
|
wolffd@0
|
98 sgraph = gt.graph.graphs[gid];
|
wolffd@0
|
99 if (~attr)
|
wolffd@0
|
100 attr = [];
|
wolffd@0
|
101 if (~attr.label)
|
wolffd@0
|
102 attr.label = '\N';
|
wolffd@0
|
103 for (aid in attr)
|
wolffd@0
|
104 sgraph.graphattr[aid] = attr[aid];
|
wolffd@0
|
105 gt.unpacksgraphattr (gt, sgraph);
|
wolffd@0
|
106 if (show)
|
wolffd@0
|
107 gt.drawsgraph (gt, gt.views, sgraph);
|
wolffd@0
|
108 return sgraph;
|
wolffd@0
|
109 };
|
wolffd@0
|
110 dotty.protogt.removesgraph = function (gt, sgraph) {
|
wolffd@0
|
111 gt.undrawsgraph (gt, gt.views, sgraph);
|
wolffd@0
|
112 remove (sgraph.name, gt.graph.graphdict);
|
wolffd@0
|
113 remove (sgraph.gid, gt.graph.graphs);
|
wolffd@0
|
114 };
|
wolffd@0
|
115 dotty.protogt.insertnode = function (gt, pos, size, name, attr, show) {
|
wolffd@0
|
116 local nid, node, aid;
|
wolffd@0
|
117
|
wolffd@0
|
118 nid = gt.graph.maxnid;
|
wolffd@0
|
119 if (~name) {
|
wolffd@0
|
120 while (gt.graph.nodedict[(name = concat ('n', nid))] >= 0)
|
wolffd@0
|
121 nid = nid + 1;
|
wolffd@0
|
122 } else if (gt.graph.nodedict[name] >= 0) {
|
wolffd@0
|
123 dotty.message (0, concat ('node: ', name, ' exists'));
|
wolffd@0
|
124 return null;
|
wolffd@0
|
125 }
|
wolffd@0
|
126 gt.graph.nodedict[name] = nid;
|
wolffd@0
|
127 gt.graph.maxnid = nid + 1;
|
wolffd@0
|
128 gt.graph.nodes[nid] = [
|
wolffd@0
|
129 dotty.keys.nid = nid;
|
wolffd@0
|
130 dotty.keys.name = name;
|
wolffd@0
|
131 dotty.keys.attr = copy (gt.graph.nodeattr);
|
wolffd@0
|
132 dotty.keys.edges = [];
|
wolffd@0
|
133 ];
|
wolffd@0
|
134 node = gt.graph.nodes[nid];
|
wolffd@0
|
135 if (~attr)
|
wolffd@0
|
136 attr = [];
|
wolffd@0
|
137 if (~attr.label)
|
wolffd@0
|
138 attr.label = '\N';
|
wolffd@0
|
139 for (aid in attr)
|
wolffd@0
|
140 node.attr[aid] = attr[aid];
|
wolffd@0
|
141 gt.unpacknodeattr (gt, node);
|
wolffd@0
|
142 if (~pos)
|
wolffd@0
|
143 pos = ['x' = 10; 'y' = 10;];
|
wolffd@0
|
144 node[dotty.keys.pos] = copy (pos);
|
wolffd@0
|
145 if (~size)
|
wolffd@0
|
146 size = ['x' = strlen (attr.label) * 30; 'y' = 30;];
|
wolffd@0
|
147 if (size.x == 0)
|
wolffd@0
|
148 size.x = 30;
|
wolffd@0
|
149 node[dotty.keys.size] = copy (size);
|
wolffd@0
|
150 node[dotty.keys.rect] = [
|
wolffd@0
|
151 0 = ['x' = pos.x - size.x / 2; 'y' = pos.y - size.y / 2;];
|
wolffd@0
|
152 1 = ['x' = pos.x + size.x / 2; 'y' = pos.y + size.y / 2;];
|
wolffd@0
|
153 ];
|
wolffd@0
|
154 node.draws = gt.simplenodedraw (node, pos, size);
|
wolffd@0
|
155 if (show)
|
wolffd@0
|
156 gt.drawnode (gt, gt.views, node);
|
wolffd@0
|
157 if (~gt.noundo) {
|
wolffd@0
|
158 gt.startadd2undo (gt);
|
wolffd@0
|
159 gt.currundo.inserted.nodes[nid] = node;
|
wolffd@0
|
160 gt.endadd2undo (gt);
|
wolffd@0
|
161 }
|
wolffd@0
|
162 return node;
|
wolffd@0
|
163 };
|
wolffd@0
|
164 dotty.protogt.removenode = function (gt, node) {
|
wolffd@0
|
165 local eid, list, edge, gid;
|
wolffd@0
|
166
|
wolffd@0
|
167 if (~gt.noundo)
|
wolffd@0
|
168 gt.startadd2undo (gt);
|
wolffd@0
|
169 for (eid in node.edges)
|
wolffd@0
|
170 list[eid] = node.edges[eid];
|
wolffd@0
|
171 for (eid in list)
|
wolffd@0
|
172 gt.removeedge (gt, list[eid]);
|
wolffd@0
|
173 gt.undrawnode (gt, gt.views, node);
|
wolffd@0
|
174 for (gid in gt.graph.graphs)
|
wolffd@0
|
175 remove (node.nid, gt.graph.graphs[gid].nodes);
|
wolffd@0
|
176 remove (node.name, gt.graph.nodedict);
|
wolffd@0
|
177 remove (node.nid, gt.graph.nodes);
|
wolffd@0
|
178 if (~gt.noundo) {
|
wolffd@0
|
179 gt.currundo.deleted.nodes[node.nid] = node;
|
wolffd@0
|
180 gt.endadd2undo (gt);
|
wolffd@0
|
181 }
|
wolffd@0
|
182 };
|
wolffd@0
|
183 dotty.protogt.insertedge = function (
|
wolffd@0
|
184 gt, nodea, porta, nodeb, portb, attr, show
|
wolffd@0
|
185 ) {
|
wolffd@0
|
186 local eid, edge, aid, tport, hport;
|
wolffd@0
|
187
|
wolffd@0
|
188 if (~nodea | ~nodeb)
|
wolffd@0
|
189 return null;
|
wolffd@0
|
190 if (porta)
|
wolffd@0
|
191 tport = porta;
|
wolffd@0
|
192 if (portb)
|
wolffd@0
|
193 hport = portb;
|
wolffd@0
|
194 eid = gt.graph.maxeid;
|
wolffd@0
|
195 while (gt.graph.edges[eid])
|
wolffd@0
|
196 eid = eid + 1;
|
wolffd@0
|
197 gt.graph.maxeid = eid + 1;
|
wolffd@0
|
198 gt.graph.edges[eid] = [
|
wolffd@0
|
199 dotty.keys.eid = eid;
|
wolffd@0
|
200 dotty.keys.tail = nodea;
|
wolffd@0
|
201 dotty.keys.tport = porta;
|
wolffd@0
|
202 dotty.keys.head = nodeb;
|
wolffd@0
|
203 dotty.keys.hport = portb;
|
wolffd@0
|
204 dotty.keys.attr = copy (gt.graph.edgeattr);
|
wolffd@0
|
205 ];
|
wolffd@0
|
206 edge = gt.graph.edges[eid];
|
wolffd@0
|
207 if (~attr)
|
wolffd@0
|
208 attr = [];
|
wolffd@0
|
209 for (aid in attr)
|
wolffd@0
|
210 edge.attr[aid] = attr[aid];
|
wolffd@0
|
211 nodea.edges[eid] = edge;
|
wolffd@0
|
212 nodeb.edges[eid] = edge;
|
wolffd@0
|
213 gt.unpackedgeattr (gt, edge);
|
wolffd@0
|
214 edge.draws = gt.simpleedgedraw (edge, nodea.pos, nodeb.pos);
|
wolffd@0
|
215 if (show)
|
wolffd@0
|
216 gt.drawedge (gt, gt.views, edge);
|
wolffd@0
|
217 if (~gt.noundo) {
|
wolffd@0
|
218 gt.startadd2undo (gt);
|
wolffd@0
|
219 gt.currundo.inserted.edges[eid] = edge;
|
wolffd@0
|
220 gt.endadd2undo (gt);
|
wolffd@0
|
221 }
|
wolffd@0
|
222 return edge;
|
wolffd@0
|
223 };
|
wolffd@0
|
224 dotty.protogt.removeedge = function (gt, edge) {
|
wolffd@0
|
225 local head, tail;
|
wolffd@0
|
226
|
wolffd@0
|
227 if (~gt.noundo)
|
wolffd@0
|
228 gt.startadd2undo (gt);
|
wolffd@0
|
229 if (edge.head.attr.support == 1)
|
wolffd@0
|
230 head = edge.head;
|
wolffd@0
|
231 if (edge.tail.attr.support == 1)
|
wolffd@0
|
232 if (head ~= edge.tail)
|
wolffd@0
|
233 tail = edge.tail;
|
wolffd@0
|
234 gt.undrawedge (gt, gt.views, edge);
|
wolffd@0
|
235 remove (edge.eid, edge.head.edges);
|
wolffd@0
|
236 remove (edge.eid, edge.tail.edges);
|
wolffd@0
|
237 remove (edge.eid, gt.graph.edges);
|
wolffd@0
|
238 if (head & tablesize (head.edges) == 0)
|
wolffd@0
|
239 gt.removenode (gt, head);
|
wolffd@0
|
240 if (tail & tablesize (tail.edges) == 0)
|
wolffd@0
|
241 gt.removenode (gt, tail);
|
wolffd@0
|
242 if (~gt.noundo) {
|
wolffd@0
|
243 gt.currundo.deleted.edges[edge.eid] = edge;
|
wolffd@0
|
244 gt.endadd2undo (gt);
|
wolffd@0
|
245 }
|
wolffd@0
|
246 };
|
wolffd@0
|
247 dotty.protogt.swapedgeids = function (gt, edge1, edge2) {
|
wolffd@0
|
248 local eid1, eid2;
|
wolffd@0
|
249
|
wolffd@0
|
250 if (edge1.eid == edge2.eid)
|
wolffd@0
|
251 return;
|
wolffd@0
|
252 if (~gt.noundo)
|
wolffd@0
|
253 gt.startadd2undo (gt);
|
wolffd@0
|
254 eid1 = edge1.eid;
|
wolffd@0
|
255 eid2 = edge2.eid;
|
wolffd@0
|
256 gt.graph.edges[eid1] = edge2;
|
wolffd@0
|
257 gt.graph.edges[eid2] = edge1;
|
wolffd@0
|
258 remove (eid1, edge1.tail.edges);
|
wolffd@0
|
259 remove (eid1, edge1.head.edges);
|
wolffd@0
|
260 remove (eid2, edge2.tail.edges);
|
wolffd@0
|
261 remove (eid2, edge2.head.edges);
|
wolffd@0
|
262 edge1.tail.edges[eid2] = edge1;
|
wolffd@0
|
263 edge1.head.edges[eid2] = edge1;
|
wolffd@0
|
264 edge2.tail.edges[eid1] = edge2;
|
wolffd@0
|
265 edge2.head.edges[eid1] = edge2;
|
wolffd@0
|
266 edge1.eid = eid2;
|
wolffd@0
|
267 edge2.eid = eid1;
|
wolffd@0
|
268 if (~gt.noundo) {
|
wolffd@0
|
269 gt.currundo.swapped.edges[eid1] = edge1;
|
wolffd@0
|
270 gt.currundo.swapped.edges[eid2] = edge2;
|
wolffd@0
|
271 gt.endadd2undo (gt);
|
wolffd@0
|
272 }
|
wolffd@0
|
273 };
|
wolffd@0
|
274 dotty.protogt.removesubtree = function (gt, obj) {
|
wolffd@0
|
275 local nlist, node, head, nid, edge, eid;
|
wolffd@0
|
276
|
wolffd@0
|
277 if (~gt.noundo)
|
wolffd@0
|
278 gt.startadd2undo (gt);
|
wolffd@0
|
279 if (obj.nid >= 0)
|
wolffd@0
|
280 node = obj;
|
wolffd@0
|
281 else if (obj.eid >= 0) {
|
wolffd@0
|
282 node = obj.head;
|
wolffd@0
|
283 gt.removeedge (gt, obj);
|
wolffd@0
|
284 if (~gt.graph.nodes[node.nid]) {
|
wolffd@0
|
285 if (~gt.noundo)
|
wolffd@0
|
286 gt.endadd2undo (gt);
|
wolffd@0
|
287 return;
|
wolffd@0
|
288 }
|
wolffd@0
|
289 for (eid in node.edges) {
|
wolffd@0
|
290 edge = node.edges[eid];
|
wolffd@0
|
291 if (edge.head == node & edge.tail ~= node) {
|
wolffd@0
|
292 if (~gt.noundo)
|
wolffd@0
|
293 gt.endadd2undo (gt);
|
wolffd@0
|
294 return;
|
wolffd@0
|
295 }
|
wolffd@0
|
296 }
|
wolffd@0
|
297 } else {
|
wolffd@0
|
298 dotty.message (0, 'bad object type in gt.removesubtree');
|
wolffd@0
|
299 return;
|
wolffd@0
|
300 }
|
wolffd@0
|
301 nlist = [node.nid = node;];
|
wolffd@0
|
302 while (node) {
|
wolffd@0
|
303 for (eid in node.edges) {
|
wolffd@0
|
304 head = node.edges[eid].head;
|
wolffd@0
|
305 if (head ~= node)
|
wolffd@0
|
306 nlist[head.nid] = head;
|
wolffd@0
|
307 }
|
wolffd@0
|
308 gt.removenode (gt, node);
|
wolffd@0
|
309 remove (node.nid, nlist);
|
wolffd@0
|
310 node = null;
|
wolffd@0
|
311 for (nid in nlist) {
|
wolffd@0
|
312 node = nlist[nid];
|
wolffd@0
|
313 for (eid in node.edges) {
|
wolffd@0
|
314 edge = node.edges[eid];
|
wolffd@0
|
315 if (edge.head == node & edge.tail ~= node) {
|
wolffd@0
|
316 node = null;
|
wolffd@0
|
317 break;
|
wolffd@0
|
318 }
|
wolffd@0
|
319 }
|
wolffd@0
|
320 if (node)
|
wolffd@0
|
321 break;
|
wolffd@0
|
322 }
|
wolffd@0
|
323 }
|
wolffd@0
|
324 if (~gt.noundo)
|
wolffd@0
|
325 gt.endadd2undo (gt);
|
wolffd@0
|
326 };
|
wolffd@0
|
327 dotty.protogt.removenodesbyattr = function (gt, key, val) {
|
wolffd@0
|
328 local nlist, nid;
|
wolffd@0
|
329
|
wolffd@0
|
330 if (~gt.noundo)
|
wolffd@0
|
331 gt.startadd2undo (gt);
|
wolffd@0
|
332 nlist = gt.getnodesbyattr (gt, key, val);
|
wolffd@0
|
333 for (nid in nlist)
|
wolffd@0
|
334 gt.removenode (gt, nlist[nid]);
|
wolffd@0
|
335 if (~gt.noundo)
|
wolffd@0
|
336 gt.endadd2undo (gt);
|
wolffd@0
|
337 };
|
wolffd@0
|
338 dotty.protogt.removesubtreesbyattr = function (gt, key, val) {
|
wolffd@0
|
339 local nlist, nid;
|
wolffd@0
|
340
|
wolffd@0
|
341 if (~gt.noundo)
|
wolffd@0
|
342 gt.startadd2undo (gt);
|
wolffd@0
|
343 nlist = gt.getnodesbyattr (gt, key, val);
|
wolffd@0
|
344 for (nid in nlist)
|
wolffd@0
|
345 if (gt.graph.nodes[nid])
|
wolffd@0
|
346 gt.removesubtree (gt, nlist[nid]);
|
wolffd@0
|
347 if (~gt.noundo)
|
wolffd@0
|
348 gt.endadd2undo (gt);
|
wolffd@0
|
349 };
|
wolffd@0
|
350 dotty.protogt.groupnodes = function (
|
wolffd@0
|
351 gt, nlist, gnode, pos, size, attr, keepmulti, show
|
wolffd@0
|
352 ) {
|
wolffd@0
|
353 local nid, node, elist, eid, edge, nodea, nodeb, inlist, outlist;
|
wolffd@0
|
354
|
wolffd@0
|
355 if (~nlist | tablesize (nlist) == 0)
|
wolffd@0
|
356 return;
|
wolffd@0
|
357 if (gnode.attr.support) {
|
wolffd@0
|
358 dotty.message (0, 'cannot group nodes in a support node');
|
wolffd@0
|
359 return;
|
wolffd@0
|
360 }
|
wolffd@0
|
361 if (~gt.noundo)
|
wolffd@0
|
362 gt.startadd2undo (gt);
|
wolffd@0
|
363 if (~gnode)
|
wolffd@0
|
364 gnode = gt.insertnode (gt, pos, size, null, attr, show);
|
wolffd@0
|
365 inlist = [];
|
wolffd@0
|
366 outlist = [];
|
wolffd@0
|
367 for (nid in nlist) {
|
wolffd@0
|
368 if ((node = nlist[nid]) == gnode)
|
wolffd@0
|
369 continue;
|
wolffd@0
|
370 elist = [];
|
wolffd@0
|
371 for (eid in node.edges)
|
wolffd@0
|
372 elist[eid] = node.edges[eid];
|
wolffd@0
|
373 for (eid in elist) {
|
wolffd@0
|
374 edge = elist[eid];
|
wolffd@0
|
375 if (edge.head == node) {
|
wolffd@0
|
376 nodea = edge.tail;
|
wolffd@0
|
377 nodeb = gnode;
|
wolffd@0
|
378 if (~keepmulti) {
|
wolffd@0
|
379 if (inlist[nodea.nid])
|
wolffd@0
|
380 continue;
|
wolffd@0
|
381 inlist[nodea.nid] = nodea;
|
wolffd@0
|
382 if (nodea == gnode)
|
wolffd@0
|
383 outlist[nodea.nid] = nodea;
|
wolffd@0
|
384 }
|
wolffd@0
|
385 } else {
|
wolffd@0
|
386 nodea = gnode;
|
wolffd@0
|
387 nodeb = edge.head;
|
wolffd@0
|
388 if (~keepmulti) {
|
wolffd@0
|
389 if (outlist[nodeb.nid])
|
wolffd@0
|
390 continue;
|
wolffd@0
|
391 outlist[nodeb.nid] = nodeb;
|
wolffd@0
|
392 if (nodeb == gnode)
|
wolffd@0
|
393 inlist[nodeb.nid] = nodeb;
|
wolffd@0
|
394 }
|
wolffd@0
|
395 }
|
wolffd@0
|
396 gt.insertedge (gt, nodea, null, nodeb, null, edge.attr, show);
|
wolffd@0
|
397 }
|
wolffd@0
|
398 gt.removenode (gt, node);
|
wolffd@0
|
399 }
|
wolffd@0
|
400 if (~gt.noundo)
|
wolffd@0
|
401 gt.endadd2undo (gt);
|
wolffd@0
|
402 return gnode;
|
wolffd@0
|
403 };
|
wolffd@0
|
404 dotty.protogt.groupnodesbyattr = function (
|
wolffd@0
|
405 gt, key, val, attr, keepmulti, show
|
wolffd@0
|
406 ) {
|
wolffd@0
|
407 local nlist, nid, pos, size;
|
wolffd@0
|
408
|
wolffd@0
|
409 pos = null;
|
wolffd@0
|
410 size = null;
|
wolffd@0
|
411 nlist = gt.getnodesbyattr (gt, key, val);
|
wolffd@0
|
412 if (show)
|
wolffd@0
|
413 for (nid in nlist) {
|
wolffd@0
|
414 pos = nlist[nid].pos;
|
wolffd@0
|
415 size = nlist[nid].size;
|
wolffd@0
|
416 break;
|
wolffd@0
|
417 }
|
wolffd@0
|
418 return gt.groupnodes (gt, nlist, null, pos, size, attr, keepmulti, show);
|
wolffd@0
|
419 };
|
wolffd@0
|
420 dotty.protogt.cut = function (gt, obj, set, mode, op) {
|
wolffd@0
|
421 local clipgt, list, node, nid, edge, eid, clipnode;
|
wolffd@0
|
422
|
wolffd@0
|
423 clipgt = dotty.clipgt;
|
wolffd@0
|
424 clipgt.graph = copy (dotty.protogt.graph);
|
wolffd@0
|
425 if (obj.eid >= 0) { # it's an edge
|
wolffd@0
|
426 list.edges[obj.eid] = obj;
|
wolffd@0
|
427 node = obj.head;
|
wolffd@0
|
428 } else if (obj.nid >= 0) {
|
wolffd@0
|
429 list.nodes[obj.nid] = obj;
|
wolffd@0
|
430 node = obj;
|
wolffd@0
|
431 for (eid in node.edges)
|
wolffd@0
|
432 list.edges[eid] = node.edges[eid];
|
wolffd@0
|
433 } else {
|
wolffd@0
|
434 dotty.message (0, 'unknown object type in gt.cut');
|
wolffd@0
|
435 return;
|
wolffd@0
|
436 }
|
wolffd@0
|
437 if (set == 'reachable') {
|
wolffd@0
|
438 list.nodes = gt.reachablenodes (gt, node);
|
wolffd@0
|
439 for (nid in list.nodes) {
|
wolffd@0
|
440 node = list.nodes[nid];
|
wolffd@0
|
441 for (eid in node.edges) {
|
wolffd@0
|
442 edge = node.edges[eid];
|
wolffd@0
|
443 list.edges[edge.eid] = edge;
|
wolffd@0
|
444 }
|
wolffd@0
|
445 }
|
wolffd@0
|
446 }
|
wolffd@0
|
447 if (mode == 'support') {
|
wolffd@0
|
448 for (eid in list.edges) {
|
wolffd@0
|
449 edge = list.edges[eid];
|
wolffd@0
|
450 if (~list.nodes[edge.tail.nid]) {
|
wolffd@0
|
451 list.support[edge.tail.nid] = edge.tail;
|
wolffd@0
|
452 list.nodes[edge.tail.nid] = edge.tail;
|
wolffd@0
|
453 }
|
wolffd@0
|
454 if (~list.nodes[edge.head.nid]) {
|
wolffd@0
|
455 list.support[edge.head.nid] = edge.head;
|
wolffd@0
|
456 list.nodes[edge.head.nid] = edge.head;
|
wolffd@0
|
457 }
|
wolffd@0
|
458 }
|
wolffd@0
|
459 }
|
wolffd@0
|
460 for (nid = 0; nid < gt.graph.maxnid; nid = nid + 1) {
|
wolffd@0
|
461 if (~list.nodes[nid])
|
wolffd@0
|
462 continue;
|
wolffd@0
|
463 node = list.nodes[nid];
|
wolffd@0
|
464 clipnode = gt.insertnode (clipgt, null, null, node.name, node.attr, 0);
|
wolffd@0
|
465 if (list.support[nid])
|
wolffd@0
|
466 clipnode.support = 1;
|
wolffd@0
|
467 list.clipnodes[nid] = clipnode;
|
wolffd@0
|
468 }
|
wolffd@0
|
469 for (eid = 0; eid < gt.graph.maxeid; eid = eid + 1) {
|
wolffd@0
|
470 if (~list.edges[eid])
|
wolffd@0
|
471 continue;
|
wolffd@0
|
472 edge = list.edges[eid];
|
wolffd@0
|
473 if (~list.nodes[edge.tail.nid] | ~list.nodes[edge.head.nid])
|
wolffd@0
|
474 continue;
|
wolffd@0
|
475 gt.insertedge (
|
wolffd@0
|
476 clipgt, list.clipnodes[edge.tail.nid], null,
|
wolffd@0
|
477 list.clipnodes[edge.head.nid], null, edge.attr, 0
|
wolffd@0
|
478 );
|
wolffd@0
|
479 }
|
wolffd@0
|
480 if (op ~= 'cut')
|
wolffd@0
|
481 return;
|
wolffd@0
|
482 if (~gt.noundo)
|
wolffd@0
|
483 gt.startadd2undo (gt);
|
wolffd@0
|
484 for (eid in list.edges)
|
wolffd@0
|
485 gt.removeedge (gt, list.edges[eid]);
|
wolffd@0
|
486 for (nid in list.nodes)
|
wolffd@0
|
487 if (~list.support[nid] & gt.graph.nodes[nid])
|
wolffd@0
|
488 gt.removenode (gt, list.nodes[nid]);
|
wolffd@0
|
489 if (~gt.noundo)
|
wolffd@0
|
490 gt.endadd2undo (gt);
|
wolffd@0
|
491 };
|
wolffd@0
|
492 dotty.protogt.paste = function (gt, pos, show) {
|
wolffd@0
|
493 local clipgt, offset, center, nid, node, eid, edge, nodes;
|
wolffd@0
|
494
|
wolffd@0
|
495 if (~gt.noundo)
|
wolffd@0
|
496 gt.startadd2undo (gt);
|
wolffd@0
|
497 clipgt = dotty.clipgt;
|
wolffd@0
|
498 if (clipgt.graph.rect)
|
wolffd@0
|
499 center = [
|
wolffd@0
|
500 'x' = (clipgt.graph.rect[1].x + clipgt.graph.rect[0].x) / 2;
|
wolffd@0
|
501 'y' = (clipgt.graph.rect[1].y + clipgt.graph.rect[0].y) / 2;
|
wolffd@0
|
502 ];
|
wolffd@0
|
503 else
|
wolffd@0
|
504 center = pos;
|
wolffd@0
|
505 offset = [
|
wolffd@0
|
506 'x' = center.x - pos.x;
|
wolffd@0
|
507 'y' = center.y - pos.y;
|
wolffd@0
|
508 ];
|
wolffd@0
|
509 for (nid = 0; clipgt.graph.nodes[nid]; nid = nid + 1) {
|
wolffd@0
|
510 node = clipgt.graph.nodes[nid];
|
wolffd@0
|
511 if (node.attr.label == '\N' | ~node.attr.label)
|
wolffd@0
|
512 node.attr.label = node.name;
|
wolffd@0
|
513 if (node.support == 1)
|
wolffd@0
|
514 nodes[nid] = gt.insertnode (gt, [
|
wolffd@0
|
515 'x' = node.pos.x - offset.x;
|
wolffd@0
|
516 'y' = node.pos.y - offset.y;
|
wolffd@0
|
517 ], null, null, [
|
wolffd@0
|
518 'support' = 1; 'shape' = 'circle';
|
wolffd@0
|
519 'label' = ''; 'width' = 0.2;
|
wolffd@0
|
520 ], show);
|
wolffd@0
|
521 else
|
wolffd@0
|
522 nodes[nid] = gt.insertnode (gt, [
|
wolffd@0
|
523 'x' = node.pos.x - offset.x;
|
wolffd@0
|
524 'y' = node.pos.y - offset.y;
|
wolffd@0
|
525 ], node.size, null, node.attr, show);
|
wolffd@0
|
526 }
|
wolffd@0
|
527 for (eid = 0; clipgt.graph.edges[eid]; eid = eid + 1) {
|
wolffd@0
|
528 edge = clipgt.graph.edges[eid];
|
wolffd@0
|
529 gt.insertedge (
|
wolffd@0
|
530 gt, nodes[edge.tail.nid], null,
|
wolffd@0
|
531 nodes[edge.head.nid], null, edge.attr, show
|
wolffd@0
|
532 );
|
wolffd@0
|
533 }
|
wolffd@0
|
534 if (~gt.noundo)
|
wolffd@0
|
535 gt.endadd2undo (gt);
|
wolffd@0
|
536 };
|
wolffd@0
|
537 dotty.protogt.startadd2undo = function (gt) {
|
wolffd@0
|
538 if (~gt.undoarray.level)
|
wolffd@0
|
539 gt.currundo = (
|
wolffd@0
|
540 gt.undoarray.entries[tablesize (gt.undoarray.entries)] = []
|
wolffd@0
|
541 );
|
wolffd@0
|
542 gt.undoarray.level = gt.undoarray.level + 1;
|
wolffd@0
|
543 };
|
wolffd@0
|
544 dotty.protogt.endadd2undo = function (gt) {
|
wolffd@0
|
545 gt.undoarray.level = gt.undoarray.level - 1;
|
wolffd@0
|
546 };
|
wolffd@0
|
547 dotty.protogt.undo = function (gt, show) {
|
wolffd@0
|
548 local entry, n, eid, edge, nid, node, edges;
|
wolffd@0
|
549
|
wolffd@0
|
550 if ((n = tablesize (gt.undoarray.entries)) < 1)
|
wolffd@0
|
551 return;
|
wolffd@0
|
552 entry = gt.undoarray.entries[n - 1];
|
wolffd@0
|
553 remove (n - 1, gt.undoarray.entries);
|
wolffd@0
|
554 remove ('currundo', gt);
|
wolffd@0
|
555 gt.noundo = 1;
|
wolffd@0
|
556 # hardwire nodes and edges back with the same id's as the originals
|
wolffd@0
|
557 for (nid in entry.deleted.nodes) {
|
wolffd@0
|
558 node = entry.deleted.nodes[nid];
|
wolffd@0
|
559 gt.graph.nodedict[node.name] = node.nid;
|
wolffd@0
|
560 gt.graph.nodes[node.nid] = node;
|
wolffd@0
|
561 node.edges = [];
|
wolffd@0
|
562 if (show)
|
wolffd@0
|
563 gt.drawnode (gt, gt.views, node);
|
wolffd@0
|
564 }
|
wolffd@0
|
565 for (eid in entry.deleted.edges) {
|
wolffd@0
|
566 edge = entry.deleted.edges[eid];
|
wolffd@0
|
567 gt.graph.edges[edge.eid] = edge;
|
wolffd@0
|
568 edge.head.edges[edge.eid] = edge;
|
wolffd@0
|
569 edge.tail.edges[edge.eid] = edge;
|
wolffd@0
|
570 if (show)
|
wolffd@0
|
571 gt.drawedge (gt, gt.views, edge);
|
wolffd@0
|
572 }
|
wolffd@0
|
573 if (entry.swapped.edges) {
|
wolffd@0
|
574 if (tablesize (entry.swapped.edges) == 2) {
|
wolffd@0
|
575 n = 0;
|
wolffd@0
|
576 for (eid in entry.swapped.edges) {
|
wolffd@0
|
577 edges[n] = entry.swapped.edges[eid];
|
wolffd@0
|
578 n = n + 1;
|
wolffd@0
|
579 }
|
wolffd@0
|
580 gt.swapedgeids (gt, edges[0], edges[1]);
|
wolffd@0
|
581 } else
|
wolffd@0
|
582 dotty.message (0, 'cannot handle undoing swap of > 2 edges');
|
wolffd@0
|
583 }
|
wolffd@0
|
584 for (eid in entry.inserted.edges) {
|
wolffd@0
|
585 edge = entry.inserted.edges[eid];
|
wolffd@0
|
586 gt.removeedge (gt, edge);
|
wolffd@0
|
587 }
|
wolffd@0
|
588 for (nid in entry.inserted.nodes) {
|
wolffd@0
|
589 node = entry.inserted.nodes[nid];
|
wolffd@0
|
590 gt.removenode (gt, node);
|
wolffd@0
|
591 }
|
wolffd@0
|
592 gt.noundo = 0;
|
wolffd@0
|
593 };
|