New setting: failInfo.
[ir-tcl-moved-to-github.git] / client.tcl
1 # IR toolkit for tcl/tk
2 # (c) Index Data 1995
3 # See the file LICENSE for details.
4 # Sebastian Hammer, Adam Dickmeiss
5 #
6 # $Log: client.tcl,v $
7 # Revision 1.48  1995-06-20 08:07:23  adam
8 # New setting: failInfo.
9 # Working on better cancel mechanism.
10 #
11 # Revision 1.47  1995/06/19  14:05:29  adam
12 # Bug fix: asked for SUTRS.
13 #
14 # Revision 1.46  1995/06/19  13:06:06  adam
15 # New define: IR_TCL_VERSION.
16 #
17 # Revision 1.45  1995/06/19  08:08:44  adam
18 # client.tcl: hotTargets now contain both database and target name.
19 # ir-tcl.c: setting protocol edited. Errors in callbacks are logged
20 # by logf(LOG_WARN, ...) calls.
21 #
22 # Revision 1.44  1995/06/16  14:55:18  adam
23 # Book logo mirrored.
24 #
25 # Revision 1.43  1995/06/16  14:41:05  adam
26 # Scan line entries can be copied to a search entry.
27 #
28 # Revision 1.42  1995/06/16  12:28:13  adam
29 # Implemented preferredRecordSyntax.
30 # Minor changes in diagnostic handling.
31 # Record list deleted when connection closes.
32 #
33 # Revision 1.41  1995/06/14  15:07:59  adam
34 # Bug fix in cascade-target-list. Uses yaz-version.h.
35 #
36 # Revision 1.40  1995/06/14  13:37:17  adam
37 # Setting recordType implemented.
38 # Setting implementationVersion implemented.
39 # Settings implementationId / implementationName edited.
40 #
41 # Revision 1.39  1995/06/14  12:16:22  adam
42 # hotTargets, textWrap and displayFormat saved in clientg.tcl.
43 #
44 # Revision 1.38  1995/06/14  07:22:45  adam
45 # Target definitions can be deleted.
46 # Listbox used in the query definition dialog.
47 #
48 # Revision 1.37  1995/06/13  14:37:59  adam
49 # Work on query setup.
50 # Better about origin/target.
51 # Better presentation formats.
52 #
53 # Revision 1.36  1995/06/13  07:42:14  adam
54 # Bindings removed from text widgets.
55 #
56 # Revision 1.35  1995/06/12  15:17:31  adam
57 # Text widget used in main window (instead of listbox) to support
58 # better presentation formats.
59 #
60 # Revision 1.34  1995/06/12  07:59:07  adam
61 # More work on geometry handling.
62 #
63 # Revision 1.33  1995/06/09  11:17:35  adam
64 # Start work on geometry management.
65 #
66 # Revision 1.32  1995/06/07  09:16:37  adam
67 # New presentation format.
68 #
69 # Revision 1.31  1995/06/06  16:31:09  adam
70 # Bug fix: target names couldn't contain blanks.
71 # Bug fix: scan.
72 #
73 # Revision 1.30  1995/06/06  11:35:41  adam
74 # Work on scan. Display of old sets.
75 #
76 # Revision 1.29  1995/06/05  14:11:18  adam
77 # Bug fix in present-more.
78 #
79 # Revision 1.28  1995/06/02  14:52:13  adam
80 # Minor changes really.
81 #
82 # Revision 1.27  1995/06/02  14:29:42  adam
83 # Work on scan interface - up/down buttons.
84 #
85 # Revision 1.26  1995/06/01  16:36:46  adam
86 # About buttons. Minor bug fixes.
87 #
88 # Revision 1.25  1995/05/31  13:09:57  adam
89 # Client searches/presents may be interrupted.
90 # New moving book-logo.
91 #
92 # Revision 1.24  1995/05/31  08:36:24  adam
93 # Bug fix in client.tcl: didn't save options on clientrc.tcl.
94 # New method: referenceId. More work on scan.
95 #
96 # Revision 1.23  1995/05/29  10:33:41  adam
97 # README and rename of startup script.
98 #
99 # Revision 1.22  1995/05/26  11:44:09  adam
100 # Bugs fixed. More work on MARC utilities and queries. Test
101 # client is up-to-date again.
102 #
103 # Revision 1.21  1995/05/11  15:34:46  adam
104 # Scan request changed a bit. This version works with RLG.
105 #
106 # Revision 1.20  1995/04/21  16:31:57  adam
107 # New radiobutton: protocol (z39v2/SR).
108 #
109 # Revision 1.19  1995/04/18  16:11:50  adam
110 # First version of graphical Scan. Some work on query-by-form.
111 #
112 # Revision 1.18  1995/04/10  10:50:22  adam
113 # Result-set name defaults to suffix of ir-set name.
114 # Started working on scan. Not finished at this point.
115 #
116 # Revision 1.17  1995/03/31  09:34:57  adam
117 # Search-button disabled when there is no connection.
118 #
119 # Revision 1.16  1995/03/31  08:56:36  adam
120 # New button "Search".
121 #
122 # Revision 1.15  1995/03/28  12:45:22  adam
123 # New ir method failback: called on disconnect/protocol error.
124 # New ir set/get method: protocol: SR / Z3950.
125 # Simple popup and disconnect when failback is invoked.
126 #
127 # Revision 1.14  1995/03/22  16:07:55  adam
128 # Minor changes.
129 #
130 # Revision 1.13  1995/03/21  17:27:26  adam
131 # Short-hand keys in setup.
132 #
133 # Revision 1.12  1995/03/21  13:41:03  adam
134 # Comstack cs_create not used too often. Non-blocking connect.
135 #
136 # Revision 1.11  1995/03/21  10:39:06  adam
137 # Diagnostic error message displayed with tkerror.
138 #
139 # Revision 1.10  1995/03/20  15:24:06  adam
140 # Diagnostic records saved on searchResponse.
141 #
142 # Revision 1.9  1995/03/17  18:26:16  adam
143 # Non-blocking i/o used now. Database names popup as cascade items.
144 #
145 # Revision 1.8  1995/03/17  15:45:00  adam
146 # Improved target/database setup.
147 #
148 # Revision 1.7  1995/03/16  17:54:03  adam
149 # Minor changes really.
150 #
151 # Revision 1.6  1995/03/15  19:10:20  adam
152 # Database setup in protocol-setup (rather target setup).
153 #
154 # Revision 1.5  1995/03/15  13:59:23  adam
155 # Minor changes.
156 #
157 # Revision 1.4  1995/03/14  17:32:29  adam
158 # Presentation of full Marc record in popup window.
159 #
160 # Revision 1.3  1995/03/12  19:31:52  adam
161 # Pattern matching implemented when retrieving MARC records. More
162 # diagnostic functions.
163 #
164 # Revision 1.2  1995/03/10  18:00:15  adam
165 # Actual presentation in line-by-line format. RPN query support.
166 #
167 # Revision 1.1  1995/03/09  16:15:07  adam
168 # First presentRequest attempts. Hot-target list.
169 #
170 #
171 set hotTargets {}
172 set hotInfo {}
173 set busy 0
174
175 set libDir ""
176
177 set profile(Default) {{} {} {210} {} 16384 8192 tcpip {} 1 {} {} Z39}
178 set hostid Default
179 set settingsChanged 0
180 set setNo 0
181 set lastSetNo 0
182 set cancelFlag 0
183 set searchEnable 0
184 set scanEnable 0
185 set fullMarcSeq 0
186 set displayFormat 1
187 set popupMarcdf 0
188 set textWrap word
189 set delayRequest {}
190
191 set queryTypes {Simple}
192 set queryButtons { { {I 0} {I 1} {I 2} } }
193 set queryInfo { { {Title {1=4 4=1}} {Author {1=1}} \
194         {Subject {1=21}} {Any {1=1016}} } }
195 wm minsize . 0 0
196
197 set setOffset 0
198 set setMax 0
199
200 proc read-formats {} {
201     global displayFormats
202     set formats [glob -nocomplain formats/*.tcl]
203     foreach f $formats {
204         source $f
205         set l [expr [string length $f] - 5]
206         lappend displayFormats [string range $f 8 $l]
207     }
208 }
209
210 proc set-wrap {m} {
211     global textWrap
212
213     set textWrap $m
214     .data.record configure -wrap $m
215 }
216
217 proc dputs {m} {
218     puts $m
219 }
220
221 proc set-display-format {f} {
222     global displayFormat
223     global setNo
224     global busy
225
226     set displayFormat $f
227     if {$setNo == 0} {
228         return
229     }
230     if {!$busy} {
231         .bot.a.status configure -text "Reformatting"
232     }
233     update idletasks
234     add-title-lines 0 10000 1
235     if {!$busy} {
236         .bot.a.status configure -text "Ready"
237     }
238 }
239
240 proc initBindings {} {
241     set w Text
242     bind $w <1> {}
243     bind $w <Double-1> {}
244     bind $w <Triple-1> {}
245     bind $w <B1-Motion> {}
246     bind $w <Shift-1> {}
247     bind $w <Shift-B1-Motion> {}
248     bind $w <2> {}
249     bind $w <B2-Motion> {}
250     bind $w <Any-KeyPress> {}
251     bind $w <Return> {}
252     bind $w <BackSpace> {}
253     bind $w <Delete> {}
254     bind $w <Control-h> {}
255     bind $w <Control-d> {}
256     bind $w <Control-v> {}
257
258     set w Listbox
259     bind $w <B1-Motion> {}
260     bind $w <Shift-B1-Motion> {}
261
262     set w Entry
263 }
264
265 proc post-menu {wbutton wmenu} {
266     $wmenu activate none
267     focus $wmenu
268     $wmenu post [winfo rootx $wbutton] \
269             [expr [winfo rooty $wbutton]+[winfo height $wbutton]]
270
271 }
272
273 proc destroyGW {w} {
274     global windowGeometry
275     set windowGeometry($w) [wm geometry $w]
276 }    
277 proc toplevelG {w} {
278     global windowGeometry
279
280     toplevel $w
281     if {[info exists windowGeometry($w)]} {
282         set g $windowGeometry($w)
283         if {$g != ""} {
284             wm geometry $w $g
285         }
286     }
287     bind $w <Destroy> [list destroyGW $w]
288 }
289
290 if {[file readable "clientrc.tcl"]} {
291     source "clientrc.tcl"
292 }
293
294 if {[file readable "clientg.tcl"]} {
295     source "clientg.tcl"
296 }
297
298 set queryButtonsFind [lindex $queryButtons 0]
299 set queryInfoFind [lindex $queryInfo 0]
300
301 proc top-down-window {w} {
302     frame $w.top -relief raised -border 1
303     frame $w.bot -relief raised -border 1
304     
305     pack  $w.top -side top -fill both -expand yes
306     pack  $w.bot -fill both
307 }
308
309 proc top-down-ok-cancel {w ok-action g} {
310     frame $w.bot.left -relief sunken -border 1
311     pack $w.bot.left -side left -expand yes -ipadx 2 -ipady 2 -padx 5 -pady 5
312     button $w.bot.left.ok -width 6 -text {Ok} \
313             -command ${ok-action}
314     pack $w.bot.left.ok -expand yes -ipadx 2 -ipady 2 -padx 3 -pady 3
315     button $w.bot.cancel -width 6 -text {Cancel} \
316             -command [list destroy $w]
317     pack $w.bot.cancel -side left -expand yes    
318
319     if {$g} {
320         grab $w
321         tkwait window $w
322     }
323 }
324
325 proc bottom-buttons {w buttonList g} {
326     set i 0
327     set l [llength $buttonList]
328
329     frame $w.bot.$i -relief sunken -border 1
330     pack $w.bot.$i -side left -expand yes -padx 5 -pady 5
331     button $w.bot.$i.ok -text [lindex $buttonList $i] \
332             -command [lindex $buttonList [expr $i+1]]
333     pack $w.bot.$i.ok -expand yes -ipadx 3 -ipady 2 -padx 3 -pady 3 -side left
334
335     incr i 2
336     while {$i < $l} {
337         button $w.bot.$i -text [lindex $buttonList $i] \
338                 -command [lindex $buttonList [expr $i+1]]
339         pack $w.bot.$i -expand yes -ipadx 2 -ipady 2 -padx 3 -pady 3 -side left
340         incr i 2
341     }
342     if {$g} {
343         # Grab ...
344         grab $w
345         tkwait window $w
346     }
347 }
348
349 proc cancel-operation {} {
350     global cancelFlag
351     global busy
352     global delayRequest
353
354     set cancelFlag 1
355     set delayRequest {}
356     if {$busy} {
357         show-status Cancel 0 1
358     }
359 }
360
361 proc show-target {target base} {
362     global profile
363
364     if {$target == ""} {
365         .bot.a.target configure -text ""
366         return
367     }
368     if {$base == ""} {
369          .bot.a.target configure -text "$target"
370     } else {
371          .bot.a.target configure -text "$target - $base"
372     }
373 }
374
375 proc show-logo {v1} {
376     global busy
377     if {$busy != 0} {
378         incr v1
379         if {$v1==10} {
380             set v1 1
381         }
382         .bot.logo configure -bitmap @book${v1}
383         after 140 [list show-logo $v1]
384         return
385     }
386     while {1} {
387         .bot.logo configure -bitmap @book1
388         tkwait variable busy
389         if {$busy} {
390             show-logo 1
391             return
392         }
393     }
394 }
395         
396 proc show-status {status b sb} {
397     global busy
398     global searchEnable
399     global scanEnable
400     global setOffset
401     global setMax
402     global setNo
403
404     .bot.a.status configure -text "$status"
405     if {$b == 1} {
406         if {$busy == 0} {set busy 1}
407     } else {
408         set busy 0
409     }
410     if {$sb == {}} {
411         return
412     }
413     if {$sb} {
414         .top.service configure -state normal
415         .mid.search configure -state normal
416         if {$scanEnable} {
417             .mid.scan configure -state normal
418         }
419         if {$setNo == 0} {
420             .top.service.m disable 1
421         } elseif {$setOffset > 0 && $setOffset <= [z39.$setNo resultCount]} {
422             .top.service.m enable 1
423             .mid.present configure -state normal
424         } else {
425             .top.service.m disable 1
426         }
427         if {[winfo exists .scan-window]} {
428             .scan-window.bot.2 configure -state normal
429             .scan-window.bot.4 configure -state normal
430         }
431         set searchEnable 1
432     } else {
433         .top.service configure -state disabled
434         .mid.search configure -state disabled
435         .mid.scan configure -state disabled
436         .mid.present configure -state disabled
437
438         if {[winfo exists .scan-window]} {
439             .scan-window.bot.2 configure -state disabled
440             .scan-window.bot.4 configure -state disabled
441         }
442         set searchEnable 0
443     }
444 }
445
446 proc show-message {msg} {
447     .bot.a.message configure -text "$msg"
448 }
449
450 proc insertWithTags {w text args} {
451     set start [$w index insert]
452     $w insert insert $text
453     foreach tag [$w tag names $start] {
454         $w tag remove $tag $start insert
455     }
456     foreach i $args {
457         $w tag add $i $start insert
458     }
459 }
460
461 proc popup-license {} {
462     set w .popup-licence
463     toplevel $w
464
465     wm title $w "License" 
466
467     wm minsize $w 0 0
468
469     top-down-window $w
470
471     text $w.top.t -width 80 -height 10 -wrap word \
472         -yscrollcommand [list $w.top.s set]
473     scrollbar $w.top.s -command [list $w.top.t yview]
474     
475     pack $w.top.s -side right -fill y
476     pack $w.top.t -expand yes -fill both
477
478     set f [open "LICENSE" r]
479     while {[gets $f buf] != -1} {
480         $w.top.t insert end $buf
481         $w.top.t insert end "\n"
482     } 
483     close $f
484     bottom-buttons $w [list {Close} [list destroy $w]] 1
485 }
486
487 proc about-target {} {
488     set w .about-target-w
489     global hostid
490
491     toplevel $w
492
493     wm title $w "About target"
494     top-down-window $w
495
496     frame $w.top.a -relief ridge -border 2
497     frame $w.top.p -relief ridge -border 2
498
499     pack $w.top.a $w.top.p -side top -fill x
500     
501     label $w.top.a.about -text "About"
502     label $w.top.a.irtcl -text $hostid \
503             -font -Adobe-Helvetica-Bold-R-Normal-*-240-*
504     pack $w.top.a.about $w.top.a.irtcl -side top
505
506     set i [z39 targetImplementationName]
507     label $w.top.p.in -text "Implementation name: $i"
508     set i [z39 targetImplementationId]
509     label $w.top.p.ii -text "Implementation id: $i"
510     set i [z39 targetImplementationVersion]
511     label $w.top.p.iv -text "Implementation version: $i"
512     set i [z39 options]
513     label $w.top.p.op -text "Protocol options: $i"
514
515     pack $w.top.p.in $w.top.p.ii $w.top.p.iv $w.top.p.op -side top -anchor nw
516
517     bottom-buttons $w [list {Close} [list destroy $w]] 1
518 }
519
520 proc about-origin-logo {n} {
521     set w .about-origin-w
522     if {![winfo exists $w]} {
523         return
524     }
525     incr n
526     if {$n==10} {
527         set n 1
528     }
529     $w.top.a.logo configure -bitmap @book$n
530     after 140 [list about-origin-logo $n]
531 }
532
533 proc about-origin {} {
534     set w .about-origin-w
535     
536     if {[winfo exists $w]} {
537         destroy $w
538     }
539     toplevel $w
540
541     wm title $w "About IrTcl"
542     place-force $w .
543     top-down-window $w
544
545     frame $w.top.a -relief ridge -border 2
546     frame $w.top.p -relief ridge -border 2
547
548     pack $w.top.a $w.top.p -side top -fill x
549     
550     label $w.top.a.irtcl -text "IrTcl" \
551             -font -Adobe-Helvetica-Bold-R-Normal-*-240-*
552     label $w.top.a.logo -bitmap @book1 
553     pack $w.top.a.irtcl $w.top.a.logo -side left -expand yes
554
555     set i [z39 implementationName]
556     label $w.top.p.in -text "Implementation name: $i"
557     set i [z39 implementationId]
558     label $w.top.p.ii -text "Implementation id: $i"
559     set i [z39 implementationVersion]
560     label $w.top.p.iv -text "Implementation version: $i"
561
562     pack $w.top.p.in $w.top.p.ii $w.top.p.iv -side top -anchor nw
563
564     about-origin-logo 1
565     bottom-buttons $w [list {Close} [list destroy $w] \
566                             {License} [list popup-license]] 0
567 }
568
569 proc popup-marc {sno no b df} {
570     global fullMarcSeq
571     global displayFormats
572     global popupMarcdf
573
574     if {[z39.$sno type $no] != "DB"} {
575         return
576     }
577     if {$b} {
578         set w .full-marc-$fullMarcSeq
579         incr fullMarcSeq
580         set df $popupMarcdf
581     } else {
582         set w .full-marc
583         set df $popupMarcdf
584     }
585     if {[winfo exists $w]} {
586         set new 0
587     } else {
588
589         toplevelG $w
590
591         wm minsize $w 0 0
592         
593         frame $w.top -relief raised -border 1
594         frame $w.bot -relief raised -border 1
595
596         pack  $w.top -side top -fill both -expand yes
597         pack  $w.bot -fill both
598
599         text $w.top.record -width 60 -height 5 -wrap word \
600                 -yscrollcommand [list $w.top.s set]
601         scrollbar $w.top.s -command [list $w.top.record yview]
602
603         if {[tk colormodel .] == "color"} {
604             $w.top.record tag configure marc-tag -foreground blue
605             $w.top.record tag configure marc-id -foreground red
606         } else {
607             $w.top.record tag configure marc-tag -foreground black
608             $w.top.record tag configure marc-id -foreground black
609         }
610         $w.top.record tag configure marc-data -foreground black
611         set new 1
612     }
613     $w.top.record delete 0.0 end
614     set recordType [z39.$sno recordType $no]
615     wm title $w "$recordType record #$no"
616
617     set ffunc [lindex $displayFormats $df]
618     set ffunc "display-$ffunc"
619
620     $ffunc $sno $no $w.top.record 0
621
622     if {$new} {
623         bind $w.top.record <Return> {destroy .full-marc}
624         
625         pack $w.top.s -side right -fill y
626         pack $w.top.record -expand yes -fill both
627         
628         if {$b} {
629             bottom-buttons $w [list \
630                 {Close} [list destroy $w]] 0
631         } else {
632             bottom-buttons $w [list \
633                     {Close} [list destroy $w] \
634                     {Duplicate} [list popup-marc $sno $no 1 0]] 0
635             menubutton $w.bot.formats -text "Format" -menu $w.bot.formats.m
636             menu $w.bot.formats.m
637             set i 0
638             foreach f $displayFormats {
639                 $w.bot.formats.m add radiobutton -label $f \
640                         -variable popupMarcdf -value $i \
641                         -command [list display-$f $sno $no $w.top.record 0]
642                 incr i
643             }
644             pack $w.bot.formats -expand yes -ipadx 2 -ipady 2 \
645                     -padx 3 -pady 3 -side left
646         }
647     } else {
648         set i 0
649         foreach f $displayFormats {
650             $w.bot.formats.m entryconfigure $i \
651                     -command [list display-$f $sno $no $w.top.record 0]
652             incr i
653         }
654     }
655 }
656
657 proc update-target-hotlist {target base} {
658     global hotTargets
659
660     set len [llength $hotTargets]
661     if {$len > 0} {
662         .top.target.m delete 6 [expr 6+[llength $hotTargets]]
663     }
664     set i 0
665     foreach e $hotTargets {
666         if {$target == [lindex $e 0] && $base == [lindex $e 1]} {
667             set hotTargets [lreplace $hotTargets $i $i]
668             break
669         }
670         incr i    
671     }
672     set hotTargets [linsert $hotTargets 0 [list $target $base]]
673     set-target-hotlist    
674
675
676 proc set-target-hotlist {} {
677     global hotTargets
678     
679     set i 1
680     foreach e $hotTargets {
681         set target [lindex $e 0]
682         set base [lindex $e 1]
683         if {$base == ""} {
684             .top.target.m add command -label "$i $target" -command \
685                 [list reopen-target $target {}]
686         } else {
687             .top.target.m add command -label "$i $target - $base" -command \
688                 [list reopen-target $target $base]
689         }
690         incr i
691         if {$i > 8} {
692              break
693         }
694     }
695 }
696
697 proc reopen-target {target base} {
698     close-target
699     open-target $target $base
700     update-target-hotlist $target $base
701 }
702
703 proc define-target-action {} {
704     global profile
705     
706     set target [.target-define.top.target.entry get]
707     if {$target == ""} {
708         return
709     }
710     foreach n [array names profile] {
711         if {$n == $target} {
712             protocol-setup $n
713             return
714         }
715     }
716     set seq [lindex $profile(Default) 12]
717     dputs "seq=${seq}"
718     set profile($target) $profile(Default)
719     set profile(Default) [lreplace $profile(Default) 12 12 [incr seq]]
720
721     protocol-setup $target
722     destroy .target-define
723 }
724
725 proc fail-response {target} {
726     set c [lindex [z39 failInfo] 0]
727     set m [lindex [z39 failInfo] 1]
728     close-target
729     tkerror "$m ($c)"
730 }
731
732 proc connect-response {target base} {
733     dputs "connect-response"
734     show-target $target $base
735     init-request
736 }
737
738 proc open-target {target base} {
739     global profile
740     global hostid
741
742     z39 disconnect
743     z39 comstack [lindex $profile($target) 6]
744     z39 protocol [lindex $profile($target) 11]
745     z39 idAuthentication [lindex $profile($target) 3]
746     z39 maximumRecordSize [lindex $profile($target) 4]
747     z39 preferredMessageSize [lindex $profile($target) 5]
748     dputs "maximumRecordSize="
749     dputs [z39 maximumRecordSize]
750     dputs "preferredMessageSize="
751     dputs [z39 preferredMessageSize]
752     show-status {Connecting} 1 0
753     if {$base == ""} {
754         z39 databaseNames [lindex [lindex $profile($target) 7] 0]
755     } else {
756         z39 databaseNames $base
757     }
758     z39 failback [list fail-response $target]
759     z39 callback [list connect-response $target $base]
760     update idletasks
761     set err [catch {
762         z39 connect [lindex $profile($target) 1]:[lindex $profile($target) 2]
763         } errorMessage]
764     if {$err} {
765         tkerror $errorMessage
766         show-status Ready 0 {}
767         return
768     }
769 #    z39 options search present scan namedResultSets triggerResourceCtrl
770     set hostid $target
771     .top.target.m disable 0
772     .top.target.m enable 1
773     .top.target.m enable 2
774 }
775
776 proc close-target {} {
777     global hostid
778     global cancelFlag
779     global setNo
780
781     set cancelFlag 0
782     set setNo 0
783     .bot.a.set configure -text ""
784     set hostid Default
785     z39 disconnect
786     show-target {} {}
787     show-status {Not connected} 0 0
788     init-title-lines
789     show-message {}
790     .top.target.m disable 1
791     .top.target.m disable 2
792     .top.target.m enable 0
793 }
794
795 proc load-set-action {} {
796     global setNo
797
798     incr setNo
799     ir-set z39.$setNo z39
800
801     set fname [.load-set.top.filename.entry get]
802     destroy .load-set
803     if {$fname != ""} {
804         show-status {Loading} 1 {}
805         update
806         z39.$setNo loadFile $fname
807
808         set no [z39.$setNo numberOfRecordsReturned]
809         add-title-lines $setNo $no 1
810     }
811     set l [format "%-4d %7d" $setNo $no]
812     .top.rset.m add command -label $l \
813             -command [list add-title-lines $setNo 10000 1]
814     show-status {Ready} 0 {}
815 }
816
817 proc load-set {} {
818     set w .load-set
819
820     set oldFocus [focus]
821     toplevel $w
822
823     place-force $w .
824     top-down-window $w
825
826     frame $w.top.filename
827     pack $w.top.filename -side top -anchor e -pady 2
828     
829     entry-fields $w.top {filename} \
830             {{Filename:}} \
831             {load-set-action} {destroy .load-set}
832     
833     top-down-ok-cancel $w {load-set-action} 1
834     focus $oldFocus
835 }
836
837 proc init-request {} {
838     global setNo
839     global cancelFlag
840
841     if {$cancelFlag} {
842         close-target
843         return
844     }
845     z39 callback {init-response}
846     show-status {Initializing} 1 {}
847     set err [catch {z39 init} errorMessage]
848     if {$err} {
849         tkerror $errorMessage
850         show-status Ready 0 {}
851     }
852 }
853
854 proc init-response {} {
855     global cancelFlag
856     global scanEnable
857
858     if {$cancelFlag} {
859         close-target
860         return
861     }
862     if {![z39 initResult]} {
863         show-status {Ready} 0 1
864         set u [z39 userInformationField]
865         close-target
866         tkerror "Connection rejected by target: $u"
867     } else {
868         if {[lsearch [z39 options] scan] >= 0} {
869             set scanEnable 1
870         } else {
871             set scanEnable 0
872         }
873         show-status {Ready} 0 1
874     }
875 }
876
877 proc search-request {} {
878     global setNo
879     global profile
880     global hostid
881     global busy
882     global cancelFlag
883     global searchEnable
884     global delayRequest
885
886     set target $hostid
887
888     dputs "search-request"
889     if {$searchEnable < 0} {
890         dputs "searchEnable == 0"
891         return
892     }
893     if {$cancelFlag} {
894         dputs "cancelFlag"
895         show-status {Searching} 1 0
896         set delayRequest search-request
897         return
898     }
899     set delayRequest {} 
900
901     set query [index-query]
902     if {$query==""} {
903         return
904     }
905     incr setNo
906     ir-set z39.$setNo z39
907
908     if {[lindex $profile($target) 10] == 1} {
909         z39.$setNo setName $setNo
910         dputs "setName=${setNo}"
911     } else {
912         z39.$setNo setName Default
913         dputs "setName=Default"
914     }
915     if {[lindex $profile($target) 8] == 1} {
916         z39.$setNo queryType rpn
917     }
918     if {[lindex $profile($target) 9] == 1} {
919         z39.$setNo queryType ccl
920     }
921     z39 callback {search-response}
922     z39.$setNo search $query
923     show-status {Searching} 1 0
924 }
925
926 proc scan-copy {y entry} {
927     set w .scan-window
928     set no [$w.top.list nearest $y]
929     dputs "no=$no"
930     .lines.$entry.e delete 0 end
931     .lines.$entry.e insert 0 [string range [$w.top.list get $no] 8 end]
932 }
933
934 proc scan-request {} {
935     set w .scan-window
936
937     global profile
938     global hostid
939     global scanView
940     global scanTerm
941     global curIndexEntry
942     global queryButtonsFind
943     global queryInfoFind
944
945     set target $hostid
946     set scanView 0
947     set scanTerm {}
948
949     set b [lindex $queryButtonsFind $curIndexEntry]
950     set attr {}
951     foreach a [lrange [lindex $queryInfoFind [lindex $b 1]] 1 end] {
952         set attr "@attr $a $attr"
953     }
954     set title [lindex [lindex $queryInfoFind [lindex $b 1]] 0]
955     ir-scan z39.scan z39
956
957     if {![winfo exists $w]} {
958         toplevelG $w
959         
960         wm minsize $w 0 0
961
962         top-down-window $w
963
964         entry $w.top.entry -relief sunken 
965         pack $w.top.entry -fill x -padx 4 -pady 2
966         bind $w.top.entry <KeyRelease> [list scan-term-h $attr]
967         if {1} {
968             listbox $w.top.list -yscrollcommand [list $w.top.scroll set] \
969                     -font fixed 
970             scrollbar $w.top.scroll -orient vertical -border 1
971             pack $w.top.list -side left -fill both -expand yes
972             pack $w.top.scroll -side right -fill y
973             $w.top.scroll config -command [list $w.top.list yview]
974         } else {
975             listbox $w.top.list -font fixed -geometry 60x14
976             pack $w.top.list -side left -fill both -expand yes
977         }
978         
979         bottom-buttons $w [list {Close} [list destroy $w] \
980                 {Up} [list scan-up $attr] \
981                 {Down} [list scan-down $attr]] 0
982         bind $w.top.list <Up> [list scan-up $attr]
983         bind $w.top.list <Down> [list scan-down $attr]
984     }
985     bind $w.top.list <Double-Button-1> [list scan-copy %y $curIndexEntry]
986     wm title $w "Scan $title"
987         
988     z39 callback [list scan-response $attr 0 35]
989     z39.scan numberOfTermsRequested 5
990     z39.scan preferredPositionInResponse 1
991     z39.scan scan "${attr} 0"
992     
993     show-status {Scanning} 1 0
994 }
995
996 proc scan-term-h {attr} {
997     global busy
998     global scanTerm
999
1000     if {$busy} {
1001         return
1002     }
1003     set w .scan-window
1004     set nScanTerm [$w.top.entry get]
1005     if {$nScanTerm == $scanTerm} {
1006         return
1007     }
1008     set scanTerm $nScanTerm
1009     z39 callback [list scan-response $attr 0 35]
1010     z39.scan numberOfTermsRequested 5
1011     z39.scan preferredPositionInResponse 1
1012     dputs "${attr} \{${scanTerm}\}"
1013     if {$scanTerm == ""} {
1014         z39.scan scan "${attr} 0"
1015     } else {
1016         z39.scan scan "${attr} \{${scanTerm}\}"
1017     }
1018     show-status {Scanning} 1 0
1019 }
1020
1021 proc scan-response {attr start toget} {
1022     global cancelFlag
1023     global scanTerm
1024     global scanView
1025
1026     set w .scan-window
1027     dputs "In scan-response"
1028     set m [z39.scan numberOfEntriesReturned]
1029     dputs $m
1030     dputs attr=$attr
1031     dputs start=$start
1032     dputs toget=$toget
1033
1034     if {![winfo exists .scan-window]} {
1035         show-status {Ready} 0 1
1036         set cancelFlag 0
1037         return
1038     }
1039     set nScanTerm [$w.top.entry get]
1040     if {$nScanTerm != $scanTerm} {
1041         z39 callback [list scan-response $attr 0 35]
1042         z39.scan numberOfTermsRequested 5
1043         z39.scan preferredPositionInResponse 1
1044         set scanTerm $nScanTerm
1045         dputs "${attr} \{${scanTerm}\}"
1046         if {$scanTerm == ""} {
1047             z39.scan scan "${attr} 0"
1048         } else {
1049             z39.scan scan "${attr} \{${scanTerm}\}"
1050         }
1051         show-status {Scanning} 1 0
1052         return
1053     }
1054     set status [z39.scan scanStatus]
1055     if {$status == 6} {
1056         tkerror "Scan fail"
1057         show-status {Ready} 0 1
1058         set cancelFlag 0
1059         return
1060     }
1061     if {$toget < 0} {
1062         for {set i 0} {$i < $m} {incr i} {
1063             set term [lindex [z39.scan scanLine $i] 1]
1064             set nostr [format " %-6d" [lindex [z39.scan scanLine $i] 2]]
1065             $w.top.list insert $i "$nostr $term"
1066         }
1067         incr scanView $m
1068         $w.top.list yview $scanView
1069     } else {
1070         $w.top.list delete $start end
1071         for {set i 0} {$i < $m} {incr i} {
1072             set term [lindex [z39.scan scanLine $i] 1]
1073             set nostr [format " %-6d" [lindex [z39.scan scanLine $i] 2]]
1074             $w.top.list insert end "$nostr $term"
1075         }
1076     }
1077     if {$cancelFlag} {
1078         show-status {Ready} 0 1
1079         set cancelFlag 0
1080         return
1081     }
1082     if {$toget > 0 && $m > 1 && $m < $toget} {
1083         set ntoget [expr $toget - $m + 1]
1084         dputs ntoget=$ntoget
1085         z39 callback [list scan-response $attr [expr $start + $m - 1] $ntoget]
1086         set q $term
1087         dputs "down continue: $q"
1088         if {$ntoget > 10} {
1089             z39.scan numberOfTermsRequested 10
1090         } else {
1091             z39.scan numberOfTermsRequested $ntoget
1092         }
1093         z39.scan preferredPositionInResponse 1
1094         dputs "${attr} \{$q\}"
1095         z39.scan scan "${attr} \{$q\}"
1096         return
1097     }
1098     if {$toget < 0 && $m > 1 && $m < [expr - $toget]} {
1099         set ntoget [expr - $toget - $m]
1100         dputs ntoget=$ntoget
1101         z39 callback [list scan-response $attr 0 -$ntoget]
1102         set q [string range [$w.top.list get 0] 8 end]
1103         dputs "up continue: $q"
1104         if {$ntoget > 10} {
1105             z39.scan numberOfTermsRequested 10
1106             z39.scan preferredPositionInResponse 11
1107         } else {
1108             z39.scan numberOfTermsRequested $ntoget
1109             z39.scan preferredPositionInResponse [incr ntoget]
1110         }
1111         dputs "${attr} \{$q\}"
1112         z39.scan scan "${attr} \{$q\}"
1113         return
1114     }
1115     show-status {Ready} 0 1
1116 }
1117
1118 proc scan-down {attr} {
1119     global scanView
1120
1121     set w .scan-window
1122     set scanView [expr $scanView + 5]
1123     set s [$w.top.list size]
1124     if {$scanView > $s} {
1125         z39 callback [list scan-response $attr [expr $s - 1] 25]
1126         set q [string range [$w.top.list get [expr $s - 1]] 8 end]
1127         dputs "down: $q"
1128         z39.scan numberOfTermsRequested 10
1129         z39.scan preferredPositionInResponse 1
1130         show-status {Scanning} 1 0
1131         dputs "${attr} \{$q\}"
1132         z39.scan scan "${attr} \{$q\}"
1133         return
1134     }
1135     $w.top.list yview $scanView
1136 }
1137
1138 proc scan-up {attr} {
1139     global scanView
1140
1141     set w .scan-window
1142     set scanView [expr $scanView - 5]
1143     if {$scanView < 0} {
1144         z39 callback [list scan-response $attr 0 -25]
1145         set q [string range [$w.top.list get 0] 8 end]
1146         dputs "up: $q"
1147         z39.scan numberOfTermsRequested 10
1148         z39.scan preferredPositionInResponse 11
1149         show-status {Scanning} 1 0
1150         z39.scan scan "${attr} \{$q\}"
1151         return
1152     }
1153     $w.top.list yview $scanView
1154 }
1155
1156 proc search-response {} {
1157     global setNo
1158     global setOffset
1159     global setMax
1160     global cancelFlag
1161     global busy
1162     global delayRequest
1163
1164     dputs "In search-response"
1165     if {$cancelFlag} {
1166         dputs "Handling cancel"
1167         set cancelFlag 0
1168         if {$delayRequest != ""} {
1169             $delayRequest
1170         }
1171         return
1172     }
1173     set delayRequest {}
1174     init-title-lines
1175     set setMax [z39.$setNo resultCount]
1176     show-message "${setMax} hits"
1177     set l [format "%-4d %7d" $setNo $setMax]
1178     .top.rset.m add command -label $l \
1179             -command [list add-title-lines $setNo 10000 1]
1180     if {$setMax <= 0} {
1181         show-status {Ready} 0 1
1182         set status [z39.$setNo responseStatus]
1183         if {[lindex $status 0] == "NSD"} {
1184             set code [lindex $status 1]
1185             set msg [lindex $status 2]
1186             set addinfo [lindex $status 3]
1187             tkerror "NSD$code: $msg: $addinfo"
1188         }
1189         return
1190     }
1191     if {$setMax > 20} {
1192         set setMax 20
1193     }
1194     set setOffset 1
1195     show-status {Ready} 0 1
1196     z39 callback {present-response}
1197     z39.$setNo present $setOffset 1
1198     show-status {Retrieving} 1 0
1199 }
1200
1201 proc present-more {number} {
1202     global setNo
1203     global setOffset
1204     global setMax
1205     global busy
1206     global cancelFlag
1207     global delayRequest
1208
1209     dputs "present-more"
1210     if {$cancelFlag} {
1211         show-status {Retrieving} 1 0
1212         set delayRequest [list present-request $number]
1213         return
1214     }
1215     set delayRequest {}
1216
1217     if {$setNo == 0} {
1218         dputs "setNo=$setNo"
1219         return
1220     }
1221     set max [z39.$setNo resultCount]
1222     if {$max <= $setOffset} {
1223         dputs "max=$max"
1224         dputs "setOffset=$setOffset"
1225         return
1226     }
1227     if {$number == ""} {
1228         set setMax $max
1229     } else {
1230         incr setMax $number
1231         if {$setMax > $max} {
1232             set setMax $max
1233         }
1234     }
1235     z39 callback {present-response}
1236
1237     set toGet [expr $setMax - $setOffset + 1]
1238     if {$toGet <= 0} {
1239         return
1240     }
1241     if {$toGet > 3} {
1242         set toGet 3
1243     } 
1244     z39.$setNo present $setOffset $toGet
1245     show-status {Retrieving} 1 0
1246 }
1247
1248 proc init-title-lines {} {
1249     .data.record delete 0.0 end
1250 }
1251
1252 proc title-press {y setno} {
1253     show-full-marc $setno [expr 1 + [.data.list nearest $y]] 0
1254 }
1255
1256 proc add-title-lines {setno no offset} {
1257     global displayFormats
1258     global displayFormat
1259     global lastSetNo
1260
1261     if {$setno == 0} {
1262         set setno $lastSetNo
1263     } else {
1264         set lastSetNo $setno
1265     }
1266     if {$offset == 1} {
1267         .bot.a.set configure -text $setno
1268         .data.record delete 0.0 end
1269     }
1270     set ffunc [lindex $displayFormats $displayFormat]
1271     set ffunc "display-$ffunc"
1272     for {set i 0} {$i < $no} {incr i} {
1273         set o [expr $i + $offset]
1274         set type [z39.$setno type $o]
1275         if {$type == ""} {
1276             break
1277         }
1278         .data.record tag bind r$o <Any-Enter> {}
1279         .data.record tag bind r$o <Any-Leave> {}
1280         set insert0 [.data.record index insert]
1281         $ffunc $setno $o .data.record 1
1282         .data.record tag add r$o $insert0 insert
1283         .data.record tag bind r$o <1> \
1284                 [list popup-marc $setno $o 0 0]
1285         update idletasks
1286     }
1287 }
1288
1289 proc present-response {} {
1290     global setNo
1291     global setOffset
1292     global setMax
1293     global cancelFlag
1294     global delayRequest
1295
1296     if {$cancelFlag} {
1297         dputs "Handling cancel"
1298         set cancelFlag 0
1299         if {$delayRequest != ""} {
1300             $delayRequest
1301         }
1302         return
1303     }
1304     dputs "In present-response"
1305     set no [z39.$setNo numberOfRecordsReturned]
1306     dputs "Returned $no records, setOffset $setOffset"
1307     add-title-lines $setNo $no $setOffset
1308     set setOffset [expr $setOffset + $no]
1309     set status [z39.$setNo responseStatus]
1310     if {[lindex $status 0] == "NSD"} {
1311         show-status {Ready} 0 1
1312         set code [lindex $status 1]
1313         set msg [lindex $status 2]
1314         set addinfo [lindex $status 3]
1315         tkerror "NSD$code: $msg: $addinfo"
1316         return
1317     }
1318     if {$no > 0 && $setOffset <= $setMax} {
1319         dputs "present-request from ${setOffset}"
1320         set toGet [expr $setMax - $setOffset + 1]
1321         if {$toGet > 3} {
1322             set toGet 3
1323         }
1324         z39.$setNo present $setOffset $toGet
1325     } else {
1326         show-status {Ready} 0 1
1327     }
1328 }
1329
1330 proc left-cursor {w} {
1331     set i [$w index insert]
1332     if {$i > 0} {
1333         incr i -1
1334         $w icursor $i
1335     }
1336 }
1337
1338 proc right-cursor {w} {
1339     set i [$w index insert]
1340     incr i
1341     $w icursor $i
1342 }
1343
1344 proc bind-fields {list returnAction escapeAction} {
1345     set max [expr [llength $list]-1]
1346     for {set i 0} {$i < $max} {incr i} {
1347         bind [lindex $list $i] <Return> $returnAction
1348         bind [lindex $list $i] <Escape> $escapeAction
1349         bind [lindex $list $i] <Tab> [list focus [lindex $list [expr $i+1]]]
1350         bind [lindex $list $i] <Left> [list left-cursor [lindex $list $i]]
1351         bind [lindex $list $i] <Right> [list right-cursor [lindex $list $i]]
1352     }
1353     bind [lindex $list $i] <Return> $returnAction
1354     bind [lindex $list $i] <Escape> $escapeAction
1355     bind [lindex $list $i] <Tab>    [list focus [lindex $list 0]]
1356     bind [lindex $list $i] <Left> [list left-cursor [lindex $list $i]]
1357     bind [lindex $list $i] <Right> [list right-cursor [lindex $list $i]]
1358     focus [lindex $list 0]
1359 }
1360
1361 proc entry-fields {parent list tlist returnAction escapeAction} {
1362     set alist {}
1363     set i 0
1364     foreach field $list {
1365         set label ${parent}.${field}.label
1366         set entry ${parent}.${field}.entry
1367         label $label -text [lindex $tlist $i] -anchor e
1368         entry $entry -width 32 -relief sunken
1369         pack $label -side left
1370         pack $entry -side right
1371         lappend alist $entry
1372         incr i
1373     }
1374     bind-fields $alist $returnAction $escapeAction
1375 }
1376
1377 proc define-target-dialog {} {
1378     set w .target-define
1379
1380     toplevel $w
1381     place-force $w .
1382     top-down-window $w
1383     frame $w.top.target
1384     pack $w.top.target \
1385             -side top -anchor e -pady 2 
1386     entry-fields $w.top {target} \
1387             {{Target:}} \
1388             {define-target-action} {destroy .target-define}
1389     top-down-ok-cancel $w {define-target-action} 1
1390 }
1391
1392 proc protocol-setup-delete {target} {
1393     global profile
1394     global settingsChanged
1395
1396     set a [alert "Are you sure you want to delete the target \
1397 definition $target ?"]
1398     if {$a} {
1399         set wno [lindex $profile($target) 12]
1400         set w .setup-${wno}
1401         destroy $w
1402         unset profile($target)
1403         set settingsChanged 1
1404         cascade-target-list
1405     }
1406 }
1407
1408 proc protocol-setup-action {target} {
1409     global profile
1410     global csRadioType
1411     global protocolRadioType
1412     global settingsChanged
1413     global RPNCheck
1414     global CCLCheck
1415     global ResultSetCheck
1416
1417     set wno [lindex $profile($target) 12]
1418     set w .setup-${wno}
1419     
1420     set b {}
1421     set settingsChanged 1
1422     set len [$w.top.databases.list size]
1423     for {set i 0} {$i < $len} {incr i} {
1424         lappend b [$w.top.databases.list get $i]
1425     }
1426     set profile($target) [list [$w.top.description.entry get] \
1427             [$w.top.host.entry get] \
1428             [$w.top.port.entry get] \
1429             [$w.top.idAuthentication.entry get] \
1430             [$w.top.maximumRecordSize.entry get] \
1431             [$w.top.preferredMessageSize.entry get] \
1432             $csRadioType \
1433             $b \
1434             $RPNCheck \
1435             $CCLCheck \
1436             $ResultSetCheck \
1437             $protocolRadioType \
1438             $wno]
1439
1440     cascade-target-list
1441     dputs $profile($target)
1442     destroy $w
1443 }
1444
1445 proc place-force {window parent} {
1446     set g [wm geometry $parent]
1447
1448     set p1 [string first + $g]
1449     set p2 [string last + $g]
1450
1451     set x [expr 40+[string range $g [expr $p1 +1] [expr $p2 -1]]]
1452     set y [expr 60+[string range $g [expr $p2 +1] end]]
1453     wm geometry $window +${x}+${y}
1454 }
1455
1456 proc add-database-action {target} {
1457     global profile
1458
1459     set wno [lindex $profile($target) 12]
1460     set w .setup-${wno}
1461
1462     $w.top.databases.list insert end \
1463             [.database-select.top.database.entry get]
1464     destroy .database-select
1465 }
1466
1467 proc add-database {target} {
1468     global profile
1469
1470     set w .database-select
1471
1472     set oldFocus [focus]
1473     toplevel $w
1474  
1475     set wno [lindex $profile($target) 12]
1476     place-force $w .setup-${wno}
1477
1478     top-down-window $w
1479
1480     frame $w.top.database
1481
1482     pack $w.top.database -side top -anchor e -pady 2
1483     
1484     entry-fields $w.top {database} \
1485             {{Database to add:}} \
1486             [list add-database-action $target] {destroy .database-select}
1487
1488     top-down-ok-cancel $w [list add-database-action $target] 1
1489     focus $oldFocus
1490 }
1491
1492 proc delete-database {target} {
1493     global profile
1494
1495     set wno [lindex $profile($target) 12]
1496     set w .setup-${wno}
1497     set l {}
1498     foreach i [$w.top.databases.list curselection] {
1499         set b [$w.top.databases.list get $i]
1500         set l "$l $b"
1501     }
1502     set a [alert "Are you sure you want to remove the database(s)${l}?"]
1503     if {$a} {
1504         foreach i [lsort -decreasing \
1505                 [$w.top.databases.list curselection]] {
1506             $w.top.databases.list delete $i
1507         }
1508     }
1509 }
1510
1511 proc protocol-setup {target} {
1512     global profile
1513     global csRadioType
1514     global protocolRadioType
1515     global RPNCheck
1516     global CCLCheck
1517     global ResultSetCheck
1518
1519     set wno [lindex $profile($target) 12]
1520     set w .setup-${wno}
1521
1522     toplevelG $w
1523
1524     wm title $w "Setup $target"
1525
1526     top-down-window $w
1527     
1528     if {$target == ""} {
1529         set target Default
1530     }
1531     dputs target
1532     dputs $profile($target)
1533
1534     frame $w.top.host
1535     frame $w.top.port
1536     frame $w.top.description
1537     frame $w.top.idAuthentication
1538     frame $w.top.maximumRecordSize
1539     frame $w.top.preferredMessageSize
1540     frame $w.top.cs-type -relief ridge -border 2
1541     frame $w.top.protocol -relief ridge -border 2
1542     frame $w.top.query -relief ridge -border 2
1543     frame $w.top.databases -relief ridge -border 2
1544
1545     # Maximum/preferred/idAuth ...
1546     pack $w.top.description $w.top.host $w.top.port \
1547             $w.top.idAuthentication $w.top.maximumRecordSize \
1548             $w.top.preferredMessageSize -side top -anchor e -pady 2
1549     
1550     entry-fields $w.top {description host port idAuthentication \
1551             maximumRecordSize preferredMessageSize} \
1552             {{Description:} {Host:} {Port:} {Id Authentication:} \
1553             {Maximum Record Size:} {Preferred Message Size:}} \
1554             [list protocol-setup-action $target] [list destroy $w]
1555     
1556     foreach sub {description host port idAuthentication \
1557             maximumRecordSize preferredMessageSize} {
1558         dputs $sub
1559         bind $w.top.$sub.entry <Control-a> [list add-database $target]
1560         bind $w.top.$sub.entry <Control-d> [list delete-database $target]
1561     }
1562     $w.top.description.entry insert 0 [lindex $profile($target) 0]
1563     $w.top.host.entry insert 0 [lindex $profile($target) 1]
1564     $w.top.port.entry insert 0 [lindex $profile($target) 2]
1565     $w.top.idAuthentication.entry insert 0 [lindex $profile($target) 3]
1566     $w.top.maximumRecordSize.entry insert 0 [lindex $profile($target) 4]
1567     $w.top.preferredMessageSize.entry insert 0 [lindex $profile($target) 5]
1568     set csRadioType [lindex $profile($target) 6]
1569     set RPNCheck [lindex $profile($target) 8]
1570     set CCLCheck [lindex $profile($target) 9]
1571     set ResultSetCheck [lindex $profile($target) 10]
1572     set protocolRadioType [lindex $profile($target) 11]
1573     if {$protocolRadioType == ""} {
1574         set protocolRadioType Z39
1575     }
1576
1577     # Databases ....
1578     pack $w.top.databases -side left -pady 4 -padx 4 -expand yes -fill both
1579
1580     label $w.top.databases.label -text "Databases"
1581     button $w.top.databases.add -text "Add" \
1582             -command [list add-database $target]
1583     button $w.top.databases.delete -text "Delete" \
1584             -command [list delete-database $target]
1585     listbox $w.top.databases.list -geometry 20x6 \
1586             -yscrollcommand "$w.top.databases.scroll set"
1587     scrollbar $w.top.databases.scroll -orient vertical -border 1
1588     pack $w.top.databases.label -side top -fill x \
1589             -padx 2 -pady 2
1590     pack $w.top.databases.add $w.top.databases.delete -side top -fill x \
1591             -padx 2 -pady 2
1592     pack $w.top.databases.list -side left -fill both -expand yes \
1593             -padx 2 -pady 2
1594     pack $w.top.databases.scroll -side right -fill y \
1595             -padx 2 -pady 2
1596     $w.top.databases.scroll config -command "$w.top.databases.list yview"
1597
1598     foreach b [lindex $profile($target) 7] {
1599         $w.top.databases.list insert end $b
1600     }
1601
1602     # Transport ...
1603     pack $w.top.cs-type -pady 4 -padx 4 -side top -fill x
1604     
1605     label $w.top.cs-type.label -text "Transport" 
1606     radiobutton $w.top.cs-type.tcpip -text "TCP/IP" -anchor w \
1607             -variable csRadioType -value tcpip
1608     radiobutton $w.top.cs-type.mosi -text "MOSI" -anchor w\
1609             -variable csRadioType -value mosi
1610     
1611     pack $w.top.cs-type.label $w.top.cs-type.tcpip $w.top.cs-type.mosi \
1612             -padx 4 -side top -fill x
1613
1614     # Protocol ...
1615     pack $w.top.protocol -pady 4 -padx 4 -side top -fill x
1616     
1617     label $w.top.protocol.label -text "Protocol" 
1618     radiobutton $w.top.protocol.z39v2 -text "Z39.50" -anchor w \
1619             -variable protocolRadioType -value Z39
1620     radiobutton $w.top.protocol.sr -text "SR" -anchor w \
1621             -variable protocolRadioType -value SR
1622     
1623     pack $w.top.protocol.label $w.top.protocol.z39v2 $w.top.protocol.sr \
1624             -padx 4 -side top -fill x
1625
1626     # Query ...
1627     pack $w.top.query -pady 4 -padx 4 -side top -fill x
1628
1629     label $w.top.query.label -text "Query support"
1630     checkbutton $w.top.query.c1 -text "RPN query" -anchor w -variable RPNCheck
1631     checkbutton $w.top.query.c2 -text "CCL query" -anchor w -variable CCLCheck
1632     checkbutton $w.top.query.c3 -text "Result sets" -anchor w -variable ResultSetCheck
1633
1634     pack $w.top.query.label -side top 
1635     pack $w.top.query.c1 $w.top.query.c2 $w.top.query.c3 \
1636             -padx 4 -side top -fill x
1637
1638     # Ok-cancel
1639     bottom-buttons $w [list {Ok} [list protocol-setup-action $target] \
1640             {Delete} [list protocol-setup-delete $target] \
1641             {Cancel} [list destroy $w]] 0   
1642 }
1643
1644 proc database-select-action {} {
1645     set w .database-select.top
1646     set b {}
1647     foreach indx [$w.databases.list curselection] {
1648         lappend b [$w.databases.list get $indx]
1649     }
1650     if {$b != ""} {
1651         z39 databaseNames $b
1652     }
1653     destroy .database-select
1654 }
1655
1656 proc database-select {} {
1657     set w .database-select
1658     global profile
1659     global hostid
1660
1661     toplevel $w
1662
1663     place-force $w .
1664
1665     top-down-window $w
1666
1667     frame $w.top.databases -relief ridge -border 2
1668
1669     pack $w.top.databases -side left -pady 6 -padx 6 -expand yes -fill x
1670
1671     label $w.top.databases.label -text "List"
1672     listbox $w.top.databases.list -geometry 20x6 \
1673             -yscrollcommand "$w.top.databases.scroll set"
1674     scrollbar $w.top.databases.scroll -orient vertical -border 1
1675     pack $w.top.databases.label -side top -fill x \
1676             -padx 2 -pady 2
1677     pack $w.top.databases.list -side left -fill both -expand yes \
1678             -padx 2 -pady 2
1679     pack $w.top.databases.scroll -side right -fill y \
1680             -padx 2 -pady 2
1681     $w.top.databases.scroll config -command "$w.top.databases.list yview"
1682
1683     foreach b [lindex $profile($hostid) 7] {
1684         $w.top.databases.list insert end $b
1685     }
1686     top-down-ok-cancel $w {database-select-action} 1
1687 }
1688
1689 proc cascade-target-list {} {
1690     global profile
1691     
1692     foreach sub [winfo children .top.target.m.clist] {
1693         destroy $sub
1694     }
1695     .top.target.m.clist delete 0 last
1696     foreach n [array names profile] {
1697         if {$n != "Default"} {
1698             set nl [lindex $profile($n) 12]
1699             if {[llength [lindex $profile($n) 7]] > 1} {
1700                 .top.target.m.clist add cascade -label $n \
1701                         -menu .top.target.m.clist.$nl
1702                 menu .top.target.m.clist.$nl
1703                 foreach b [lindex $profile($n) 7] {
1704                     .top.target.m.clist.$nl add command -label $b \
1705                             -command [list reopen-target $n $b]
1706                 }
1707             } else {
1708                 .top.target.m.clist add command -label $n \
1709                         -command [list reopen-target $n {}]
1710             }
1711         }
1712     }
1713     .top.target.m.slist delete 0 last
1714     foreach n [array names profile] {
1715         if {$n != "Default"} {
1716             .top.target.m.slist add command -label $n \
1717                     -command [list protocol-setup $n]
1718         }
1719     }
1720 }
1721
1722 proc query-select {i} {
1723     global queryButtonsFind
1724     global queryInfoFind
1725     global queryButtons
1726     global queryInfo
1727
1728     set queryInfoFind [lindex $queryInfo $i]
1729     set queryButtonsFind [lindex $queryButtons $i]
1730
1731     index-lines .lines 1 $queryButtonsFind $queryInfoFind activate-index
1732 }
1733
1734 proc query-new-action {} {
1735     global queryTypes
1736     global queryButtons
1737     global queryInfo
1738     global settingsChanged
1739
1740     set settingsChanged 1
1741     lappend queryTypes [.query-new.top.index.entry get]
1742     lappend queryButtons {}
1743     lappend queryInfo {}
1744
1745     destroy .query-new
1746     cascade-query-list
1747 }
1748
1749 proc query-new {} {
1750     set w .query-new
1751
1752     toplevel $w
1753     place-force $w .
1754     top-down-window $w
1755     frame $w.top.index
1756     pack $w.top.index \
1757             -side top -anchor e -pady 2 
1758     entry-fields $w.top index \
1759             {{Query Name:}} \
1760             query-new-action {destroy .query-new}
1761     top-down-ok-cancel $w query-new-action 1
1762 }
1763
1764 proc query-delete-action {queryNo} {
1765     global queryTypes
1766     global queryButtons
1767     global queryInfo
1768     global settingsChanged
1769
1770     set settingsChanged 1
1771
1772     set queryTypes [lreplace $queryTypes $queryNo $queryNo]
1773     set queryButtons [lreplace $queryButtons $queryNo $queryNo]
1774     set queryInfo [lreplace $queryInfo $queryNo $queryNo]
1775     destroy .query-delete
1776     cascade-query-list
1777 }
1778
1779 proc query-delete {queryNo} {
1780     global queryTypes
1781
1782     set w .query-delete
1783
1784     toplevel $w
1785     place-force $w .
1786     top-down-window $w
1787     set n [lindex $queryTypes $queryNo]
1788
1789     label $w.top.warning -bitmap warning
1790     message $w.top.quest -text "Are you sure you want to delete the \
1791 query type $n ?"  -aspect 200
1792     pack $w.top.warning $w.top.quest -side left -expand yes -padx 10 -pady 5
1793     bottom-buttons $w [list {Ok} [list query-delete-action $queryNo] \
1794                             {Cancel} [list destroy $w]] 1
1795 }
1796
1797 proc cascade-query-list {} {
1798     global queryTypes
1799     set w .top.options.m.query
1800
1801     set i 0
1802     $w.slist delete 0 last
1803     foreach n $queryTypes {
1804         $w.slist add command -label $n -command [list query-setup $i]
1805         incr i
1806     }
1807
1808     set i 0
1809     $w.clist delete 0 last
1810     foreach n $queryTypes {
1811         $w.clist add command -label $n -command [list query-select $i]
1812         incr i
1813     }
1814     set i 0
1815     $w.dlist delete 0 last
1816     foreach n $queryTypes {
1817         $w.dlist add command -label $n -command [list query-delete $i]
1818         incr i
1819     }
1820 }
1821
1822 proc save-geometry {} {
1823     global windowGeometry
1824     global hotTargets
1825     global textWrap
1826     global displayFormat
1827     global popupMarcdf
1828     
1829     set windowGeometry(.) [wm geometry .]
1830
1831     set f [open "clientg.tcl" w]
1832
1833     puts $f "set hotTargets \{ $hotTargets \}"
1834     puts $f "set textWrap $textWrap"
1835     puts $f "set displayFormat $displayFormat"
1836     puts $f "set popupMarcdf $popupMarcdf"
1837     foreach n [array names windowGeometry] {
1838         puts -nonewline $f "set \{windowGeometry($n)\} \{"
1839         puts -nonewline $f $windowGeometry($n)
1840         puts $f "\}"
1841     }
1842     close $f
1843 }
1844
1845 proc save-settings {} {
1846     global profile
1847     global settingsChanged
1848     global queryTypes
1849     global queryButtons
1850     global queryInfo
1851     
1852     set f [open "clientrc.tcl" w]
1853     puts $f "# Setup file"
1854
1855     foreach n [array names profile] {
1856         puts -nonewline $f "set \{profile($n)\} \{"
1857         puts -nonewline $f $profile($n)
1858         puts $f "\}"
1859     }
1860     puts -nonewline $f "set queryTypes \{" 
1861     puts -nonewline $f $queryTypes
1862     puts $f "\}"
1863     
1864     puts -nonewline $f "set queryButtons \{" 
1865     puts -nonewline $f $queryButtons
1866     puts $f "\}"
1867     
1868     puts -nonewline $f "set queryInfo \{"
1869     puts -nonewline $f $queryInfo
1870     puts $f "\}"
1871     close $f
1872     set settingsChanged 0
1873 }
1874
1875 proc alert {ask} {
1876     set w .alert
1877
1878     global alertAnswer
1879
1880     toplevel $w
1881     place-force $w .
1882     top-down-window $w
1883
1884     label $w.top.warning -bitmap warning
1885     message $w.top.message -text $ask -aspect 200 \
1886             -font -Adobe-Times-Medium-R-Normal-*-180-*
1887
1888     pack $w.top.warning $w.top.message -side left -pady 5 -padx 10 -expand yes
1889   
1890     set alertAnswer 0
1891     top-down-ok-cancel $w {alert-action} 1
1892     return $alertAnswer
1893 }
1894
1895 proc alert-action {} {
1896     global alertAnswer
1897     set alertAnswer 1
1898     destroy .alert
1899 }
1900
1901 proc exit-action {} {
1902     global settingsChanged
1903
1904     if {$settingsChanged} {
1905         set a [alert "you haven't saved your settings. Do you wish to save?"]
1906         if {$a} {
1907             save-settings
1908         }
1909     }
1910     save-geometry
1911     exit 0
1912 }
1913
1914 proc listbuttonaction {w name h user i} {
1915     $w configure -text [lindex $name 0]
1916     $h [lindex $name 1] $user $i
1917 }
1918     
1919 proc listbuttonx {button no names handle user} {
1920     if {[winfo exists $button]} {
1921         $button configure -text [lindex [lindex $names $no] 0]
1922         ${button}.m delete 0 last
1923     } else {
1924         menubutton $button -text [lindex [lindex $names $no] 0] \
1925                 -width 10 -menu ${button}.m -relief raised -border 1
1926         menu ${button}.m
1927     }
1928     set i 0
1929     foreach name $names {
1930         ${button}.m add command -label [lindex $name 0] \
1931                 -command [list listbuttonaction ${button} $name \
1932                 $handle $user $i]
1933         incr i
1934     }
1935 }
1936
1937 proc listbutton {button no names} {
1938     menubutton $button -text [lindex $names $no] -width 10 -menu ${button}.m \
1939             -relief raised -border 1
1940     menu ${button}.m
1941     foreach name $names {
1942         ${button}.m add command -label $name \
1943                 -command [list ${button} configure -text $name]
1944     }
1945 }
1946
1947 proc listbuttonv-action {button var names i} {
1948     global $var
1949
1950     set $var [lindex $names [expr $i+1]]
1951     $button configure -text [lindex $names $i]
1952 }
1953
1954 proc listbuttonv {button var names} {
1955     global $var
1956
1957     set n "-"
1958     eval "set val $$var"
1959     set l [llength $names]
1960     for {set i 1} {$i < $l} {incr i 2} {
1961         if {$val == [lindex $names $i]} {
1962             incr i -1
1963             set n [lindex $names $i]
1964             break
1965         }
1966     }
1967     if {[winfo exists $button]} {
1968         $button configure -text $n
1969         return
1970     }
1971     menubutton $button -text $n -menu ${button}.m \
1972             -relief raised -border 1
1973     menu ${button}.m
1974     for {set i 0} {$i < $l} {incr i 2} {
1975         ${button}.m add command -label [lindex $names $i] \
1976                 -command [list listbuttonv-action $button $var $names $i]
1977     }
1978 }
1979
1980 proc query-add-index-action {queryNo} {
1981     set w .query-setup
1982
1983     global queryInfoTmp
1984     global queryButtonsTmp
1985
1986     set newI [.query-add-index.top.index.entry get]
1987     lappend queryInfoTmp [list $newI {}]
1988     $w.top.index.list insert end $newI
1989     destroy .query-add-index
1990     #destroy $w.top.lines
1991     #frame $w.top.lines -relief ridge -border 2
1992     index-lines $w.top.lines 0 $queryButtonsTmp $queryInfoTmp activate-e-index
1993     #pack $w.top.lines -side left -pady 6 -padx 6 -fill y
1994 }
1995
1996 proc query-add-line {queryNo} {
1997     set w .query-setup
1998
1999     global queryInfoTmp
2000     global queryButtonsTmp
2001
2002     lappend queryButtonsTmp {I 0}
2003
2004     #destroy $w.top.lines
2005     #frame $w.top.lines -relief ridge -border 2
2006     index-lines $w.top.lines 0 $queryButtonsTmp $queryInfoTmp activate-e-index
2007     #pack $w.top.lines -side left -pady 6 -padx 6 -fill y
2008 }
2009
2010 proc query-del-line {queryNo} {
2011     set w .query-setup
2012
2013     global queryInfoTmp
2014     global queryButtonsTmp
2015
2016     set l [llength $queryButtonsTmp]
2017     if {$l <= 0} {
2018         return
2019     }
2020     incr l -1
2021     set queryButtonsTmp [lreplace $queryButtonsTmp $l $l]
2022     index-lines $w.top.lines 0 $queryButtonsTmp $queryInfoTmp activate-e-index
2023 }
2024
2025 proc query-add-index {queryNo} {
2026     set w .query-add-index
2027
2028     toplevel $w
2029     place-force $w .query-setup
2030     top-down-window $w
2031     frame $w.top.index
2032     pack $w.top.index \
2033             -side top -anchor e -pady 2 
2034     entry-fields $w.top {index} \
2035             {{Index Name:}} \
2036             [list query-add-index-action $queryNo] [list destroy $w]
2037     top-down-ok-cancel $w [list query-add-index-action $queryNo] 1
2038 }
2039
2040 proc query-setup-action {queryNo} {
2041     global queryButtons
2042     global queryInfo
2043     global queryButtonsTmp
2044     global queryInfoTmp
2045     global queryButtonsFind
2046     global queryInfoFind
2047     
2048     global settingsChanged 
2049
2050     set settingsChanged 1
2051
2052     set queryInfo [lreplace $queryInfo $queryNo $queryNo \
2053             $queryInfoTmp]
2054     set queryButtons [lreplace $queryButtons $queryNo $queryNo \
2055             $queryButtonsTmp]
2056     set queryInfoFind $queryInfoTmp
2057     set queryButtonsFind $queryButtonsTmp
2058
2059     destroy .query-setup
2060     index-lines .lines 1 $queryButtonsFind $queryInfoFind activate-index
2061 }
2062
2063 proc activate-e-index {value no i} {
2064     global queryButtonsTmp
2065     global queryIndexTmp
2066     
2067     set queryButtonsTmp [lreplace $queryButtonsTmp $no $no [list I $i]]
2068     dputs $queryButtonsTmp
2069     set queryIndexTmp $i
2070 }
2071
2072 proc activate-index {value no i} {
2073     global queryButtonsFind
2074
2075     set queryButtonsFind [lreplace $queryButtonsFind $no $no [list I $i]]
2076
2077     dputs "queryButtonsFind $queryButtonsFind"
2078 }
2079
2080 proc update-attr {} {
2081     set w .index-setup
2082     listbuttonv $w.top.relation.b relationTmpValue\
2083             {{None} 0 {Less than} 1 {Greater than or equal} 2 {Equal} 3 \
2084             {Greater than or equal} 4 {Greater than} 5 {Not equal} 6 \
2085             {Phonetic} 100 {Stem} 101 {Relevance} 102 {AlwaysMatches} 103}
2086     listbuttonv $w.top.position.b positionTmpValue {{None} 0 \
2087             {First in field} 1 {First in subfield} 2 {Any position in field} 3}
2088     listbuttonv $w.top.structure.b structureTmpValue {{None} 0 {Phrase} 1 \
2089             {Word} 2 {Key} 3 {Year} 4 {Date (norm)} 5 {Word list}  6 \
2090             {Date (un-norm)} 100 {Name (norm)} 101 {Date (un-norm)} 102 \
2091             {Structure} 103 {urx} 104 {free-form} 105 {doc-text} 106 \
2092             {local-number} 107 {string} 108 {numeric string} 109}
2093     listbuttonv $w.top.truncation.b truncationTmpValue {{Auto} 0 {Right} 1 \
2094             {Left} 2 {Left and right} 3 {No truncation} 100 \
2095             {Process #} 101 {Re-1} 102 {Re-2} 103}
2096     listbuttonv $w.top.completeness.b completenessTmpValue {{None} 0 \
2097             {Incomplete subfield} 1 {Complete subfield} 2 {Complete field} 3}
2098 }
2099
2100 proc use-attr {init} {
2101     set attr {
2102         {None}                           0
2103         {Personal name}                  1 
2104         {Corporate name}                 2 
2105         {Conference name}                3 
2106         {Title}                          4 
2107         {Title-series}                   5 
2108         {Title-uniform}                  6 
2109         {ISBN}                           7 
2110         {ISSN}                           8 
2111         {LC card number}                 9 
2112         {BNB card number}                10
2113         {BGF(sic) number}                11 
2114         {Local number}                   12 
2115         {Dewey classification}           13 
2116         {UDC classification}             14 
2117         {Bliss classification}           15 
2118         {LC call number}                 16 
2119         {NLM call number}                17 
2120         {NAL call number}                18 
2121         {MOS call number}                19 
2122         {Local classification}           20 
2123         {Subject heading}                21 
2124         {Subject-RAMEAU}                 22 
2125         {BDI-index-subject}              23 
2126         {INSPEC-subject}                 24 
2127         {MESH-subject}                   25 
2128         {PA-subject}                     26 
2129         {LC-subject-heading}             27 
2130         {RVM-subject-heading}            28 
2131         {Local subject index}            29 
2132         {Date}                           30 
2133         {Date of publication}            31 
2134         {Date of acquisition}            32 
2135         {Title-key}                      33 
2136         {Title-collective}               34 
2137         {Title-parallel}                 35 
2138         {Title-cover}                    36 
2139         {Title-added-title-page}         37 
2140         {Title-caption}                  38 
2141         {Title-running}                  39 
2142         {Title-spine}                    40 
2143         {Title-other-variant}            41 
2144         {Title-former}                   42 
2145         {Title-abbreviated}              43 
2146         {Title-expanded}                 44 
2147         {Subject-PRECIS}                 45 
2148         {Subject-RSWK}                   46 
2149         {Subject-subdivision}            47 
2150         {Number-natl-bibliography}       48 
2151         {Number-legal-deposit}           49 
2152         {Number-govt-publication}        50 
2153         {Number-publisher-for-music}     51 
2154         {Number-DB}                      52 
2155         {Number-local-call}              53 
2156         {Code-language}                  54 
2157         {Code-geographic-area}           55 
2158         {Code-institution}               56 
2159         {Name and title}                 57 
2160         {Name-geographic}                58 
2161         {Place-publication}              59 
2162         {CODEN}                          60 
2163         {Microform-generation}           61 
2164         {Abstract}                       62 
2165         {Note}                           63 
2166         {Author-title}                 1000 
2167         {Record type}                  1001 
2168         {Name}                         1002 
2169         {Author}                       1003 
2170         {Author-name-personal}         1004 
2171         {Author-name-corporate}        1005 
2172         {Author-name-conference}       1006 
2173         {Identifier-standard}          1007 
2174         {Subject-LC-children's}        1008 
2175         {Subject-name-personal}        1009 
2176         {Body of text}                 1010 
2177         {Date/time added to database}  1011 
2178         {Date/time last modified}      1012 
2179         {Authority/format identifier}  1013 
2180         {Concept-text}                 1014 
2181         {Concept-reference}            1015 
2182         {Any}                          1016 
2183         {Server choice}                1017 
2184         {Publisher}                    1018 
2185         {Record source}                1019 
2186         {Editor}                       1020 
2187         {Bib-level}                    1021 
2188         {Geographic class}             1022 
2189         {Indexed by}                   1023 
2190         {Map scale}                    1024 
2191         {Music key}                    1025 
2192         {Related periodical}           1026 
2193         {Report number}                1027 
2194         {Stock number}                 1028 
2195         {Thematic number}              1030 
2196         {Material type}                1031 
2197         {Doc ID}                       1032 
2198         {Host item}                    1033 
2199         {Content type}                 1034 
2200         {Anywhere}                     1035 
2201     }
2202     set w .index-setup
2203     global useTmpValue
2204     set l [llength $attr]
2205
2206     if {$init} {
2207         set s 0
2208         set lno 0
2209         for {set i 0} {$i < $l} {incr i} {
2210             $w.top.use.list insert end [lindex $attr $i]
2211             incr i
2212             if {$useTmpValue == [lindex $attr $i]} {
2213                 set s $lno
2214             }
2215             incr lno
2216         }
2217         $w.top.use.list select from $s
2218         $w.top.use.list select to $s
2219         incr s -3
2220         if {$s < 0} {
2221             set s 0
2222         }
2223         $w.top.use.list yview $s
2224     } else {
2225         set lno [lindex [$w.top.use.list curselection] 0]
2226         set i [expr $lno+$lno+1]
2227         set useTmpValue [lindex $attr $i]
2228         dputs "useTmpValue=$useTmpValue"
2229     }
2230 }
2231
2232 proc index-setup-action {oldAttr queryNo indexNo} {
2233     set attr [lindex $oldAttr 0]
2234
2235     global useTmpValue
2236     global relationTmpValue
2237     global structureTmpValue
2238     global truncationTmpValue
2239     global completenessTmpValue
2240     global positionTmpValue
2241     global queryInfoTmp
2242
2243     use-attr 0
2244
2245     dputs "index-setup-action"
2246     dputs "queryNo $queryNo"
2247     dputs "indexNo $indexNo"
2248     if {$useTmpValue > 0} {
2249         lappend attr "1=$useTmpValue"
2250     }
2251     if {$relationTmpValue > 0} {
2252         lappend attr "2=$relationTmpValue"
2253     }
2254     if {$positionTmpValue > 0} {
2255         lappend attr "3=$positionTmpValue"
2256     }
2257     if {$structureTmpValue > 0} {
2258         lappend attr "4=$structureTmpValue"
2259     }
2260     if {$truncationTmpValue > 0} {
2261         lappend attr "5=$truncationTmpValue"
2262     }
2263     if {$completenessTmpValue > 0} {
2264         lappend attr "6=$completenessTmpValue"
2265     }
2266     dputs "new attr $attr"
2267     set queryInfoTmp [lreplace $queryInfoTmp $indexNo $indexNo $attr]
2268     destroy .index-setup
2269 }
2270
2271 proc index-setup {attr queryNo indexNo} {
2272     set w .index-setup
2273
2274     global relationTmpValue
2275     global structureTmpValue
2276     global truncationTmpValue
2277     global completenessTmpValue
2278     global positionTmpValue
2279     global useTmpValue
2280     set relationTmpValue 0
2281     set truncationTmpValue 0
2282     set structureTmpValue 0
2283     set positionTmpValue 0
2284     set completenessTmpValue 0
2285     set useTmpValue 0
2286
2287     set len [llength $attr]
2288     for {set i 1} {$i < $len} {incr i} {
2289         set q [lindex $attr $i]
2290         set l [string first = $q]
2291         if {$l > 0} {
2292             set t [string range $q 0 [expr $l - 1]]
2293             set v [string range $q [expr $l + 1] end]
2294             switch $t {
2295                 1
2296                 { set useTmpValue $v }
2297                 2
2298                 { set relationTmpValue $v }
2299                 3
2300                 { set positionTmpValue $v }
2301                 4
2302                 { set structureTmpValue $v }
2303                 5
2304                 { set truncationTmpValue $v }
2305                 6
2306                 { set completenessTmpValue $v }
2307             }
2308         }
2309     }
2310     if {[winfo exists $w]} {
2311         destroy $w
2312     }
2313     toplevelG $w
2314
2315     set n [lindex $attr 0]
2316     wm title $w "Index setup $n"
2317
2318     top-down-window $w
2319
2320     frame $w.top.use -relief ridge -border 2
2321     frame $w.top.relation -relief ridge -border 2
2322     frame $w.top.position -relief ridge -border 2
2323     frame $w.top.structure -relief ridge -border 2
2324     frame $w.top.truncation -relief ridge -border 2
2325     frame $w.top.completeness -relief ridge -border 2
2326
2327     update-attr
2328
2329     # Use Attributes
2330
2331     pack $w.top.use -side left -pady 6 -padx 6 -fill y
2332
2333     label $w.top.use.label -text "Use"
2334     listbox $w.top.use.list -geometry 26x10 \
2335             -yscrollcommand "$w.top.use.scroll set"
2336     scrollbar $w.top.use.scroll -orient vertical -border 1
2337     pack $w.top.use.label -side top -fill x \
2338             -padx 2 -pady 2
2339     pack $w.top.use.list -side left -fill both -expand yes \
2340             -padx 2 -pady 2
2341     pack $w.top.use.scroll -side right -fill y \
2342             -padx 2 -pady 2
2343     $w.top.use.scroll config -command "$w.top.use.list yview"
2344
2345     use-attr 1
2346
2347     # Relation Attributes
2348
2349     pack $w.top.relation -pady 6 -padx 6 -side top
2350     label $w.top.relation.label -text "Relation" -width 18
2351     
2352     pack $w.top.relation.label $w.top.relation.b -fill x 
2353
2354     # Position Attributes
2355
2356     pack $w.top.position -pady 6 -padx 6 -side top
2357     label $w.top.position.label -text "Position" -width 18
2358
2359     pack $w.top.position.label $w.top.position.b -fill x
2360
2361     # Structure Attributes
2362
2363     pack $w.top.structure -pady 6 -padx 6 -side top
2364     label $w.top.structure.label -text "Structure" -width 18
2365
2366     pack $w.top.structure.label $w.top.structure.b -fill x
2367
2368     # Truncation Attributes
2369
2370     pack $w.top.truncation -pady 6 -padx 6 -side top
2371     label $w.top.truncation.label -text "Truncation" -width 18
2372
2373     pack $w.top.truncation.label $w.top.truncation.b -fill x
2374
2375     # Completeness Attributes
2376
2377     pack $w.top.completeness -pady 6 -padx 6 -side top
2378     label $w.top.completeness.label -text "Completeness" -width 18
2379
2380     pack $w.top.completeness.label $w.top.completeness.b -fill x
2381
2382     # Ok-cancel
2383     bottom-buttons $w [list \
2384             {Ok} [list index-setup-action $attr $queryNo $indexNo] \
2385             {Cancel} [list destroy $w]] 0
2386
2387 }
2388
2389 proc query-edit-index {queryNo} {
2390     global queryInfoTmp
2391     set w .query-setup
2392
2393     set i [lindex [$w.top.index.list curselection] 0]
2394     if {$i == ""} {
2395         return
2396     }
2397     set attr [lindex $queryInfoTmp $i]
2398     dputs "Editing no $i $attr"
2399     index-setup $attr $queryNo $i
2400 }
2401
2402 proc query-delete-index {queryNo} {
2403     global queryInfoTmp
2404     global queryButtonsTmp
2405     set w .query-setup
2406
2407     set i [lindex [$w.top.index.list curselection] 0]
2408     if {$i == ""} {
2409         return
2410     }
2411     set queryInfoTmp [lreplace $queryInfoTmp $i $i]
2412     index-lines $w.top.lines 0 $queryButtonsTmp $queryInfoTmp activate-e-index
2413     $w.top.index.list delete $i
2414 }
2415     
2416 proc query-setup {queryNo} {
2417     set w .query-setup
2418
2419     global queryTypes
2420     global queryButtons
2421     global queryInfo
2422     global queryButtonsTmp
2423     global queryInfoTmp
2424     global queryIndexTmp
2425     
2426     set queryIndexTmp 0
2427     set queryName [lindex $queryTypes $queryNo]
2428     set queryInfoTmp [lindex $queryInfo $queryNo]
2429     set queryButtonsTmp [lindex $queryButtons $queryNo]
2430
2431     toplevelG $w
2432
2433     wm minsize $w 0 0
2434     wm title $w "Query setup $queryName"
2435
2436     top-down-window $w
2437
2438     frame $w.top.lines -relief ridge -border 2
2439
2440     pack $w.top.lines -side left -pady 6 -padx 6 -fill y
2441
2442     # Index Lines
2443
2444     index-lines $w.top.lines 0 $queryButtonsTmp $queryInfoTmp activate-e-index
2445
2446     button $w.top.lines.add -text "Add" \
2447             -command [list query-add-line $queryNo]
2448     button $w.top.lines.del -text "Remove" \
2449             -command [list query-del-line $queryNo]
2450
2451     pack $w.top.lines.del -fill x -side bottom
2452     pack $w.top.lines.add -fill x -pady 10 -side bottom
2453
2454     # Indexes
2455
2456     frame $w.top.index -relief ridge -border 2
2457     pack $w.top.index -pady 6 -padx 6 -side right -fill y
2458
2459     listbox $w.top.index.list -yscrollcommand [list $w.top.index.scroll set]
2460     scrollbar $w.top.index.scroll -orient vertical -border 1 \
2461         -command [list $w.top.index.list yview]
2462     bind $w.top.index.list <2> [list query-edit-index $queryNo]
2463
2464     pack $w.top.index.list -side left -fill both -expand yes -padx 2 -pady 2
2465     pack $w.top.index.scroll -side right -fill y -padx 2 -pady 2
2466
2467     $w.top.index.list select from 0
2468     $w.top.index.list select to 0
2469
2470     foreach x $queryInfoTmp {
2471         $w.top.index.list insert end [lindex $x 0]
2472     }
2473     # Bottom
2474     bottom-buttons $w [list \
2475             {Ok} [list query-setup-action $queryNo] \
2476             {Add index} [list query-add-index $queryNo] \
2477             {Edit index} [list query-edit-index $queryNo] \
2478             {Delete index} [list query-delete-index $queryNo] \
2479             {Cancel} [list destroy $w]] 0
2480 }
2481
2482 proc index-clear {} {
2483     global queryButtonsFind
2484
2485     set i 0
2486     foreach b $queryButtonsFind {
2487         .lines.$i.e delete 0 end
2488         incr i
2489     }
2490 }
2491     
2492 proc index-query {} {
2493     global queryButtonsFind
2494     global queryInfoFind
2495
2496     set i 0
2497     set qs {}
2498
2499     foreach b $queryButtonsFind {
2500         set term [string trim [.lines.$i.e get]]
2501         if {$term != ""} {
2502             set attr [lrange [lindex $queryInfoFind [lindex $b 1]] 1 end]
2503
2504             set len [string length $term]
2505             incr len -1
2506             set left 0
2507             set right 0
2508             if {[string index $term $len] == "?"} {
2509                 set right 1
2510                 set term [string range $term 0 [expr $len - 1]]
2511             }
2512             if {[string index $term 0] == "?"} {
2513                 set left 1
2514                 set term [string range $term 1 end]
2515             }
2516             set term "\{${term}\}"
2517             if {$right && $left} {
2518                 set term "@attr 5=3 ${term}"
2519             } elseif {$right} {
2520                 set term "@attr 5=1 ${term}"
2521             } elseif {$left} {
2522                 set term "@attr 5=2 ${term}"
2523             }
2524             foreach a $attr {
2525                 set term "@attr $a ${term}"
2526             }
2527             if {$qs != ""} {
2528                 set qs "@and ${qs} ${term}"
2529             } else {
2530                 set qs $term
2531             }
2532         }
2533         incr i
2534     }
2535     dputs "qs=  $qs"
2536     return $qs
2537 }
2538
2539 proc index-focus-in {w i} {
2540     global curIndexEntry
2541
2542     $w.$i configure -background red
2543     set curIndexEntry $i
2544 }
2545
2546 proc index-lines {w realOp buttonInfo queryInfo handle} {
2547     set i 0
2548     foreach b $buttonInfo {
2549         if {! [winfo exists $w.$i]} {
2550             frame $w.$i -background white -border 1
2551         }
2552         listbuttonx $w.$i.l [lindex $b 1] $queryInfo $handle $i
2553
2554         if {$realOp} {
2555             if {! [winfo exists $w.$i.e]} {
2556                 entry $w.$i.e -width 32 -relief sunken -border 1
2557                 bind $w.$i.e <FocusIn> [list index-focus-in $w $i]
2558                 bind $w.$i.e <FocusOut> [list $w.$i configure \
2559                         -background white]
2560                 pack $w.$i.l -side left
2561                 pack $w.$i.e -side left -fill x -expand yes
2562                 pack $w.$i -side top -fill x -padx 2 -pady 2
2563                 bind $w.$i.e <Left> [list left-cursor $w.$i.e]
2564                 bind $w.$i.e <Right> [list right-cursor $w.$i.e]
2565                 bind $w.$i.e <Return> search-request
2566             }
2567         } else {
2568             pack $w.$i.l -side left
2569             pack $w.$i -side top -fill x -padx 2 -pady 2
2570         }
2571         incr i
2572     }
2573     set j $i
2574     while {[winfo exists $w.$j]} {
2575         destroy $w.$j
2576         incr j
2577     }
2578     if {! $realOp} {
2579         return
2580     }
2581     set j 0
2582     incr i -1
2583     while {$j < $i} {
2584         set k [expr $j+1]
2585         bind $w.$j.e <Tab> "focus $w.$k.e"
2586         set j $k
2587     }
2588     if {$i >= 0} {
2589         bind $w.$i.e <Tab> "focus $w.0.e"
2590         focus $w.0.e
2591     }
2592 }
2593
2594 proc search-fields {w buttondefs} {
2595     set i 0
2596     foreach buttondef $buttondefs {
2597         frame $w.$i -background white
2598         
2599         listbutton $w.$i.l 0 $buttondef
2600         entry $w.$i.e -width 32 -relief sunken
2601         
2602         pack $w.$i.l -side left
2603         pack $w.$i.e -side left -fill x -expand yes
2604
2605         pack $w.$i -side top -fill x -padx 2 -pady 2
2606
2607         bind $w.$i.e <Left> [list left-cursor $w.$i.e]
2608         bind $w.$i.e <Right> [list right-cursor $w.$i.e]
2609
2610         incr i
2611     }
2612     set j 0
2613     incr i -1
2614     while {$j < $i} {
2615         set k [expr $j+1]
2616         bind $w.$j.e <Tab> "focus $w.$k.e \n
2617         $w.$k configure -background red \n
2618         $w.$j configure -background white"
2619         set j $k
2620     }
2621     bind $w.$i.e <Tab> "focus $w.0.e \n
2622         $w.0 configure -background red \n
2623         $w.$i configure -background white"
2624     focus $w.0.e
2625     $w.0 configure -background red
2626 }
2627
2628 if {[info exists windowGeometry(.)]} {
2629     set g $windowGeometry(.)
2630     if {$g != ""} {
2631         wm geometry . $g
2632     }
2633 }    
2634
2635 read-formats
2636
2637 frame .top  -border 1 -relief raised
2638 frame .lines  -border 1 -relief raised
2639 frame .mid  -border 1 -relief raised
2640 frame .data -border 1 -relief raised
2641 frame .bot  -border 1 -relief raised
2642 pack .top .lines .mid -side top -fill x
2643 pack .data -side top -fill both -expand yes
2644 pack .bot -fill x
2645
2646 menubutton .top.file -text "File" -menu .top.file.m
2647 menu .top.file.m
2648 .top.file.m add command -label "Save settings" -command {save-settings}
2649 .top.file.m add separator
2650 .top.file.m add command -label "Exit" -command {exit-action}
2651
2652 menubutton .top.target -text "Target" -menu .top.target.m
2653 menu .top.target.m
2654 .top.target.m add cascade -label "Connect" -menu .top.target.m.clist
2655 .top.target.m add command -label "Disconnect" -command {close-target}
2656 .top.target.m add command -label "About" -command {about-target}
2657 .top.target.m add cascade -label "Setup" -menu .top.target.m.slist
2658 .top.target.m add command -label "Setup new" -command {define-target-dialog}
2659 .top.target.m add separator
2660 set-target-hotlist
2661
2662 .top.target.m disable 1
2663 .top.target.m disable 2
2664
2665 menu .top.target.m.clist
2666 menu .top.target.m.slist
2667 cascade-target-list
2668
2669 menubutton .top.service -text "Service" -menu .top.service.m
2670 menu .top.service.m
2671 .top.service.m add command -label "Database" -command {database-select}
2672 .top.service.m add cascade -label "Present" -menu .top.service.m.present
2673 menu .top.service.m.present
2674 .top.service.m.present add command -label "10 More" \
2675         -command [list present-more 10]
2676 .top.service.m.present add command -label "All" \
2677         -command [list present-more {}]
2678 .top.service.m add command -label "Search" -command {search-request}
2679 .top.service.m add command -label "Scan" -command {scan-request}
2680
2681 .top.service configure -state disabled
2682
2683 menubutton .top.rset -text "Set" -menu .top.rset.m
2684 menu .top.rset.m
2685 .top.rset.m add command -label "Load" -command {load-set}
2686 .top.rset.m add separator
2687
2688 menubutton .top.options -text "Options" -menu .top.options.m
2689 menu .top.options.m
2690 .top.options.m add cascade -label "Query" -menu .top.options.m.query
2691 .top.options.m add cascade -label "Format" -menu .top.options.m.formats
2692 .top.options.m add cascade -label "Wrap" -menu .top.options.m.wrap
2693
2694 menu .top.options.m.query
2695 .top.options.m.query add cascade -label "Select" \
2696         -menu .top.options.m.query.clist
2697 .top.options.m.query add cascade -label "Edit" \
2698         -menu .top.options.m.query.slist
2699 .top.options.m.query add command -label "New" \
2700         -command {query-new}
2701 .top.options.m.query add cascade -label "Delete" \
2702         -menu .top.options.m.query.dlist
2703
2704 menu .top.options.m.query.slist
2705 menu .top.options.m.query.clist
2706 menu .top.options.m.query.dlist
2707 cascade-query-list
2708
2709 menu .top.options.m.formats
2710 set i 0
2711 foreach f $displayFormats {
2712     .top.options.m.formats add radiobutton -label $f -value $i \
2713             -command [list set-display-format $i] -variable displayFormat
2714     incr i
2715 }
2716
2717 menu .top.options.m.wrap
2718 .top.options.m.wrap add radiobutton -label "Character" \
2719         -value char -variable textWrap -command {set-wrap char}
2720 .top.options.m.wrap add radiobutton -label "Word" \
2721         -value word -variable textWrap -command {set-wrap word}
2722 .top.options.m.wrap add radiobutton -label "None" \
2723         -value none -variable textWrap -command {set-wrap none}
2724
2725 menubutton .top.help -text "Help" -menu .top.help.m
2726 menu .top.help.m
2727
2728 .top.help.m add command -label "Help on help" \
2729         -command {tkerror "Help on help not available. Sorry"}
2730 .top.help.m add command -label "About" -command {about-origin}
2731
2732 pack .top.file .top.target .top.service .top.rset .top.options -side left
2733 pack .top.help -side right
2734
2735 index-lines .lines 1 $queryButtonsFind [lindex $queryInfo 0] activate-index
2736
2737 button .mid.search -width 7 -text {Search} -command search-request \
2738         -state disabled
2739 button .mid.scan -width 7 -text {Scan} \
2740         -command scan-request -state disabled 
2741 button .mid.present -width 7 -text {Present} -command [list present-more 10] \
2742         -state disabled
2743
2744 button .mid.clear -width 7 -text {Clear} -command index-clear
2745 pack .mid.search .mid.scan .mid.present .mid.clear -side left \
2746         -fill y -padx 5 -pady 3
2747
2748 text .data.record -height 2 -width 20 -wrap none \
2749         -yscrollcommand [list .data.scroll set] -wrap $textWrap
2750 scrollbar .data.scroll -command [list .data.record yview]
2751 pack .data.scroll -side right -fill y
2752 pack .data.record -expand yes -fill both
2753 initBindings
2754
2755 if {[tk colormodel .] == "color"} {
2756     .data.record tag configure marc-tag -foreground blue
2757     .data.record tag configure marc-id -foreground red
2758 } else {
2759     .data.record tag configure marc-tag -foreground black
2760     .data.record tag configure marc-id -foreground black
2761 }
2762 .data.record tag configure marc-data -foreground black
2763
2764 button .bot.logo  -bitmap @book1 -command cancel-operation
2765 frame .bot.a
2766 pack .bot.a -side left -fill x
2767 pack .bot.logo -side right -padx 2 -pady 2
2768
2769 message .bot.a.target -text "" -aspect 1000 -border 1
2770
2771 label .bot.a.status -text "Not connected" -width 15 -relief \
2772         sunken -anchor w -border 1
2773 label .bot.a.set -text "" -width 5 -relief \
2774         sunken -anchor w -border 1
2775 label .bot.a.message -text "" -width 15 -relief \
2776         sunken -anchor w -border 1
2777
2778 pack .bot.a.target -side top -anchor nw -padx 2 -pady 2
2779 pack .bot.a.status .bot.a.set .bot.a.message \
2780         -side left -padx 2 -pady 2
2781
2782 ir z39
2783
2784 show-logo 1
2785