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