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