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