Work on scan interface - up/down buttons.
[ir-tcl-moved-to-github.git] / client.tcl
1 #
2 # $Log: client.tcl,v $
3 # Revision 1.27  1995-06-02 14:29:42  adam
4 # Work on scan interface - up/down buttons.
5 #
6 # Revision 1.26  1995/06/01  16:36:46  adam
7 # About buttons. Minor bug fixes.
8 #
9 # Revision 1.25  1995/05/31  13:09:57  adam
10 # Client searches/presents may be interrupted.
11 # New moving book-logo.
12 #
13 # Revision 1.24  1995/05/31  08:36:24  adam
14 # Bug fix in client.tcl: didn't save options on clientrc.tcl.
15 # New method: referenceId. More work on scan.
16 #
17 # Revision 1.23  1995/05/29  10:33:41  adam
18 # README and rename of startup script.
19 #
20 # Revision 1.22  1995/05/26  11:44:09  adam
21 # Bugs fixed. More work on MARC utilities and queries. Test
22 # client is up-to-date again.
23 #
24 # Revision 1.21  1995/05/11  15:34:46  adam
25 # Scan request changed a bit. This version works with RLG.
26 #
27 # Revision 1.20  1995/04/21  16:31:57  adam
28 # New radiobutton: protocol (z39v2/SR).
29 #
30 # Revision 1.19  1995/04/18  16:11:50  adam
31 # First version of graphical Scan. Some work on query-by-form.
32 #
33 # Revision 1.18  1995/04/10  10:50:22  adam
34 # Result-set name defaults to suffix of ir-set name.
35 # Started working on scan. Not finished at this point.
36 #
37 # Revision 1.17  1995/03/31  09:34:57  adam
38 # Search-button disabled when there is no connection.
39 #
40 # Revision 1.16  1995/03/31  08:56:36  adam
41 # New button "Search".
42 #
43 # Revision 1.15  1995/03/28  12:45:22  adam
44 # New ir method failback: called on disconnect/protocol error.
45 # New ir set/get method: protocol: SR / Z3950.
46 # Simple popup and disconnect when failback is invoked.
47 #
48 # Revision 1.14  1995/03/22  16:07:55  adam
49 # Minor changes.
50 #
51 # Revision 1.13  1995/03/21  17:27:26  adam
52 # Short-hand keys in setup.
53 #
54 # Revision 1.12  1995/03/21  13:41:03  adam
55 # Comstack cs_create not used too often. Non-blocking connect.
56 #
57 # Revision 1.11  1995/03/21  10:39:06  adam
58 # Diagnostic error message displayed with tkerror.
59 #
60 # Revision 1.10  1995/03/20  15:24:06  adam
61 # Diagnostic records saved on searchResponse.
62 #
63 # Revision 1.9  1995/03/17  18:26:16  adam
64 # Non-blocking i/o used now. Database names popup as cascade items.
65 #
66 # Revision 1.8  1995/03/17  15:45:00  adam
67 # Improved target/database setup.
68 #
69 # Revision 1.7  1995/03/16  17:54:03  adam
70 # Minor changes really.
71 #
72 # Revision 1.6  1995/03/15  19:10:20  adam
73 # Database setup in protocol-setup (rather target setup).
74 #
75 # Revision 1.5  1995/03/15  13:59:23  adam
76 # Minor changes.
77 #
78 # Revision 1.4  1995/03/14  17:32:29  adam
79 # Presentation of full Marc record in popup window.
80 #
81 # Revision 1.3  1995/03/12  19:31:52  adam
82 # Pattern matching implemented when retrieving MARC records. More
83 # diagnostic functions.
84 #
85 # Revision 1.2  1995/03/10  18:00:15  adam
86 # Actual presentation in line-by-line format. RPN query support.
87 #
88 # Revision 1.1  1995/03/09  16:15:07  adam
89 # First presentRequest attempts. Hot-target list.
90 #
91 #
92 set hotTargets {}
93 set hotInfo {}
94 set busy 0
95
96 set profile(Default) {{} {} {210} {} 16384 8192 tcpip {} 1 {} {} z39v2}
97 set hostid Default
98 set settingsChanged 0
99 set setNo 0
100 set cancelFlag 0
101 set searchEnable 0
102 set fullMarcSeq 0
103
104 set queryTypes {Simple}
105 set queryButtons { { {I 0} {I 1} {I 2} } }
106 set queryInfo { { {Title {1=4}} {Author {1=1}} \
107         {Subject {1=21}} {Any {1=1016}} } }
108
109 wm minsize . 0 0
110
111 if {[file readable "clientrc.tcl"]} {
112     source "clientrc.tcl"
113 }
114
115 set queryButtonsFind [lindex $queryButtons 0]
116 set queryInfoFind [lindex $queryInfo 0]
117
118 proc top-down-window {w} {
119     frame $w.top -relief raised -border 1
120     frame $w.bot -relief raised -border 1
121     
122     pack  $w.top -side top -fill both -expand yes
123     pack  $w.bot -fill both
124 }
125
126 proc top-down-ok-cancel {w ok-action g} {
127     frame $w.bot.left -relief sunken -border 1
128     pack $w.bot.left -side left -expand yes -ipadx 2 -ipady 2 -padx 5 -pady 5
129     button $w.bot.left.ok -width 6 -text {Ok} \
130             -command ${ok-action}
131     pack $w.bot.left.ok -expand yes -ipadx 2 -ipady 2 -padx 3 -pady 3
132     button $w.bot.cancel -width 6 -text {Cancel} \
133             -command "destroy $w"
134     pack $w.bot.cancel -side left -expand yes    
135
136     if {$g} {
137         grab $w
138         tkwait window $w
139     }
140 }
141
142 proc bottom-buttons {w buttonList g} {
143     set i 0
144     set l [llength $buttonList]
145
146     frame $w.bot.$i -relief sunken -border 1
147     pack $w.bot.$i -side left -expand yes -padx 5 -pady 5
148     button $w.bot.$i.ok -text [lindex $buttonList $i] \
149             -command [lindex $buttonList [expr $i+1]]
150     pack $w.bot.$i.ok -expand yes -ipadx 2 -ipady 2 -padx 3 -pady 3 -side left
151
152     incr i 2
153     while {$i < $l} {
154         button $w.bot.$i -text [lindex $buttonList $i] \
155                 -command [lindex $buttonList [expr $i+1]]
156         pack $w.bot.$i -expand yes -ipadx 2 -ipady 2 -padx 3 -pady 3 -side left
157         incr i 2
158     }
159     if {$g} {
160         # Grab ...
161         grab $w
162         tkwait window $w
163     }
164 }
165
166 proc cancel-operation {} {
167     global cancelFlag
168     global busy
169
170     set cancelFlag 1
171     if {$busy} {
172         show-status Cancelled 0 {}
173     }
174 }
175
176 proc show-target {target} {
177     .bot.a.target configure -text "$target"
178 }
179
180 proc show-logo {v1} {
181     global busy
182     if {$busy != 0} {
183         incr v1 -1
184         if {$v1==0} {
185             set v1 9
186         }
187         .bot.logo configure -bitmap @book${v1}
188         after 140 [list show-logo $v1]
189         return
190     }
191     while {1} {
192         .bot.logo configure -bitmap @book1
193         tkwait variable busy
194         if {$busy} {
195             show-logo 1
196             return
197         }
198     }
199 }
200         
201 proc show-status {status b sb} {
202     global busy
203     global searchEnable
204
205     .bot.a.status configure -text "$status"
206     if {$b == 1} {
207         if {$busy == 0} {set busy 1}
208     } else {
209         set busy 0
210     }
211     if {$sb == {}} {
212         return
213     }
214     if {$sb} {
215         .top.search configure -state normal
216         .mid.search configure -state normal
217         .mid.scan configure -state normal
218         .mid.present configure -state normal
219         if {[winfo exists .scan-window]} {
220             .scan-window.bot.2 configure -state normal
221             .scan-window.bot.4 configure -state normal
222         }
223         set searchEnable 1
224     } else {
225         .top.search configure -state disabled
226         .mid.search configure -state disabled
227         .mid.scan configure -state disabled
228         .mid.present configure -state disabled
229
230         if {[winfo exists .scan-window]} {
231             .scan-window.bot.2 configure -state disabled
232             .scan-window.bot.4 configure -state disabled
233         }
234         set searchEnable 0
235     }
236 }
237
238 proc show-message {msg} {
239     .bot.a.message configure -text "$msg"
240 }
241
242 proc insertWithTags {w text args} {
243     set start [$w index insert]
244     $w insert insert $text
245     foreach tag [$w tag names $start] {
246         $w tag remove $tag $start insert
247     }
248     foreach i $args {
249         $w tag add $i $start insert
250     }
251 }
252
253 proc about-target {} {
254     set w .about-target-w
255
256     toplevel $w
257
258     wm title $w "About target"
259     place-force $w .
260     top-down-window $w
261
262     set i [z39 targetImplementationName]
263     label $w.top.in -text "Implementation name: $i"
264     set i [z39 targetImplementationId]
265     label $w.top.ii -text "Implementation id: $i"
266     set i [z39 targetImplementationVersion]
267     label $w.top.iv -text "Implementation version: $i"
268     set i [z39 options]
269     label $w.top.op -text "Protocol options: $i"
270
271     pack $w.top.in $w.top.ii $w.top.iv $w.top.op -side top -anchor nw
272
273     bottom-buttons $w [list {Close} [list destroy $w]] 1
274 }
275
276 proc about-origin {} {
277     set w .about-origin-w
278
279     toplevel $w
280
281     wm title $w "About IrTcl"
282     place-force $w .
283     top-down-window $w
284
285     set i [z39 implementationName]
286     label $w.top.in -text "Implementation name: $i"
287     set i [z39 implementationId]
288     label $w.top.ii -text "Implementation id: $i"
289
290     pack $w.top.in $w.top.ii -side top -anchor nw
291
292     bottom-buttons $w [list {Close} [list destroy $w]] 1
293 }
294
295 proc show-full-marc {no b} {
296     global setNo
297     global fullMarcSeq
298
299     if {[z39.$setNo type $no] != "DB"} {
300         return
301     }
302     if {$b} {
303         set w .full-marc-$fullMarcSeq
304         incr fullMarcSeq
305     } else {
306         set w .full-marc
307     }
308     if {[winfo exists $w]} {
309         $w.top.record delete 0.0 end
310         set new 0
311     } else {
312
313         toplevel $w
314
315         wm minsize $w 0 0
316         
317         frame $w.top -relief raised -border 1
318         frame $w.bot -relief raised -border 1
319
320         pack  $w.top -side top -fill both -expand yes
321         pack  $w.bot -fill both
322
323         text $w.top.record -width 60 -height 12 -wrap word \
324                 -yscrollcommand [list $w.top.s set]
325         scrollbar $w.top.s -command [list $w.top.record yview]
326
327         set new 1
328     }
329     set r [z39.$setNo getMarc $no list * * *]
330
331     $w.top.record tag configure marc-tag -foreground blue
332     $w.top.record tag configure marc-data -foreground black
333     $w.top.record tag configure marc-id -foreground red
334
335     foreach line $r {
336         set tag [lindex $line 0]
337         set indicator [lindex $line 1]
338         set fields [lindex $line 2]
339
340         if {$indicator != ""} {
341             insertWithTags $w.top.record "$tag $indicator" marc-tag
342         } else {
343             insertWithTags $w.top.record "$tag    " marc-tag
344         }
345         foreach field $fields {
346             set id [lindex $field 0]
347             set data [lindex $field 1]
348             if {$id != ""} {
349                 insertWithTags $w.top.record " $id " marc-id
350             }
351             set start [$w.top.record index insert]
352             insertWithTags $w.top.record $data {}
353         }
354         $w.top.record insert end "\n"
355     }
356     if {$new} {
357         bind $w <Return> {destroy .full-marc}
358         
359         pack $w.top.s -side right -fill y
360         pack $w.top.record -expand yes -fill both
361
362         bottom-buttons $w [list \
363                 {Close} [list destroy $w] \
364                 {Duplicate} [list show-full-marc $no 1]] 0
365     }
366 }
367
368 proc update-target-hotlist {target} {
369     global hotTargets
370
371     set len [llength $hotTargets]
372     if {$len > 0} {
373         .top.target.m delete 6 [expr 6+[llength $hotTargets]]
374     }
375     set indx [lsearch $hotTargets $target]
376     if {$indx >= 0} {
377         set hotTargets [lreplace $hotTargets $indx $indx]
378     }
379     set hotTargets [linsert $hotTargets 0 $target]
380     set-target-hotlist    
381
382
383 proc set-target-hotlist {} {
384     global hotTargets
385     
386     set i 1
387     foreach target $hotTargets {
388         .top.target.m add command -label "$i $target" -command \
389                 "reopen-target $target {}"
390         incr i
391         if {$i > 8} {
392              break
393         }
394     }
395 }
396
397 proc reopen-target {target base} {
398     close-target
399     open-target $target $base
400     update-target-hotlist $target
401 }
402
403 proc define-target-action {} {
404     global profile
405
406     set target [.target-define.top.target.entry get]
407     if {$target == ""} {
408         return
409     }
410     update-target-hotlist $target
411     foreach n [array names profile] {
412         if {$n == $target} {
413             protocol-setup $n
414             return
415         }
416     }
417     set profile($target) $profile(Default)
418     protocol-setup $target
419     destroy .target-define
420 }
421
422 proc fail-response {target} {
423     close-target
424     tkerror "Target connection closed or protocol error"
425 }
426
427 proc connect-response {target} {
428     puts "connect-response"
429     show-target $target
430     init-request
431 }
432
433 proc open-target {target base} {
434     global profile
435     global hostid
436
437     z39 disconnect
438     z39 comstack [lindex $profile($target) 6]
439     z39 idAuthentication [lindex $profile($target) 3]
440     z39 maximumRecordSize [lindex $profile($target) 4]
441     z39 preferredMessageSize [lindex $profile($target) 5]
442     puts -nonewline "maximumRecordSize="
443     puts [z39 maximumRecordSize]
444     puts -nonewline "preferredMessageSize="
445     puts [z39 preferredMessageSize]
446     show-status {Connecting} 0 0
447     if {$base == ""} {
448         z39 databaseNames [lindex [lindex $profile($target) 7] 0]
449     } else {
450         z39 databaseNames $base
451     }
452     z39 failback [list fail-response $target]
453     z39 callback [list connect-response $target]
454     z39 connect [lindex $profile($target) 1]:[lindex $profile($target) 2]
455     show-status {Connecting} 1 {}
456     set hostid $target
457     .top.target.m disable 0
458     .top.target.m enable 1
459     .top.target.m enable 2
460 }
461
462 proc close-target {} {
463     global hostid
464     global cancelFlag
465
466     set cancelFlag 0
467     set hostid Default
468     z39 disconnect
469     show-target {}
470     show-status {Not connected} 0 0
471     show-message {}
472     .top.target.m disable 1
473     .top.target.m disable 2
474     .top.target.m enable 0
475 }
476
477 proc load-set-action {} {
478     global setNo
479
480     incr setNo
481     ir-set z39.$setNo z39
482
483     set fname [.load-set.top.filename.entry get]
484     destroy .load-set
485     if {$fname != ""} {
486         init-title-lines
487
488         show-status {Loading} 1 {}
489         z39.$setNo loadFile $fname
490
491         set no [z39.$setNo numberOfRecordsReturned]
492         add-title-lines $setNo $no 1
493     }
494     show-status {Ready} 0 {}
495 }
496
497 proc load-set {} {
498     set w .load-set
499
500     set oldFocus [focus]
501     toplevel $w
502
503     place-force $w .
504
505     top-down-window $w
506
507     frame $w.top.filename
508     
509     pack $w.top.filename -side top -anchor e -pady 2
510     
511     entry-fields $w.top {filename} \
512             {{Filename:}} \
513             {load-set-action} {destroy .load-set}
514     
515     top-down-ok-cancel $w {load-set-action} 1
516     focus $oldFocus
517 }
518
519 proc init-request {} {
520     global setNo
521     global cancelFlag
522
523     if {$cancelFlag} {
524         close-target
525         return
526     }
527     z39 callback {init-response}
528     show-status {Initializing} 1 {}
529     z39 init
530 }
531
532 proc init-response {} {
533     global cancelFlag
534
535     if {$cancelFlag} {
536         close-target
537         return
538     }
539     show-status {Ready} 0 1
540     if {![z39 initResult]} {
541         set u [z39 userInformationField]
542         close-target
543         tkerror "Connection rejected by target: $u"
544     }
545 }
546
547 proc search-request {} {
548     global setNo
549     global profile
550     global hostid
551     global busy
552     global cancelFlag
553     global searchEnable
554
555     set target $hostid
556
557     if {$searchEnable == 0} {
558         return
559     }
560     set query [index-query]
561     if {$query==""} {
562         return
563     }
564     incr setNo
565     ir-set z39.$setNo z39
566
567     if {[lindex $profile($target) 10] == 1} {
568         z39.$setNo setName $setNo
569         puts "setName=${setNo}"
570     } else {
571         z39.$setNo setName Default
572         puts "setName=Default"
573     }
574     if {[lindex $profile($target) 8] == 1} {
575         z39.$setNo queryType rpn
576     }
577     if {[lindex $profile($target) 9] == 1} {
578         z39.$setNo queryType ccl
579     }
580     z39 callback {search-response}
581     z39.$setNo search $query
582     show-status {Search} 1 0
583 }
584
585 proc scan-request {attr} {
586     set w .scan-window
587
588     global profile
589     global hostid
590     global scanView
591
592     set target $hostid
593     set scanView 0
594
595     ir-scan z39.scan z39
596
597     z39 callback [list scan-response $attr 0 25]
598     if {![winfo exists $w]} {
599         toplevel $w
600         
601         wm title $w "Scan"
602         
603         wm minsize $w 0 0
604
605         top-down-window $w
606         
607         if {1} {
608             listbox $w.top.list -yscrollcommand [list $w.top.scroll set] \
609                     -font fixed -geometry 50x14
610             scrollbar $w.top.scroll -orient vertical -border 1
611             pack $w.top.list -side left -fill both -expand yes
612             pack $w.top.scroll -side right -fill y
613             $w.top.scroll config -command [list $w.top.list yview]
614         } else {
615             listbox $w.top.list -font fixed -geometry 60x14
616             pack $w.top.list -side left -fill both -expand yes
617         }
618         
619         bottom-buttons $w [list {Close} [list destroy $w] \
620                 {Up} [list scan-up $attr] \
621                 {Down} [list scan-down $attr]] 0
622         bind $w.top.list <Up> [list scan-up $attr]
623         bind $w.top.list <Down> [list scan-down $attr]
624     }
625     focus $w.top.list
626     z39.scan numberOfTermsRequested 5
627     z39.scan preferredPositionInResponse 1
628     z39.scan scan "${attr} b"
629     
630     show-status {Scan} 1 0
631 }
632
633
634 proc scan-response {attr start toget} {
635     global cancelFlag
636
637     set w .scan-window
638     puts "In scan-response"
639     set m [z39.scan numberOfEntriesReturned]
640     puts $m
641     puts attr=$attr
642     puts start=$start
643     puts toget=$toget
644
645     if {![winfo exists .scan-window]} {
646         show-status {Ready} 0 1
647         set cancelFlag 0
648         return
649     }
650     if {$toget < 0} {
651         for {set i 0} {$i < $m} {incr i} {
652             set term [lindex [z39.scan scanLine $i] 1]
653             set nostr [format " %-6d" [lindex [z39.scan scanLine $i] 2]]
654             $w.top.list insert $i "$nostr $term"
655         }
656     } else {
657         $w.top.list delete $start end
658         for {set i 0} {$i < $m} {incr i} {
659             set term [lindex [z39.scan scanLine $i] 1]
660             set nostr [format " %-6d" [lindex [z39.scan scanLine $i] 2]]
661             $w.top.list insert end "$nostr $term"
662         }
663     }
664     if {$cancelFlag} {
665         show-status {Ready} 0 1
666         set cancelFlag 0
667         return
668     }
669     if {$toget > 0 && $m > 1 && $m < $toget} {
670         set ntoget [expr $toget - $m + 1]
671         puts ntoget=$ntoget
672         z39 callback [list scan-response $attr [expr $start + $m - 1] $ntoget]
673         set q $term
674         puts "down continue: $q"
675         if {$ntoget > 10} {
676             z39.scan numberOfTermsRequested 10
677         } else {
678             z39.scan numberOfTermsRequested $ntoget
679         }
680         z39.scan preferredPositionInResponse 1
681         z39.scan scan "${attr} \{$q\}"
682         return
683     }
684     if {$toget < 0 && $m > 1 && $m < [expr - $toget]} {
685         set ntoget [expr - $toget - $m]
686         puts ntoget=$ntoget
687         z39 callback [list scan-response $attr 0 -$ntoget]
688         set q [string range [$w.top.list get 0] 7 end]
689         puts "up continue: $q"
690         if {$ntoget > 10} {
691             z39.scan numberOfTermsRequested 10
692             z39.scan preferredPositionInResponse 11
693         } else {
694             z39.scan numberOfTermsRequested $ntoget
695             z39.scan preferredPositionInResponse [incr ntoget]
696         }
697         z39.scan scan "${attr} \{$q\}"
698         return
699     }
700     show-status {Ready} 0 1
701 }
702
703 proc scan-down {attr} {
704     global scanView
705
706     set w .scan-window
707     set scanView [expr $scanView + 5]
708     set s [$w.top.list size]
709     if {$scanView > $s} {
710         z39 callback [list scan-response $attr [expr $s - 1] 30]
711         set q [string range [$w.top.list get [expr $s - 1]] 7 end]
712         puts "down: $q"
713         z39.scan numberOfTermsRequested 10
714         z39.scan preferredPositionInResponse 1
715         show-status {Scan} 1 0
716         z39.scan scan "${attr} \{$q\}"
717         return
718     }
719     $w.top.list yview $scanView
720 }
721
722 proc scan-up {attr} {
723     global scanView
724
725     set w .scan-window
726     if {$scanView < 5} {
727         z39 callback [list scan-response $attr 0 -30]
728         set q [string range [$w.top.list get 0] 7 end]
729         puts "up: $q"
730         z39.scan numberOfTermsRequested 10
731         z39.scan preferredPositionInResponse 11
732         show-status {Scan} 1 0
733         z39.scan scan "${attr} \{$q\}"
734         return
735     }
736     set scanView [expr $scanView - 5]
737     $w.top.list yview $scanView
738 }
739
740 proc search-response {} {
741     global setNo
742     global setOffset
743     global setMax
744     global cancelFlag
745     global busy
746
747     puts "In search-response"
748     init-title-lines
749     show-status {Ready} 0 1
750     show-message "[z39.$setNo resultCount] hits"
751     set setMax [z39.$setNo resultCount]
752     if {$setMax == 0} {
753         set status [z39.$setNo responseStatus]
754         if {[lindex $status 0] == "NSD"} {
755             set code [lindex $status 1]
756             set msg [lindex $status 2]
757             set addinfo [lindex $status 3]
758             tkerror "NSD$code: $msg: $addinfo"
759         }
760         return
761     }
762     if {$setMax > 20} {
763         set setMax 20
764     }
765     set setOffset 1
766     if {$cancelFlag} {
767         set cancelFlag 0
768         return
769     }
770     z39 callback {present-response}
771     z39.$setNo present $setOffset 1
772     show-status {Retrieve} 1 0
773 }
774
775 proc present-more {number} {
776     global setNo
777     global setOffset
778     global setMax
779
780     puts "present-more"
781     if {$setNo == 0} {
782         return
783     }
784     set max [z39.$setNo resultCount]
785     if {$max <= $setMax} {
786         return
787     }
788     if {$number == ""} {
789         set setMax $max
790     } else {
791         incr setMax $number
792     }
793     z39 callback {present-response}
794
795     set toGet [expr $setMax - $setOffset + 1]
796     if {$toGet > 3} {
797         set toGet 3
798     }
799     z39.$setNo present $setOffset $toGet
800     show-status {Retrieve} 1 0
801 }
802
803 proc init-title-lines {} {
804     .data.list delete 0 end
805 }
806
807 proc add-title-lines {setno no offset} {
808     for {set i 0} {$i < $no} {incr i} {
809         set o [expr $i + $offset]
810         set type [z39.$setno type $o]
811         if {$type == "DB"} {
812             set title [lindex [z39.$setno getMarc $o field 245 * a] 0]
813             set year  [lindex [z39.$setno getMarc $o field 260 * c] 0]
814             set nostr [format "%5d" $o]
815             .data.list insert end "$nostr $title - $year"
816         } elseif {$type == "SD"} {
817             set err [lindex [z39.$setno diag $o] 1]
818             set add [lindex [z39.$setno diag $o] 2]
819             if {$add != {}} {
820                 set add " :${add}"
821             }
822             .data.list insert end "Error ${err}${add}"
823         } elseif {$type == ""} {
824             .data.list insert end "empty"
825         }
826     }
827 }
828
829 proc present-response {} {
830     global setNo
831     global setOffset
832     global setMax
833     global cancelFlag
834
835     puts "In present-response"
836     set no [z39.$setNo numberOfRecordsReturned]
837     puts "Returned $no records, setOffset $setOffset"
838     add-title-lines $setNo $no $setOffset
839     set setOffset [expr $setOffset + $no]
840     set status [z39.$setNo responseStatus]
841     if {[lindex $status 0] == "NSD"} {
842         show-status {Ready} 0 1
843         set code [lindex $status 1]
844         set msg [lindex $status 2]
845         set addinfo [lindex $status 3]
846         tkerror "NSD$code: $msg: $addinfo"
847         return
848     }
849     if {$cancelFlag} {
850         show-status {Ready} 0 1
851         set cancelFlag 0
852         return
853     }
854     if {$no > 0 && $setOffset <= $setMax} {
855         puts "present from ${setOffset}"
856         set toGet [expr $setMax - $setOffset + 1]
857         if {$toGet > 3} {
858             set toGet 3
859         }
860         z39.$setNo present $setOffset $toGet
861     } else {
862         show-status {Finished} 0 1
863     }
864 }
865
866 proc left-cursor {w} {
867     set i [$w index insert]
868     if {$i > 0} {
869         incr i -1
870         $w icursor $i
871     }
872 }
873
874 proc right-cursor {w} {
875     set i [$w index insert]
876     incr i
877     $w icursor $i
878 }
879
880 proc bind-fields {list returnAction escapeAction} {
881     set max [expr [llength $list]-1]
882     for {set i 0} {$i < $max} {incr i} {
883         bind [lindex $list $i] <Return> $returnAction
884         bind [lindex $list $i] <Escape> $escapeAction
885         bind [lindex $list $i] <Tab> [list focus [lindex $list [expr $i+1]]]
886         bind [lindex $list $i] <Left> [list left-cursor [lindex $list $i]]
887         bind [lindex $list $i] <Right> [list right-cursor [lindex $list $i]]
888     }
889     bind [lindex $list $i] <Return> $returnAction
890     bind [lindex $list $i] <Escape> $escapeAction
891     bind [lindex $list $i] <Tab>    [list focus [lindex $list 0]]
892     bind [lindex $list $i] <Left> [list left-cursor [lindex $list $i]]
893     bind [lindex $list $i] <Right> [list right-cursor [lindex $list $i]]
894     focus [lindex $list 0]
895 }
896
897 proc entry-fields {parent list tlist returnAction escapeAction} {
898     set alist {}
899     set i 0
900     foreach field $list {
901         set label ${parent}.${field}.label
902         set entry ${parent}.${field}.entry
903         label $label -text [lindex $tlist $i] -anchor e
904         entry $entry -width 32 -relief sunken
905         pack $label -side left
906         pack $entry -side right
907         lappend alist $entry
908         incr i
909     }
910     bind-fields $alist $returnAction $escapeAction
911 }
912
913 proc define-target-dialog {} {
914     set w .target-define
915
916     toplevel $w
917     place-force $w .
918     top-down-window $w
919     frame $w.top.target
920     pack $w.top.target \
921             -side top -anchor e -pady 2 
922     entry-fields $w.top {target} \
923             {{Target:}} \
924             {define-target-action} {destroy .target-define}
925     top-down-ok-cancel $w {define-target-action} 1
926 }
927
928 proc protocol-setup-action {target} {
929     global profile
930     global csRadioType
931     global protocolRadioType
932     global settingsChanged
933     global RPNCheck
934     global CCLCheck
935     global ResultSetCheck
936
937     set w .setup-${target}.top
938
939     #set w .protocol-setup.top
940     
941     set b {}
942     set settingsChanged 1
943     set len [$w.databases.list size]
944     for {set i 0} {$i < $len} {incr i} {
945         lappend b [$w.databases.list get $i]
946     }
947     set profile($target) [list [$w.description.entry get] \
948             [$w.host.entry get] \
949             [$w.port.entry get] \
950             [$w.idAuthentication.entry get] \
951             [$w.maximumRecordSize.entry get] \
952             [$w.preferredMessageSize.entry get] \
953             $csRadioType \
954             $b \
955             $RPNCheck \
956             $CCLCheck \
957             $ResultSetCheck \
958             $protocolRadioType ]
959
960     cascade-target-list
961     puts $profile($target)
962     destroy .setup-${target}
963 }
964
965 proc place-force {window parent} {
966     set g [wm geometry $parent]
967
968     set p1 [string first + $g]
969     set p2 [string last + $g]
970
971     set x [expr 40+[string range $g [expr $p1 +1] [expr $p2 -1]]]
972     set y [expr 60+[string range $g [expr $p2 +1] end]]
973     wm geometry $window +${x}+${y}
974 }
975
976 proc add-database-action {target} {
977     set w .setup-${target}
978     
979     ${w}.top.databases.list insert end \
980             [.database-select.top.database.entry get]
981     destroy .database-select
982 }
983
984 proc add-database {target} {
985     set w .database-select
986
987     set oldFocus [focus]
988     toplevel $w
989
990     place-force $w .setup-${target}
991
992     top-down-window $w
993
994     frame $w.top.database
995
996     pack $w.top.database -side top -anchor e -pady 2
997     
998     entry-fields $w.top {database} \
999             {{Database to add:}} \
1000             [list add-database-action $target] {destroy .database-select}
1001
1002     top-down-ok-cancel $w [list add-database-action $target] 1
1003     focus $oldFocus
1004 }
1005
1006 proc delete-database {target} {
1007     set w .setup-${target}
1008     
1009     foreach i [lsort -decreasing \
1010             [$w.top.databases.list curselection]] {
1011         $w.top.databases.list delete $i
1012     }
1013 }
1014
1015 proc protocol-setup {target} {
1016     set w .setup-$target
1017
1018     global profile
1019     global csRadioType
1020     global protocolRadioType
1021     global RPNCheck
1022     global CCLCheck
1023     global ResultSetCheck
1024
1025     toplevel $w
1026
1027     wm title $w "Setup $target"
1028     place-force $w .
1029
1030     top-down-window $w
1031     
1032     if {$target == ""} {
1033         set target Default
1034     }
1035     puts target
1036     puts $profile($target)
1037
1038     frame $w.top.host
1039     frame $w.top.port
1040     frame $w.top.description
1041     frame $w.top.idAuthentication
1042     frame $w.top.maximumRecordSize
1043     frame $w.top.preferredMessageSize
1044     frame $w.top.cs-type -relief ridge -border 2
1045     frame $w.top.protocol -relief ridge -border 2
1046     frame $w.top.query -relief ridge -border 2
1047     frame $w.top.databases -relief ridge -border 2
1048
1049     # Maximum/preferred/idAuth ...
1050     pack $w.top.description $w.top.host $w.top.port \
1051             $w.top.idAuthentication $w.top.maximumRecordSize \
1052             $w.top.preferredMessageSize -side top -anchor e -pady 2
1053     
1054     entry-fields $w.top {description host port idAuthentication \
1055             maximumRecordSize preferredMessageSize} \
1056             {{Description:} {Host:} {Port:} {Id Authentication:} \
1057             {Maximum Record Size:} {Preferred Message Size:}} \
1058             [list protocol-setup-action $target] [list destroy $w]
1059     
1060     foreach sub {description host port idAuthentication \
1061             maximumRecordSize preferredMessageSize} {
1062         puts $sub
1063         bind $w.top.$sub.entry <Control-a> "add-database $target"
1064         bind $w.top.$sub.entry <Control-d> "delete-database $target"
1065     }
1066     $w.top.description.entry insert 0 [lindex $profile($target) 0]
1067     $w.top.host.entry insert 0 [lindex $profile($target) 1]
1068     $w.top.port.entry insert 0 [lindex $profile($target) 2]
1069     $w.top.idAuthentication.entry insert 0 [lindex $profile($target) 3]
1070     $w.top.maximumRecordSize.entry insert 0 [lindex $profile($target) 4]
1071     $w.top.preferredMessageSize.entry insert 0 [lindex $profile($target) 5]
1072     set csRadioType [lindex $profile($target) 6]
1073     set RPNCheck [lindex $profile($target) 8]
1074     set CCLCheck [lindex $profile($target) 9]
1075     set ResultSetCheck [lindex $profile($target) 10]
1076     set protocolRadioType [lindex $profile($target) 11]
1077     if {$protocolRadioType == ""} {
1078         set protocolRadioType z39v2
1079     }
1080
1081     # Databases ....
1082     pack $w.top.databases -side left -pady 6 -padx 6 -expand yes -fill both
1083
1084     label $w.top.databases.label -text "Databases"
1085     button $w.top.databases.add -text "Add" \
1086             -command "add-database $target"
1087     button $w.top.databases.delete -text "Delete" \
1088             -command "delete-database $target"
1089     listbox $w.top.databases.list -geometry 20x6 \
1090             -yscrollcommand "$w.top.databases.scroll set"
1091     scrollbar $w.top.databases.scroll -orient vertical -border 1
1092     pack $w.top.databases.label -side top -fill x \
1093             -padx 2 -pady 2
1094     pack $w.top.databases.add $w.top.databases.delete -side top -fill x \
1095             -padx 2 -pady 2
1096     pack $w.top.databases.list -side left -fill both -expand yes \
1097             -padx 2 -pady 2
1098     pack $w.top.databases.scroll -side right -fill y \
1099             -padx 2 -pady 2
1100     $w.top.databases.scroll config -command "$w.top.databases.list yview"
1101
1102     foreach b [lindex $profile($target) 7] {
1103         $w.top.databases.list insert end $b
1104     }
1105
1106     # Transport ...
1107     pack $w.top.cs-type -pady 6 -padx 6 -side top -fill x
1108     
1109     label $w.top.cs-type.label -text "Transport" 
1110     radiobutton $w.top.cs-type.tcpip -text "TCP/IP" -anchor w \
1111             -command {puts tcp/ip} -variable csRadioType -value tcpip
1112     radiobutton $w.top.cs-type.mosi -text "MOSI" -anchor w\
1113             -command {puts mosi} -variable csRadioType -value mosi
1114     
1115     pack $w.top.cs-type.label $w.top.cs-type.tcpip $w.top.cs-type.mosi \
1116             -padx 4 -side top -fill x
1117
1118     # Protocol ...
1119     pack $w.top.protocol -pady 6 -padx 6 -side top -fill x
1120     
1121     label $w.top.protocol.label -text "Protocol" 
1122     radiobutton $w.top.protocol.z39v2 -text "Z39.50" -anchor w \
1123             -command {puts z39v2} -variable protocolRadioType -value z39v2
1124     radiobutton $w.top.protocol.sr -text "SR" -anchor w \
1125             -command {puts sr} -variable protocolRadioType -value sr
1126     
1127     pack $w.top.protocol.label $w.top.protocol.z39v2 $w.top.protocol.sr \
1128             -padx 4 -side top -fill x
1129
1130     # Query ...
1131     pack $w.top.query -pady 6 -padx 6 -side top -fill x
1132
1133     label $w.top.query.label -text "Query support"
1134     checkbutton $w.top.query.c1 -text "RPN query" -anchor w -variable RPNCheck
1135     checkbutton $w.top.query.c2 -text "CCL query" -anchor w -variable CCLCheck
1136     checkbutton $w.top.query.c3 -text "Result sets" -anchor w -variable ResultSetCheck
1137
1138     pack $w.top.query.label -side top 
1139     pack $w.top.query.c1 $w.top.query.c2 $w.top.query.c3 \
1140             -padx 4 -side top -fill x
1141
1142     # Ok-cancel
1143     top-down-ok-cancel $w [list protocol-setup-action $target] 0
1144 }
1145
1146 proc database-select-action {} {
1147     set w .database-select.top
1148     set b {}
1149     foreach indx [$w.databases.list curselection] {
1150         lappend b [$w.databases.list get $indx]
1151     }
1152     if {$b != ""} {
1153         z39 databaseNames $b
1154     }
1155     destroy .database-select
1156 }
1157
1158 proc database-select {} {
1159     set w .database-select
1160     global profile
1161     global hostid
1162
1163     toplevel $w
1164
1165     place-force $w .
1166
1167     top-down-window $w
1168
1169     frame $w.top.databases -relief ridge -border 2
1170
1171     pack $w.top.databases -side left -pady 6 -padx 6 -expand yes -fill x
1172
1173     label $w.top.databases.label -text "List"
1174     listbox $w.top.databases.list -geometry 20x6 \
1175             -yscrollcommand "$w.top.databases.scroll set"
1176     scrollbar $w.top.databases.scroll -orient vertical -border 1
1177     pack $w.top.databases.label -side top -fill x \
1178             -padx 2 -pady 2
1179     pack $w.top.databases.list -side left -fill both -expand yes \
1180             -padx 2 -pady 2
1181     pack $w.top.databases.scroll -side right -fill y \
1182             -padx 2 -pady 2
1183     $w.top.databases.scroll config -command "$w.top.databases.list yview"
1184
1185     foreach b [lindex $profile($hostid) 7] {
1186         $w.top.databases.list insert end $b
1187     }
1188     top-down-ok-cancel $w {database-select-action} 1
1189 }
1190
1191 proc cascade-target-list {} {
1192     global profile
1193     
1194     foreach sub [winfo children .top.target.m.clist] {
1195         puts "deleting $sub"
1196         destroy $sub
1197     }
1198     .top.target.m.clist delete 0 last
1199     foreach n [array names profile] {
1200         if {$n != "Default"} {
1201             set nl [string tolower $n]
1202             if {[llength [lindex $profile($n) 7]] > 1} {
1203                 .top.target.m.clist add cascade -label $n \
1204                         -menu .top.target.m.clist.$nl
1205                 menu .top.target.m.clist.$nl
1206                 foreach b [lindex $profile($n) 7] {
1207                     .top.target.m.clist.$nl add command -label $b \
1208                             -command "reopen-target $n $b"
1209                 }
1210             } else {
1211                 .top.target.m.clist add command -label $n \
1212                         -command "reopen-target $n {}"
1213             }
1214         }
1215     }
1216     .top.target.m.slist delete 0 last
1217     foreach n [array names profile] {
1218         if {$n != "Default"} {
1219             .top.target.m.slist add command -label $n \
1220                     -command "protocol-setup $n"
1221         }
1222     }
1223 }
1224
1225 proc cascade-query-list {} {
1226     global queryTypes
1227
1228     set i 0
1229     .top.query.m.slist delete 0 last
1230     foreach n $queryTypes {
1231         .top.query.m.slist add command -label $n \
1232                 -command [list query-setup $i]
1233         incr i
1234     }
1235
1236     set i 0
1237     .top.query.m.clist delete 0 last
1238     foreach n $queryTypes {
1239         .top.query.m.clist add command -label $n \
1240                 -command [list query-select $i]
1241         incr i
1242     }
1243 }
1244
1245 proc save-settings {} {
1246     global hotTargets 
1247     global profile
1248     global settingsChanged
1249     global queryTypes
1250     global queryButtons
1251     global queryInfo
1252
1253     set f [open "clientrc.tcl" w]
1254     puts $f "# Setup file"
1255     puts $f "set hotTargets \{ $hotTargets \}"
1256
1257     foreach n [array names profile] {
1258         puts -nonewline $f "set profile($n) \{"
1259         puts -nonewline $f $profile($n)
1260         puts $f "\}"
1261     }
1262     puts -nonewline $f "set queryTypes \{" 
1263     puts -nonewline $f $queryTypes
1264     puts $f "\}"
1265     
1266     puts -nonewline $f "set queryButtons \{" 
1267     puts -nonewline $f $queryButtons
1268     puts $f "\}"
1269     
1270     puts -nonewline $f "set queryInfo \{"
1271     puts -nonewline $f $queryInfo
1272     puts $f "\}"
1273     
1274     close $f
1275     set settingsChanged 0
1276 }
1277
1278 proc alert {ask} {
1279     set w .alert
1280
1281     global alertAnswer
1282
1283     toplevel $w
1284     place-force $w .
1285     top-down-window $w
1286
1287     message $w.top.message -text $ask
1288
1289     pack $w.top.message -side left -pady 6 -padx 20 -expand yes -fill x
1290   
1291     set alertAnswer 0
1292     top-down-ok-cancel $w {alert-action} 1
1293     return $alertAnswer
1294 }
1295
1296 proc alert-action {} {
1297     global alertAnswer
1298     set alertAnswer 1
1299     destroy .alert
1300 }
1301
1302 proc exit-action {} {
1303     global settingsChanged
1304
1305     if {$settingsChanged} {
1306         set a [alert "you havent saved your settings. Do you wish to save?"]
1307         if {$a} {
1308             save-settings
1309         }
1310     }
1311     exit 0
1312 }
1313
1314 proc listbuttonaction {w name h user i} {
1315     $w configure -text [lindex $name 0]
1316     $h [lindex $name 1] $user $i
1317 }
1318     
1319 proc listbuttonx {button no names handle user} {
1320     if {[winfo exists $button]} {
1321         $button configure -text [lindex [lindex $names $no] 0]
1322         ${button}.m delete 0 last
1323     } else {
1324         menubutton $button -text [lindex [lindex $names $no] 0] \
1325                 -width 10 -menu ${button}.m -relief raised -border 1
1326         menu ${button}.m
1327     }
1328     set i 0
1329     foreach name $names {
1330         ${button}.m add command -label [lindex $name 0] \
1331                 -command [list listbuttonaction ${button} $name \
1332                 $handle $user $i]
1333         incr i
1334     }
1335 }
1336
1337 proc listbutton {button no names} {
1338     menubutton $button -text [lindex $names $no] -width 10 -menu ${button}.m \
1339             -relief raised -border 1
1340     menu ${button}.m
1341     foreach name $names {
1342         ${button}.m add command -label $name \
1343                 -command [list ${button} configure -text $name]
1344     }
1345 }
1346
1347 proc query-add-index-action {queryNo} {
1348     set w .setup-query-$queryNo
1349
1350     global queryInfoTmp
1351     global queryButtonsTmp
1352
1353     lappend queryInfoTmp [list [.query-add-index.top.index.entry get] {}]
1354
1355     destroy .query-add-index
1356     #destroy $w.top.lines
1357     #frame $w.top.lines -relief ridge -border 2
1358     index-lines $w.top.lines 0 $queryButtonsTmp $queryInfoTmp activate-e-index
1359     #pack $w.top.lines -side left -pady 6 -padx 6 -fill y
1360 }
1361
1362 proc query-add-line {queryNo} {
1363     set w .setup-query-$queryNo
1364
1365     global queryInfoTmp
1366     global queryButtonsTmp
1367
1368     lappend queryButtonsTmp {I 0}
1369
1370     #destroy $w.top.lines
1371     #frame $w.top.lines -relief ridge -border 2
1372     index-lines $w.top.lines 0 $queryButtonsTmp $queryInfoTmp activate-e-index
1373     #pack $w.top.lines -side left -pady 6 -padx 6 -fill y
1374 }
1375
1376 proc query-del-line {queryNo} {
1377     set w .setup-query-$queryNo
1378
1379     global queryInfoTmp
1380     global queryButtonsTmp
1381
1382     set l [llength $queryButtonsTmp]
1383     if {$l <= 0} {
1384         return
1385     }
1386     incr l -1
1387     set queryButtonsTmp [lreplace $queryButtonsTmp $l $l]
1388     index-lines $w.top.lines 0 $queryButtonsTmp $queryInfoTmp activate-e-index
1389 }
1390
1391 proc query-add-index {queryNo} {
1392     set w .query-add-index
1393
1394     toplevel $w
1395     place-force $w .setup-query-$queryNo
1396     top-down-window $w
1397     frame $w.top.index
1398     pack $w.top.index \
1399             -side top -anchor e -pady 2 
1400     entry-fields $w.top {index} \
1401             {{Index Name:}} \
1402             [list query-add-index-action $queryNo] {destroy .query-add-index}
1403     top-down-ok-cancel $w [list query-add-index-action $queryNo] 1
1404 }
1405
1406 proc query-setup-action {queryNo} {
1407     global queryButtons
1408     global queryInfo
1409     global queryButtonsTmp
1410     global queryInfoTmp
1411     global queryButtonsFind
1412     global queryInfoFind
1413
1414     set queryInfo [lreplace $queryInfo $queryNo $queryNo \
1415             $queryInfoTmp]
1416     set queryButtons [lreplace $queryButtons $queryNo $queryNo \
1417             $queryButtonsTmp]
1418     set queryInfoFind $queryInfoTmp
1419     set queryButtonsFind $queryButtonsTmp
1420
1421     puts $queryInfo
1422     puts $queryButtons
1423     destroy .setup-query-$queryNo
1424
1425     index-lines .lines 1 $queryButtonsFind $queryInfoFind activate-index
1426 }
1427
1428 proc activate-e-index {value no i} {
1429     global queryButtonsTmp
1430     
1431     puts $queryButtonsTmp
1432     set queryButtonsTmp [lreplace $queryButtonsTmp $no $no [list I $i]]
1433     puts $queryButtonsTmp
1434     puts "value $value"
1435     puts "no $no"
1436     puts "i $i"
1437 }
1438
1439 proc activate-index {value no i} {
1440     global queryButtonsFind
1441
1442     set queryButtonsFind [lreplace $queryButtonsFind $no $no [list I $i]]
1443
1444     puts "queryButtonsFind $queryButtonsFind"
1445     puts "value $value"
1446     puts "no $no"
1447     puts "i $i"
1448 }
1449
1450 proc query-setup {queryNo} {
1451     set w .setup-query-$queryNo
1452     global queryTypes
1453     set queryTypes {Simple}
1454     global queryButtons
1455     global queryInfo
1456     global queryButtonsTmp
1457     global queryInfoTmp
1458
1459     set queryName [lindex $queryTypes $queryNo]
1460     set queryInfoTmp [lindex $queryInfo $queryNo]
1461     set queryButtonsTmp [lindex $queryButtons $queryNo]
1462
1463     #set queryButtons { {I 0 I 1 I 2} }
1464     #set queryInfo { { {Title ti} {Author au} {Subject sh} } }
1465
1466     toplevel $w
1467
1468     wm title $w "Query setup $queryName"
1469     place-force $w .
1470
1471     top-down-window $w
1472
1473     frame $w.top.lines -relief ridge -border 2
1474     frame $w.top.use -relief ridge -border 2
1475     frame $w.top.relation -relief ridge -border 2
1476     frame $w.top.position -relief ridge -border 2
1477     frame $w.top.structure -relief ridge -border 2
1478     frame $w.top.truncation -relief ridge -border 2
1479     frame $w.top.completeness -relief ridge -border 2
1480
1481     # Index Lines
1482
1483     index-lines $w.top.lines 0 $queryButtonsTmp $queryInfoTmp activate-e-index
1484
1485     pack $w.top.lines -side left -pady 6 -padx 6 -fill y
1486
1487     # Use Attributes
1488     pack $w.top.use -side left -pady 6 -padx 6 -fill y
1489
1490     label $w.top.use.label -text "Use"
1491     listbox $w.top.use.list -geometry 20x10 \
1492             -yscrollcommand "$w.top.use.scroll set"
1493     scrollbar $w.top.use.scroll -orient vertical -border 1
1494     pack $w.top.use.label -side top -fill x \
1495             -padx 2 -pady 2
1496     pack $w.top.use.list -side left -fill both -expand yes \
1497             -padx 2 -pady 2
1498     pack $w.top.use.scroll -side right -fill y \
1499             -padx 2 -pady 2
1500     $w.top.use.scroll config -command "$w.top.use.list yview"
1501
1502     foreach u {{Personal name} {Corporate name}} {
1503         $w.top.use.list insert end $u
1504     }
1505     # Relation Attributes
1506     pack $w.top.relation -pady 6 -padx 6 -side top
1507
1508     label $w.top.relation.label -text "Relation" -width 18
1509     
1510     listbutton $w.top.relation.b 0\
1511             {{None} {Less than} {Greater than or equal} \
1512             {Equal} {Greater than or equal} {Greater than} {Not equal} \
1513             {Phonetic} \
1514             {Stem} {Relevance} {AlwaysMatches}}
1515     
1516     pack $w.top.relation.label $w.top.relation.b -fill x 
1517
1518     # Position Attributes
1519     pack $w.top.position -pady 6 -padx 6 -side top
1520
1521     label $w.top.position.label -text "Position" -width 18
1522
1523     listbutton $w.top.position.b 0 {{None} {First in field} {First in subfield}
1524     {Any position in field}}
1525     
1526     pack $w.top.position.label $w.top.position.b -fill x
1527
1528     # Structure Attributes
1529
1530     pack $w.top.structure -pady 6 -padx 6 -side top
1531     
1532     label $w.top.structure.label -text "Structure" -width 18
1533
1534     listbutton $w.top.structure.b 0 {{None} {Phrase} {Word} {Key} {Year}
1535     {Date (norm)} {Word list} {Date (un-norm)} {Name (norm)} {Date (un-norm)}
1536     {Structure} {urx} {free-form} {doc-text} {local-number} {string}
1537     {numeric string}}
1538
1539     pack $w.top.structure.label $w.top.structure.b -fill x
1540
1541     # Truncation Attributes
1542
1543     pack $w.top.truncation -pady 6 -padx 6 -side top
1544     
1545     label $w.top.truncation.label -text "Truncation" -width 18
1546
1547     listbutton $w.top.truncation.b 0 {{Auto} {Right} {Left} {Left and right} \
1548             {No truncation} {Process #} {Re-1} {Re-2}}
1549     pack $w.top.truncation.label $w.top.truncation.b -fill x
1550
1551     # Completeness Attributes
1552
1553     pack $w.top.completeness -pady 6 -padx 6 -side top
1554     
1555     label $w.top.completeness.label -text "Truncation" -width 18
1556
1557     listbutton $w.top.completeness.b 0 {{None} {Incomplete subfield} \
1558             {Complete subfield} {Complete field}}
1559     pack $w.top.completeness.label $w.top.completeness.b -fill x
1560
1561     # Ok-cancel
1562     bottom-buttons $w [list \
1563             {Ok} [list query-setup-action $queryNo] \
1564             {Add index} [list query-add-index $queryNo] \
1565             {Add line} [list query-add-line $queryNo] \
1566             {Delete line} [list query-del-line $queryNo] \
1567             {Cancel} [list destroy $w]] 0
1568 }
1569
1570 proc index-clear {} {
1571     global queryButtonsFind
1572
1573     set i 0
1574     foreach b $queryButtonsFind {
1575         .lines.$i.e delete 0 end
1576         incr i
1577     }
1578 }
1579     
1580 proc index-query {} {
1581     global queryButtonsFind
1582     global queryInfoFind
1583
1584     set i 0
1585     set qs {}
1586
1587     foreach b $queryButtonsFind {
1588         set term [string trim [.lines.$i.e get]]
1589         if {$term != ""} {
1590             set attr [lindex [lindex $queryInfoFind [lindex $b 1]] 1]
1591
1592             set term "\{${term}\}"
1593             foreach a $attr {
1594                 set term "@attr $a ${term}"
1595             }
1596             if {$qs != ""} {
1597                 set qs "@and ${qs} ${term}"
1598             } else {
1599                 set qs $term
1600             }
1601         }
1602         incr i
1603     }
1604     puts "qs=  $qs"
1605     return $qs
1606 }
1607
1608 proc index-lines {w realOp buttonInfo queryInfo handle} {
1609     set i 0
1610     foreach b $buttonInfo {
1611         if {! [winfo exists $w.$i]} {
1612             frame $w.$i -background white -border 1
1613         }
1614         listbuttonx $w.$i.l [lindex $b 1] $queryInfo $handle $i
1615
1616         if {$realOp} {
1617             if {! [winfo exists $w.$i.e]} {
1618                 entry $w.$i.e -width 32 -relief sunken -border 1
1619                 bind $w.$i.e <FocusIn> [list $w.$i configure \
1620                         -background red]
1621                 bind $w.$i.e <FocusOut> [list $w.$i configure \
1622                         -background white]
1623                 pack $w.$i.l -side left
1624                 pack $w.$i.e -side left -fill x -expand yes
1625                 pack $w.$i -side top -fill x -padx 2 -pady 2
1626                 bind $w.$i.e <Left> [list left-cursor $w.$i.e]
1627                 bind $w.$i.e <Right> [list right-cursor $w.$i.e]
1628                 bind $w.$i.e <Return> search-request
1629             }
1630         } else {
1631             pack $w.$i.l -side left
1632             pack $w.$i -side top -fill x -padx 2 -pady 2
1633         }
1634         incr i
1635     }
1636     set j $i
1637     while {[winfo exists $w.$j]} {
1638         destroy $w.$j
1639         incr j
1640     }
1641     if {! $realOp} {
1642         return
1643     }
1644     set j 0
1645     incr i -1
1646     while {$j < $i} {
1647         set k [expr $j+1]
1648         bind $w.$j.e <Tab> "focus $w.$k.e"
1649         set j $k
1650     }
1651     if {$i >= 0} {
1652         bind $w.$i.e <Tab> "focus $w.0.e"
1653         focus $w.0.e
1654     }
1655 }
1656
1657 proc search-fields {w buttondefs} {
1658     set i 0
1659     foreach buttondef $buttondefs {
1660         frame $w.$i -background white
1661         
1662         listbutton $w.$i.l 0 $buttondef
1663         entry $w.$i.e -width 32 -relief sunken
1664         
1665         pack $w.$i.l -side left
1666         pack $w.$i.e -side left -fill x -expand yes
1667
1668         pack $w.$i -side top -fill x -padx 2 -pady 2
1669
1670         bind $w.$i.e <Left> [list left-cursor $w.$i.e]
1671         bind $w.$i.e <Right> [list right-cursor $w.$i.e]
1672
1673         incr i
1674     }
1675     set j 0
1676     incr i -1
1677     while {$j < $i} {
1678         set k [expr $j+1]
1679         bind $w.$j.e <Tab> "focus $w.$k.e \n
1680         $w.$k configure -background red \n
1681         $w.$j configure -background white"
1682         set j $k
1683     }
1684     bind $w.$i.e <Tab> "focus $w.0.e \n
1685         $w.0 configure -background red \n
1686         $w.$i configure -background white"
1687     focus $w.0.e
1688     $w.0 configure -background red
1689 }
1690
1691 frame .top  -border 1 -relief raised
1692 frame .lines  -border 1 -relief raised
1693 frame .mid  -border 1 -relief raised
1694 frame .data -border 1 -relief raised
1695 frame .bot  -border 1 -relief raised
1696 pack .top .lines .mid -side top -fill x
1697 pack .data -side top -fill both -expand yes
1698 pack .bot -fill x
1699
1700 menubutton .top.file -text "File" -underline 0 -menu .top.file.m
1701 menu .top.file.m
1702 .top.file.m add command -label "Save settings" -command {save-settings}
1703 .top.file.m add command -label "Load Set" -command {load-set}
1704 .top.file.m add separator
1705 .top.file.m add command -label "Exit" -command {exit-action}
1706 .top.file.m add separator
1707 .top.file.m add command -label "About" -command {about-origin}
1708
1709 menubutton .top.target -text "Target" -underline 0 -menu .top.target.m
1710 menu .top.target.m
1711 .top.target.m add cascade -label "Connect" -menu .top.target.m.clist
1712 .top.target.m add command -label "Disconnect" -command {close-target}
1713 .top.target.m add command -label "About" -command {about-target}
1714 .top.target.m add cascade -label "Setup" -menu .top.target.m.slist
1715 .top.target.m add command -label "Setup new" -command {define-target-dialog}
1716 .top.target.m add separator
1717 set-target-hotlist
1718
1719 .top.target.m disable 1
1720 .top.target.m disable 2
1721
1722 menu .top.target.m.clist
1723 menu .top.target.m.slist
1724 cascade-target-list
1725
1726 menubutton .top.search -text "Search" -underline 0 -menu .top.search.m
1727 menu .top.search.m
1728 .top.search.m add command -label "Database" -command {database-select}
1729 .top.search.m add cascade -label "Query type" -menu .top.search.m.querytype
1730 menu .top.search.m.querytype
1731 .top.search.m.querytype add radiobutton -label "RPN"
1732 .top.search.m.querytype add radiobutton -label "CCL"
1733 .top.search.m add cascade -label "Present" -menu .top.search.m.present
1734 menu .top.search.m.present
1735 .top.search.m.present add command -label "More" -command [list present-more 10]
1736 .top.search.m.present add command -label "All" -command [list present-more {}]
1737 .top.search configure -state disabled
1738
1739 menubutton .top.query -text "Query" -underline 0 -menu .top.query.m
1740 menu .top.query.m
1741 .top.query.m add cascade -label "Choose" -menu .top.query.m.clist
1742 .top.query.m add command -label "Define" -command {new-query-dialog}
1743 .top.query.m add cascade -label "Edit" -menu .top.query.m.slist
1744 menu .top.query.m.clist
1745 menu .top.query.m.slist
1746 cascade-query-list
1747
1748 menubutton .top.help -text "Help" -menu .top.help.m
1749 menu .top.help.m
1750
1751 .top.help.m add command -label "Help on help" \
1752         -command {tkerror "Help on help not available. Sorry"}
1753 .top.help.m add command -label "About" \
1754         -command {tkerror "About not available. Sorry"}
1755
1756 pack .top.file .top.target .top.query .top.search -side left
1757 pack .top.help -side right
1758
1759 index-lines .lines 1 $queryButtonsFind [lindex $queryInfo 0] activate-index
1760
1761 button .mid.search -width 7 -text {Search} -command search-request \
1762         -state disabled
1763 button .mid.scan -width 7 -text {Scan} \
1764         -command [list scan-request "@attr 1=4"] -state disabled 
1765 button .mid.present -width 7 -text {Present} -command [list present-more 10] \
1766         -state disabled
1767
1768 button .mid.clear -width 7 -text {Clear} -command index-clear
1769 pack .mid.search .mid.scan .mid.present .mid.clear -side left \
1770         -fill y -padx 5 -pady 3
1771
1772 listbox .data.list -yscrollcommand {.data.scroll set} -font fixed
1773 scrollbar .data.scroll -orient vertical -border 1
1774 pack .data.list -side left -fill both -expand yes
1775 pack .data.scroll -side right -fill y
1776 .data.scroll config -command {.data.list yview}
1777
1778 button .bot.logo  -bitmap @book1 -command cancel-operation
1779 frame .bot.a
1780 pack .bot.a -side left -fill x
1781 pack .bot.logo -side right -padx 2 -pady 2
1782
1783 message .bot.a.target -text "" -aspect 1000 -border 1
1784
1785 label .bot.a.status -text "Not connected" -width 15 -relief \
1786         sunken -anchor w -border 1
1787 label .bot.a.set -textvariable setNo -width 5 -relief \
1788         sunken -anchor w -border 1
1789 label .bot.a.message -text "" -width 15 -relief \
1790         sunken -anchor w -border 1
1791
1792 pack .bot.a.target -side top -anchor nw -padx 2 -pady 2
1793 pack .bot.a.status .bot.a.set .bot.a.message \
1794         -side left -padx 2 -pady 2
1795
1796 bind .data.list <Double-Button-1> {set indx [.data.list nearest %y]
1797 show-full-marc [incr indx] 0}
1798
1799 ir z39
1800
1801 show-logo 1
1802