]>
Commit | Line | Data |
---|---|---|
bac41a7b A |
1 | # file: .../tcl-lib/snacced.tcl |
2 | # | |
a66d0d4a | 3 | # $Header: /cvs/root/Security/SecuritySNACCRuntime/tcl-lib/Attic/snacced.tcl,v 1.1.1.1 2001/05/18 23:14:11 mb Exp $ |
bac41a7b A |
4 | # $Log: snacced.tcl,v $ |
5 | # Revision 1.1.1.1 2001/05/18 23:14:11 mb | |
6 | # Move from private repository to open source repository | |
7 | # | |
8 | # Revision 1.1.1.1 1999/03/16 18:06:56 aram | |
9 | # Originals from SMIME Free Library. | |
10 | # | |
11 | # Revision 1.2 1997/02/28 13:39:57 wan | |
12 | # Modifications collected for new version 1.3: Bug fixes, tk4.2. | |
13 | # | |
14 | # Revision 1.1 1997/01/01 23:12:00 rj | |
15 | # first check-in | |
16 | # | |
17 | ||
18 | # todo: | |
19 | # int, enum and bit string editors with scrollbar | |
20 | ||
21 | #\[banner "initialization"]--------------------------------------------------------------------------------------------------------- | |
22 | ||
23 | set version 1.0 | |
24 | ||
25 | #tk colormodel . monochrome | |
26 | ||
27 | # check all types whether they were marked as PDU. | |
28 | # collect them in an associative array (indexed by module name) | |
29 | foreach t [snacc types] \ | |
30 | { | |
31 | if {[lindex [snacc type $t] 1] == {pdu}} \ | |
32 | { | |
33 | set module [lindex $t 0] | |
34 | set type [lindex $t 1] | |
35 | lappend pdus($module) $type | |
36 | } | |
37 | } | |
38 | ||
39 | #foreach n [array names pdus] \ | |
40 | #{ | |
41 | # debug "module $n: $pdus($n)" | |
42 | #} | |
43 | ||
44 | #\[banner "debugging aid"]---------------------------------------------------------------------------------------------------------- | |
45 | ||
46 | set debug 0 | |
47 | ||
48 | proc debug {text} \ | |
49 | { | |
50 | global debug | |
51 | if $debug {puts $text} | |
52 | } | |
53 | ||
54 | #\[banner "help texts"]------------------------------------------------------------------------------------------------------------- | |
55 | ||
56 | set helptext(about) "SnaccEd $version" | |
57 | ||
58 | set helptext(manoeuv) \ | |
59 | "Button 1 | |
60 | on label | |
61 | show/hide subnodes (except for lists) | |
62 | on list | |
63 | perform action (selected with button 3's popup) | |
64 | ||
65 | Button 2 | |
66 | on label | |
67 | open/close value editor | |
68 | on canvas, list or text | |
69 | drag view | |
70 | ||
71 | Button 3 | |
72 | on label | |
73 | show/hide parent | |
74 | on list | |
75 | select action mode (for button 1) | |
76 | on text | |
77 | pops up menu for text import/export | |
78 | " | |
79 | ||
80 | #\[banner "File loading and saving"]------------------------------------------------------------------------------------------------ | |
81 | ||
82 | # called from file_reload and file_load_from | |
83 | # clears the display so that only the file's root gets shown | |
84 | proc file_prune {fileref} \ | |
85 | { | |
86 | upvar #0 $fileref file | |
87 | ||
88 | set tree $file(tree) | |
89 | set handle $file(handle) | |
90 | ||
91 | list_cleanup /$handle $handle | |
92 | $tree prune {} | |
93 | ||
94 | ed_addnode $tree {} {} {} $handle $handle valid | |
95 | $tree draw | |
96 | } | |
97 | ||
98 | # this function is called from the "File" menu. | |
99 | # it reloads the file contents from its old origin: | |
100 | proc file_reload {fileref} \ | |
101 | { | |
102 | set rc 1 | |
103 | upvar #0 $fileref file | |
104 | # file_prune must be called before the snacc object is modified: | |
105 | file_prune $fileref | |
106 | $file(toplevel) config -cursor watch | |
107 | update idletasks | |
108 | if {[catch {snacc read $file(handle)} msg]} \ | |
109 | { | |
110 | tk_dialog .d load "Couldn't reload: $msg" warning 0 Dismiss | |
111 | } \ | |
112 | else \ | |
113 | { | |
114 | set file(modified) 0 | |
115 | set rc 0 | |
116 | } | |
117 | $file(toplevel) config -cursor arrow | |
118 | return $rc | |
119 | } | |
120 | ||
121 | # this function is called from the "File" menu. | |
122 | # it lets the user select a file and loads its contents | |
123 | proc file_load_from {fileref} \ | |
124 | { | |
125 | set rc 1 | |
126 | upvar #0 $fileref file | |
127 | if {[selbox fn ct]} \ | |
128 | { | |
129 | # file_prune must be called before the snacc object is modified: | |
130 | file_prune $fileref | |
131 | $file(toplevel) config -cursor watch | |
132 | update idletasks | |
133 | if {[catch {snacc read $file(handle) $ct $fn} msg]} \ | |
134 | { | |
135 | tk_dialog .d load "Couldn't load $fn: $msg" warning 0 Dismiss | |
136 | } \ | |
137 | else \ | |
138 | { | |
139 | set file(modified) 0 | |
140 | set rc 0 | |
141 | } | |
142 | $file(toplevel) config -cursor arrow | |
143 | } | |
144 | return $rc | |
145 | } | |
146 | ||
147 | # this function is called from the "File" menu. | |
148 | # it saves the file contents to its old origin: | |
149 | proc file_save {fileref} \ | |
150 | { | |
151 | set rc 1 | |
152 | upvar #0 $fileref file | |
153 | $file(toplevel) config -cursor watch | |
154 | update idletasks | |
155 | if {[catch {snacc write $file(handle)} msg]} \ | |
156 | { | |
157 | tk_dialog .d save "Couldn't save: $msg" warning 0 Dismiss | |
158 | } \ | |
159 | else \ | |
160 | { | |
161 | set file(modified) 0 | |
162 | set rc 0 | |
163 | } | |
164 | $file(toplevel) config -cursor arrow | |
165 | return $rc | |
166 | } | |
167 | ||
168 | # this function is called from the "File" menu. | |
169 | # it lets the user select a file and saves the file's contents | |
170 | proc file_save_as {fileref} \ | |
171 | { | |
172 | set rc 1 | |
173 | upvar #0 $fileref file | |
174 | if {[selbox fn {}]} \ | |
175 | { | |
176 | $file(toplevel) config -cursor watch | |
177 | update idletasks | |
178 | if {[catch {snacc write $file(handle) $fn} msg]} \ | |
179 | { | |
180 | tk_dialog .d save "Couldn't save $fn: $msg" warning 0 Dismiss | |
181 | } \ | |
182 | else \ | |
183 | { | |
184 | set file(modified) 0 | |
185 | set rc 0 | |
186 | } | |
187 | $file(toplevel) config -cursor arrow | |
188 | } | |
189 | return $rc | |
190 | } | |
191 | ||
192 | #\[sep]----------------------------------------------------------------------------------------------------------------------------- | |
193 | # this function is called from prune_or_add_children, list_click, new_choice, toggle_se* and set_or_add_root | |
194 | # it adds the node's children to the display | |
195 | # some of the children may already be displayed (this is usually the case when the function gets called from list_click or set_or_add_root). | |
196 | # ed_addnode will be called for every child. | |
197 | ||
198 | proc ed_expand {tree treepath snaccpath} \ | |
199 | { | |
200 | set canvas [$tree canvas] | |
201 | ||
202 | set info [snacc info $snaccpath] | |
203 | set type [lindex $info 2] | |
204 | ||
205 | switch $type \ | |
206 | { | |
207 | SEQUENCE - | |
208 | SET \ | |
209 | { | |
210 | debug "$type:" | |
211 | foreach elem [lindex $info 3] \ | |
212 | { | |
213 | set name [lindex $elem 0] | |
214 | set validity [lindex $elem 1] | |
215 | debug " $validity $name" | |
216 | ed_addnode $tree $treepath $treepath $snaccpath $name $name $validity | |
217 | } | |
218 | } | |
219 | SEQUENCE\ OF - | |
220 | SET\ OF \ | |
221 | { | |
222 | set len [lindex $info 3] | |
223 | set varname var:$treepath | |
224 | upvar #0 $varname var | |
225 | debug [list treepath=$treepath] | |
226 | debug [list varname=$varname] | |
227 | debug [list idlist=$var(idlist)] | |
228 | debug [list expand list ($type) len=$len] | |
229 | for {set i 0} {$i < $len} {incr i} \ | |
230 | { | |
231 | set id [lindex $var(idlist) $i] | |
232 | debug [list index $i id $id] | |
233 | if {$id} \ | |
234 | { | |
235 | ed_addnode $tree $treepath $treepath $snaccpath $id $i valid | |
236 | } | |
237 | } | |
238 | } | |
239 | CHOICE \ | |
240 | { | |
241 | set name [lindex $info 3] | |
242 | set validity [lindex $info 4] | |
243 | debug " $validity $name" | |
244 | ed_addnode $tree $treepath $treepath $snaccpath $name $name $validity | |
245 | } | |
246 | } | |
247 | } | |
248 | ||
249 | #\[sep]----------------------------------------------------------------------------------------------------------------------------- | |
250 | ||
251 | # ed_addnode is called from set_or_add_root, new_file, file_prune and ed_expand. | |
252 | # the node may already be displayed (this is usually the case when the function ed_expand gets called from list_click or set_or_add_root). in this case the node gets moved to the right position. | |
253 | # otherwise the node is created at the right place. | |
254 | ||
255 | # the arguments are: | |
256 | # tree name of the tree widget | |
257 | # treeparent tag of the displayed parent node. this is usually the same as the treeparentpath, except when the display gets extended into the parent direction where the root tag is {} | |
258 | # treeparentpath tag of the logical parent node. | |
259 | # snaccparentpath names of the | |
260 | # treenode node's name, gets appended to the treeparentpath | |
261 | # snaccnode node's name, gets appended to the snaccparentpath | |
262 | # validity | |
263 | ||
264 | proc ed_addnode {tree treeparent treeparentpath snaccparentpath treenode snaccnode validity} \ | |
265 | { | |
266 | set canvas [$tree canvas] | |
267 | ||
268 | set treepath "$treeparentpath/$treenode" | |
269 | set snaccpath "$snaccparentpath $snaccnode" | |
270 | ||
271 | if [llength [$canvas find withtag $treepath]] \ | |
272 | { | |
273 | debug [list movelink $treepath $treeparent] | |
274 | $tree movelink $treepath $treeparent | |
275 | } \ | |
276 | else \ | |
277 | { | |
278 | #debug [list addnode $snaccpath] | |
279 | if {[llength $snaccparentpath] > 0} \ | |
280 | { | |
281 | set nodelabeltext $snaccnode | |
282 | } \ | |
283 | else \ | |
284 | { | |
285 | set finfo [snacc finfo [string range $snaccpath 1 end]] | |
286 | if {[lindex $finfo 0] == {}} \ | |
287 | { | |
288 | set nodelabeltext {(unnamed)} | |
289 | } \ | |
290 | else \ | |
291 | { | |
292 | set nodelabeltext [lindex $finfo 0] | |
293 | } | |
294 | } | |
295 | $canvas create text 0 0 -text $nodelabeltext -tags [list $validity-label $treepath $treepath:label] | |
296 | ||
297 | set line [$canvas create line 0 0 0 0] | |
298 | ||
299 | # fix for canvas bug: for reverse video, the canvas displays black items on a black background | |
300 | if {[tk colormodel .] == {monochrome} && [lindex [$canvas config -background] 4] == {black}} \ | |
301 | { | |
302 | $canvas itemconfigure $treepath -fill white | |
303 | $canvas itemconfigure $line -fill white | |
304 | } | |
305 | ||
306 | if {$validity == {void}} \ | |
307 | { | |
308 | if {[tk colormodel .] == {color}} \ | |
309 | { | |
310 | # #b0b0b0 is the light grey of disabled checkbuttons: | |
311 | $canvas itemconfigure $treepath -fill #b0b0b0 | |
312 | $canvas itemconfigure $line -fill #b0b0b0 | |
313 | } \ | |
314 | else \ | |
315 | { | |
316 | $canvas itemconfigure $treepath -stipple gray50 | |
317 | $canvas itemconfigure $line -stipple gray50 | |
318 | } | |
319 | } | |
320 | ||
321 | debug [list addlink $treeparent $treepath $line] | |
322 | $tree addlink $treeparent $treepath $line | |
323 | } | |
324 | } | |
325 | ||
326 | #\[sep]----------------------------------------------------------------------------------------------------------------------------- | |
327 | # open/drop subtree | |
328 | proc prune_or_add_children {canvas} \ | |
329 | { | |
330 | set tree $canvas.t | |
331 | # debug $canvas | |
332 | set id [$canvas find withtag current] | |
333 | if {$id == {}} \ | |
334 | { | |
335 | debug "no item" | |
336 | } \ | |
337 | else \ | |
338 | { | |
339 | set treepath [lindex [$canvas gettags $id] 1] | |
340 | set snaccpath [tree2snacc $treepath] | |
341 | set type [lindex [snacc info $snaccpath] 2] | |
342 | switch $type \ | |
343 | { | |
344 | SEQUENCE\ OF - SET\ OF | |
345 | {} | |
346 | default | |
347 | { | |
348 | # debug $treepath | |
349 | if {[$tree isleaf $treepath]} \ | |
350 | { | |
351 | debug [list expanding $treepath $snaccpath] | |
352 | ed_expand $tree $treepath $snaccpath | |
353 | } \ | |
354 | else \ | |
355 | { | |
356 | debug [list cutting $treepath] | |
357 | # !!! list_cleanup usually has to be called with the node that gets removed! | |
358 | # in this case calling it with the node that stays around doesn't hurt because it is guaranteed not to be a SEQUENCE OF or SET OF type (they are handled a few lines above) | |
359 | list_cleanup $treepath $snaccpath | |
360 | $tree prune $treepath | |
361 | } | |
362 | } | |
363 | } | |
364 | } | |
365 | $tree draw | |
366 | } | |
367 | ||
368 | #\[sep]----------------------------------------------------------------------------------------------------------------------------- | |
369 | # this function has to be called whenever a subtree that may contain SET OF or SEQUENCE of types gets removed from the display | |
370 | # it must be called *before* the snacc object gets destroyed, the function examines it! | |
371 | proc list_cleanup {treepath snaccpath} \ | |
372 | { | |
373 | set info [snacc info $snaccpath] | |
374 | set type [lindex $info 2] | |
375 | switch $type \ | |
376 | { | |
377 | SET - SEQUENCE - CHOICE | |
378 | { | |
379 | foreach elem [lindex $info 3] \ | |
380 | { | |
381 | set name [lindex $elem 0] | |
382 | set validity [lindex $elem 1] | |
383 | if {$validity == {valid}} \ | |
384 | { | |
385 | set subtreepath "$treepath/$name" | |
386 | set subsnaccpath "$snaccpath $name" | |
387 | list_cleanup $subtreepath $subsnaccpath | |
388 | } | |
389 | } | |
390 | } | |
391 | SET\ OF - SEQUENCE\ OF | |
392 | { | |
393 | set varname var:$treepath | |
394 | global $varname | |
395 | debug [list varname=$varname] | |
396 | if {[info exists $varname]} \ | |
397 | { | |
398 | set idlist [set $varname\(idlist)] | |
399 | debug [list idlist=$idlist] | |
400 | set i 0 | |
401 | foreach id $idlist \ | |
402 | { | |
403 | if {$id != 0} \ | |
404 | { | |
405 | set subtreepath "$treepath/$id" | |
406 | set subsnaccpath "$snaccpath $i" | |
407 | list_cleanup $subtreepath $subsnaccpath | |
408 | } | |
409 | incr i | |
410 | } | |
411 | unset $varname | |
412 | } | |
413 | } | |
414 | } | |
415 | } | |
416 | ||
417 | # this function must be called when calling "$tree root $treepath". | |
418 | # it calls list_cleanup for all nodes that are neither parent nor in the subtree pointed to by $treepath. | |
419 | proc list_cleanup_not_me {treepath snaccpath} \ | |
420 | { | |
421 | if {[set i [llength $snaccpath]] > 1} \ | |
422 | { | |
423 | incr i -1 | |
424 | set parenttreepath [join [lrange [split $treepath /] 0 $i] /] | |
425 | incr i -1 | |
426 | set parentsnaccpath [lrange $snaccpath 0 $i] | |
427 | ||
428 | set info [snacc info $parentsnaccpath] | |
429 | set type [lindex $info 2] | |
430 | switch $type \ | |
431 | { | |
432 | SET - SEQUENCE - CHOICE | |
433 | { | |
434 | foreach elem [lindex $info 3] \ | |
435 | { | |
436 | set name [lindex $elem 0] | |
437 | set validity [lindex $elem 1] | |
438 | if {$validity == {valid}} \ | |
439 | { | |
440 | set subparenttreepath "$parenttreepath/$name" | |
441 | set subparentsnaccpath "$parentsnaccpath $name" | |
442 | if {$subparenttreepath != $treepath} \ | |
443 | { | |
444 | list_cleanup $subparenttreepath $subparentsnaccpath | |
445 | } | |
446 | } | |
447 | } | |
448 | } | |
449 | SET\ OF - SEQUENCE\ OF | |
450 | { | |
451 | set varname var:$parenttreepath | |
452 | global $varname | |
453 | debug [list varname=$varname] | |
454 | set idlist [set $varname\(idlist)] | |
455 | debug [list idlist=$idlist] | |
456 | set i 0 | |
457 | foreach id $idlist \ | |
458 | { | |
459 | if {$id != 0} \ | |
460 | { | |
461 | set subparenttreepath "$parenttreepath/$id" | |
462 | set subparentsnaccpath "$parentsnaccpath $i" | |
463 | if {$subparenttreepath != $treepath} \ | |
464 | { | |
465 | list_cleanup $subparenttreepath $subparentsnaccpath | |
466 | set $varname\(idlist) [lreplace [set $varname\(idlist)] $i $i 0] | |
467 | } | |
468 | } | |
469 | incr i | |
470 | } | |
471 | } | |
472 | } | |
473 | # recursion: | |
474 | list_cleanup_not_me $parenttreepath $parentsnaccpath | |
475 | } | |
476 | } | |
477 | ||
478 | #\[sep]----------------------------------------------------------------------------------------------------------------------------- | |
479 | # /file0/files/1/name \(-> { file0 files 0 name} | |
480 | ||
481 | proc tree2snacc {treepath} \ | |
482 | { | |
483 | set subtreepath {} | |
484 | foreach elem [lrange [split $treepath /] 1 end] \ | |
485 | { | |
486 | set treeelem $elem | |
487 | if {[regexp {^[0-9]} $elem]} \ | |
488 | { | |
489 | set varname var:$subtreepath | |
490 | global $varname | |
491 | set idlist [set $varname\(idlist)] | |
492 | set id $elem | |
493 | set index 0 | |
494 | foreach lid $idlist \ | |
495 | { | |
496 | if {$lid == $id} break | |
497 | incr index | |
498 | } | |
499 | if {$index == [llength $idlist]} \ | |
500 | { | |
501 | error "tree2snacc: id $id not found in idlist [list $idlist]" | |
502 | } | |
503 | set snaccelem $index | |
504 | } \ | |
505 | else \ | |
506 | { | |
507 | set snaccelem $elem | |
508 | } | |
509 | append subtreepath /$treeelem | |
510 | append subsnaccpath " $snaccelem" | |
511 | debug [list >>$subtreepath--$subsnaccpath<<] | |
512 | } | |
513 | debug [list >>$subtreepath--$subsnaccpath<<] | |
514 | return $subsnaccpath | |
515 | } | |
516 | ||
517 | #\[sep]----------------------------------------------------------------------------------------------------------------------------- | |
518 | proc import_text {text_w treepath} \ | |
519 | { | |
520 | if {[selbox fn {}]} \ | |
521 | { | |
522 | if {[catch {set text [snacc import $fn]} msg]} \ | |
523 | { | |
524 | tk_dialog .d import "Couldn't import $fn: $msg" warning 0 Dismiss | |
525 | } \ | |
526 | else \ | |
527 | { | |
528 | $text_w delete 0.0 end | |
529 | $text_w insert end $text | |
530 | snacc set [tree2snacc $treepath] $text | |
531 | } | |
532 | } | |
533 | } | |
534 | ||
535 | #\[sep]----------------------------------------------------------------------------------------------------------------------------- | |
536 | proc export_text {text_w} \ | |
537 | { | |
538 | if {[selbox fn {}]} \ | |
539 | { | |
540 | if {[catch {snacc export [$text_w get 0.0 end] $fn} msg]} \ | |
541 | { | |
542 | tk_dialog .d import "Couldn't export $fn: $msg" warning 0 Dismiss | |
543 | } | |
544 | } | |
545 | } | |
546 | ||
547 | proc frame_resize_bindings {fileref treepath} \ | |
548 | { | |
549 | upvar #0 $fileref file | |
550 | ||
551 | set frame $file(canvas).edit$treepath | |
552 | ||
553 | bind $frame <ButtonPress-1> [list frame_resize_start $fileref %x %y] | |
554 | bind $frame <Button1-Motion> [list frame_resize_cont $fileref $treepath %x %y] | |
555 | bind $frame <ButtonRelease-1> [list frame_resize_end $fileref $treepath] | |
556 | ||
557 | $frame config -cursor bottom_right_corner | |
558 | } | |
559 | ||
560 | proc frame_resize_start {fileref x y} \ | |
561 | { | |
562 | #debug [list frame_resize_start $fileref $x $y] | |
563 | ||
564 | upvar #0 $fileref file | |
565 | ||
566 | set file(resize_x) $x | |
567 | set file(resize_y) $y | |
568 | } | |
569 | ||
570 | proc frame_resize_cont {fileref treepath x y} \ | |
571 | { | |
572 | #debug [list frame_resize_cont $fileref $treepath $x $y] | |
573 | ||
574 | upvar #0 $fileref file | |
575 | ||
576 | set frame $file(canvas).edit$treepath | |
577 | set frametag $treepath:edit | |
578 | ||
579 | set oldw [lindex [$file(canvas) itemconfig $frametag -width] 4] | |
580 | set oldh [lindex [$file(canvas) itemconfig $frametag -height] 4] | |
581 | debug "old: $oldw x $oldh" | |
582 | set neww [max 1 [expr $oldw+$x-$file(resize_x)]] | |
583 | set newh [max 1 [expr $oldh+$y-$file(resize_y)]] | |
584 | debug "new: $neww x $newh" | |
585 | $file(canvas) itemconfig $frametag -width $neww -height $newh | |
586 | set file(resize_x) $x | |
587 | set file(resize_y) $y | |
588 | } | |
589 | ||
590 | proc frame_resize_end {fileref treepath} \ | |
591 | { | |
592 | #debug [list frame_resize_end $fileref $treepath] | |
593 | ||
594 | upvar #0 $fileref file | |
595 | ||
596 | $file(tree) nodeconfig $treepath | |
597 | $file(tree) draw | |
598 | } | |
599 | ||
600 | #\[sep]----------------------------------------------------------------------------------------------------------------------------- | |
601 | # toggle content editor | |
602 | proc toggle_editor {canvas} \ | |
603 | { | |
604 | set tree $canvas.t | |
605 | set id [$canvas find withtag current] | |
606 | if {$id == {}} \ | |
607 | { | |
608 | debug "no item" | |
609 | } \ | |
610 | else \ | |
611 | { | |
612 | set treepath [lindex [$canvas gettags $id] 1] | |
613 | set snaccpath [tree2snacc $treepath] | |
614 | set frame $canvas.edit$treepath | |
615 | if [llength [$canvas find withtag $treepath:edit]] \ | |
616 | { | |
617 | debug "removing editor for [list $treepath]" | |
618 | $canvas delete $treepath:edit | |
619 | destroy $frame | |
620 | $tree nodeconfig $treepath -remove {} | |
621 | } \ | |
622 | else \ | |
623 | { | |
624 | debug "opening editor for [list $treepath]" | |
625 | ||
626 | set fileref [lindex [split $treepath /] 1] | |
627 | ||
628 | frame $frame -borderwidth 3 -bg #cdb79e | |
629 | set cleanup [list [list destroy $frame]] | |
630 | ||
631 | set info [snacc info $snaccpath] | |
632 | set type [lindex $info 2] | |
633 | ||
634 | switch $type \ | |
635 | { | |
636 | NULL \ | |
637 | { | |
638 | set label $frame.label | |
639 | label $label -text NULL | |
640 | pack $label | |
641 | } | |
642 | BOOLEAN \ | |
643 | { | |
644 | set value [snacc get $snaccpath] | |
645 | ||
646 | set var var:$treepath | |
647 | global $var | |
648 | set $var $value | |
649 | ||
650 | set button $frame.button | |
651 | #checkbutton $button -variable $var | |
652 | checkbutton $button -onvalue TRUE -offvalue FALSE -variable $var -textvariable $var -command [list debug [list $canvas $treepath]] | |
653 | pack $button | |
654 | ||
655 | trace variable $var w change_simple | |
656 | } | |
657 | INTEGER \ | |
658 | { | |
659 | set value [snacc get $snaccpath] | |
660 | ||
661 | set var var:$treepath | |
662 | global $var | |
663 | set $var $value | |
664 | ||
665 | if {[lindex $info 0] != {{} {}}} \ | |
666 | { | |
667 | set typeinfo [snacc type [lindex $info 0]] | |
668 | ||
669 | foreach elem [lindex $typeinfo 3] \ | |
670 | { | |
671 | set en [lindex $elem 0] | |
672 | set ev [lindex $elem 1] | |
673 | set button $frame.button$en | |
674 | radiobutton $button -text $en -variable $var -value $ev -anchor w | |
675 | pack $button -fill x | |
676 | } | |
677 | } | |
678 | ||
679 | set entry $frame.entry | |
680 | entry $entry -textvariable $var -width 9 -relief sunken | |
681 | ||
682 | int_entry_bindings $entry | |
683 | ||
684 | pack $entry -anchor w -fill x | |
685 | ||
686 | focus $entry | |
687 | ||
688 | trace variable $var w change_simple | |
689 | } | |
690 | ENUMERATED \ | |
691 | { | |
692 | set typeinfo [snacc type [lindex $info 0]] | |
693 | ||
694 | if {[catch {set value [snacc get $snaccpath]} msg] == 1} \ | |
695 | { | |
696 | global errorInfo errorCode | |
697 | if {$errorCode == {SNACC ILLENUM}} \ | |
698 | { | |
699 | set value [lindex [lindex $typeinfo 3] 0] | |
700 | snacc set $snaccpath $value | |
701 | append msg "--setting to first legal symbolic value \"$value\"" | |
702 | tk_dialog .d illenum "$msg" warning 0 Dismiss | |
703 | } \ | |
704 | else \ | |
705 | { | |
706 | error $msg $errorInfo $errorCode | |
707 | } | |
708 | } | |
709 | ||
710 | set var var:$treepath | |
711 | global $var | |
712 | set $var $value | |
713 | ||
714 | foreach ev [lindex $typeinfo 3] \ | |
715 | { | |
716 | set button $frame.button$ev | |
717 | radiobutton $button -text $ev -variable $var -value $ev -anchor w | |
718 | pack $button -fill x | |
719 | } | |
720 | ||
721 | trace variable $var w change_simple | |
722 | } | |
723 | REAL \ | |
724 | { | |
725 | set value [snacc get $snaccpath] | |
726 | ||
727 | set var var:$treepath | |
728 | global $var | |
729 | set $var $value | |
730 | ||
731 | set entry $frame.entry | |
732 | entry $entry -textvariable $var -relief sunken | |
733 | pack $entry | |
734 | ||
735 | frame_resize_bindings $fileref $treepath | |
736 | ||
737 | focus $entry | |
738 | ||
739 | trace variable $var w change_simple | |
740 | } | |
741 | BIT\ STRING \ | |
742 | { | |
743 | set value [snacc get $snaccpath] | |
744 | ||
745 | set var var:$treepath | |
746 | global $var | |
747 | set $var $value | |
748 | ||
749 | set max_ev 0 | |
750 | if {[lindex $info 0] != {{} {}}} \ | |
751 | { | |
752 | set typeinfo [snacc type [lindex $info 0]] | |
753 | ||
754 | foreach elem [lindex $typeinfo 3] \ | |
755 | { | |
756 | set en [lindex $elem 0] | |
757 | set ev [lindex $elem 1] | |
758 | set max_ev [max $ev $max_ev] | |
759 | set button $frame.button$en | |
760 | checkbutton $button -text $en -variable $var:$ev -command [list toggle_bit $var $ev] -anchor w | |
761 | pack $button -fill x | |
762 | } | |
763 | } | |
764 | ||
765 | set entry $frame.entry | |
766 | entry $entry -textvariable $var -relief sunken | |
767 | set len [max 8 [string length $value] [expr $max_ev + 1]] | |
768 | if {$len > 0} \ | |
769 | { | |
770 | debug [list length of entry is $len] | |
771 | $entry config -width $len | |
772 | } | |
773 | pack $entry -anchor w -fill x | |
774 | ||
775 | bit_string_entry_bindings $entry | |
776 | ||
777 | focus $entry | |
778 | ||
779 | trace variable $var w change_bits | |
780 | set $var $value; # trigger the trace | |
781 | } | |
782 | OBJECT\ IDENTIFIER \ | |
783 | { | |
784 | set value [snacc get $snaccpath] | |
785 | ||
786 | set var var:$treepath | |
787 | global $var | |
788 | set $var $value | |
789 | ||
790 | set entry $frame.entry | |
791 | entry $entry -textvariable $var -relief sunken | |
792 | pack $entry -fill both | |
793 | ||
794 | frame_resize_bindings $fileref $treepath | |
795 | ||
796 | focus $entry | |
797 | ||
798 | trace variable $var w change_simple | |
799 | } | |
800 | OCTET\ STRING \ | |
801 | { | |
802 | set value [snacc get $snaccpath] | |
803 | ||
804 | set text $frame.text | |
805 | set sb $frame.sb | |
806 | ||
807 | text $text -borderwidth 2 -relief sunken -yscrollcommand [list $sb set] -width 32 -height 8 | |
808 | scrollbar $sb -relief sunken -command [list $text yview] -width 10 -cursor arrow | |
809 | ||
810 | pack $sb -side right -fill y | |
811 | pack $text -side left -expand true -fill both | |
812 | ||
813 | bind $text <ButtonPress-2> [list $text scan mark %y] | |
814 | bind $text <Button2-Motion> [list $text scan dragto %y] | |
815 | ||
816 | bind $text <Leave> "snacc set \[tree2snacc $treepath\] \[$text get 0.0 end\]" | |
817 | bind $text <FocusOut> "snacc set \[tree2snacc $treepath\] \[$text get 0.0 end\]" | |
818 | ||
819 | set m $frame.menu | |
820 | menu $m | |
821 | $m add command -label Load... -command "[list import_text $text $treepath]; [list $m unpost]" | |
822 | $m add command -label Save... -command "[list export_text $text]; [list $m unpost]" | |
823 | ||
824 | bind $text <ButtonPress-3> "[list $m] post \[expr %X -16\] \[expr %Y -8\]" | |
825 | bind $m <ButtonPress-3> [list $m unpost] | |
826 | bind $m <Any-Leave> [list $m unpost] | |
827 | ||
828 | $text insert end $value | |
829 | focus $text | |
830 | ||
831 | frame_resize_bindings $fileref $treepath | |
832 | } | |
833 | SEQUENCE - | |
834 | SET \ | |
835 | { | |
836 | set typeinfo [snacc type [lindex $info 0]] | |
837 | ||
838 | debug "$type:" | |
839 | ||
840 | set varelems [lindex $info 3] | |
841 | set typeelems [lindex $typeinfo 3] | |
842 | ||
843 | for {set i 0; set len [llength $varelems]} {$i < $len} {incr i} \ | |
844 | { | |
845 | set varelem [lindex $varelems $i] | |
846 | set typeelem [lindex $typeelems $i] | |
847 | ||
848 | set name [lindex $varelem 0] | |
849 | set validity [lindex $varelem 1] | |
850 | debug " $validity $name" | |
851 | ||
852 | set var var:$treepath:$name | |
853 | global $var | |
854 | set $var $validity | |
855 | ||
856 | set button $frame.$name | |
857 | checkbutton $button -text $name -onvalue valid -offvalue void -variable $var -command [list toggle_se* $canvas $treepath $name] -anchor w | |
858 | if {[lindex $typeelem 4] == {mandatory}} \ | |
859 | { | |
860 | #$button configure -disabledforeground [lindex [$button configure -fg] 4] -state disabled | |
861 | $button configure -state disabled | |
862 | } | |
863 | pack $button -fill x | |
864 | } | |
865 | } | |
866 | SEQUENCE\ OF - | |
867 | SET\ OF \ | |
868 | { | |
869 | set len [lindex $info 3] | |
870 | ||
871 | set varname var:$treepath | |
872 | upvar #0 $varname var | |
873 | if {![info exists var(idlist)]} \ | |
874 | { | |
875 | set var(idlist) {} | |
876 | set var(lastid) 0 | |
877 | } | |
878 | # no! needs a longer lifetime! | |
879 | #lappend cleanup [list global $varname] [list unset $varname] | |
880 | ||
881 | # set mbar $frame.mbar | |
882 | set list $frame.list | |
883 | set sb $frame.sb | |
884 | ||
885 | scrollbar $sb -command [list $list yview] -width 10 -relief sunken -cursor arrow | |
886 | # listbox $list -yscroll [list $sb set] -relief sunken -width 4 -height 5 | |
887 | text $list -borderwidth 2 -relief sunken -yscrollcommand [list $sb set] -width 4 -height 8 -exportselection 0 | |
888 | pack $sb -side right -fill y | |
889 | pack $list -side left -expand true -fill both | |
890 | ||
891 | # frame $mbar -relief raised -bd 2 | |
892 | # pack $mbar -side top -fill x | |
893 | ||
894 | # set mode $mbar.mode | |
895 | # set mode $frame.mode | |
896 | # set m $mode.m | |
897 | # menubutton $mode -text Mode -menu $m | |
898 | set m $frame.mode | |
899 | menu $m | |
900 | set lm "[list list_mode $canvas $treepath]; [list $m unpost]" | |
901 | $m add radiobutton -label Display -variable ${varname}(mode) -value display -command $lm | |
902 | $m invoke last | |
903 | $m add radiobutton -label Insert -variable ${varname}(mode) -value insert -command $lm | |
904 | $m add radiobutton -label Append -variable ${varname}(mode) -value append -command $lm | |
905 | $m add radiobutton -label Delete -variable ${varname}(mode) -value delete -command $lm | |
906 | # pack $mode -side left | |
907 | ||
908 | # pack $mode -side top -fill x | |
909 | ||
910 | $list tag config display -background #b2dfee -relief raised | |
911 | bind $list <Button-1> [list list_click $canvas $treepath] | |
912 | bind $list <Double-Button-1> { } | |
913 | bind $list <Triple-Button-1> { } | |
914 | bind $list <Button1-Motion> { } | |
915 | ||
916 | bind $list <ButtonPress-3> "[list $m] post \[expr %X-16\] \[expr %Y-8\]" | |
917 | bind $m <ButtonPress-3> [list $m unpost] | |
918 | bind $m <Any-Leave> [list $m unpost] | |
919 | debug $m | |
920 | ||
921 | for {set i 0} {$i < $len} {incr i} \ | |
922 | { | |
923 | $list insert end [format "%4d\n" $i] | |
924 | ||
925 | if {[llength $var(idlist)] > $i} \ | |
926 | { | |
927 | if {[set id [lindex $var(idlist) $i]]} \ | |
928 | { | |
929 | set line [expr $i + 1] | |
930 | $list tag add display $line.0 $line.end | |
931 | } | |
932 | } \ | |
933 | else \ | |
934 | { | |
935 | set var(idlist) [linsert $var(idlist) $i 0] | |
936 | } | |
937 | } | |
938 | ||
939 | frame_resize_bindings $fileref $treepath | |
940 | } | |
941 | CHOICE \ | |
942 | { | |
943 | set name [lindex $info 3] | |
944 | set validity [lindex $info 4] | |
945 | set typeinfo [snacc type [lindex $info 0]] | |
946 | ||
947 | set var var:$treepath | |
948 | set oldvar oldvar:$treepath | |
949 | global $var $oldvar | |
950 | set $var $name | |
951 | set $oldvar $name | |
952 | ||
953 | foreach elem [lindex $typeinfo 3] \ | |
954 | { | |
955 | set en [lindex $elem 0] | |
956 | set button $frame.button$en | |
957 | radiobutton $button -text $en -variable $var -value $en -command [list new_choice $canvas $treepath] -anchor w | |
958 | pack $button -fill x | |
959 | } | |
960 | debug " $validity $name" | |
961 | } | |
962 | default \ | |
963 | { | |
964 | error "unexpected type $type" | |
965 | } | |
966 | } | |
967 | ||
968 | scan [$canvas bbox $treepath:label] "%d%d%d%d" lx uy rx ly | |
969 | $canvas create window $lx $ly -anchor nw -tags [list edit $treepath $treepath:edit] -window $frame | |
970 | ||
971 | update idletasks; # calculate frame's size (needed by tree widget) | |
972 | ||
973 | # explicitly set the frame's width&height to avoid nasty effects when resizing: | |
974 | scan [$canvas bbox $treepath:edit] "%d%d%d%d" lx uy rx ly | |
975 | $canvas itemconfig $treepath:edit -width [expr $rx - $lx] -height [expr $ly - $uy] | |
976 | ||
977 | #debug [list cleanup = [join $cleanup \;]] | |
978 | $tree nodeconfig $treepath -remove [join $cleanup \;] | |
979 | } | |
980 | } | |
981 | $tree draw | |
982 | } | |
983 | ||
984 | #\[sep]----------------------------------------------------------------------------------------------------------------------------- | |
985 | proc list_click {canvas treepath} \ | |
986 | { | |
987 | set tree $canvas.t | |
988 | set snaccpath [tree2snacc $treepath] | |
989 | ||
990 | debug [list treepath=$treepath] | |
991 | debug [list snaccpath=$snaccpath] | |
992 | debug [list tree2snacc: [tree2snacc $treepath]] | |
993 | set varname var:$treepath | |
994 | upvar #0 $varname var | |
995 | set frame $canvas.edit$treepath | |
996 | set list $frame.list | |
997 | ||
998 | debug [list list_click: $list] | |
999 | debug [list varname=$varname] | |
1000 | debug [list idlist=$var(idlist)] | |
1001 | # debug [$list tag ranges display] | |
1002 | set text_index [$list index current] | |
1003 | #debug [list index: $index] | |
1004 | if {$text_index != ""} \ | |
1005 | { | |
1006 | # strip the column number: | |
1007 | set line [lindex [split $text_index .] 0] | |
1008 | # lines numbers start at 1, indices at 0: | |
1009 | set index [expr $line - 1] | |
1010 | set len [llength $var(idlist)] | |
1011 | set tags [$list tag names $text_index] | |
1012 | switch $var(mode) \ | |
1013 | { | |
1014 | display \ | |
1015 | { | |
1016 | debug [list tags: $tags] | |
1017 | debug [list line: $line] | |
1018 | if {$index < $len} \ | |
1019 | { | |
1020 | set id [lindex $var(idlist) $index] | |
1021 | debug [list index $index id $id] | |
1022 | if {$id} \ | |
1023 | { | |
1024 | $list tag remove display $line.0 $line.end | |
1025 | list_cleanup $treepath/$id "$snaccpath $index" | |
1026 | debug [list $tree rmlink $treepath/$id] | |
1027 | $tree rmlink $treepath/$id | |
1028 | set var(idlist) [lreplace $var(idlist) $index $index 0] | |
1029 | } \ | |
1030 | else \ | |
1031 | { | |
1032 | $list tag add display $line.0 $line.end | |
1033 | set var(idlist) [lreplace $var(idlist) $index $index [incr var(lastid)]] | |
1034 | ed_expand $tree $treepath $snaccpath | |
1035 | } | |
1036 | } | |
1037 | } | |
1038 | insert - | |
1039 | append \ | |
1040 | { | |
1041 | if {$var(mode) == {append}} {incr index} | |
1042 | debug [list insert $index 0] | |
1043 | set var(idlist) [linsert $var(idlist) $index 0] | |
1044 | debug [list $var(idlist)] | |
1045 | debug [list catch [list snacc set "$snaccpath {insert $index}" {}]] | |
1046 | catch [list snacc set "$snaccpath {insert $index}" {}] | |
1047 | set file(modified) 1 | |
1048 | debug [list [snacc get $snaccpath]] | |
1049 | ||
1050 | $list insert end [format "%4d\n" [expr [lindex [split [$list index end] .] 0] - 1]] | |
1051 | ||
1052 | for {set i $len} {$i > $index} {incr i -1} \ | |
1053 | { | |
1054 | set line [expr $i + 1] | |
1055 | if {[set id [lindex $var(idlist) $i]]} \ | |
1056 | { | |
1057 | debug [list $canvas itemconfigure $treepath/$id:label -text $i] | |
1058 | $canvas itemconfigure $treepath/$id:label -text $i | |
1059 | if {![lindex $var(idlist) [expr $i - 1]]} \ | |
1060 | { | |
1061 | debug [list $list tag add display $line.0 $line.end] | |
1062 | $list tag add display $line.0 $line.end | |
1063 | } | |
1064 | } \ | |
1065 | else \ | |
1066 | { | |
1067 | if {![lindex $var(idlist) [expr $i - 1]]} \ | |
1068 | { | |
1069 | debug [list $list tag remove display $line.0 $line.end] | |
1070 | $list tag remove display $line.0 $line.end | |
1071 | } | |
1072 | } | |
1073 | } | |
1074 | set line [expr $index + 1] | |
1075 | debug [list $list tag remove display $line.0 $line.end] | |
1076 | $list tag remove display $line.0 $line.end | |
1077 | } | |
1078 | delete \ | |
1079 | { | |
1080 | if {$index < $len} \ | |
1081 | { | |
1082 | debug [list delete $index] | |
1083 | ||
1084 | if {[set id [lindex $var(idlist) $index]]} \ | |
1085 | { | |
1086 | # list_cleanup must be called before the snacc object is modified: | |
1087 | list_cleanup $treepath/$id "$snaccpath $index" | |
1088 | $tree rmlink $treepath/$id | |
1089 | } | |
1090 | incr len -1 | |
1091 | for {set i $index} {$i < $len} {incr i} \ | |
1092 | { | |
1093 | set line [expr $i + 1] | |
1094 | if {[set id [lindex $var(idlist) [expr $i + 1]]]} \ | |
1095 | { | |
1096 | debug [list $canvas itemconfigure $treepath/$id:label -text $i] | |
1097 | $canvas itemconfigure $treepath/$id:label -text $i | |
1098 | if {![lindex $var(idlist) $i]} \ | |
1099 | { | |
1100 | debug [list $list tag add display $line.0 $line.end] | |
1101 | $list tag add display $line.0 $line.end | |
1102 | } | |
1103 | } \ | |
1104 | else \ | |
1105 | { | |
1106 | if {[lindex $var(idlist) $i]} \ | |
1107 | { | |
1108 | debug [list $list tag remove display $line.0 $line.end] | |
1109 | $list tag remove display $line.0 $line.end | |
1110 | } | |
1111 | } | |
1112 | } | |
1113 | ||
1114 | set var(idlist) [lreplace $var(idlist) $index $index] | |
1115 | debug [list $var(idlist)] | |
1116 | debug [list snacc unset "$snaccpath $index"] | |
1117 | snacc unset "$snaccpath $index" | |
1118 | set file(modified) 1 | |
1119 | debug [list [snacc get $snaccpath]] | |
1120 | $list delete [$list index {end - 1 line}] [$list index end] | |
1121 | } | |
1122 | } | |
1123 | } | |
1124 | $tree draw | |
1125 | } | |
1126 | } | |
1127 | ||
1128 | #\[sep]----------------------------------------------------------------------------------------------------------------------------- | |
1129 | proc list_mode {canvas treepath} \ | |
1130 | { | |
1131 | set var var:$treepath | |
1132 | global $var | |
1133 | set mode [set ${var}(mode)] | |
1134 | set frame $canvas.edit$treepath | |
1135 | set list $frame.list | |
1136 | ||
1137 | switch $mode \ | |
1138 | { | |
1139 | display {set cursor arrow} | |
1140 | insert {set cursor based_arrow_up} | |
1141 | append {set cursor based_arrow_down} | |
1142 | delete {set cursor pirate} | |
1143 | } | |
1144 | $list config -cursor $cursor | |
1145 | ||
1146 | debug [list list_mode: ${var}(mode) set to $mode] | |
1147 | } | |
1148 | ||
1149 | #\[sep]----------------------------------------------------------------------------------------------------------------------------- | |
1150 | proc toggle_bit {var i} \ | |
1151 | { | |
1152 | global $var:$i $var | |
1153 | set bit [set $var:$i] | |
1154 | set val [set $var] | |
1155 | ||
1156 | debug [list toggle_bit $val $i to $bit] | |
1157 | ||
1158 | set pre [string range $val 0 [expr $i - 1]] | |
1159 | ||
1160 | set fill {} | |
1161 | for {set l [string length $val]} {$l < $i} {incr l} \ | |
1162 | { | |
1163 | append fill 0 | |
1164 | debug [list appending: $val] | |
1165 | } | |
1166 | ||
1167 | set post [string range $val [expr $i + 1] end] | |
1168 | ||
1169 | debug [list toggle_bit combining $pre $fill $bit $post] | |
1170 | set $var $pre$fill$bit$post | |
1171 | } | |
1172 | ||
1173 | #\[sep]----------------------------------------------------------------------------------------------------------------------------- | |
1174 | proc change_bits {var element op} \ | |
1175 | { | |
1176 | global $var | |
1177 | set val [set $var] | |
1178 | debug [list change_bits $var set to $val] | |
1179 | ||
1180 | debug [list set l [string length $val]] | |
1181 | set l [string length $val] | |
1182 | for {set i 0} {$i < $l} {incr i} \ | |
1183 | { | |
1184 | global $var:$i | |
1185 | if {[info exists $var:$i]} \ | |
1186 | { | |
1187 | debug [list set $var:$i [string index $val $i]] | |
1188 | set $var:$i [string index $val $i] | |
1189 | } \ | |
1190 | else \ | |
1191 | { | |
1192 | debug [list non-exist: $var:$i] | |
1193 | } | |
1194 | } | |
1195 | ||
1196 | foreach bitvar [info globals $var:*] \ | |
1197 | { | |
1198 | set i [lindex [split $bitvar :] 2] | |
1199 | if {$i >= $l} \ | |
1200 | { | |
1201 | global $bitvar | |
1202 | set $bitvar 0 | |
1203 | } | |
1204 | } | |
1205 | ||
1206 | change_simple $var $element $op | |
1207 | } | |
1208 | ||
1209 | #\[sep]----------------------------------------------------------------------------------------------------------------------------- | |
1210 | proc change_simple {var element op} \ | |
1211 | { | |
1212 | global $var | |
1213 | set val [set $var] | |
1214 | debug [list change_simple $var set to $val] | |
1215 | ||
1216 | set treepath [lindex [split $var :] 1] | |
1217 | debug [list treepath= $treepath] | |
1218 | set fileref [lindex [split $treepath /] 1] | |
1219 | upvar #0 $fileref file | |
1220 | set canvas $file(canvas) | |
1221 | debug [list canvas= $canvas] | |
1222 | set snaccpath [tree2snacc $treepath] | |
1223 | debug [list snaccpath= $snaccpath] | |
1224 | snacc set $snaccpath $val | |
1225 | set file(modified) 1 | |
1226 | } | |
1227 | ||
1228 | #\[sep]----------------------------------------------------------------------------------------------------------------------------- | |
1229 | proc new_choice {canvas treepath} \ | |
1230 | { | |
1231 | set tree $canvas.t | |
1232 | set snaccpath [tree2snacc $treepath] | |
1233 | ||
1234 | set var var:$treepath | |
1235 | set oldvar oldvar:$treepath | |
1236 | global $var $oldvar | |
1237 | set val [set $var] | |
1238 | set oldval [set $oldvar] | |
1239 | ||
1240 | set fileref [lindex [split $treepath /] 1] | |
1241 | upvar #0 $fileref file | |
1242 | ||
1243 | debug "$file(modified)" | |
1244 | debug [list new choice: $snaccpath = $val] | |
1245 | ||
1246 | # list_cleanup must be called before the snacc object is modified: | |
1247 | list_cleanup $treepath/$oldval "$snaccpath $oldval" | |
1248 | ||
1249 | catch {snacc set $snaccpath [list $val {}]} | |
1250 | set file(modified) 1 | |
1251 | debug "$file(modified)" | |
1252 | ||
1253 | if {[llength [$canvas find withtag "$treepath/$oldval"]]} \ | |
1254 | { | |
1255 | $tree rmlink "$treepath/$oldval" | |
1256 | ed_expand $tree $treepath $snaccpath | |
1257 | $tree draw | |
1258 | } | |
1259 | ||
1260 | set $oldvar $val | |
1261 | } | |
1262 | ||
1263 | #\[sep]----------------------------------------------------------------------------------------------------------------------------- | |
1264 | proc toggle_se* {canvas treepath name} \ | |
1265 | { | |
1266 | set tree $canvas.t | |
1267 | set snaccpath [tree2snacc $treepath] | |
1268 | ||
1269 | set var var:$treepath:$name | |
1270 | global $var | |
1271 | set val [set $var] | |
1272 | ||
1273 | set fileref [lindex [split $treepath /] 1] | |
1274 | upvar #0 $fileref file | |
1275 | ||
1276 | debug "$snaccpath $name = $val" | |
1277 | ||
1278 | # this procedure is called after the button value has changed, so adjust the display to the current (new) setting: | |
1279 | if {$val == {void}} \ | |
1280 | { | |
1281 | # (change valid \(-> void) | |
1282 | # list_cleanup must be called before the snacc object is modified: | |
1283 | list_cleanup $treepath/$name "$snaccpath $name" | |
1284 | snacc unset "$snaccpath $name" | |
1285 | } \ | |
1286 | else \ | |
1287 | { | |
1288 | # (change void \(-> valid) | |
1289 | catch {snacc set "$snaccpath $name" {}} | |
1290 | } | |
1291 | set file(modified) 1 | |
1292 | ||
1293 | if {[llength [$canvas find withtag "$treepath/$name"]]} \ | |
1294 | { | |
1295 | debug [list rmlink "$treepath/$name"] | |
1296 | $tree rmlink "$treepath/$name" | |
1297 | # a bug in the tree widget requires us to redraw here: | |
1298 | $tree draw | |
1299 | ed_expand $tree $treepath $snaccpath | |
1300 | $tree draw | |
1301 | } | |
1302 | } | |
1303 | ||
1304 | #\[sep]----------------------------------------------------------------------------------------------------------------------------- | |
1305 | # add/drop parent and siblings | |
1306 | proc set_or_add_root {canvas} \ | |
1307 | { | |
1308 | set tree $canvas.t | |
1309 | set id [$canvas find withtag current] | |
1310 | if {$id == {}} \ | |
1311 | { | |
1312 | debug "no item" | |
1313 | } \ | |
1314 | else \ | |
1315 | { | |
1316 | set treepath [lindex [$canvas gettags $id] 1] | |
1317 | set snaccpath [tree2snacc $treepath] | |
1318 | # debug $path | |
1319 | if {[llength $snaccpath] == 1} \ | |
1320 | { | |
1321 | debug "at root already" | |
1322 | } \ | |
1323 | else \ | |
1324 | { | |
1325 | if {[$tree isroot $treepath]} \ | |
1326 | { | |
1327 | # show the parent: | |
1328 | debug [list expanding [list $treepath $snaccpath]] | |
1329 | set i [llength $snaccpath] | |
1330 | ||
1331 | incr i -1 | |
1332 | ||
1333 | set treeparentpath [join [lrange [split $treepath /] 0 $i] /] | |
1334 | set treeparentnode [lindex [split $treepath /] $i] | |
1335 | incr i -1 | |
1336 | set snaccparentpath [lrange $snaccpath 0 $i] | |
1337 | set snaccparentnode [lindex $snaccpath $i] | |
1338 | ||
1339 | set treeparentparentpath [join [lrange [split $treepath /] 0 $i] /] | |
1340 | incr i -1 | |
1341 | set snaccparentparentpath [lrange $snaccpath 0 $i] | |
1342 | ||
1343 | #debug [list ed_addnode $tree {} $parentparentpath $parentnode valid] | |
1344 | ed_addnode $tree {} $treeparentparentpath $snaccparentparentpath $treeparentnode $snaccparentnode valid | |
1345 | #debug [list ed_expand $tree $parentpath] | |
1346 | ed_expand $tree $treeparentpath $snaccparentpath | |
1347 | } \ | |
1348 | else \ | |
1349 | { | |
1350 | # hide everything above this subtree: | |
1351 | # debug "cutting $path" | |
1352 | list_cleanup_not_me $treepath $snaccpath | |
1353 | $tree root $treepath | |
1354 | } | |
1355 | # debug [snacc info $path] | |
1356 | } | |
1357 | } | |
1358 | $tree draw | |
1359 | } | |
1360 | ||
1361 | #\[sep]----------------------------------------------------------------------------------------------------------------------------- | |
1362 | proc file_open {} \ | |
1363 | { | |
1364 | if {[selbox fn ct nullfn]} \ | |
1365 | { | |
1366 | debug "fn=$fn ct=$ct" | |
1367 | if {$fn != {}} \ | |
1368 | { | |
1369 | if {[catch {set f [snacc open $ct $fn create]} msg]} \ | |
1370 | { | |
1371 | tk_dialog .d load "Couldn't open $fn {$ct}: $msg" warning 0 Dismiss | |
1372 | return -1 | |
1373 | } | |
1374 | } \ | |
1375 | else \ | |
1376 | { | |
1377 | if {[catch {set f [snacc create $ct]} msg]} \ | |
1378 | { | |
1379 | tk_dialog .d create "Couldn't create {$ct}: $msg" warning 0 Dismiss | |
1380 | return -1 | |
1381 | } | |
1382 | } | |
1383 | new_file $f | |
1384 | return 0 | |
1385 | } | |
1386 | return -1 | |
1387 | } | |
1388 | ||
1389 | #\[sep]----------------------------------------------------------------------------------------------------------------------------- | |
1390 | ||
1391 | set #file 0 | |
1392 | set #files 0 | |
1393 | ||
1394 | # returns 1 on `cancel', otherwise exits or returns 0 | |
1395 | proc close_file {fileref} \ | |
1396 | { | |
1397 | upvar #0 $fileref file | |
1398 | ||
1399 | if {$file(modified)} \ | |
1400 | { | |
1401 | set fi [snacc finfo $file(handle)] | |
1402 | set fn [lindex $fi 0] | |
1403 | set hasfn [expr {$fn != {}}] | |
1404 | set isrw [expr {[lindex $fi 1] == {rw}}] | |
1405 | set msg {There are unsaved changes} | |
1406 | if {$hasfn} \ | |
1407 | { | |
1408 | append msg " in `$fn'" | |
1409 | } | |
1410 | append msg {. Save them?} | |
1411 | switch [lindex {save discard cancel} [tk_dialog .d modified $msg questhead 0 Yes No Cancel]] \ | |
1412 | { | |
1413 | cancel \ | |
1414 | { | |
1415 | return 1 | |
1416 | } | |
1417 | save \ | |
1418 | { | |
1419 | if {$hasfn && $isrw} \ | |
1420 | { | |
1421 | if {[file_save $fileref]} \ | |
1422 | { | |
1423 | return 1 | |
1424 | } | |
1425 | } \ | |
1426 | else \ | |
1427 | { | |
1428 | if {[file_save_as $fileref]} \ | |
1429 | { | |
1430 | return 1 | |
1431 | } | |
1432 | } | |
1433 | } | |
1434 | } | |
1435 | } | |
1436 | ||
1437 | destroy $file(toplevel) | |
1438 | global #files | |
1439 | if {![incr #files -1]} \ | |
1440 | { | |
1441 | exit | |
1442 | } | |
1443 | return 0 | |
1444 | } | |
1445 | ||
1446 | proc file_quit {} \ | |
1447 | { | |
1448 | global #files | |
1449 | for {set i 0} {${#files}} {incr i} \ | |
1450 | { | |
1451 | if {[winfo exists .[set fileref file$i]]} \ | |
1452 | { | |
1453 | if {[close_file $fileref]} \ | |
1454 | { | |
1455 | return | |
1456 | } | |
1457 | } | |
1458 | } | |
1459 | } | |
1460 | ||
1461 | proc new_file {handle} \ | |
1462 | { | |
1463 | global #file | |
1464 | ||
1465 | while {[winfo exists [set toplevel .[set fileref file${#file}]]]} \ | |
1466 | { | |
1467 | incr #file | |
1468 | } | |
1469 | ||
1470 | #global $fileref | |
1471 | upvar #0 $fileref file | |
1472 | ||
1473 | set file(handle) $handle | |
1474 | ||
1475 | set file(toplevel) [toplevel $toplevel] | |
1476 | wm title $toplevel snaccEd | |
1477 | wm minsize $toplevel 150 100 | |
1478 | wm geometry $toplevel 500x500 | |
1479 | ||
1480 | global #files | |
1481 | incr #files | |
1482 | ||
1483 | set file(modified) 0 | |
1484 | ||
1485 | $toplevel config -cursor arrow | |
1486 | ||
1487 | set menubar $toplevel.menu | |
1488 | frame $menubar -relief raised -bd 2 | |
1489 | pack $menubar -side top -fill x | |
1490 | ||
1491 | set filem $menubar.file | |
1492 | set m $filem.m | |
1493 | menubutton $filem -text File -menu $m | |
1494 | menu $m | |
1495 | $m add command -label Reload -command [list file_reload $fileref] | |
1496 | $m add command -label Load... -command [list file_load_from $fileref] | |
1497 | $m add command -label Save -command [list file_save $fileref] | |
1498 | $m add command -label {Save As...} -command [list file_save_as $fileref] | |
1499 | $m add command -label Close -command [list close_file $fileref] | |
1500 | $m add separator | |
1501 | $m add command -label Open... -command file_open | |
1502 | $m add separator | |
1503 | $m add command -label Quit -command file_quit | |
1504 | set fi [snacc finfo $handle] | |
1505 | set hasnofn [expr {[lindex $fi 0] == {}}] | |
1506 | set isro [expr {[lindex $fi 1] == {ro}}] | |
1507 | if {$hasnofn} \ | |
1508 | { | |
1509 | $m entryconfigure Reload -state disabled | |
1510 | } | |
1511 | if {$hasnofn || $isro} \ | |
1512 | { | |
1513 | $m entryconfigure Save -state disabled | |
1514 | } | |
1515 | pack $filem -side left | |
1516 | ||
1517 | set help $menubar.help | |
1518 | set m $help.m | |
1519 | menubutton $help -text Help -menu $help.m | |
1520 | menu $m | |
1521 | $m add command -label About -command "help [list $m] \$helptext(about)" | |
1522 | $m add command -label Manoeuvering -command "help [list $m] \$helptext(manoeuv)" | |
1523 | pack $help -side right | |
1524 | ||
1525 | tk_menuBar $menubar $filem $help | |
1526 | ||
1527 | frame $toplevel.f0 | |
1528 | frame $toplevel.f1 | |
1529 | ||
1530 | pack $toplevel.f0 -expand true -fill both | |
1531 | pack $toplevel.f1 -fill x | |
1532 | ||
1533 | set file(canvas) [set canvas [canvas $toplevel.c -width 0 -height 0]] | |
1534 | ||
1535 | set hsb [scrollbar $toplevel.hsb -orient horiz -relief sunken -command [list $canvas xview]] | |
1536 | set vsb [scrollbar $toplevel.vsb -relief sunken -command [list $canvas yview]] | |
1537 | ||
1538 | $canvas config -xscroll [list $hsb set] -yscroll [list $vsb set] | |
1539 | ||
1540 | set blind [frame $toplevel.blind -width [lindex [$vsb config -width] 4]] | |
1541 | ||
1542 | pack $vsb -in $toplevel.f0 -side right -fill y | |
1543 | pack $canvas -in $toplevel.f0 -side left -expand true -fill both | |
1544 | ||
1545 | pack $blind -in $toplevel.f1 -side right | |
1546 | pack $hsb -in $toplevel.f1 -side left -expand true -fill x | |
1547 | ||
1548 | bind $canvas <ButtonPress-2> [list $canvas scan mark %x %y] | |
1549 | bind $canvas <Button2-Motion> [list $canvas scan dragto %x %y] | |
1550 | ||
1551 | $canvas bind valid-label <Button-1> {prune_or_add_children %W} | |
1552 | $canvas bind valid-label <Button-2> {toggle_editor %W} | |
1553 | $canvas bind valid-label <Button-3> {set_or_add_root %W} | |
1554 | ||
1555 | set file(tree) [set tree [tree $canvas.t]] | |
1556 | ||
1557 | ed_addnode $tree {} {} {} $handle $handle valid | |
1558 | ||
1559 | $tree draw | |
1560 | ||
1561 | tkwait visibility $toplevel | |
1562 | } | |
1563 | ||
1564 | proc snacced {} \ | |
1565 | { | |
1566 | wm withdraw . | |
1567 | ||
1568 | global argc argv | |
1569 | ||
1570 | if {$argc == 0} \ | |
1571 | { | |
1572 | if {[file_open]} \ | |
1573 | { | |
1574 | exit 1 | |
1575 | } | |
1576 | } \ | |
1577 | else \ | |
1578 | { | |
1579 | if {$argc == 3} \ | |
1580 | { | |
1581 | set ct [lrange $argv 0 1] | |
1582 | set fn [lindex $argv 2] | |
1583 | if {[catch {set f [snacc open $ct $fn create]} msg]} \ | |
1584 | { | |
1585 | tk_dialog .d load "Couldn't open $fn {$ct}: $msg" warning 0 Dismiss | |
1586 | exit 1 | |
1587 | } | |
1588 | } \ | |
1589 | elseif {$argc == 2} \ | |
1590 | { | |
1591 | set ct [lrange $argv 0 1] | |
1592 | if {[catch {set f [snacc create $ct]} msg]} \ | |
1593 | { | |
1594 | tk_dialog .d create "Couldn't create {$ct}: $msg" warning 0 Dismiss | |
1595 | exit 1 | |
1596 | } | |
1597 | } \ | |
1598 | else \ | |
1599 | { | |
1600 | exit 1 | |
1601 | } | |
1602 | new_file $f | |
1603 | } | |
1604 | } |