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