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