1#! /bin/sh
2# \
3	exec wish $0 ${1+"$@"}
4
5# BEGIN LICENSE BLOCK
6# Version: CMPL 1.1
7#
8# The contents of this file are subject to the Cisco-style Mozilla Public
9# License Version 1.1 (the "License"); you may not use this file except
10# in compliance with the License.  You may obtain a copy of the License
11# at www.eclipse-clp.org/license.
12#
13# Software distributed under the License is distributed on an "AS IS"
14# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See
15# the License for the specific language governing rights and limitations
16# under the License.
17#
18# The Original Code is  The ECLiPSe Constraint Logic Programming System.
19# The Initial Developer of the Original Code is  Cisco Systems, Inc.
20# Portions created by the Initial Developer are
21# Copyright (C) 1999 - 2006 Cisco Systems, Inc.  All Rights Reserved.
22#
23# Contributor(s):
24#
25# END LICENSE BLOCK
26#
27# ECLiPSe Development Tools in Tcl
28#
29#
30# $Id: eclipse_tools.tcl,v 1.43 2015/01/14 01:31:10 jschimpf Exp $
31#
32# Code in this file must only rely on primitives in eclipse.tcl.
33# Don't assume these tools to be embedded into a particular
34# application (like the tkeclipse toplevel)!
35#
36# All tools in this package has .ec_tools as the root frame. New
37# tools should be added under .ec_tools, and the code should be
38# placed after the creation and initialisation of the widget defaults
39
40#----------------------------------------------------------------------
41# Find and load the eclipse package
42# Also determines font preferences
43#----------------------------------------------------------------------
44
45package provide eclipse_tools 1.0
46
47set tkecl(version) 6.2 ;# update also in tkeclipse and examples!
48# including mapdebugdemo.tcl in <ECLiPSe>/document/tutorial/mapdebugdemo.tcl
49
50
51switch $tcl_platform(platform) {
52    unix {
53	set tkecl(ECLIPSEDIR) $env(ECLIPSEDIR)
54	lappend tkecl(preferences) \
55		{monofont_family   fixed       font     tkeclipsetoolsrc \
56                  "Font used for monospaced font (Tk font family)"} \
57		{monofont_size     ""          fontsize tkeclipsetoolsrc \
58                  "Font size used for monospace font in points (+ integer)" } \
59		{labelfont_family  helvetica   font     tkeclipsetoolsrc \
60                  "Font used for labels (Tk font family)"} \
61		{labelfont_size    ""          fontsize tkeclipsetoolsrc \
62                  "Font size used for labels in points (+ integer)" }
63    }
64    windows {
65	# For Windows 64 bit, the 64 bit version of Tcl must be run to
66	# access the correct (i.e. 64 bit) set of registry entries!
67	package require registry
68	set tkecl(ECLIPSEDIR) [registry get \
69	    HKEY_LOCAL_MACHINE\\SOFTWARE\\IC-Parc\\Eclipse\\$tkecl(version) ECLIPSEDIR]
70	# fixed does not alias to a mono-spaced font in Windows!
71	set tkecl(windows_registry_path) HKEY_CURRENT_USER\\Software\\IC-Parc\\ECLiPSe\\
72	lappend tkecl(preferences) \
73		{monofont_family   courier       font     tkeclipsetoolsrc \
74                 "Font used for monospaced font (Tk font family)"} \
75		{monofont_size     8            fontsize tkeclipsetoolsrc \
76                 "Font size used for monospace font in points (+ integer)" } \
77		{labelfont_family  helvetica     font     tkeclipsetoolsrc \
78                 "Font used for labels (Tk font family)"} \
79		{labelfont_size    8            fontsize tkeclipsetoolsrc \
80                 "Font size used for labels in points (+ integer)"}
81    }
82    default {
83	error "$tcl_platform(platform) not supported"
84	exit
85    }
86}
87
88lappend auto_path [file join $tkecl(ECLIPSEDIR) lib_tcl]
89
90
91#----------------------------------------------------------------------
92# Setup the defaults for preferences and set them to the defaults
93# Note fonts preferences have already been set
94#----------------------------------------------------------------------
95
96set tkecl(pref,editor) ""
97if [info exists env(VISUAL)] { set tkecl(pref,editor) $env(VISUAL) }
98if {$tkecl(pref,editor) == ""} {
99    if [catch {set pf $env(PROGRAMFILES)}] { set pf "C:\\Program Files" }
100    if [file exists "$pf\\Windows NT\\Accessories\\wordpad.exe"] {
101	set tkecl(pref,editor) "$pf\\Windows NT\\Accessories\\wordpad.exe"
102    } elseif [file exists "$pf\\Accessories\\wordpad.exe"] {
103	set tkecl(pref,editor) "$pf\\Accessories\\wordpad.exe"
104    }
105}
106
107switch -glob $tkecl(pref,editor) {
108    *emacs -
109    *emacs.* -
110    *vile {
111	set tkecl(pref,edit_line_option) "+"
112    }
113    *notepad++ {
114	set tkecl(pref,edit_line_option) "-n"
115    }
116    default {
117	set tkecl(pref,edit_line_option) ""
118    }
119}
120
121# the preferences are defined in tkecl(preferences), which is a list of the
122# preferences and information on them. To add a preference, append the
123# following list of information for the perference to the the variable:
124#     {<name>  <default value>  <type>  <family> <description>}
125#
126#  <name>              Name of the preference parameter.
127#  <default value>     The system default value for the parameter.
128#  <type>              Type of the parameter. This will determine how the
129#                      initialisation routines and preference editor will
130#                      handle the parameter.
131#  <family>            The family the parameter belongs to. Currently
132#                      either tkeclipsetoolsrc or tkeclipserc. The
133#                      preference values for the family will be stored in
134#                      a file named .<family> in Unix, or with <family>
135#                      being the last path of the registry path.
136#  <description>       This is the description that will be displayed
137#                      with the parameter in the editor
138#
139#  A corresponding variable tkecl(pref,<name>) will be created for each
140#  parameter in the development tools, storing its current value. The
141#  variable need to be created for the other families.
142
143lappend tkecl(preferences) \
144	{background_colour ""  colour tkeclipsetoolsrc \
145	   "Default background colour for widgets (colour)" }  \
146        {defaultextension   .ecl   string          tkeclipsetoolsrc \
147           "Default extension for file browser (string)"}   \
148	{stats_interval     1      stats_interval  tkeclipsetoolsrc \
149           "Interval for updating statistics tool (+ float)"}  \
150	{text_truncate      2000   +integer        tkeclipsetoolsrc \
151           "Threshold length for truncation of text lines (+ int)" } \
152	{tracer_prdepth     5      tracer_prdepth  tkeclipsetoolsrc \
153           "Print depth used by tracer tool (+ int)"} \
154	{balloonhelp        1      boolean         tkeclipsetoolsrc \
155           "Balloon help"}  \
156	{trace_source   1      boolean         tkeclipsetoolsrc \
157	     "Show source while tracing"}  \
158	{trace_refresh_dg   1      boolean         tkeclipsetoolsrc \
159           "Refresh delayed goals display at every trace line"}  \
160	{trace_refresh_stack   0      boolean         tkeclipsetoolsrc \
161           "Refresh tracer stack display at every trace line"}  \
162	{trace_raise_tracer   1      boolean         tkeclipsetoolsrc \
163           "Raise tracer window at every trace line"}  \
164	{dgf_spiedonly      0      boolean         tkeclipsetoolsrc \
165           "Show spied goals in delayed goals tool"}  \
166        {dgf_tracedonly     1      boolean         tkeclipsetoolsrc \
167           "Show traced goals in delayed goals tool"}  \
168        {dgf_wakeonly       0      boolean         tkeclipsetoolsrc \
169           "Show scheduled goals in delayed goals tool"}  \
170	{inspect_prdepth    5      +integer        tkeclipsetoolsrc \
171           "Print depth for inspector tool"} \
172	{inspect_ldepth    20      +integer        tkeclipsetoolsrc \
173           "List depth for inspector tool"} \
174	{inspect_nosymbols  1      boolean         tkeclipsetoolsrc \
175           "Display symbols for inspector tool"} \
176        [list editor  $tkecl(pref,editor)  string  tkeclipsetoolsrc {Text editor to use (command)}] \
177	[list edit_line_option $tkecl(pref,edit_line_option) string tkeclipsetoolsrc \
178	      "Editor's command line option to start at a specific line"]
179
180# use procedure to avoid creating extra global variables
181proc tkecl:set_initial_prefs {} {
182    global tkecl
183
184    foreach preference $tkecl(preferences) {
185	foreach {option default type family help} $preference {
186		set tkecl(pref,$option) $default
187	}
188    }
189}
190
191tkecl:set_initial_prefs
192
193#----------------------------------------------------------------------
194# Load packages and initialise global settings
195#----------------------------------------------------------------------
196
197package require AllWidgets
198package require tkinspect
199package require eclipse_peer_multitask
200
201balloonhelp enable .
202balloonhelp delay 1000
203
204# other global variables
205
206set tkecl(last_source_file) {}
207
208set tkecl(filetypes) {
209	{{ECLiPSe Files} {.ecl .pl}}
210	{{ECLiPSe specific Files} {.ecl}}
211	{{Prolog Files} {.pl}}
212	{{ECLiPSe Precompiled Files} {.eco}}
213	{{All Files} {*}}
214}
215
216#--------------------------------------------
217# setting tk-based preferences/defaults
218#-------------------------------------------
219
220# don't set size, use default instead; tk seems to have a bug with size 12
221# fonts are created here; their settings can be changed later to the user
222# defaults
223font create tkeclmono -family $tkecl(pref,monofont_family)
224font create tkeclmonobold -family $tkecl(pref,monofont_family) -weight bold
225font create tkecllabel -family $tkecl(pref,labelfont_family) -weight bold
226
227if ![regexp "^\[ \t]*$" $tkecl(pref,background_colour)] {
228    tk_setPalette background $tkecl(pref,background_colour)
229}
230
231# this sets the Tk defaults for widgets that has $root as a parent. This
232# should be called before any widgets of root are created!
233proc tkecl:set_tkecl_tkdefaults {root} {
234    option add *$root*font tkecllabel userDefault ;# the default
235    option add *$root*Text.font tkeclmono
236    option add *$root*Entry.font tkeclmono
237    option add *$root*Hierarchy.font tkeclmono
238    option add *$root*Text.font tkeclmono
239}
240
241tkecl:set_tkecl_tkdefaults ec_tools
242
243frame .ec_tools  ;# dummy toplevel frame for all eclipse tools
244
245#----------------------------------------------------------------------
246# Testing code
247#----------------------------------------------------------------------
248
249proc tkecl:test {} {
250    ec_rpcq_check {exit_block abort} (())
251}
252
253proc tkecl:rpc {} {
254    global tkecl
255
256    set ec_rpc .ec_tools.ec_rpc
257    if ![winfo exists $ec_rpc] {
258	toplevel $ec_rpc
259	wm title $ec_rpc "ECLiPSe Simple Query"
260	pack [label $ec_rpc.entrylabel -justify left -text "Enter a goal in ECLiPSe syntax:"] -fill x
261	pack [entry $ec_rpc.entry -bg white -textvariable tkecl(rpc_goal)] \
262		-fill x
263	pack [label $ec_rpc.textlabel -text "Reply:"] -fill x
264	pack [text $ec_rpc.text -bg white -height 8] -expand 1 -fill both
265	bind $ec_rpc.entry <Return> tkecl:run_rpc
266	button $ec_rpc.run -text "Run (once)" -command tkecl:run_rpc
267	button $ec_rpc.close -text Close -command "destroy $ec_rpc"
268	pack $ec_rpc.run $ec_rpc.close -side left -expand 1 -fill x
269	focus $ec_rpc.entry
270	balloonhelp $ec_rpc.run "Execute an ECLiPSe goal once at a new break level."
271	bind $ec_rpc <Alt-h> "tkecl:Get_helpfileinfo rpc $ec_rpc"
272    } else {
273	tkinspect:RaiseWindow $ec_rpc
274    }
275}
276
277proc tkecl:run_rpc {} {
278    global tkecl
279    .ec_tools.ec_rpc.text insert end [ec_rpc $tkecl(rpc_goal)]
280    .ec_tools.ec_rpc.text insert end "\n"
281    .ec_tools.ec_rpc.text see end
282}
283
284proc ec_rpc_check {goal {format S}} {
285    set result [ec_rpc $goal $format]
286    switch $result {
287	fail {
288	    tk_messageBox -type ok -message "ECLiPSe goal failed: $goal"
289	}
290	throw {
291	    tk_messageBox -type ok -message "ECLiPSe goal aborted: $goal"
292	}
293    }
294    return $result
295}
296
297# Call a module-qualified (default:eclipse_language) predicate.
298# Return fail, throw, or module-less goal term on success.
299proc ec_rpcq {goal exdr_type {module eclipse_language}} {
300#    .tkecl.pane.stdio.tout insert end "qcall $goal\n"
301    set result [ec_rpc [list : $module $goal] (()$exdr_type)]
302#    .tkecl.pane.stdio.tout insert end "qexit $result\n"
303    update
304    switch $result {
305	fail -
306	throw {return $result}
307    }
308    lindex $result 2
309}
310
311# Like ec_rpcq, but message on fail/throw
312proc ec_rpcq_check {goal exdr_type {module eclipse_language}} {
313#    .tkecl.pane.stdio.tout insert end "ccall $goal\n"
314    set result [ec_rpc [list : $module $goal] (()$exdr_type)]
315#    .tkecl.pane.stdio.tout insert end "cexit $result\n"
316    update
317    switch $result {
318	fail {
319	    tk_messageBox -type ok -message "ECLiPSe goal failed: $goal"
320	    return $result
321	}
322	throw {
323	    tk_messageBox -type ok -message "ECLiPSe goal aborted: $goal"
324	    return $result
325	}
326    }
327    lindex $result 2
328}
329
330# Call a goal with given context-module (and optional lookup-module)
331# Return fail, throw, or module-less goal term on success.
332# We call lm:(lm:goal@cm) because @/2 may not be visible (ISO).
333proc ec_rpcatq {goal exdr_type at_module {module eclipse_language} } {
334#    .tkecl.pane.stdio.tout insert end "atqcall $goal\n"
335    set result [ec_rpc [list : $module [list @ [list : $module $goal] $at_module]]\
336    		(()((()$exdr_type)())) ]
337#    .tkecl.pane.stdio.tout insert end "atqexit $result\n"
338    switch $result {
339	fail -
340	throw {return $result}
341    }
342    lindex $result 2 1 2
343}
344
345
346#----------------------------------------------------------------------
347# Library browser and help tool
348#----------------------------------------------------------------------
349
350proc tkecl:library_browser {} {
351    global tkecl
352
353    set lb .ec_tools.ec_libbrowse
354    set tkecl(lbloadtext) "No library selected"
355    set tkecl(lbmodule) ""
356    if ![winfo exists $lb] {
357	toplevel $lb
358	ec_rpcq init_library_info () tracer_tcl
359	set htmldoc [lindex [ec_rpcq {return_html_root _} (_) tracer_tcl] 1]
360	wm title $lb "ECLiPSe Library Browser and Help"
361
362	set htmlinfo [text $lb.ref -relief groove  -borderwidth 3 -height 3 ]
363
364	bind $htmlinfo <Any-Key> "tkecl:readonly_keypress %A"
365	bind $htmlinfo <ButtonRelease-2> {break} ;# disable paste
366	$htmlinfo tag configure highlight  -justify center -font tkecllabel
367	$htmlinfo insert end "To obtain more information on ECLiPSe, point your browser at:\n$htmldoc" highlight
368
369	set close [button $lb.close -text "Close" -command "destroy $lb"]
370
371	set top [frame $lb.top -width 700 -height 500]
372	  set treeframe [frame $top.tframe]
373
374            set tree [hierarchy $treeframe.tree -browsecmd tkecl:lb_getchildren \
375	       -nodelook tkecl:lbnode_look -expand 2 -selectmode single \
376	       -selectcmd tkecl:lbnode_info \
377	       -background white -selectbackground gray -root top \
378	       -paddepth 20 -padstack 3]
379
380	   set loadsel [button $treeframe.load -textvariable tkecl(lbloadtext) \
381                 -state disabled -command "tkecl:lb_load_module $tree"]
382
383	  set tf [frame $top.tf]
384	    set tlabel [label $tf.label -justify left -text \
385               "Type in a string to match, or predicate_name/arity:"]
386
387	    set tinput [entry $tf.input -bg white -width 86 \
388               -textvariable tkecl(help_input)]
389
390	    set t [text $tf.t -setgrid true -relief sunken \
391               -background white -width 86 \
392               -yscrollcommand "$tf.y set" -xscrollcommand "$tf.x set"]
393
394	    bind $tinput <Return> "tkecl:display_help $tinput $t"
395
396	    bind $t <Any-Key> "tkecl:readonly_keypress %A"   ;# read only
397	    bind $t <ButtonRelease-2> {break} ;# disable paste
398	    bind $t <Button-1> "tkecl:lb_insert_input $tinput $t"
399	    bind $t <Double-Button-1> "tkecl:display_help $tinput $t; break"
400
401	    $t configure -cursor left_ptr
402	    $t tag configure highlight -foreground blue -wrap none
403	    $t tag configure normal -lmargin2 0 -wrap none
404 	    $t tag configure heading -underline 1 -spacing1 5 -spacing3 5
405
406
407	pack $close -side bottom -fill x -expand true
408	pack $htmlinfo -side bottom -fill x -expand true
409	pack $top -side top -fill both -expand true
410          pane $treeframe $tf -orient horizontal -initfrac [list 0.4 0.6]
411	    pack $loadsel -side top -fill x
412	    pack $tree -side bottom -expand 1 -fill both
413
414	    pack $tlabel -side top -fill x
415	    pack $tinput -side top -fill x
416	    scrollbar $tf.y -orient vert -command "$t yview"
417	    pack $tf.y -side right -fill y
418	    scrollbar $tf.x -orient hori -command "$t xview"
419	    pack $tf.x -side bottom -fill x
420	    pack $t -side right -fill both -expand true
421
422	 ;#pack $treeframe -expand true -fill both -side left
423	 ;#pack $tf -expand true -fill both -side right
424
425	bind $lb <Alt-h> "tkecl:Get_helpfileinfo help $lb"
426	focus $tinput
427
428
429	balloonhelp $t "Help Information Window: displays description of ECLiPSe libraries or predicates\n selected from either the tree display or the entry window.\nSelect item from tree display to obtain short description here,\n or type in entry window for longer description of predicates.\nLeft click on any word to put it in entry\nDouble left-click to look word up directly"
430	balloonhelp $tinput "Entry window: enter a string to match built-in predicates, or Name/Arity for exact match."
431	balloonhelp $tree "Hierarchical tree display of available libraries and their exported interface.\nLibraries in blue are currently loaded, green are unloaded libraries.\n Left-click to select an item; Double left-click to expand and item;\n select an expanded item to display more information in information window."
432	balloonhelp $loadsel "This shows the currently selected library (if any) of the tree display.\nClick the load button to load the library."
433	balloonhelp $htmlinfo "On-line webpages of the ECLiPSe manual should be available at this URL.\nCopy it to a browser to view."
434	balloonhelp $close "Close this window."
435
436    } else {
437	tkinspect:RaiseWindow $lb
438    }
439}
440
441
442proc tkecl:lb_insert_input {tinput t} {
443    $tinput delete 0 end
444    $tinput insert end [$t get "current wordstart" "current wordend"]
445}
446
447proc tkecl:lb_load_module {tree} {
448    global tkecl
449
450    if {$tkecl(lbmodule) != ""} {
451	ec_rpcq_check [list lbnode_loadmodule $tkecl(lbmodule)] (()) tracer_tcl
452	$tree refresh
453    }
454}
455
456proc tkecl:lb_getchildren {tree path} {
457    return [lindex [ec_rpcq\
458    		[list expand_lbnode $path _] {([S*]_)} tracer_tcl] 2]
459
460}
461
462proc tkecl:lbnode_look {tree path isopen} {
463    foreach {pred in nodetext highlight isopen} \
464    	[ec_rpcq [list lbnode_display $path _ _] {([S*]__)} tracer_tcl] {
465          switch -exact -- $highlight {
466	      highlight {
467		  set colour #00b000
468	      }
469	      current {
470		  set colour blue
471	      }
472	      none {
473		  set colour black
474	      }
475	  }
476      }
477    return [list $nodetext {} {} $colour]
478}
479
480proc tkecl:lbnode_info {t selected prevsel} {
481    global tkecl
482
483    set lb .ec_tools.ec_libbrowse
484    $t centreitem $selected 0.1 0.9 0.0 1.0
485    set path [lindex [$t get $selected] 0]
486    set isopen [$t isopen $path]
487    foreach {infoitems tkecl(lbmodule)} [lrange \
488      [ec_rpcq [list lbnode_info $path $isopen _ _] {([S*]I__)} tracer_tcl]\
489      3 4] {break}
490     if {$tkecl(lbmodule) != ""} {
491	 set toplevel [lindex [ec_rpcq {get_flag toplevel_module _} (()_)] 2]
492	 set tkecl(lbloadtext) "load $tkecl(lbmodule) library into  module $toplevel"
493	 $lb.top.tframe.load configure -state normal
494     } else {
495	 set tkecl(lbloadtext) "No library selected"
496	 $lb.top.tframe.load configure -state disabled
497     }
498
499    $lb.top.tf.t tag remove highlight 1.0 end
500
501    foreach item $infoitems {
502
503	foreach {format text} $item {
504	    break
505	}
506        $lb.top.tf.t insert end $text [list $format highlight]
507	$lb.top.tf.t insert end "\n"
508    }
509    if {$infoitems != ""} {
510    ;# only insert newline if there are some infoitems
511	$lb.top.tf.t insert end "\n"
512	$lb.top.tf.t see end
513    }
514}
515
516proc tkecl:display_help {input text} {
517    global tkecl
518    $input selection range 0 end
519    $text tag remove highlight 1.0 end
520    $text configure -cursor watch ; update idletasks
521    $text insert end [lindex [ec_rpcq\
522	 [list gui_help_string $tkecl(help_input) _] (S_) tracer_tcl] 2]\
523	highlight
524    $text see end
525    $text configure -cursor left_ptr
526
527}
528
529
530#----------------------------------------------------------------------
531# Predicate properties window
532#----------------------------------------------------------------------
533
534set tkecl(predproppred) ""
535set tkecl(predpropmodule) ""
536
537proc tkecl:combo_add_modules {w} {
538    foreach item [tkecl:list_modules] {
539	$w add $item
540    }
541}
542
543proc tkecl:list_modules {} {
544    # use string because of shared variable
545    # fullstop at end in case we are in strict_iso context
546    lindex [ec_rpc_check {eclipse_language:setof(X,eclipse_language:current_module(X),L).}] 2 3
547}
548
549proc tkecl:popup_pred_prop {} {
550    global tkecl
551
552    set predprop .ec_tools.predprop
553    if ![winfo exists $predprop] {
554	toplevel $predprop
555	wm title $predprop "ECLiPSe Predicate Browser"
556
557	set tkecl(predpropwhich) defined
558	set tkecl(predpropauxfilter) 1
559	frame $predprop.f1 -relief raised -bd 1
560	combobox $predprop.which -click single \
561		-list {defined exported imported local visible} \
562		-listheight 5 \
563		-labeltext "Predicates " \
564		-textvariable tkecl(predpropwhich) -editable 0 \
565		-command tkecl:display_predicates
566	pack $predprop.which -in $predprop.f1 -side left -expand 1 -fill x
567
568	pack [checkbutton $predprop.filter -text "filter aux." \
569	         -variable tkecl(predpropauxfilter) \
570		 -command {tkecl:display_predicates dummy} \
571	     ] -in $predprop.f1 -side right  -expand 1 -fill x
572
573	set modules [tkecl:list_modules]
574	combobox $predprop.modules -list $modules -click single \
575		-labeltext " in module: " \
576		-listheight 6  \
577		-textvariable tkecl(predpropmodule) -editable 0 \
578		-command tkecl:display_predicates
579	pack $predprop.modules -in $predprop.f1 -side left -expand 1 -fill x
580
581	listbox $predprop.preds -width 20 \
582		-yscrollcommand "$predprop.vscroll set"
583	scrollbar $predprop.vscroll -command "$predprop.preds yview"
584	bind $predprop.preds <<ListboxSelect>> {+tkecl:display_predprops .ec_tools.predprop.preds}
585
586	bind $predprop.preds <Enter> "tkecl:listbox_search_init $predprop.preds"
587	bind $predprop.preds <Leave> "tkecl:listbox_search_exit $predprop.preds"
588	bind $predprop.preds <Control-KeyPress> {continue}
589	bind $predprop.preds <Control-Key-s> "tkecl:listbox_search $predprop.preds %A Control_S %X %Y"
590	bind $predprop.preds <KeyPress> "tkecl:listbox_search $predprop.preds %A %K %X %Y"
591
592	button $predprop.close -text Close -command "destroy $predprop"
593
594	frame $predprop.f2 -relief groove -bd 1
595	pack [label $predprop.predlabel -text "Properties of Predicate:"] -in $predprop.f2 -side top -fill x
596	pack [label $predprop.predname -relief sunken] -in $predprop.f2 -side top -fill x
597	tkecl:add_rb $predprop.f2 disabled auxiliary {off on}
598	tkecl:add_rb $predprop.f2 disabled defined {off on}
599	tkecl:add_rb $predprop.f2 disabled debugged {off on}
600	tkecl:add_rb $predprop.f2 disabled stability {static dynamic}
601	tkecl:add_rb $predprop.f2 disabled call_type {prolog external}
602	tkecl:add_rb $predprop.f2 disabled type {built_in user}
603	tkecl:add_rb $predprop.f2 disabled tool {off on}
604#	tkecl:add_rb $predprop.f2 disabled visibility {local imported exported global}
605	tkecl:add_rb $predprop.f2 disabled demon {off on}
606	tkecl:add_rb $predprop.f2 disabled parallel {off on}
607#	tkecl:add_rb $predprop.f2 disabled statistics {off on}
608	tkecl:add_rb $predprop.f2 active leash {stop notrace}
609	tkecl:add_rb $predprop.f2 active skip {off on}
610	tkecl:add_rb $predprop.f2 active start_tracing {off on}
611	tkecl:add_rb $predprop.f2 active spy {off on}
612
613	button $predprop.f2.show -text "Show source" -command tkecl:display_source
614	pack $predprop.f2.show -side top -fill x
615
616	pack $predprop.f1 -side top -expand 1 -fill x
617	pack $predprop.preds -side left -expand 1 -fill both
618	pack $predprop.vscroll -side left -fill y
619	pack $predprop.f2 -side top -expand 1 -fill x -padx 3 -pady 3 -ipadx 3 -ipady 3
620	pack $predprop.close -side top -fill x
621
622        balloonhelp $predprop.preds "Predicates list - select one to view its \
623	    properties\n (see manual for details on properties)\n\
624	    Typing in this window will search for matching predicate.\n\
625	    Type escape to stop search, or Control-S to find next."
626        balloonhelp $predprop.which "Type of predicates listed in predicates list.\n\
627	    click arrow on right to change type"
628        balloonhelp $predprop.modules "Module of predicates listed in predicates list.\n\
629	    click arrow on right to change module"
630        balloonhelp $predprop.predname "Name, operator and mode information for predicate if known"
631	bind $predprop <Alt-h> "tkecl:Get_helpfileinfo pred $predprop"
632        tkecl:display_predicates dummy
633    } else {
634	tkinspect:RaiseWindow $predprop
635    }
636
637}
638
639proc tkecl:display_predicates {dummy} {
640    global tkecl
641
642    set predprop .ec_tools.predprop
643    $predprop.preds delete 0 end
644    set preds [lindex [ec_rpcq_check [list \
645	    list_predicates $tkecl(predpropwhich) $tkecl(predpropmodule) $tkecl(predpropauxfilter) _] \
646            (()()I_) tracer_tcl] 4]
647    foreach item $preds {
648	$predprop.preds insert end $item
649    }
650}
651
652proc tkecl:add_rb {parent state name values} {
653    global tkecl
654#    frame $parent.$name -relief groove -bd 1
655    frame $parent.$name
656    label $parent.$name.label -text $name -anchor w -width 20
657    pack $parent.$name.label -side left
658    foreach val $values {
659	radiobutton $parent.$name.$val -text $val -variable tkecl(pp_$name) \
660		-value $val -anchor w -state $state -command "tkecl:update_predprop $name"
661	pack $parent.$name.$val -side left
662    }
663    pack $parent.$name -side top -fill x
664}
665
666proc tkecl:update_predprop {name} {
667    global tkecl
668    if {$tkecl(predproppred) != ""} {
669	;# only update if a predicate has been selected...
670	tkecl:set_pred_flag $tkecl(predproppred) $tkecl(predpropmodule) $name $tkecl(pp_$name)
671    }
672}
673
674proc tkecl:display_predprops {w} {
675    global tkecl
676
677    set selected [$w curselection]
678    if ![string match "" $selected] {
679	set tkecl(predproppred) [$w get $selected]
680    }
681    set home [tkecl:pred_flag_value $tkecl(predproppred) $tkecl(predpropmodule) definition_module]
682    set mode [tkecl:pred_flag_value $tkecl(predproppred) $tkecl(predpropmodule) mode]
683    .ec_tools.predprop.predname configure -text "$home : $mode"
684    foreach name {auxiliary call_type debugged defined leash \
685	    skip spy stability tool type demon parallel statistics start_tracing} {
686	set tkecl(pp_$name) [tkecl:pred_flag_value $tkecl(predproppred) $tkecl(predpropmodule) $name]
687    }
688    if [winfo exists .ec_source] {
689	tkecl:display_source
690    }
691}
692
693proc tkecl:pred_flag_value {pred module name} {
694    set result [ec_rpcq \
695    	[list flag_value $pred $name $module _] (S()()_) tracer_tcl]
696    # rpc can fail, return "" in that case
697    lindex $result 4
698}
699
700proc tkecl:set_pred_flag {pred module name value} {
701    ec_rpcq [list set_flag_string $pred $name $value $module] (S()()()) tracer_tcl
702}
703
704
705#----------------------------------------------------------------------
706# Predicate source window
707#----------------------------------------------------------------------
708
709proc tkecl:display_source {} {
710    global tkecl
711
712    if {$tkecl(predproppred) == ""} return
713
714    set res [ec_rpcq [list get_source_info $tkecl(predproppred) $tkecl(predpropmodule) _ _] (S()__) tracer_tcl]
715    switch $res {
716	throw -
717	fail {
718	    if [winfo exists .ec_tools.ec_tracer] {
719		set parent .ec_tools.ec_tracer
720	    } else {
721		set parent .
722	    }
723	    tk_messageBox -type ok -parent $parent -icon info -message "No source information found for $tkecl(predproppred) in module $tkecl(predpropmodule)."
724	    return
725	}
726	default {
727	    set file [lindex [lindex $res 3] 0]	;# atom type (singleton list)
728	    set offset [lindex $res 4]
729	}
730    }
731
732    tkecl:popup_tracer
733    if {$tkecl(source_debug,file) != $file} {
734	if {[tkecl:load_source_debug_file $file] == 0} {
735	    tk_messageBox -type ok -parent .ec_tools.ec_tracer -icon info -message "Can't load source file $file"
736	    return
737	}
738    }
739
740    set ec_tracer .ec_tools.ec_tracer.tab
741    $ec_tracer activate "Source Context"
742    incr offset   ;# increment to get pass newline normally at end of last item
743    set idx [$ec_tracer.source.context.text index "1.0 + $offset chars"]
744    $ec_tracer.source.context.text see $idx
745}
746
747
748proc tkecl:set_and_display_source {pred module} {
749    global tkecl
750    set tkecl(predproppred) $pred
751    set tkecl(predpropmodule) $module
752    tkecl:display_source
753}
754
755proc tkecl:display_source_for_callport {t} {
756    global tkecl
757
758    if {$tkecl(source_debug,file) == ""} return
759    set line [tkecl:get_current_text_line $t]
760    # Caution: the predicate expects an atom. For quoting-sensitive arguments
761    # like file names, we have to pass a 1-element list with the () type.
762    set res [ec_rpcq [list find_exact_callinfo [list $tkecl(source_debug,file)] $line _] (()I_) tracer_tcl]
763
764    switch $res {
765	throw -
766	fail {
767	    # no port at line, no action
768	    return
769	}
770	default {
771	    set callport [lindex $res 3]
772	}
773    }
774    set calldefmodule [lindex $callport 1]
775    set callspec [lindex $callport 2]
776    # need to convert spec to a string as that is expected
777    # no modle needed for call as only need '/'/2 to be defined normally
778    set predspecs [lindex [ec_rpcq \
779	[list term_string $callspec _] ((()I)_)] 2]
780    tkecl:set_and_display_source $predspecs $calldefmodule
781}
782
783#----------------------------------------------------------------------
784# Global settings window
785#----------------------------------------------------------------------
786
787proc tkecl:popup_global_state {} {
788    global tkecl
789
790    set gstate .ec_tools.gstate
791    if ![winfo exists $gstate] {
792	toplevel $gstate
793	wm withdraw $gstate
794	wm title $gstate "ECLiPSe Global Settings"
795
796	tkecl:add_radiobutton $gstate after_event_timer "real virtual"
797	tkecl:add_radiobutton $gstate breal_exceptions "off on"
798	tkecl:add_radiobutton $gstate coroutine "off on"
799	tkecl:add_radiobutton $gstate debugging "nodebug creep leap"
800	tkecl:add_radiobutton $gstate debug_compile "off on"
801	tkecl:add_radiobutton $gstate enable_interrupts "off on"
802	tkecl:add_radiobutton $gstate gc "off on verbose"
803	tkecl:add_radiobutton $gstate gc_policy "adaptive fixed"
804	tkecl:add_radiobutton $gstate goal_expansion "off on"
805	tkecl:add_radiobutton $gstate macro_expansion "off on"
806	tkecl:add_radiobutton $gstate prefer_rationals "off on"
807	tkecl:add_radiobutton $gstate variable_names "off on check_singletons"
808
809	tkecl:add_popupentry $gstate output_mode "tkecl:edit_output_mode global" Change {}
810	tkecl:add_entry $gstate gc_interval number I
811	tkecl:add_entry $gstate gc_interval_dict number I
812#    tkecl:add_entry $gstate output_mode none S
813	tkecl:add_entry $gstate print_depth number I
814#    tkecl:add_entry $gstate cwd none S
815	tkecl:add_popupentry $gstate cwd {tkecl:get_newcwd} Change S
816	tkecl:add_menuentry $gstate library_path tkecl:paths_menu Change S
817	button $gstate.close -text Close -command "destroy $gstate"
818	pack $gstate.close -side top -fill x
819	wm minsize $gstate 380 30
820	wm resizable $gstate 1 0
821	wm deiconify $gstate
822
823	balloonhelp $gstate "ECLiPSe global state - see manual for descriptions of flags"
824	balloonhelp $gstate.library_path "left click in entry to see all paths"
825	bind $gstate <Alt-h> "tkecl:Get_helpfileinfo glob $gstate"
826    } else {
827	tkinspect:RaiseWindow $gstate
828    }
829}
830
831
832proc tkecl:add_radiobutton {parent name values} {
833    global tkecl
834
835    set tkecl($name) [lindex [ec_rpcq_check [list get_flag $name _] (()_)] 2]
836#    frame $parent.$name -relief groove -bd 1
837    frame $parent.$name
838    label $parent.$name.label -text $name -anchor w -width 20
839    pack $parent.$name.label -side left
840    foreach val $values {
841	radiobutton $parent.$name.$val -text $val -variable tkecl($name) \
842		-value $val -anchor w -command "tkecl:set_flag $name ()"
843	pack $parent.$name.$val -side left
844    }
845    pack $parent.$name -side top -fill x
846}
847
848proc tkecl:add_popupentry {parent name command ctext exdr_type} {
849    global tkecl
850
851    set f [frame $parent.$name]
852    pack [label $f.label -text $name -anchor w -width 20] -side left
853    if {$exdr_type == ""} {
854	set info [label $f.val -justify right -relief groove -textvariable tkecl($name)]
855    } else {
856	set info [entry $f.val -bg white -justify right -relief sunken -textvariable tkecl($name)]
857	bind $f.val <Return> "tkecl:set_flag $name $exdr_type"
858    }
859    pack $info -side left -expand 1 -fill x
860#    bind $parent.$name.val <Return> "tkecl:set_flag $name S"
861    set tkecl($name) [lindex [ec_rpcq_check [list get_flag $name _] (()_)] 2]
862    pack [button $f.b -anchor e -text $ctext -command $command] -side right
863    pack $f -side top -fill x
864}
865
866proc tkecl:add_menuentry {parent name buildmenu mtext exdr_type} {
867    global tkecl
868
869    set f [frame $parent.$name]
870    pack [label $f.label -text $name -anchor w -width 20] -side left
871    if {$exdr_type == ""} {
872	set info [label $f.val -justify right -relief groove -textvariable tkecl($name)]
873    } else {
874	set info [entry $f.val -bg white -justify right -relief sunken -textvariable tkecl($name)]
875	bind $f.val <Return> "tkecl:set_flag $name $exdr_type"
876    }
877    pack $info -side left -expand 1 -fill x
878#    bind $parent.$name.val <Return> "tkecl:set_flag $name S"
879    set tkecl($name) [lindex [ec_rpcq_check [list get_flag $name _] (()_)] 2]
880    pack [menubutton $f.b -text $mtext -menu $f.b.m -relief raised] -side right
881    $buildmenu $f.b $name
882    pack $f -side top -fill x
883}
884
885proc tkecl:add_entry {parent name vtype exdr_type} {
886    global tkecl
887#    frame $parent.$name -relief groove -bd 1
888    switch -exact -- $vtype {
889	number {
890	    set vstring {regexp {^[0-9]*$} %P}
891	}
892	none {
893	    set vstring {regexp {.*} %P}
894	}
895    }
896    frame $parent.$name
897    label $parent.$name.label -text $name -anchor w -width 20
898    set tkecl($name) [lindex [ec_rpcq_check [list get_flag $name _] (()_)] 2]
899    if {$exdr_type != ""} {
900	ventry $parent.$name.val -bg white -justify right -relief sunken -textvariable tkecl($name) -validate key -invalidcmd bell -vcmd $vstring
901	bind $parent.$name.val <Return> "tkecl:set_flag $name $exdr_type"
902    } else {
903	entry $parent.$name.val -relief groove -justify right -textvariable tkecl($name)
904	bind $parent.$name.val <Any-Key> {break}
905	bind $parent.$name.val <Button-2> {break}
906	bind $parent.$name.val <ButtonRelease-2> {break}
907	bind $parent.$name.val <Button-1> {break}
908    }
909    pack $parent.$name.label -side left
910    pack $parent.$name.val -side right -expand 1 -fill x
911    pack $parent.$name -side top -fill x
912}
913
914# Set eclipse flag name from the tcl variable $tkecl(name)
915proc tkecl:set_flag {name exdr_type} {
916    global tkecl
917    ec_rpcq_check [list set_flag $name $tkecl($name)] (()$exdr_type)
918}
919
920
921#----------------------------------------------------------------------
922# Change output modes and print depth (both global and tracer settings)
923#----------------------------------------------------------------------
924
925set tkecl(output_mode_spec_nr) 7
926set tkecl(output_mode_spec) {
927	{{Variables}		{"" v V _}	{"X" "_123" "X_123" "_"}}
928	{{Attributes}		{"" m M}	{none pretty full}}
929	{{Operators}		{"" O}		{1+2 +(1,2)}}
930	{{Spaces}		{"" K}		{"a,  b" "a,b"}}
931	{{Quoting}		{"" Q}		{A 'A'}}
932	{{Lists}		{"" .}		{{[a,b|_]} {.(a,.(b,_))}}}
933	{{Use portray/1,2  }	{"" P}		{no yes}}
934	{{Transformations  }	{T ""}		{no yes}}
935}
936# These are almost never used and mostly confusing for the user:
937#	{{Treat as clause}	{"" C}		{no yes}}
938#	{{Treat as goal}	{"" G}		{no yes}}
939
940
941proc tkecl:edit_output_mode {which} {
942    global tkecl
943    set w .ec_tools.ec_om_$which
944    if [winfo exists $w] {
945	tkinspect:RaiseWindow $w
946	return
947    }
948
949    # get the old settings
950    switch -- $which {
951	tracer {
952	    set title "Tracer Output Options"
953	    set tkecl(prdepth_$which) [lindex [ec_rpcatq\
954		{getval dbg_print_depth _} (()_) tracer_tcl] 2]
955	    set oldmode [lindex [ec_rpcq_check {get_tracer_output_modes _}\
956		(_) tracer_tcl] 1]
957	}
958	global {
959	    set title "Global Output Options"
960	    set tkecl(prdepth_$which) [lindex [ec_rpcq_check\
961		{get_flag print_depth _} (()_) ] 2]
962	    set oldmode [lindex [ec_rpcq_check\
963		{get_flag output_mode _} (()_) ] 2]
964	}
965    }
966
967    toplevel $w
968    wm transient $w .
969    wm title $w $title
970
971    # Make radiobuttons for the different options, linked to
972    # variables tkecl(om_$which0)..tkecl(om_$which$tkecl(output_mode_spec_nr))
973    frame $w.flags -relief raised -bd 1
974    set row 0
975    foreach descr $tkecl(output_mode_spec) {
976	# set the button variables according to the old mode
977	set tkecl(om_$which$row) ""
978	foreach letter [lindex $descr 1] {
979	    set occ [string first $letter $oldmode]
980	    if {$occ >= 0} {
981		set oldmode [string replace $oldmode $occ $occ {}]
982		set tkecl(om_$which$row) $letter
983	    }
984	}
985	grid [label $w.flags.label$row -text [lindex $descr 0]] -row $row -column 0 -sticky w
986	set rb_name $w.flags.rb$row
987	append rb_name _
988	set col 1
989	foreach val [lindex $descr 1] what [lindex $descr 2] {
990	    grid [radiobutton $rb_name$col -text $what -value $val -variable tkecl(om_$which$row)] \
991	    	-row $row -column $col -sticky w
992	    incr col
993	}
994	incr row
995    }
996    # Make a scale and a "full"-checkbutton for the print depth
997    label $w.label$row -text "Print depth"
998    scale $w.scale -from 0 -to 100 -orient horizontal \
999    	-tickinterval 10 -length 60m  -sliderlength 4m \
1000	-variable tkecl(prdepth_$which)
1001    set occ [string first "D" $oldmode]
1002    if {$occ >= 0} {
1003	set oldmode [string replace $oldmode $occ $occ {}]
1004	set tkecl(om_fullpd$which) D
1005    } else {
1006	set tkecl(om_fullpd$which) {}
1007    }
1008    checkbutton $w.fulldepth -text full -offvalue {} -onvalue D \
1009    	-variable tkecl(om_fullpd$which) -command "tkecl:toggle_scale om_fullpd$which $w.scale"
1010
1011    frame $w.buttons
1012    pack [button $w.buttons.apply -text Apply -command [list tkecl:apply_output_mode $which $oldmode]] -side left -expand 1 -fill both
1013    pack [button $w.buttons.cancel -text Cancel -command "destroy $w"] -side left -expand 1 -fill both
1014    pack [button $w.buttons.ok -text Ok -command "[list tkecl:apply_output_mode $which $oldmode] ; destroy $w"] -side left -expand 1 -fill both
1015
1016    pack $w.flags -side top -expand 1 -fill both
1017    pack $w.buttons -side bottom -expand 1 -fill both
1018    pack $w.label$row -side left -expand 1 -fill both
1019    pack $w.scale -side left
1020    pack $w.fulldepth -side left
1021}
1022
1023# the scale is only active if the "full" button is not checked
1024proc tkecl:toggle_scale {var scale} {
1025    global tkecl
1026    if [string match "" $tkecl($var)] {
1027    	$scale configure -state normal -foreground black
1028    } else {
1029    	$scale configure -state disabled -foreground grey
1030    }
1031}
1032
1033proc tkecl:apply_output_mode {which newmode} {
1034    global tkecl
1035    # newmode contains the remainder of oldmode that was ignored by the gui
1036    for {set i 0} {$i <= $tkecl(output_mode_spec_nr)} {incr i} {
1037        append newmode $tkecl(om_$which$i)
1038    }
1039    append newmode $tkecl(om_fullpd$which)
1040
1041    switch -- $which {
1042	tracer {
1043	    ec_rpcq_check [list set_tracer_output_modes $newmode] (S) tracer_tcl
1044	    ec_rpcq_check [list set_tracer_print_depth $tkecl(prdepth_$which)] (I) tracer_tcl
1045	    tkecl:refresh_current_trace_line
1046	}
1047	global {
1048	    ec_rpcq_check [list set_flag output_mode $newmode] (()S)
1049	    ec_rpcq_check [list set_flag print_depth $tkecl(prdepth_$which)] (()I)
1050	    # these two are only for updating the Global Settings window:
1051	    set tkecl(output_mode) $newmode
1052	    set tkecl(print_depth) $tkecl(prdepth_$which)
1053	}
1054    }
1055}
1056
1057
1058#----------------------------------------------------------------------
1059# Files window
1060#----------------------------------------------------------------------
1061
1062proc tkecl:compile_popup {dir} {
1063
1064    set file [tkecl:getEcFile $dir "Compile File"]
1065
1066    if {$file != ""} {
1067	tkecl:compile_file $file
1068    }
1069}
1070
1071proc tkecl:xref_popup {} {
1072
1073    set file [tkecl:getEcFile [pwd] "Xref File"]
1074
1075    if {$file != ""} {
1076	if {[file exists $file] && [file readable $file]} {
1077	    set file [lindex [ec_rpcq [list os_file_name _ $file] (_S)] 1]
1078	    ec_rpcq [list xref $file [list [list : output graphviz]]] \
1079		   {(S[(()())])} xref
1080	} else {
1081	    tk_messageBox -icon error -type ok -message "Cannot access file $file"
1082	}
1083    }
1084}
1085
1086proc tkecl:lint_popup {} {
1087
1088    set file [tkecl:getEcFile [pwd] "Lint File"]
1089
1090    if {$file != ""} {
1091	if {[file exists $file] && [file readable $file]} {
1092	    set file [lindex [ec_rpcq [list os_file_name _ $file] (_S)] 1]
1093	    ec_rpcq [list lint $file] (S) lint
1094	} else {
1095	    tk_messageBox -icon error -type ok -message "Cannot access file $file"
1096	}
1097    }
1098}
1099
1100proc tkecl:compile_file {file {module ""}} {
1101    if {$file != ""} {
1102	if {$module == ""} {
1103	    set module [lindex [ec_rpcq_check {get_flag toplevel_module _} (()_) ] 2]
1104	}
1105	if {[file exists $file] && [file readable $file]} {
1106	    ec_rpcq [list compile_os_file $file $module] (S()) tracer_tcl
1107	} else {
1108	    tk_messageBox -icon error -type ok -message "Cannot access file $file"
1109	}
1110	tkecl:refresh_file_window
1111    }
1112}
1113
1114proc tkecl:use_module_popup {} {
1115
1116    set file [tkecl:getEcFile [pwd] "Use Module"]
1117
1118    if {$file != ""} {
1119	tkecl:use_module $file
1120    }
1121}
1122
1123proc tkecl:use_module {file {module ""}} {
1124    if {$file != ""} {
1125	if {$module == ""} {
1126	    set module [lindex [ec_rpcq_check {get_flag toplevel_module _} (()_) ] 2]
1127	}
1128	if {[file exists $file] && [file readable $file]} {
1129	    ec_rpcq [list use_module_os $file $module] (S()) tracer_tcl
1130	} else {
1131	    tk_messageBox -icon error -type ok -message "Cannot access file $file"
1132	}
1133	tkecl:refresh_file_window
1134    }
1135}
1136
1137proc tkecl:edit_popup {} {
1138
1139    set file [tkecl:getEcFile [pwd] "Edit File"]
1140
1141    if {$file != ""} {
1142	tkecl:edit_file $file
1143	tkecl:add_source_file $file
1144    }
1145}
1146
1147proc tkecl:edit_new_popup {} {
1148
1149    set file [tkecl:getNewEcFile [pwd] "New Source File"]
1150
1151    if {$file != ""} {
1152	tkecl:edit_file $file
1153	tkecl:add_source_file $file
1154    }
1155}
1156
1157proc tkecl:edit_file {file {line -1}} {
1158    global tkecl
1159
1160    if {$tkecl(pref,editor) == ""} {
1161	tk_messageBox -icon error -type ok -message "Cannot start an editor, as none is defined.\nDefine a third-party text editor using\nTools->'TkECLiPSe Preference Editor'\nto edit programs."
1162	return
1163    }
1164    if {![file exists $file]} {
1165	# Create the file (some editors require it)
1166	close [open $file w]
1167    }
1168    if {$line != -1 && $tkecl(pref,edit_line_option) != ""} {
1169	eval [list exec $tkecl(pref,editor) $tkecl(pref,edit_line_option)$line $file &]
1170    } else {
1171	eval [list exec $tkecl(pref,editor) $file &]
1172    }
1173}
1174
1175proc tkecl:popup_file_window {} {
1176
1177    set ec_files .ec_tools.ec_files
1178    if ![winfo exists $ec_files] {
1179	toplevel $ec_files
1180	wm title $ec_files "ECLiPSe Source File Manager"
1181
1182	listbox $ec_files.names -selectmode single -width 20 -height 25\
1183		-yscrollcommand "tkecl:scroll_lb_sb $ec_files.state $ec_files.vscroll"
1184	listbox $ec_files.state -selectmode browse -width 11 -height 25\
1185		-yscrollcommand "tkecl:scroll_lb_sb $ec_files.names $ec_files.vscroll"
1186	scrollbar $ec_files.vscroll -command "tkecl:scroll_lb_lb $ec_files.names $ec_files.state"
1187	bind $ec_files.names <Double-Button-1> {
1188	    tkecl:edit_file [.ec_tools.ec_files.names get [.ec_tools.ec_files.names curselection]]
1189	}
1190
1191	frame $ec_files.buttons
1192	button $ec_files.buttons.browse -text "Add file" -command {
1193	    set file [tkecl:getEcFile [pwd] "Add Source File"]
1194
1195		if {$file != ""} [list tkecl:add_source_file $file]
1196	    }
1197	    pack $ec_files.buttons.browse -side left -fill x -expand 1
1198	button $ec_files.buttons.edit -text Edit -command {
1199		set sel [.ec_tools.ec_files.names curselection]
1200		if {$sel != ""} {
1201		    tkecl:edit_file [.ec_tools.ec_files.names get $sel]
1202		} else {
1203		    set file [tkecl:getNewEcFile "" "New Source File"]
1204
1205		    if {$file != ""} {
1206			;# add_source done later in case edit_file fails
1207			tkecl:edit_file $file
1208			tkecl:add_source_file $file
1209		    }
1210		}}
1211	    pack $ec_files.buttons.edit -side left -fill x -expand 1
1212	button $ec_files.buttons.compile -text Compile -command {
1213		set sel [.ec_tools.ec_files.names curselection]
1214		if {$sel != ""} {
1215		    tkecl:compile_file [.ec_tools.ec_files.names get $sel]
1216		} else {
1217		    tkecl:compile_popup [pwd]
1218		}}
1219	    pack $ec_files.buttons.compile -side left -fill x -expand 1
1220	button $ec_files.buttons.refresh -text Redisplay -command tkecl:refresh_file_window
1221	    pack $ec_files.buttons.refresh -side left -fill x -expand 1
1222	button $ec_files.buttons.make -text Make -command {
1223	    	ec_rpcq_check make ()
1224	    	ec_rpcq_check {flush output} (())
1225	    	ec_rpcq_check {flush error} (())
1226		tkecl:refresh_file_window }
1227	    pack $ec_files.buttons.make -side left -fill x -expand 1
1228	button $ec_files.buttons.close -text Close -command "destroy $ec_files"
1229	    pack $ec_files.buttons.close -side left -fill x -expand 1
1230
1231	pack $ec_files.buttons -side bottom -fill x
1232	pack $ec_files.vscroll -side left -fill y
1233	pack $ec_files.names -side left -fill both -expand 1
1234	pack $ec_files.state -side left -fill y
1235	balloonhelp $ec_files.names "ECLiPSe source files - files tracked by ECLiPSe for compilation by `make'"
1236	balloonhelp $ec_files.state "`ok' - previously compiled file\n \
1237		`modified' - previously compiled file that has been modified \
1238		(will be recompiled with `make')\n `new' - file names added to source list \
1239		(will not be compiled by `make' until it is explicitly compiled first)"
1240	balloonhelp $ec_files.buttons.browse "Add a file to list"
1241	balloonhelp $ec_files.buttons.edit "edit a file. If file is not in source list, it will be added."
1242	balloonhelp $ec_files.buttons.compile "compile selected file from source list"
1243	balloonhelp $ec_files.buttons.refresh "Refresh display - update status of files in source list"
1244	bind $ec_files <Alt-h> "tkecl:Get_helpfileinfo file $ec_files "
1245    } else {
1246	tkinspect:RaiseWindow $ec_files
1247    }
1248    tkecl:refresh_file_window
1249}
1250
1251proc tkecl:add_source_file {file} {
1252    ec_rpcq_check [list record_source_file $file] (S) tracer_tcl
1253    tkecl:refresh_file_window
1254}
1255
1256proc tkecl:scroll_lb_lb {lb1 lb2 args} {
1257    eval "$lb1 yview $args"
1258    eval "$lb2 yview $args"
1259}
1260
1261proc tkecl:scroll_lb_sb {lb sb from to} {
1262    $lb yview moveto $from
1263    $sb set $from $to
1264}
1265
1266proc tkecl:refresh_file_window {} {
1267
1268    set ec_files .ec_tools.ec_files
1269    if [winfo exists $ec_files] {
1270	$ec_files.names delete 0 end
1271	$ec_files.state delete 0 end
1272	set files [lindex [ec_rpcq_check {list_files _} (_) tracer_tcl] 1]
1273	foreach item [lsort -index 0 $files] {
1274	    $ec_files.names insert end [lindex $item 0]
1275	    $ec_files.state insert end [lindex $item 1]
1276	}
1277	# adjust view such that nothing is hidden to the right
1278	set current [.ec_tools.ec_files.names xview]
1279	.ec_tools.ec_files.names xview moveto [expr 1 - [lindex $current 1] + [lindex $current 0]]
1280    }
1281}
1282
1283
1284#----------------------------------------------------------------------
1285# Delayed goals
1286#----------------------------------------------------------------------
1287
1288proc tkecl:popup_dg_window {} {
1289    global tkecl
1290
1291    set ec_dg .ec_tools.ec_dg
1292    if ![winfo exists $ec_dg] {
1293	toplevel $ec_dg
1294	wm title $ec_dg "ECLiPSe Delayed Goals"
1295
1296	set tkecl(dg_select_triggers) 0
1297	set tkecl(dg_trigger) postponed
1298
1299	text $ec_dg.text -bg white -yscrollcommand "$ec_dg.vscroll set" -wrap none -xscrollcommand "$ec_dg.hscroll set"
1300	scrollbar $ec_dg.vscroll -command "$ec_dg.text yview"
1301	scrollbar $ec_dg.hscroll -command "$ec_dg.text xview" -orient horizontal
1302
1303	set ff [frame $ec_dg.filters]
1304	pack [checkbutton $ff.traced -text "traced only" -variable tkecl(pref,dgf_tracedonly)] -side left
1305	pack [checkbutton $ff.spied -text "spied only" -variable tkecl(pref,dgf_spiedonly)] -side left
1306	pack [checkbutton $ff.wake -text "scheduled only" -variable tkecl(pref,dgf_wakeonly)] -side left
1307	set tf [frame $ff.triggers -relief ridge -borderwidth 2]
1308	pack [combobox $tf.triggers -click single -listheight 5 -bg white \
1309		  -postcommand "tkecl:dg_get_triggers $tf.triggers" \
1310		  -textvariable tkecl(dg_trigger) -editable 0 -click single \
1311		  -labeltext "Select from triggers:" -state disabled] \
1312	    -expand y -side right -fill x
1313	pack [checkbutton $tf.select_trig -variable tkecl(dg_select_triggers) \
1314		  -command "tkecl:select_dg_triggers $tf.triggers"] -side left
1315	pack $tf -side right -expand y -fill x
1316
1317	menu $ec_dg.mbar
1318	$ec_dg config -menu $ec_dg.mbar
1319	menu $ec_dg.mbar.options
1320	$ec_dg.mbar add cascade -label Options -menu $ec_dg.mbar.options
1321	$ec_dg.mbar.options add command -label "Change print options ..." -command "tkecl:edit_output_mode tracer"
1322	$ec_dg.mbar.options add check -label "Refresh delayed goals at every trace line" -variable tkecl(pref,trace_refresh_dg)
1323	menu $ec_dg.mbar.help
1324	$ec_dg.mbar add cascade -label Help -menu $ec_dg.mbar.help
1325        $ec_dg.mbar.help add command -label "Delayed Goals Help" -command "tkecl:Get_helpfileinfo dela $ec_dg"
1326
1327	frame $ec_dg.buttons
1328	button $ec_dg.buttons.refresh -text Refresh -command {tkecl:refresh_dg}
1329	    pack $ec_dg.buttons.refresh -side left -fill x -expand 1
1330	button $ec_dg.buttons.close -text Close -command "destroy $ec_dg"
1331	    pack $ec_dg.buttons.close -side left -fill x -expand 1
1332
1333	pack $ec_dg.filters -side top -fill x
1334	pack $ec_dg.buttons -side bottom -fill x
1335	pack $ec_dg.vscroll -side left -fill y
1336	pack $ec_dg.hscroll -side bottom -fill x
1337	pack $ec_dg.text -expand 1 -fill both
1338	bind $ec_dg.text <Any-Key> "tkecl:readonly_keypress %A"
1339	bind $ec_dg.text <ButtonRelease-2> {break}
1340
1341	balloonhelp $ec_dg.text "Delayed goals are displayed here. Green indicates goal has been scheduled.\n Right (or control-left) click on goal for a popup menu related to that goal and\n double left click to inspect goal (only if goal has invocation number)."
1342	balloonhelp $ec_dg.buttons "List of goals that are currently being delayed.\n\
1343		Can be set to automatically refresh at every trace line from tracer window."
1344	balloonhelp $ff "Filter options for filtering displayed delayed goals."
1345	balloonhelp $ff.traced "Show only goals which can be traced when selected."
1346	balloonhelp $ff.spied "Show only goals which are being spied when selected."
1347	balloonhelp $ff.wake "Show only goals which have been scheduled when selected."
1348	balloonhelp $tf "Show only goals which have been suspended on a global trigger.\n Select the trigger from the list."
1349	bind $ec_dg <Alt-h> "tkecl:Get_helpfileinfo dela $ec_dg"
1350    } else {
1351	tkinspect:RaiseWindow $ec_dg
1352    }
1353    tkecl:refresh_dg
1354}
1355
1356proc tkecl:refresh_dg {} {
1357    global tkecl
1358
1359    set ec_dg .ec_tools.ec_dg
1360    if [winfo exists $ec_dg] {
1361	$ec_dg.text delete 1.0 end
1362	eval $ec_dg.text tag delete [$ec_dg.text tag names]
1363	$ec_dg.text tag configure highlight -foreground #00b000
1364	$ec_dg.text tag configure truncated -background pink
1365	ec_rpcq_check [list gui_dg\
1366			$tkecl(dg_select_triggers)\
1367			$tkecl(dg_trigger)\
1368			[list dg_filter\
1369			    $tkecl(pref,dgf_tracedonly)\
1370			    $tkecl(pref,dgf_spiedonly)\
1371			    $tkecl(pref,dgf_wakeonly)]]\
1372		   (I()(III)) tracer_tcl
1373    }
1374}
1375
1376proc tkecl:handle_dg_print {stream {length {}}} {
1377    global tkecl
1378
1379    set gui_dg_info [ec_streamnum_to_channel $stream]
1380    set info [ec_read_exdr $gui_dg_info]
1381    while {$info != "end"} {
1382	set state [lindex $info 1]
1383	set prio [lindex $info 2]
1384	set invoc [lindex $info 3]
1385	set linelength [lindex $info 4]
1386	set line [lindex $info 5]
1387	if {$state == 1} {
1388	    set Tag highlight
1389	} else {
1390	    set Tag {}
1391	}
1392
1393	set ec_dg .ec_tools.ec_dg
1394	if [winfo exists $ec_dg] {
1395	    if {[string length $line] >= $tkecl(pref,text_truncate)} {
1396		set line [string range $line 0 $tkecl(pref,text_truncate)]
1397		set truncated 1
1398	    } else {
1399		set truncated 0
1400	    }
1401	    set gstart [$ec_dg.text index end]
1402	    $ec_dg.text insert end $line $Tag
1403	    if $truncated {
1404		$ec_dg.text insert end "..." truncated
1405	    }
1406	    $ec_dg.text tag bind g$invoc <Button-3> "tkecl:popup_delaymenu $ec_dg.text $invoc $prio %X %Y; break"
1407	    $ec_dg.text tag bind g$invoc <Control-Button-1> "tkecl:popup_delaymenu $ec_dg.text $invoc $prio %X %Y; break"
1408	    $ec_dg.text tag bind g$invoc <Double-Button-1> "tkinspect:Inspect_term_init invoc($invoc); break"
1409	    $ec_dg.text tag add g$invoc $gstart "$gstart lineend"
1410	    $ec_dg.text tag raise g$invoc
1411	}
1412	set info [ec_read_exdr $gui_dg_info]
1413    }
1414}
1415
1416proc tkecl:select_dg_triggers {w} {
1417    global tkecl
1418
1419    if {$tkecl(dg_select_triggers) == 1} {
1420	$w configure -state normal
1421	$w configure -editable 0
1422    } else {
1423	$w configure -state disabled
1424    }
1425}
1426
1427proc tkecl:dg_get_triggers {w} {
1428
1429    $w configure -list [lindex [ec_rpcq [list get_triggers _] (_) tracer_tcl] 1]
1430}
1431
1432proc tkecl:popup_delaymenu {w invoc prio x y} {
1433    global tkecl
1434
1435    if [winfo exists $w.gpopup] {
1436	destroy $w.gpopup
1437    }
1438    set m [menu $w.gpopup -tearoff 0]
1439
1440    if {$invoc != 0} {
1441	set greturn [ec_rpcq_check [list get_goal_info_by_invoc $invoc _ _ _ _ _ _ _] (I_______) tracer_tcl]
1442	set spec [lindex  $greturn 2]
1443	set tspec [lindex $greturn 3]
1444	set module [lindex $greturn 4]
1445	;# spec should be Name/Arity if valid
1446	if {$spec != "unknown"} {
1447	    set spied [tkecl:pred_flag_value $spec $module spy]
1448	    if {$spied == "on"} {
1449		set spytext "Nospy $spec"
1450		set spyval off
1451	    } else {
1452		set spytext "Spy $spec"
1453		set spyval on
1454	    }
1455	    if {$invoc != 0} {
1456		set invtext "($invoc)"
1457	    } else {
1458		set invtext ""
1459	    }
1460	    $m add command -label "$tspec @ $module $invtext <$prio>" -state disabled
1461	    $m add command -label $spytext -command \
1462		    [list tkecl:set_pred_flag $spec $module spy $spyval]
1463	    $m add command -label "Display source for this predicate" -command \
1464		    [list tkecl:set_and_display_source $spec $module]
1465	    $m add command -label "Inspect this goal" -command \
1466		    "tkinspect:Inspect_term_init invoc($invoc)"
1467	    $m add command -label "Observe this goal" -command "tkecl:observe_goal $invoc"
1468	} else {
1469	    $m add command -label "No goal found for invocation $invoc. Please refresh." \
1470		    -state disabled
1471	}
1472    } else {
1473	$m add command -label "Goal information unavailable: please use tracer." \
1474		-state disabled
1475    }
1476
1477    tk_popup $m $x $y
1478}
1479
1480
1481#----------------------------------------------------------------------
1482# Tracer
1483#----------------------------------------------------------------------
1484
1485proc tkecl:set_fail_invoc {invoc} {
1486    global tkecl
1487
1488    set tkecl(fail_invoc) $invoc
1489    tkecl:set_tracercommand f
1490}
1491
1492proc tkecl:set_jumpto_invoc {invoc} {
1493    global tkecl
1494
1495    if [regexp -- {^[0-9]+$} $invoc]  {
1496	set tkecl(cont_invoc) $invoc
1497	tkecl:set_tracercommand i
1498    }
1499}
1500
1501proc tkecl:set_jumpto_depth {depth} {
1502    global tkecl
1503
1504    if [regexp -- {^[0-9]+$} $depth]  {
1505	set tkecl(cont_mindepth) $depth
1506	set tkecl(cont_maxdepth) $depth
1507	tkecl:set_tracercommand j
1508    }
1509}
1510
1511proc tkecl:setup_creep {} {
1512    global tkecl
1513
1514    set tkecl(press_creep) 1
1515    tkecl:set_tracercommand c
1516}
1517
1518proc tkecl:end_creep {} {
1519    global tkecl
1520
1521    after cancel $tkecl(creepwaitevent)
1522    set tkecl(press_creep) 0
1523    set tkecl(creepwaitover) 1
1524}
1525
1526proc tkecl:analyze_failure {parent} {
1527    global tkecl
1528
1529    set result [ec_rpcq {failure_culprit _ _} (__) sepia_kernel]
1530    switch $result {
1531	throw -
1532	fail {
1533	    tk_messageBox -type ok -icon info -parent $parent \
1534		    -message "No failure culprit stored yet"
1535	}
1536	default {
1537	    set fculprit [lindex $result 1]
1538	    set invoc   [lindex $result 2]
1539	    if { $fculprit > $invoc } {
1540		set answer [ tk_messageBox -type yesno -icon question -parent $parent \
1541			-message "Most recent failure was caused by goal with invocation number ($fculprit).\
1542			Do you want to jump there now?" ]
1543		switch $answer {
1544		    yes { tkecl:set_jumpto_invoc $fculprit }
1545		}
1546	    } elseif {[string match $tkecl(tracer_state) disabled]} {
1547		tk_messageBox -type ok -icon info -parent $parent \
1548			-message "Most recent failure was caused by goal with invocation number ($fculprit).\
1549			To jump there\n\
1550			1. re-run the query\n\
1551			2. select \"Analyze failure\" immediately"
1552	    } elseif {$fculprit == $invoc && ![regexp $tkecl(current_port) fail|leave] } {
1553		tk_messageBox -type ok -icon info -parent $parent \
1554			    -message "Most recent failure was caused by goal with invocation number ($fculprit).\
1555			    This is the goal you are currently at."
1556	    } else {
1557		tk_messageBox -type ok -icon info -parent $parent \
1558		    -message "Most recent failure was caused by goal with invocation number ($fculprit).\
1559		    To jump there\n\
1560		    1. click \"Abort\" or \"Nodebug\"\n\
1561		    2. re-run the query\n\
1562		    3. select \"Analyze failure\" immediately"
1563	    }
1564	}
1565    }
1566}
1567
1568proc tkecl:kill_tracer {} {
1569    set ec_tracer .ec_tools.ec_tracer
1570
1571    if [winfo exists $ec_tracer] {
1572	destroy $ec_tracer
1573    }
1574}
1575
1576proc tkecl:refresh_current_trace_line {} {
1577    global tkecl
1578
1579    set ec_tracer .ec_tools.ec_tracer
1580    if ![winfo exists $ec_tracer] return
1581
1582    tkecl:edit_output_mode tracer
1583    set trace_info [ec_rpcq [list get_current_traceline _ _ _ _] (____) tracer_tcl]
1584    set invoc [lindex $trace_info 4]
1585    set style [lindex $trace_info 2]
1586    if {$style == "fail_style"} return ;# no point refreshing if failure/abort
1587    set depth [expr [lindex $trace_info 1] + 1]
1588    set line  [lindex $trace_info 3]
1589    if {[string length $line] >= $tkecl(pref,text_truncate)} {
1590	set truncated 1
1591	set line [string range $line 0 $tkecl(pref,text_truncate)]
1592    } else {
1593	set truncated 0
1594    }
1595
1596    ;# only refresh current trace line if the current line has the same tag
1597    ;# (invocation number) as the current debug goal from ECLiPSe
1598    if {[lsearch [$ec_tracer.stack.text tag names $depth.0] $invoc] != -1} {
1599	$ec_tracer.stack.text delete $depth.0 "$depth.end+1 char"
1600	$ec_tracer.stack.text insert $depth.0 $line $style
1601	if $truncated {
1602	    $ec_tracer.stack.text insert end "..." truncate_style
1603	}
1604	$ec_tracer.stack.text insert $depth.end "\n" $style
1605	;# add the tag back to the refreshed line...
1606	$ec_tracer.stack.text tag add $invoc $depth.0 $depth.end
1607	$ec_tracer.stack.text tag raise $invoc
1608    }
1609}
1610
1611proc tkecl:popup_tracer {} {
1612    global tkecl
1613
1614    set ec_tracer .ec_tools.ec_tracer
1615    if ![winfo exists $ec_tracer] {
1616	toplevel $ec_tracer
1617	wm title $ec_tracer "ECLiPSe Tracer"
1618
1619	# initialize global tracer variables
1620	set tkecl(tracercommand) N
1621	set tkecl(tracercommand_issued) 0
1622	set tkecl(current_port) ....
1623	set tkecl(next_trace_line_depth) 1
1624	set tkecl(press_creep) 0
1625	set tkecl(creepwaitevent) 0
1626	set tkecl(cont_invoc) 0
1627	set tkecl(cont_mindepth) 0
1628	set tkecl(cont_maxdepth) 9999
1629	set tkecl(zap_port) {Not Current}
1630	set tkecl(filter_predtype) any
1631	set tkecl(filter_predmodule2) eclipse
1632	set tkecl(filter_mininvoc) 0
1633	set tkecl(filter_maxinvoc) 999999999
1634	set tkecl(filter_mindepth) 0
1635	set tkecl(filter_maxdepth) 999999999
1636	set tkecl(filter_count) 1
1637	set tkecl(filter_hits) 0
1638	set tkecl(portlist) [lindex [ec_rpcq_check {debug_port_names _} (_) sepia_kernel] 1]
1639	set tkecl(portsets) {all none current previous entering exiting failing}
1640	set tkecl(portset,current) $tkecl(portlist)
1641	set tkecl(portset,previous) $tkecl(portlist)
1642	set tkecl(portset,all) $tkecl(portlist)
1643	set tkecl(portset,none) {}
1644	set tkecl(portset,entering) {call redo resume}
1645	set tkecl(portset,exiting) {exit *exit fail leave}
1646	set tkecl(portset,failing) {fail next else}
1647	foreach port $tkecl(portlist) {
1648	    set tkecl(filter_port,$port) 1
1649	}
1650
1651	# filter,changable is a list of filter properties for the tracer filter
1652        # that can be changed for a filter command. Each property is
1653        # represented by the variables tkecl(filter_<name>) (current value) and
1654        # tkecl(filter_last<name>) (previous value). The last values are for
1655        # determining if the property has been changed since the last filter
1656	set tkecl(filter,changable) \
1657            [list mininvoc maxinvoc mindepth maxdepth  wanted_ports predtype]
1658	# filterpred are the properties for the `specific predicate instance'
1659        # filter. These are treated separately from the other filter properties
1660	set tkecl(filterpred,changable) \
1661            [list predcondition predmatch predmodule predmodule2]
1662	foreach filterprop $tkecl(filter,changable) {
1663	    set tkecl(filter_last$filterprop) {}
1664	}
1665	foreach filterprop $tkecl(filterpred,changable) {
1666	    set tkecl(filter_last$filterprop) {}
1667	}
1668
1669	set tmbar [menu $ec_tracer.menubar]
1670	$ec_tracer config -menu $tmbar
1671	$tmbar add cascade -label "Windows" -menu $tmbar.win -underline 0
1672	menu $tmbar.win
1673	$tmbar.win add command -label "Raise top-level" -command "tkinspect:RaiseWindow ."
1674	$tmbar.win add command -label "Predicate Browser" -command tkecl:popup_pred_prop
1675	$tmbar.win add command -label "Delayed Goals" -command tkecl:popup_dg_window
1676	$tmbar.win add separator
1677	$tmbar.win add command -label "Close Tracer" -command "destroy $ec_tracer"
1678	$tmbar add cascade -label "Options" -menu $tmbar.opt -underline 0
1679	menu $tmbar.opt
1680	$tmbar.opt add command -label "Configure filter ..." -command tkecl:popup_filter
1681	$tmbar.opt add command -label "Change print options ..." -command "tkecl:edit_output_mode tracer"
1682	$tmbar.opt add command -label "Analyze failure ..." -command "tkecl:analyze_failure $ec_tracer"
1683	$tmbar.opt add command -label "Refresh goal stack now" -command tkecl:refresh_goal_stack
1684	$tmbar.opt add check -label "Refresh goal stack at every trace line" -variable tkecl(pref,trace_refresh_stack)
1685	$tmbar.opt add check -label "Refresh delayed goals at every trace line" -variable tkecl(pref,trace_refresh_dg)
1686	$tmbar.opt add check -label "Raise tracer window at every trace line" -variable tkecl(pref,trace_raise_tracer)
1687	$tmbar add cascade -label "Help" -menu $tmbar.help -underline 0
1688	menu $tmbar.help
1689        $tmbar.help add command -label "Tracer Help" -command "tkecl:Get_helpfileinfo trac $ec_tracer"
1690
1691	set ec_tracertab $ec_tracer.tab
1692	tabnotebook $ec_tracertab -padx 14 -pady 4 -background darkgray \
1693	    -activebackground #f0f0f0 -disabledbackground darkgray \
1694	    -normalbackground gray -borderwidth 0 -font tkecllabel
1695	frame $ec_tracertab.trace
1696	$ec_tracertab add "Trace Log" -window $ec_tracertab.trace
1697#	$ec_tracertab activate "Trace Log"
1698#	label $ec_tracertab.trace.label -text "Trace Log"
1699	text $ec_tracertab.trace.text -bg white -yscrollcommand "$ec_tracertab.trace.vscroll set" -wrap none -xscrollcommand "$ec_tracertab.trace.hscroll set"
1700	$ec_tracertab.trace.text tag configure call_style -foreground blue
1701	$ec_tracertab.trace.text tag configure exit_style -foreground #00b000
1702	$ec_tracertab.trace.text tag configure fail_style -foreground red
1703	$ec_tracertab.trace.text tag configure truncate_style -background pink
1704	scrollbar $ec_tracertab.trace.vscroll -command "$ec_tracertab.trace.text yview"
1705	scrollbar $ec_tracertab.trace.hscroll -command "$ec_tracertab.trace.text xview" -orient horizontal
1706	pack $ec_tracertab.trace.vscroll -side left -fill y
1707	pack $ec_tracertab.trace.hscroll -side bottom -fill x
1708	pack $ec_tracertab.trace.text -side bottom -expand 1 -fill both
1709#	pack $ec_tracertab.trace.label -side left -expand 1 -fill x
1710
1711	bind $ec_tracertab.trace.text <Any-Key> "tkecl:readonly_keypress %A"
1712	bind $ec_tracertab.trace.text <ButtonRelease-2> {break}
1713
1714	tkecl:setup_source_debug_window
1715
1716	frame $ec_tracer.stack
1717	label $ec_tracer.stack.label -text "Call Stack"
1718	text $ec_tracer.stack.text -height 15 -bg white -yscrollcommand "$ec_tracer.stack.vscroll set" -wrap none -xscrollcommand "$ec_tracer.stack.hscroll set"
1719	$ec_tracer.stack.text tag configure call_style -foreground blue
1720	$ec_tracer.stack.text tag configure exit_style -foreground #00b000
1721	$ec_tracer.stack.text tag configure fail_style -foreground red
1722	$ec_tracer.stack.text tag configure truncate_style -background pink
1723	$ec_tracer.stack.text configure -cursor left_ptr
1724	scrollbar $ec_tracer.stack.vscroll -command "$ec_tracer.stack.text yview"
1725	scrollbar $ec_tracer.stack.hscroll -command "$ec_tracer.stack.text xview" -orient horizontal
1726	pack $ec_tracer.stack.vscroll -side left -fill y
1727	pack $ec_tracer.stack.hscroll -side bottom -fill x
1728	pack $ec_tracer.stack.text -side bottom -expand 1 -fill both
1729	pack $ec_tracer.stack.label -side left -expand 1 -fill x
1730
1731	bind $ec_tracer.stack.text <Any-Key> "tkecl:readonly_keypress %A"
1732	bind $ec_tracer.stack.text <ButtonRelease-2> {break}
1733
1734	frame $ec_tracer.buttons
1735	bind $ec_tracer <Enter> "tkecl:enable_tracer_keys $ec_tracer"
1736        # remember underline for button if keyboard shortcut added!
1737	bind $ec_tracer.buttons <Key-c> {tkecl:set_tracercommand c}
1738	bind $ec_tracer.buttons <Key-l> {tkecl:set_tracercommand l}
1739	bind $ec_tracer.buttons <Key-s> {tkecl:set_tracercommand s}
1740	bind $ec_tracer.buttons <Key-u> {tkecl:set_tracercommand up}
1741	bind $ec_tracer.buttons <Key-p> {tkecl:set_tracercommand z}
1742	bind $ec_tracer.buttons <Key-f> {tkecl:set_tracercommand filter}
1743	bind $ec_tracer.buttons <Key-i> {tkecl:set_tracercommand i}
1744	bind $ec_tracer.buttons <Key-d> {tkecl:set_tracercommand j}
1745#	bind $ec_tracer.buttons <Key-plus> {tkecl:set_tracercommand +}
1746#	bind $ec_tracer.buttons <Key-minus> {tkecl:set_tracercommand -}
1747	button $ec_tracer.buttons.creep -text Creep -underline 0 -command {}
1748	bind $ec_tracer.buttons.creep <Button-1> {tkecl:setup_creep}
1749	bind $ec_tracer.buttons.creep <ButtonRelease-1> {tkecl:end_creep}
1750	    pack $ec_tracer.buttons.creep -side left -fill x -expand 1
1751	;# destroy are sent to all widgets of a window, chose one for
1752	;# code to cope with the closing of the tracer window
1753	bind $ec_tracer.buttons.creep <Destroy> "if {![ec_running]} {tkecl:tracer_off}"
1754	button $ec_tracer.buttons.skip -text Skip -underline 0 -command {tkecl:set_tracercommand s}
1755	    pack $ec_tracer.buttons.skip -side left -fill x -expand 1
1756	button $ec_tracer.buttons.up -text Up -underline 0 -command {tkecl:set_tracercommand up}
1757	    pack $ec_tracer.buttons.up -side left -fill x -expand 1
1758	button $ec_tracer.buttons.leap -text Leap -underline 0 -command {tkecl:set_tracercommand l}
1759	    pack $ec_tracer.buttons.leap -side left -fill x -expand 1
1760	button $ec_tracer.buttons.filter -text {Filter} -underline 0 -command {tkecl:set_tracercommand filter}
1761	    pack $ec_tracer.buttons.filter -side left -fill x -expand 1
1762	button $ec_tracer.buttons.abort -text Abort -command {tkecl:set_tracercommand a}
1763	    pack $ec_tracer.buttons.abort -side left -fill x -expand 1
1764	button $ec_tracer.buttons.nodebug -text Nodebug -command {tkecl:set_tracercommand n ; tkinspect:RaiseWindow .}
1765	    pack $ec_tracer.buttons.nodebug -side left -fill x -expand 1
1766
1767	frame $ec_tracer.cont
1768	button $ec_tracer.cont.button -text "To Invoc:" -underline 3 -command {tkecl:set_tracercommand i}
1769	    pack $ec_tracer.cont.button -side left -fill x -expand 1
1770	ventry $ec_tracer.cont.invoc \
1771		-vcmd {regexp {^[0-9]*$} %P} -validate key -invalidcmd bell \
1772		-width 8 -textvariable tkecl(cont_invoc) -bg white
1773	    pack $ec_tracer.cont.invoc -side left
1774	    bind $ec_tracer.cont.invoc <Return> "tkecl:set_tracercommand i"
1775	button $ec_tracer.cont.jump -text "To Depth:" -underline 3 -command {tkecl:set_tracercommand j}
1776	    pack $ec_tracer.cont.jump -side left -fill x -expand 1
1777	ventry $ec_tracer.cont.mindepth \
1778		-vcmd {regexp {^[0-9]*$} %P} -validate key -invalidcmd bell \
1779		-width 5 -textvariable tkecl(cont_mindepth) -bg white
1780	    pack $ec_tracer.cont.mindepth -side left
1781	ventry $ec_tracer.cont.maxdepth -labeltext ..  \
1782		-vcmd {regexp {^[0-9]*$} %P} -validate key -invalidcmd bell \
1783		-width 5 -textvariable tkecl(cont_maxdepth) -bg white
1784	    pack $ec_tracer.cont.maxdepth -side left
1785	button $ec_tracer.cont.zap -text "To Port:" -underline 3 -command {tkecl:set_tracercommand z}
1786	    pack $ec_tracer.cont.zap -side left
1787
1788	combobox $ec_tracer.cont.ports -click single -listheight 16 -bg white \
1789		-width 10 -list "{Not Current} $tkecl(portlist)" -textvariable tkecl(zap_port)
1790	    pack $ec_tracer.cont.ports -side left
1791	button $ec_tracer.close -text Close -command "destroy $ec_tracer"
1792	tkecl:configure_tracer_buttons disabled
1793
1794	pack $ec_tracer.stack -side top -expand 1 -fill both
1795	pack $ec_tracer.buttons -side top -fill x
1796	pack $ec_tracer.cont -side top -fill x
1797	pack $ec_tracertab -expand 1 -fill both
1798	pack $ec_tracer.close -side top -fill x
1799
1800	ec_rpcq {set_flag debugging creep} (()())
1801
1802#--------------------------------------------------------------------
1803# Balloon Help for tracer
1804#--------------------------------------------------------------------
1805       balloonhelp $ec_tracer "Tracer for ECLiPSe execution - start execution from main window"
1806       balloonhelp $ec_tracer.stack.label "Execution call stack - \
1807   shows the current goal and its ancestors.\n \
1808   Calls for current goal in blue, failure in red, success in green. \
1809   Ancestors printed with non-current bindings in black\n \
1810   Press right (or control-left) mouse button over a stack item for popup \
1811 menu related to that goal/predicate.\n Double-click left mouse button over \
1812 a stack item to inspect it.\n Single click left mouse button on the \
1813 information (left) part of\n the stack item to show source contxt\n "
1814       balloonhelp $ec_tracertab.trace "Trace log: chronological log of traced goals.\n Calls in blue, successes in green, failures in red\n Leading indentation indicates depth"
1815       balloonhelp $ec_tracer.buttons.creep "Creep to next tracable goal's debug port.\n\
1816   Keyboard shortcut: `c'\nPress and hold button for continuous creep."
1817       balloonhelp $ec_tracer.buttons.skip "Skip to exit/fail port of goal (creep\
1818   if already at port).\nKeyboard shortcut: `s'"
1819       balloonhelp $ec_tracer.buttons.leap "Leap to next spied predicate port or next breakpoint.\n\
1820   Keyboard shortcut: `l'"
1821       balloonhelp $ec_tracer.buttons.up "Continue until back to parent's\
1822   depth\nKeyboard shortcut: `u'"
1823       balloonhelp $ec_tracer.buttons.filter "Continue until filter \
1824   conditions hold.\nKeyboard shortcut: `f'.\n\
1825   See Options for how to configure the filter."
1826       balloonhelp $ec_tracer.buttons.abort "Abort execution"
1827       balloonhelp $ec_tracer.buttons.nodebug "Turn off debugging and\
1828   continue execution\n(Further outputs will be displayed on main window)"
1829       balloonhelp $ec_tracer.cont.button "Jump to port for goal with \
1830   invocation number on right\nKeyboard shortcut: `i'"
1831       balloonhelp $ec_tracer.cont.jump "Jump to port for next goal with \
1832   depth in the ranges on the right.\nKeyboard shortcut: `d'"
1833       balloonhelp $ec_tracer.cont.zap "Jump to port selected on the right\
1834   \nKeyboard shortcut: `p'"
1835       bind $ec_tracer <Alt-h> "tkecl:Get_helpfileinfo trac $ec_tracer"
1836   } else {
1837       tkinspect:RaiseWindow $ec_tracer
1838   }
1839}
1840
1841# enable tracing via keyboard shortcuts if tracer is enabled
1842proc tkecl:enable_tracer_keys {ec_tracer} {
1843    global tkecl
1844
1845    if {$tkecl(tracer_state) == "normal"} {
1846	focus $ec_tracer.buttons
1847    }
1848}
1849
1850proc tkecl:handle_debug_output {stream {length {}}} {
1851    if {![winfo exists .ec_tools.ec_tracer]} {
1852	return
1853    }
1854    ec_stream_to_window_sync {} .ec_tools.ec_tracer.tab.trace.text $stream $length
1855}
1856
1857# CAUTION: text widgets positions are a bit weird: the text widget always
1858# has a newline at the end, and the end-index is just after that. Therefore,
1859# an empty text widget has a newline at 1.0 and end == 2.0
1860
1861proc tkecl:handle_trace_line {stream {length {}}} {
1862    global tkecl
1863
1864    set ec_tracer .ec_tools.ec_tracer
1865    if ![winfo exists $ec_tracer] {
1866	tkecl:popup_tracer
1867    }
1868    set tkecl(tracercommand_issued) 0
1869    set trace_info [ec_read_exdr [ec_streamnum_to_channel $stream]]
1870    if {[llength $trace_info] == 0} {
1871	# start of new trace session
1872	# make sure current source file is reloaded
1873	# cannot simply set file to "" as we may need the file name (for
1874        # placing breakpoints etc.)
1875	if {$tkecl(source_debug,file) != ""} {
1876	    tkecl:load_source_debug_file $tkecl(source_debug,file)
1877	}
1878	return
1879    }
1880    set depth [lindex $trace_info 0]
1881    set style [lindex $trace_info 1]
1882    set line [lindex $trace_info 2]
1883    set invoc [lindex $trace_info 3]
1884    set tkecl(current_port) [lindex $trace_info 4]
1885    set prio [lindex $trace_info 5]
1886    set fpath_info [lindex $trace_info 6]
1887    set from [lindex $trace_info 7]
1888    set to [lindex $trace_info 8]
1889    set tkecl(cont_invoc) $invoc  ;# defaults to current
1890    set tkecl(tracer_up_depth) [expr $depth>0 ? $depth-1 : 0]
1891
1892    if {[string length $line] >= $tkecl(pref,text_truncate)} {
1893	set truncated 1
1894	set line [string range $line 0 $tkecl(pref,text_truncate)]
1895    } else {
1896	set truncated 0
1897    }
1898    $ec_tracer.tab.trace.text tag configure $depth -lmargin1 "$depth m"
1899    $ec_tracer.tab.trace.text insert end $line "$style $depth"
1900    if $truncated {
1901	$ec_tracer.tab.trace.text insert end "..." truncate_style
1902    }
1903    ;# make sure at least a partial line at the start is visible
1904    $ec_tracer.tab.trace.text see "end -1 line linestart +40 chars"
1905    $ec_tracer.tab.trace.text insert end "\n" $style
1906
1907    set stdepth [expr $depth + 1] ;# actual depth in printed stack
1908    set next_line [lindex [split [$ec_tracer.stack.text index end-1chars] .] 0]
1909    if {$style == "fail_style" && $next_line > $stdepth} {
1910	;# we did not jump to this fail port..
1911	$ec_tracer.stack.text tag remove call_style $stdepth.0 end
1912	if {[$ec_tracer.stack.text compare $stdepth.end == $stdepth.0]} {
1913	    ;# if the line is empty, we don't have the port, print it
1914	    ;# don't bother to add a popup...not very useful here
1915	    $ec_tracer.stack.text insert $stdepth.0 $line $style
1916	}
1917	$ec_tracer.stack.text tag add fail_style $stdepth.0 end
1918	$ec_tracer.stack.text see $stdepth.0
1919	set tkecl(next_trace_line_depth) $stdepth
1920    } else {
1921	if {$next_line > $tkecl(next_trace_line_depth)} {
1922	    # delete leftover exit/fail lines
1923	    # and tags to goals that are no longer accessible
1924	    tkecl:cleanup_goal_stack_line $tkecl(next_trace_line_depth) [expr $next_line - 1]
1925	    set next_line $tkecl(next_trace_line_depth)
1926	}
1927	if {$next_line < $stdepth} {
1928	    while {$next_line < $stdepth} {
1929		$ec_tracer.stack.text insert end "\n"
1930		incr next_line
1931	    }
1932	} elseif {$next_line > $stdepth} {
1933	    tkecl:cleanup_goal_stack_line $stdepth [expr $next_line - 1]
1934	}
1935	$ec_tracer.stack.text tag remove call_style 1.0 end
1936	$ec_tracer.stack.text insert end $line $style
1937	if $truncated {
1938	    $ec_tracer.stack.text insert end "..." truncate_style
1939	}
1940	$ec_tracer.stack.text insert end "\n" $style
1941	tkecl:set_goalpopup $depth $invoc $prio $line
1942	$ec_tracer.stack.text see end
1943	if {$style == "call_style"} {
1944	    ;# extract into tkecl(next_trace_line_depth) the line number
1945	    ;# from an index of the form line.char
1946	    scan [$ec_tracer.stack.text index end-1chars] \
1947		    {%u} tkecl(next_trace_line_depth)
1948	} else {
1949	    set tkecl(next_trace_line_depth) $stdepth
1950	}
1951    }
1952
1953    # Refresh stack, delayed goals and debug source displays
1954    if {$tkecl(pref,trace_refresh_stack) && $style != "fail_style"} {
1955	# don't refresh during failures because we'd lose displayed information
1956    	tkecl:refresh_goal_stack
1957    }
1958    if {$tkecl(pref,trace_refresh_dg)} { tkecl:refresh_dg }
1959    tkecl:update_source_debug $style $from $to $fpath_info
1960}
1961
1962proc tkecl:handle_tracer_port_start {} {
1963    global tkecl
1964
1965    # Enable the buttons, and add some delay if repeating creep from mouse hold
1966    tkecl:configure_tracer_buttons normal
1967    if {($tkecl(press_creep) > 0) && \
1968	    [string match $tkecl(tracercommand) "c"]} {
1969	if {$tkecl(press_creep) == 1} { ;# initial press, wait longer
1970	    set interval 700
1971	} else {
1972	    set interval 50
1973	    set tkecl(press_creep) 2
1974	}
1975	set tkecl(creepwaitevent) [after $interval {set tkecl(creepwaitover) 1}]
1976	vwait tkecl(creepwaitover)
1977	if {($tkecl(press_creep) > 0) && \
1978		[string match $tkecl(tracercommand) "c"]} {
1979	    # did not select any other tracer command during wait...
1980	    set tkecl(press_creep) 2
1981	    tkecl:set_tracercommand c
1982	}
1983    }
1984    # update the filter hits
1985    set tkecl(filter_hits) [lindex \
1986	[ec_rpcatq [list getval filter_hits _] (()_) tracer_tcl] 2]
1987}
1988
1989proc tkecl:send_tracer_command {cmd {type S}} {
1990
1991    ec_rpcq [list set_tracer_command $cmd] ($type) tracer_tcl
1992}
1993
1994proc tkecl:handle_tracer_command {} {
1995    global tkecl
1996
1997    # interpret the command and configure Eclipse for continuation
1998    # tracer_state must be set to disabled before command is handled
1999    # as this indicates that we are ready to continue from the debug port
2000    switch -exact -- $tkecl(tracercommand) {
2001	N {
2002	    # caution: if tracercommand = N the window is already destroyed!
2003	    set tkecl(tracer_state) disabled
2004	    tkecl:send_tracer_command N
2005	}
2006	i {
2007	    if [regexp -- {^[0-9]+$} $tkecl(cont_invoc)] {
2008		tkecl:configure_tracer_buttons disabled
2009		ec_rpcq_check [list configure_prefilter $tkecl(cont_invoc) _ _ _ _]\
2010			(I____) sepia_kernel
2011		tkecl:send_tracer_command i
2012	    }
2013	}
2014	j {
2015	    if {[regexp -- {^[0-9]+$} $tkecl(cont_mindepth)] && \
2016		    [regexp -- {^[0-9]+$} $tkecl(cont_mindepth)]} {
2017		tkecl:configure_tracer_buttons disabled
2018		ec_rpcq_check [list configure_prefilter _ [list .. $tkecl(cont_mindepth) $tkecl(cont_maxdepth)] _ _ _]\
2019			(_(II)___) sepia_kernel
2020		tkecl:send_tracer_command j
2021	    }
2022	}
2023	up { ;# jump one level up
2024	    tkecl:configure_tracer_buttons disabled
2025	    ec_rpcq_check [list configure_prefilter _ [list .. 0 $tkecl(tracer_up_depth)] _ _ _]\
2026		    (_(II)___) sepia_kernel
2027	    tkecl:send_tracer_command j
2028	}
2029	f { ;# fail to $tkecl(fail_invoc)
2030	    tkecl:configure_tracer_buttons disabled
2031	    tkecl:send_tracer_command [list f $tkecl(fail_invoc)] {(I)}
2032	}
2033	z { ;# zap to $tkecl(zap_port)
2034	    tkecl:configure_tracer_buttons disabled
2035	    if {$tkecl(zap_port) != "Not Current"} {
2036		ec_rpcq_check [list configure_prefilter _ _ $tkecl(zap_port) _ dontcare]]\
2037			(__()_()) sepia_kernel
2038		tkecl:send_tracer_command ""
2039	    } else {
2040		tkecl:send_tracer_command z
2041	    }
2042	}
2043	filter {
2044	    tkecl:configure_tracer_buttons disabled
2045
2046	    # for the third case we only need to stop at predicates
2047	    # with spypoints as we will set one up on the template
2048	    # predicate.
2049
2050	    set changed 0
2051
2052	    # now set the count
2053	    if {$tkecl(filter_count) < 1} { set tkecl(filter_count) 1}
2054
2055	    # prepare ECLiPSe side for filter command. This must be done
2056	    # before setting any specialised condition (e.g. goal filtering).
2057	    ec_rpcq [list prepare_filter $tkecl(filter_count)] (I) tracer_tcl
2058
2059	    switch -exact -- $tkecl(filter_predtype) {
2060		any {
2061		    set filter_spy all
2062		}
2063		anyspy {
2064		    set filter_spy spied
2065		}
2066		goalmatching {
2067		    switch [tkecl:configure_pred] {
2068			    error {
2069				tkecl:reset_traceport
2070				return
2071			    }
2072			    spy_set {
2073				set filter_spy spied
2074				set tkecl(last_filter_spy) $filter_spy
2075				incr changed
2076			    }
2077			    continue {
2078				# same filter, no need to change
2079				set filter_spy $tkecl(last_filter_spy)
2080			    }
2081			    default {
2082				set filter_spy all
2083				set tkecl(last_filter_spy) $filter_spy
2084				incr changed
2085			    }
2086		    }
2087		}
2088	    }
2089
2090	    set tkecl(filter_wanted_ports) {}
2091	    foreach port $tkecl(portlist) {
2092		if $tkecl(filter_port,$port) {
2093		    lappend tkecl(filter_wanted_ports) $port
2094		}
2095	    }
2096	    if {$tkecl(filter_wanted_ports) != $tkecl(portset,current)} {
2097		set tkecl(portset,previous) $tkecl(portset,current)
2098		set tkecl(portset,current) $tkecl(filter_wanted_ports)
2099	    }
2100
2101	    # sepia_kernel:configure_prefilter(Invoc, Depth, Ports, Preds, Module)
2102	    foreach filterprop $tkecl(filter,changable) {
2103		if [tkecl:check_if_changed $filterprop] { incr changed}
2104	    }
2105
2106	    if [catch { ec_rpcq_check [list configure_prefilter \
2107				       [list .. $tkecl(filter_mininvoc) $tkecl(filter_maxinvoc)] \
2108				       [list .. $tkecl(filter_mindepth) $tkecl(filter_maxdepth)] \
2109				       $tkecl(filter_wanted_ports) \
2110				       $filter_spy \
2111				       dontcare] \
2112			    {((II)(II)[()*]()())} sepia_kernel }\
2113		   ] {
2114		tk_messageBox -icon error -type ok -message "Filter Error: some entries for filter conditions are invalid. "
2115		tkecl:reset_traceport
2116		return
2117	    }
2118
2119	    if {$changed > 0} {
2120		;# change in filter condition, reset filter count
2121		ec_rpcatq [list setval filter_hits 0] (()I) tracer_tcl
2122	    }
2123	    tkecl:send_tracer_command filter
2124	}
2125	default {
2126	    tkecl:configure_tracer_buttons disabled
2127	    tkecl:send_tracer_command $tkecl(tracercommand)
2128	}
2129    }
2130    ec_multi:terminate_phase
2131}
2132
2133proc tkecl:check_if_changed {filterprop} {
2134    global tkecl
2135
2136    if {$tkecl(filter_$filterprop) != $tkecl(filter_last$filterprop)} {
2137	set tkecl(filter_last$filterprop) $tkecl(filter_$filterprop)
2138	return 1
2139    } else {
2140	return 0
2141    }
2142}
2143
2144proc tkecl:reset_traceport {} {
2145    global tkecl
2146
2147    tkecl:configure_tracer_buttons normal
2148    set tkecl(tracercommand) N
2149    set tkecl(tracercommand_issued) 0
2150}
2151
2152proc tkecl:set_tracercommand {command} {
2153    global tkecl
2154
2155    if [winfo exists .ec_tools.ec_tracer] {
2156	set tkecl(tracercommand) $command
2157	set tkecl(tracercommand_issued) 1
2158    }
2159}
2160
2161proc tkecl:check_tracer_interaction {} {
2162    global tkecl tcl_platform
2163
2164    if {[winfo exists .ec_tools.ec_tracer]} {
2165	if {$tkecl(tracercommand_issued) == 1} {
2166	tkecl:handle_tracer_command
2167	}
2168    }
2169}
2170
2171
2172proc tkecl:tracer_off {} {
2173    global tkecl
2174
2175    if [string match $tkecl(tracer_state) disabled] {
2176	ec_rpcq {set_flag debugging nodebug} (()())
2177    } else {
2178	# tracer window may have already disappeared, pass command directly
2179	set tkecl(tracercommand) N
2180	tkecl:handle_tracer_command
2181    }
2182}
2183
2184proc tkecl:configure_tracer_buttons {state} {
2185    global tkecl
2186    set tkecl(tracer_state) $state	;# normal or disabled
2187    set ec_tracer .ec_tools.ec_tracer
2188    $ec_tracer.buttons.creep configure -state $state
2189    $ec_tracer.buttons.leap configure -state $state
2190    $ec_tracer.buttons.up configure -state $state
2191    $ec_tracer.buttons.filter configure -state $state
2192    $ec_tracer.buttons.skip configure -state $state
2193    $ec_tracer.buttons.abort configure -state $state
2194    $ec_tracer.buttons.nodebug configure -state $state
2195    $ec_tracer.cont.button configure -state $state
2196    $ec_tracer.cont.jump configure -state $state
2197    $ec_tracer.cont.zap configure -state $state
2198    if [winfo exists $ec_tracer.filter] {
2199	$ec_tracer.filter.go configure -state $state
2200# Don't see any reason why this should be done (?)
2201#	if {$tkecl(predtype) == "goalmatching"} {
2202#	    if {$state == "disabled"} {
2203#		tkecl:fields_disable $ec_tracer
2204#	    }
2205#	    if {$state == "normal"} {
2206#		tkecl:enable_pred $ec_tracer
2207#	    }
2208#	}
2209    }
2210    if {$state == "normal"} {
2211	if {[tkecl:pointer_window] == "$ec_tracer"} {
2212	    focus $ec_tracer.buttons
2213	}
2214	if {$tkecl(pref,trace_raise_tracer)} {
2215	    tkinspect:RaiseWindow $ec_tracer
2216	}
2217    } else { ;# $state == "disabled"
2218	if {[focus] == "$ec_tracer.buttons"} {
2219	    ;# assume buttons had focus, so remove it to ignore any
2220            ;# stray key presses while buttons are disabled
2221	    focus $ec_tracer
2222	}
2223    }
2224}
2225
2226
2227proc tkecl:popup_goalmenu {w invoc depth prio greturn x y} {
2228    global tkecl
2229
2230    if [winfo exists $w.gpopup] {
2231	destroy $w.gpopup
2232    }
2233    set m [menu $w.gpopup -tearoff 0]
2234    set spec [lindex  $greturn 2]
2235    set tspec [lindex $greturn 3]
2236    set module [lindex $greturn 4]
2237    set lookup_module [lindex $greturn 5]
2238    set path_info [lindex $greturn 6]
2239
2240    if {![string match unknown $spec] } {
2241	$m add command -label "$tspec @ $module <$prio>" -state disabled
2242	set spied [tkecl:pred_flag_value $spec $lookup_module spy]
2243	if {$spied == "on"} {
2244	    set spytext "Nospy $spec"
2245	    set spyval off
2246	} else {
2247	    set spytext "Spy $spec"
2248	    set spyval on
2249	}
2250	$m add command -label $spytext -command \
2251		[list tkecl:set_pred_flag $spec $lookup_module spy $spyval]
2252	$m add command -label "Display source for this predicate" -command \
2253		[list tkecl:set_and_display_source $spec $module]
2254	if {$path_info == "no"} {set gstate disabled} else {set gstate normal}
2255	$m add command -label "Display source context for this call" -command \
2256	    "tkecl:show_source_context $invoc {$greturn}" -state $gstate
2257	$m add command -label "Inspect this goal" -command \
2258		"tkinspect:Inspect_term_init invoc($invoc)"
2259	$m add command -label "Observe this goal" -command "tkecl:observe_goal $invoc"
2260	$m add command -label "Force failure of this goal" -command \
2261		"tkecl:set_fail_invoc $invoc"
2262	$m add command -label "Jump to this invocation number ($invoc)" -command \
2263		"tkecl:set_jumpto_invoc $invoc"
2264
2265    }
2266    $m add command -label "Jump to this depth $depth" -command \
2267    	"tkecl:set_jumpto_depth $depth"
2268    $m add separator
2269    $m add command -label "Refresh goal stack" -command \
2270	    "tkecl:refresh_goal_stack"
2271
2272    tk_popup $m $x $y
2273}
2274
2275proc tkecl:cleanup_goal_stack_line {depth next_line} {
2276    set ec_tracer .ec_tools.ec_tracer
2277
2278    for {set line $depth} {$line <= $next_line} {incr line 1} {
2279	set taglist [$ec_tracer.stack.text tag names $line.0]
2280	set invocidx [lsearch -regexp $taglist  {^[0-9]+$}]
2281	;# tags in the lines are also deleted
2282	if {$invocidx >= 0} {
2283	    $ec_tracer.stack.text tag delete [lindex $taglist $invocidx]
2284	}
2285    }
2286    $ec_tracer.stack.text delete $depth.0 $next_line.end+1char
2287}
2288
2289proc tkecl:refresh_goal_stack {} {
2290    global tkecl
2291
2292    foreach anc  [lindex [ec_rpcq {get_ancestors _} (_) tracer_tcl] 1] {
2293	foreach {pred depth invoc prio line} $anc {break}
2294	set stdepth [expr $depth+1]
2295	;# only clean up line if it is actually there!
2296	if [.ec_tools.ec_tracer.stack.text compare end-1char > $stdepth.0] {
2297	    tkecl:cleanup_goal_stack_line $stdepth $stdepth
2298	}
2299	if {[string length $line] >= $tkecl(pref,text_truncate)} {
2300	    set line [string range $line 0 $tkecl(pref,text_truncate)]
2301	    .ec_tools.ec_tracer.stack.text insert $stdepth.0 "\n"
2302            ;# put in the newline first, then insert things before it
2303	    .ec_tools.ec_tracer.stack.text insert $stdepth.0 $line call_style
2304	    .ec_tools.ec_tracer.stack.text insert $stdepth.end "..." truncate_style
2305	} else {
2306	    .ec_tools.ec_tracer.stack.text insert $stdepth.0 "\n"
2307	    .ec_tools.ec_tracer.stack.text insert $stdepth.0 $line call_style
2308	}
2309	tkecl:set_goalpopup $depth $invoc $prio $line
2310    }
2311
2312    .ec_tools.ec_tracer.stack.text see end
2313}
2314
2315proc tkecl:set_goalpopup {depth invoc prio line} {
2316# print goal line in the stack display and set up the tag for it
2317    set ec_tracer .ec_tools.ec_tracer
2318    set greturn [ec_rpcq_check\
2319	    [list get_goal_info_by_invoc $invoc _ _ _ _ _ _ _] (I_______) tracer_tcl]
2320    $ec_tracer.stack.text tag bind $invoc <Button-3> \
2321	"tkecl:popup_goalmenu $ec_tracer.stack.text $invoc $depth $prio {$greturn} %X %Y; break"
2322    $ec_tracer.stack.text tag bind $invoc <Control-Button-1> \
2323	"tkecl:popup_goalmenu $ec_tracer.stack.text $invoc $depth $prio {$greturn} %X %Y; break"
2324    $ec_tracer.stack.text tag bind info$invoc <Button-3> \
2325	"tkecl:popup_goalmenu $ec_tracer.stack.text $invoc $depth $prio {$greturn} %X %Y; break"
2326    $ec_tracer.stack.text tag bind info$invoc <Control-Button-1> \
2327	"tkecl:popup_goalmenu $ec_tracer.stack.text $invoc $depth $prio {$greturn} %X %Y; break"
2328    $ec_tracer.stack.text tag bind $invoc <Double-Button-1> "tkinspect:Inspect_term_init invoc($invoc); break"
2329    $ec_tracer.stack.text tag bind info$invoc <Button-1> "tkecl:show_source_context $invoc {$greturn}; break"
2330
2331    # find the information part (the part before the goal) of the line
2332    # if the format for this part changes, the regexp may also need to change
2333    if {[regexp {[^)]+\) [^ ]+ [^ ]+} $line info] == 1} {
2334	set length [string length $info]
2335    } else {
2336	# this probably shouldn't happen
2337	set length 0
2338    }
2339    set stdepth [expr $depth + 1]
2340    # $stdepth.$length is one char after the port name
2341    $ec_tracer.stack.text tag add info$invoc $stdepth.0 $stdepth.$length
2342    $ec_tracer.stack.text tag raise info$invoc
2343    incr length
2344    $ec_tracer.stack.text tag add $invoc $stdepth.$length $stdepth.end
2345    $ec_tracer.stack.text tag raise $invoc
2346}
2347
2348proc tkecl:popup_filter {} {
2349    global tkecl
2350
2351    set ec_tracer .ec_tools.ec_tracer
2352    if [winfo exists $ec_tracer.filter] {
2353	tkinspect:RaiseWindow $ec_tracer.filter
2354	return
2355    }
2356
2357    toplevel $ec_tracer.filter
2358    wm title $ec_tracer.filter "Filter"
2359
2360    label $ec_tracer.filter.label -text "Continue to a port with all of the following properties:"
2361    pack $ec_tracer.filter.label -side top
2362    frame $ec_tracer.filter.depthsettings -relief groove -bd 1
2363    pack $ec_tracer.filter.depthsettings -side top -ipadx 3 -ipady 3 -pady 5 -padx 5 -fill x
2364
2365    set row 0
2366    set col 0
2367    set cols 4
2368
2369    label $ec_tracer.filter.depthsettings.mininvoclabel -text "Invocation number from .."
2370
2371    ventry $ec_tracer.filter.depthsettings.mininvoc  \
2372	    -vcmd {regexp {^[0-9]*$} %P} -validate key -invalidcmd bell \
2373	    -width 8 -textvariable tkecl(filter_mininvoc) -bg white
2374
2375    label $ec_tracer.filter.depthsettings.maxinvoclabel -text ".. to .."
2376
2377    ventry $ec_tracer.filter.depthsettings.maxinvoc \
2378	    -vcmd {regexp {^[0-9]*$} %P} -validate key -invalidcmd bell \
2379	    -width 10 -textvariable tkecl(filter_maxinvoc) -bg white
2380
2381    grid $ec_tracer.filter.depthsettings.mininvoclabel $ec_tracer.filter.depthsettings.mininvoc $ec_tracer.filter.depthsettings.maxinvoclabel $ec_tracer.filter.depthsettings.maxinvoc
2382
2383    incr row
2384
2385    label $ec_tracer.filter.depthsettings.mindepthlabel -text "Depth from .."
2386
2387    ventry $ec_tracer.filter.depthsettings.mindepth \
2388	    -vcmd {regexp {^[0-9]*$} %P} -validate key -invalidcmd bell \
2389	    -width 8 -textvariable tkecl(filter_mindepth) -bg white
2390
2391    label $ec_tracer.filter.depthsettings.maxdepthlabel -text ".. to .."
2392
2393    ventry $ec_tracer.filter.depthsettings.maxdepth \
2394	    -vcmd {regexp {^[0-9]*$} %P} -validate key -invalidcmd bell \
2395	    -width 10 -textvariable tkecl(filter_maxdepth) -bg white
2396
2397    grid $ec_tracer.filter.depthsettings.mindepthlabel $ec_tracer.filter.depthsettings.mindepth $ec_tracer.filter.depthsettings.maxdepthlabel $ec_tracer.filter.depthsettings.maxdepth -sticky w
2398
2399    frame $ec_tracer.filter.settings -relief groove -bd 1
2400    pack $ec_tracer.filter.settings -side top -ipadx 3 -ipady 3 -pady 5 -padx 5 -fill x
2401
2402    set row 0
2403    set col 0
2404    set cols 7
2405
2406    label $ec_tracer.filter.settings.ports  -anchor w -text "Port types:"
2407    grid $ec_tracer.filter.settings.ports -columnspan $cols -sticky ew
2408    incr row
2409
2410
2411    foreach port $tkecl(portlist) {
2412	checkbutton $ec_tracer.filter.settings.port_$port -text $port -variable tkecl(filter_port,$port)
2413	grid $ec_tracer.filter.settings.port_$port -row $row -column $col -sticky w
2414	set col [expr ($col+1)%$cols]
2415	set row [expr $col?$row:$row+1]
2416    }
2417    set w $ec_tracer.filter.settings.portsets
2418    combobox $w -labeltext Tick -click single -editable 0 \
2419	-listheight [llength $tkecl(portsets)] -width 8 \
2420	-postcommand [list tkecl:combo_add_portsets $w] \
2421	-command tkecl:tick_portset
2422    grid $w -row $row -column $col -sticky w
2423
2424
2425    frame $ec_tracer.filter.predsettings -relief groove -bd 1
2426    pack $ec_tracer.filter.predsettings -side top -ipadx 3 -ipady 3 -pady 5 -padx 5 -fill x
2427
2428    set row 0
2429    set col 0
2430    set cols 5
2431
2432    label $ec_tracer.filter.predsettings.predtypetitle -text "Predicate specification:"
2433    grid $ec_tracer.filter.predsettings.predtypetitle -columnspan $cols -sticky w
2434    incr row
2435
2436    radiobutton $ec_tracer.filter.predsettings.predtype1 -text "Any predicate" \
2437	    -variable tkecl(filter_predtype) -value any -command "tkecl:fields_disable $ec_tracer" \
2438
2439    grid $ec_tracer.filter.predsettings.predtype1 -columnspan $cols -sticky w
2440    incr row
2441    radiobutton $ec_tracer.filter.predsettings.predtype2 -text "Any predicate with a spypoint or call with a breakpoint" \
2442	    -variable tkecl(filter_predtype) -value anyspy -command "tkecl:fields_disable $ec_tracer"
2443    grid $ec_tracer.filter.predsettings.predtype2 -columnspan 5 -sticky w
2444    incr row
2445    radiobutton $ec_tracer.filter.predsettings.predtype3 -text "Specific predicate instance:" \
2446	    -variable tkecl(filter_predtype) -value goalmatching -command "tkecl:enable_pred $ec_tracer"
2447    grid $ec_tracer.filter.predsettings.predtype3 -columnspan $cols -sticky w
2448
2449    incr row
2450
2451    label $ec_tracer.filter.predsettings.predmodule2label -text "Defining module:"
2452    label $ec_tracer.filter.predsettings.blank -text " "
2453
2454    label $ec_tracer.filter.predsettings.predmatchlabel -text "Goal template:"
2455
2456    grid x $ec_tracer.filter.predsettings.predmodule2label $ec_tracer.filter.predsettings.blank $ec_tracer.filter.predsettings.predmatchlabel -sticky w
2457
2458    incr row
2459
2460    combobox $ec_tracer.filter.predsettings.predmodule2combo -click single -listheight 6 -width 15 -editable 0 \
2461	-postcommand [list tkecl:combo_add_modules $ec_tracer.filter.predsettings.predmodule2combo] \
2462	-textvariable tkecl(filter_predmodule2)
2463
2464    label $ec_tracer.filter.predsettings.predmodule2colon -text ":"
2465
2466
2467    ventry $ec_tracer.filter.predsettings.predmatch  -textvariable tkecl(filter_predmatch) -state disabled -width 40
2468
2469    grid x $ec_tracer.filter.predsettings.predmodule2combo $ec_tracer.filter.predsettings.predmodule2colon $ec_tracer.filter.predsettings.predmatch -sticky w
2470
2471    incr row
2472
2473    label $ec_tracer.filter.predsettings.predconditionlabel -text "Condition:"
2474
2475    grid x $ec_tracer.filter.predsettings.predconditionlabel -sticky w
2476
2477    incr row
2478
2479    ventry $ec_tracer.filter.predsettings.predcondition  -textvariable tkecl(filter_predcondition) -state disabled -width 70
2480
2481    grid x $ec_tracer.filter.predsettings.predcondition -columnspan 3 -sticky w
2482    incr row
2483
2484    label $ec_tracer.filter.predsettings.predmodulelabel -text "Calling module:"
2485
2486    grid x $ec_tracer.filter.predsettings.predmodulelabel -sticky w
2487
2488    incr row
2489
2490    combobox $ec_tracer.filter.predsettings.predmodule -click single -listheight 6 -width 15 -editable 1 \
2491	-postcommand [list tkecl:combo_add_modules $ec_tracer.filter.predsettings.predmodule] \
2492	-textvariable tkecl(filter_predmodule)
2493
2494    grid x $ec_tracer.filter.predsettings.predmodule -sticky w
2495
2496
2497    tkecl:fields_disable $ec_tracer
2498
2499
2500    pack [frame $ec_tracer.filter.after -relief groove -bd 1] \
2501	 -side top -ipadx 3 -ipady 3 -pady 5 -padx 5 -fill x
2502    pack [frame $ec_tracer.filter.after.hits] -fill x
2503    pack [label $ec_tracer.filter.after.hits.left -text "Conditions already met "] -side left
2504    pack [label $ec_tracer.filter.after.hits.hits -textvariable tkecl(filter_hits)] -side left
2505    pack [label $ec_tracer.filter.after.hits.right -text " times using this filter."] -side left
2506
2507
2508    pack [frame $ec_tracer.filter.after.count] -fill x
2509    pack [label $ec_tracer.filter.after.count.label -text \
2510	      "Stop after the conditions have been met"] -side left
2511    pack [ventry $ec_tracer.filter.after.count.entry \
2512	      -vcmd {regexp {^[0-9]*$} %P} \-validate key -invalidcmd bell \
2513	      -width 10 -textvariable tkecl(filter_count) -bg white \
2514	 ] -side left
2515    pack [label $ec_tracer.filter.after.count.endlabel -text "time(s)."] -side left
2516
2517    button $ec_tracer.filter.go -text "Go" -state $tkecl(tracer_state) \
2518	-command {tkecl:set_tracercommand filter}
2519    balloonhelp $ec_tracer.filter.go "Continue program execution until filter conditions hold"
2520    button $ec_tracer.filter.close -text "Close" -command "wm withdraw $ec_tracer.filter"
2521    pack $ec_tracer.filter.go $ec_tracer.filter.close -side left -expand 1 -fill x
2522
2523    focus [$ec_tracer.filter.depthsettings.mininvoc subwidget entry]
2524    return $ec_tracer.filter
2525}
2526
2527proc tkecl:combo_add_portsets {w} {
2528    global tkecl
2529    foreach portset $tkecl(portsets) {
2530	$w add $portset
2531    }
2532}
2533
2534proc tkecl:tick_portset {portset} {
2535    global tkecl
2536
2537    foreach port $tkecl(portlist) {
2538	set tkecl(filter_port,$port) 0
2539    }
2540    foreach port $tkecl(portset,$portset) {
2541	set tkecl(filter_port,$port) 1
2542    }
2543}
2544
2545proc tkecl:configure_pred {} {
2546    global tkecl
2547
2548    set changed 0
2549
2550    if {$tkecl(filter_predcondition) == ""} then {
2551	set usepredcondition true
2552    } else {
2553	set usepredcondition $tkecl(filter_predcondition)
2554    }
2555    if {$tkecl(filter_predmatch) == ""} then {
2556	set usepredmatch "_"
2557    } else {
2558	set usepredmatch $tkecl(filter_predmatch)
2559    }
2560    if {$tkecl(filter_predmodule) == ""} then {
2561	set usepredmodule "_"
2562    } else {
2563	set usepredmodule $tkecl(filter_predmodule)
2564    }
2565
2566    foreach filterprop $tkecl(filterpred,changable) {
2567	if [tkecl:check_if_changed $filterprop] { incr changed }
2568    }
2569
2570    # set_usepred_info($usepredmatch,
2571    #                  $usepredmodule,
2572    #                  $usepredmodule2,
2573    #                  $usepredcondition,
2574    #                  Status)
2575    if {$changed > 0} {
2576	# predmodule2 cannot be undefined: it is taken from a list of modules
2577	# the eclipse side code also assumes it cannot be a variable
2578	set res [ec_rpcq [list set_usepred_info \
2579		 $usepredmatch $usepredmodule $tkecl(filter_predmodule2) $usepredcondition _] \
2580		 (SSSS_) tracer_tcl]
2581
2582	switch $res {
2583	    fail  -
2584	    throw {
2585		tk_messageBox -icon error -type ok -message "Filter Error: Exception raised when setting the conditional goal filter. Please check goal template/condition for syntax error."
2586		set status error
2587	    }
2588	    default {
2589		set status [lindex $res 5]
2590		if {$status == "not_found"} {
2591		    tk_messageBox -icon warning -type ok -message "Filter Error: Failed to set conditional goal filter. Goal template or module may be undefined."
2592		    ;# treat as an error
2593		    set status error
2594		}
2595	    }
2596	}
2597	set tkecl(filter,status) $status
2598    } elseif {$tkecl(filter,status) != "error"} {
2599	# enable filter goal
2600	set res [ec_rpcq reenable_usepred () tracer_tcl]
2601	switch $res {
2602	    fail  -
2603	    throw {
2604		tk_messageBox -icon error -type ok -message "Filter Error: Exception raised when setting the conditional goal filter. Please check goal template/condition for syntax error."
2605		set tkecl(filter,status) error
2606	    }
2607	    default {
2608		set tkecl(filter,status) continue
2609	    }
2610	}
2611}
2612
2613    return $tkecl(filter,status)
2614}
2615
2616
2617proc tkecl:fields_disable {ec_tracer} {
2618    $ec_tracer.filter.predsettings.predmatch configure -state disabled
2619    $ec_tracer.filter.predsettings.predmatch config -foreground darkgray
2620    $ec_tracer.filter.predsettings.predmatch config -background lightgray
2621    $ec_tracer.filter.predsettings.predmodule configure -state disabled
2622    $ec_tracer.filter.predsettings.predmodule config -foreground darkgray
2623    $ec_tracer.filter.predsettings.predmodule config -background lightgray
2624    $ec_tracer.filter.predsettings.predmodule2combo configure -state disabled
2625    $ec_tracer.filter.predsettings.predmodule2combo config -foreground darkgray
2626    $ec_tracer.filter.predsettings.predmodule2combo config -background lightgray
2627    $ec_tracer.filter.predsettings.predcondition configure -state disabled
2628    $ec_tracer.filter.predsettings.predcondition config -foreground darkgray
2629    $ec_tracer.filter.predsettings.predcondition config -background lightgray
2630
2631    $ec_tracer.filter.settings.port_fail configure -state normal
2632    $ec_tracer.filter.settings.port_leave configure -state normal
2633
2634}
2635
2636proc tkecl:enable_pred {ec_tracer} {
2637    global tkecl
2638
2639    $ec_tracer.filter.predsettings.predmatch configure -state normal
2640    $ec_tracer.filter.predsettings.predmatch config -foreground black
2641    $ec_tracer.filter.predsettings.predmatch config -background white
2642    $ec_tracer.filter.predsettings.predmodule configure -state normal
2643    $ec_tracer.filter.predsettings.predmodule configure -editable 1
2644    $ec_tracer.filter.predsettings.predmodule config -foreground black
2645    $ec_tracer.filter.predsettings.predmodule config -background white
2646    $ec_tracer.filter.predsettings.predmodule2combo configure -state normal
2647    $ec_tracer.filter.predsettings.predmodule2combo configure -editable 0
2648    $ec_tracer.filter.predsettings.predmodule2combo config -foreground black
2649    $ec_tracer.filter.predsettings.predmodule2combo config -background white
2650    $ec_tracer.filter.predsettings.predcondition configure -state normal
2651    $ec_tracer.filter.predsettings.predcondition config -foreground black
2652    $ec_tracer.filter.predsettings.predcondition config -background white
2653
2654    set tkecl(filter_port,fail) 0
2655    $ec_tracer.filter.settings.port_fail configure -state disabled
2656    set tkecl(filter_port,leave) 0
2657    $ec_tracer.filter.settings.port_leave configure -state disabled
2658
2659}
2660
2661
2662proc tkecl:observe_goal {invoc} {
2663
2664    tkinspect:inspect_command invoc($invoc) [list record_observed invoc($invoc) [list 1] Invocation:$invoc] {S[S*]S}
2665}
2666
2667
2668#---------------------------------------------------------------
2669# Directory selection
2670#---------------------------------------------------------------
2671proc tkecl:get_newcwd {} {
2672    tkecl:newcwd [tkecl:getDirectory [pwd] "Set Current Working Directory"]
2673}
2674
2675# change eclipse's cwd and set $tkecl(cwd) to its eclipse name
2676proc tkecl:newcwd {newdir} {
2677    global tkecl
2678
2679    if {![string match "" $newdir]} {
2680	set tkecl(cwd) [lindex [ec_rpcq [list os_file_name _ $newdir] {(_S)}] 1]
2681	;# cd now done in ECLiPSe to ensure that it is the ECLiPSe side's
2682	;# cwd that is changed
2683	switch [ec_rpcq [list cd $tkecl(cwd)] {(S)}] {
2684	    fail -
2685	    throw {
2686		tk_messageBox -icon warning -type ok -message "Unable to set current directory to $newdir"
2687	    }
2688	}
2689
2690    }
2691}
2692
2693proc tkecl:paths_menu {p name} {
2694    set menu [menu $p.m -tearoff 0 -postcommand [list tkecl:build_path_menu $p.m $p $name]]
2695}
2696
2697proc tkecl:build_path_menu {menu p name} {
2698    global tkecl
2699
2700    $menu delete 0 end ;# get rid of old entries
2701    $menu add command -label "Add a new directory" -command \
2702	    [list tkecl:add_new_path $name]
2703    $menu add separator
2704
2705    set i 0
2706    foreach {item} $tkecl($name) {
2707	;# probably treat all spaces as breaks in name!
2708	$menu add command -label $item -command [list tkecl:change_one_path $name $p $item $i]
2709	incr i
2710    }
2711}
2712
2713proc tkecl:add_new_path {name} {
2714    global tkecl
2715
2716    tkecl:gui_edit_one_path Insert $name [pwd] 0
2717
2718    if {[llength $tkecl($name)] != 0} {
2719	ec_rpcq [list set_flag $name $tkecl($name)] {(()[S*])}
2720    }
2721
2722}
2723
2724proc tkecl:getDirectory {initdir title} {
2725    return [tkecl:get_path_popup $initdir directory \
2726		[list tk_chooseDirectory -initialdir $initdir -title $title]]
2727}
2728
2729proc tkecl:getEcFile {initdir title} {
2730    global tkecl
2731
2732    # we used to have -initialfile $tkecl(last_source_file), but that
2733    # overrides -initialdir, and is not available on Aqua Tk (b418)
2734    set tkecl(last_source_file) \
2735	[tkecl:get_path_popup $initdir "file" [list tk_getOpenFile \
2736	       -defaultextension $tkecl(pref,defaultextension) \
2737	       -filetypes $tkecl(filetypes) -title $title \
2738	       -initialdir $initdir \
2739	       ] \
2740	]
2741    return $tkecl(last_source_file)
2742}
2743
2744# like tkecl:getEcFile but allows non-existing files to be selected
2745# note that underlying widget has `Save' for the select button, and also
2746# a warning about overwritting the file if the file already exists.
2747# *No* file is saved, only the filename is returned. Should try and see
2748# if we can disable this `feature'
2749proc tkecl:getNewEcFile {initdir title} {
2750    global tkecl
2751
2752    set tkecl(last_source_file) \
2753    	[tkecl:get_path_popup $initdir "file" [list tk_getSaveFile \
2754               -defaultextension $tkecl(pref,defaultextension) \
2755	       -filetypes $tkecl(filetypes) -title $title -initialdir $initdir \
2756	       ] \
2757	]
2758    return $tkecl(last_source_file)
2759}
2760
2761
2762# only allow a GUI path selection if embedded, or if Tcl side has same host as
2763# ECLiPSe side, as filespace may be different otherwise
2764proc tkecl:get_path_popup {initpath pathtype browsecmd} {
2765    global tkecl
2766
2767    set echostname [lindex [ec_rpcq [list get_flag hostname _] (()_)] 2]
2768    if {([ec_interface_type] == "embedded") ||
2769       ([string compare [info hostname] $echostname] == 0)} {
2770	    return [eval $browsecmd]
2771
2772    } else {
2773	;# ask user to type in path name instead
2774	set tkecl(get_path_name) $initpath
2775	set gdir [toplevel .ec_tools.get_path]
2776	wm title $gdir "Get $pathtype name"
2777	pack [frame $gdir.bf] -side bottom -expand true -fill x
2778	pack [entry $gdir.e -relief sunken -width 25 -textvariable tkecl(get_dir_name)] -side right -expand true -fill x
2779	pack [label $gdir.l -text "Please type in the $pathtype name"] -side left
2780	pack [button $gdir.bf.ok -command "destroy $gdir" -text OK] -side left -expand true -fill x
2781	pack [button $gdir.bf.cancel -text Cancel -command "set tkecl(get_path_name) {}; destroy $gdir"] -side right -expand true -fill x
2782	bind $gdir.e <Return> "destroy $gdir"
2783	$gdir.e xview moveto 1.0
2784	$gdir.e icursor end
2785	focus $gdir.e
2786	tkwait window $gdir
2787	return $tkecl(get_path_name)
2788    }
2789}
2790
2791proc tkecl:change_one_path {name p item i} {
2792    global tkecl
2793
2794    set w $p.change
2795
2796    if ![winfo exists $w] {
2797	set old [focus]
2798	set tkecl(path_to_change) [lindex [ec_rpcq [list os_file_name $item _] \
2799		(S_)] 2]
2800	toplevel $w
2801	wm title $w "Change one path for $name"
2802	tkwait visibility $w
2803	focus $w
2804	grab $w
2805	pack [entry $w.e -bg white -width 40 -textvariable tkecl(path_to_change) \
2806		-relief sunken] -side top -expand 1 -fill both
2807	bind $w.e <Return> [list tkecl:perform_path_change Replace $name \
2808		$tkecl(path_to_change) $i]
2809	pack [button $w.replace -command [list tkecl:gui_edit_one_path Replace $name\
2810		$item $i] -text Replace] -side left -expand 1 -fill both
2811	pack [button $w.delete -command [list tkecl:perform_path_change Delete $name \
2812		$item $i] -text Delete] -side left -expand 1 -fill both
2813	pack [button $w.insert -command [list tkecl:gui_edit_one_path Insert $name \
2814		$item $i] -text Insert] -side left -expand 1 -fill both
2815	pack [button $w.cancel -text Cancel -command "destroy $w; set tkecl($name) [list $tkecl($name)]"] -side left -expand 1 -fill both
2816    }
2817    tkwait variable tkecl($name)
2818
2819    if {[llength $tkecl($name)] == 0} {
2820	ec_rpcq [list set_flag $name $tkecl($name)] {(()[])}
2821    } else {
2822	ec_rpcq [list set_flag $name $tkecl($name)] {(()[S*])}
2823    }
2824    grab release $w
2825    focus $old
2826    destroy $w
2827
2828}
2829
2830proc tkecl:gui_edit_one_path {action name path i} {
2831    global tkecl
2832
2833    set path [lindex [ec_rpcq [list os_file_name $path _] (S_) ] 2]
2834    set new [tkecl:getDirectory $path "$action a path"]
2835    if ![string match "" $new] {
2836	set new [lindex [ec_rpcq [list os_file_name _ $new] (_S) ] 1]
2837	tkecl:perform_path_change $action $name $new $i
2838    } else {
2839	set tkecl($name) $tkecl($name) ;# make sure that tkwait does get its `changes'
2840    }
2841}
2842
2843proc tkecl:perform_path_change {action name new i} {
2844    global tkecl
2845
2846    switch -exact -- $action {
2847	Replace {
2848	    set tkecl($name) [lreplace $tkecl($name) $i $i $new]
2849	}
2850	Insert {
2851	    set tkecl($name) [linsert $tkecl($name) $i $new]
2852	}
2853	Delete {
2854	    set tkecl($name) [lreplace $tkecl($name) $i $i]
2855	}
2856    }
2857}
2858
2859#---------------------------------------------------------------
2860# Change Output mode
2861#---------------------------------------------------------------
2862
2863proc tkecl:Set_output_mode {popmode return} {
2864    global outputmodes
2865
2866    bind $popmode <Enter> {focus %W}
2867    foreach {f modes status descr unsetd triopts tridesc tristatus} [lindex $return 2] {
2868	set i -1
2869	foreach m $modes s $status d $descr u $unsetd {
2870	    set l $m
2871	    if [string match "." $m] {set m period} ;# catch special chars. here
2872	    set outputmodes($popmode.l$m) $s
2873	    set outputmodes($popmode.l$m,set) $d
2874	    set outputmodes($popmode.l$m,unset) $u
2875	    incr i
2876	    grid [checkbutton $popmode.c$m -onvalue 1 -offvalue 0 -text $l\
2877		    -anchor w -variable outputmodes($popmode.l$m) -command "tkecl:Change_output_options $m $popmode.l$m"] \
2878		    -sticky news -row $i -column 0
2879	    if {$s == 1} {
2880		set label $d
2881	    } else {
2882		set label $u
2883	    }
2884	    grid [label $popmode.l$m -text $label] -sticky w -row $i -column 1
2885	    bind $popmode <Key-$m> {
2886		regexp {^(.+)\.[^\.]+$} %W null parent
2887		set lw $parent.l%K
2888		if {$outputmodes($lw) == 1} {
2889		    set outputmodes($lw) 0
2890		} else {
2891		    set outputmodes($lw) 1
2892		}
2893		tkecl:Change_output_options %K $lw
2894	    }
2895
2896#	    balloonhelp $popmode.c$m $d
2897	} ;# foreach m ...
2898
2899	set trinames ""
2900	foreach tri0 $triopts tdes0 $tridesc s $tristatus {
2901	    incr i
2902	    set f [frame $popmode.c$i]
2903	    set tri [lrange $tri0 1 end] ;# drop functor
2904	    set tdes [lrange $tdes0 1 end]
2905	    set name ""
2906	    append name [lindex $tri 0] [lindex $tri 1]
2907	    lappend trinames $name
2908	    set j 0
2909	    set outputmodes($popmode,t$name) $s
2910	    set outputmodes($popmode,t$name,s) $tri
2911	    set outputmodes($popmode,t$name,d) $tdes
2912	    foreach mode $tri d $tdes {
2913		grid [radiobutton $f.b$mode -variable outputmodes($popmode,t$name) \
2914			-text $mode -value $mode -anchor w\
2915		        -command "tkecl:Change_output_trioptions $mode $name \
2916			    $popmode.l$name $popmode"] -row 0 -column $j
2917		incr j
2918		if [string match $mode $s] {
2919		    grid [label $popmode.l$name -text $d] -sticky w -row $i -column 1
2920		}
2921	    }
2922	    grid $f -sticky news -row $i -column 0
2923	}
2924	grid [button $popmode.end -command "destroy $popmode" -text Set] \
2925	        -sticky news -row [expr $i + 1] -column 0 -columnspan 2
2926#	        -sticky news -row [expr ($i/3) + 1] -column 0 -columnspan 3
2927    }
2928    tkwait window $popmode
2929    set newmodes "\""
2930    foreach m $modes {
2931	set l $m
2932	if [string match "." $m] {set m period} ;# catch special chars. here
2933	if {$outputmodes($popmode.l$m) == 1} {
2934	    append newmodes $l
2935	}
2936    }
2937    foreach name $trinames { ;# add in the tristate modes
2938	if {![string match $outputmodes($popmode,t$name) off]} {
2939	    append newmodes $outputmodes($popmode,t$name)
2940	}
2941    }
2942    return [append newmodes \"]
2943
2944}
2945
2946# update label for the simple output options
2947proc tkecl:Change_output_options {mode w} {
2948    global outputmodes
2949
2950    ;# called after mode has been changed to new value
2951    if {$outputmodes($w) == 1} {
2952	$w configure -text $outputmodes($w,set)
2953    } else {
2954	$w configure -text $outputmodes($w,unset)
2955    }
2956}
2957
2958# update label for the tri-state options
2959proc tkecl:Change_output_trioptions {selected name label w} {
2960    global outputmodes
2961
2962    foreach opt $outputmodes($w,t$name,s) d $outputmodes($w,t$name,d) {
2963	;# find the one that matches selected
2964	if [string match $selected $opt] {
2965	    $label configure -text $d
2966	}
2967    }
2968}
2969
2970
2971#----------------------------------------------------------------------
2972# Compile note pad
2973#----------------------------------------------------------------------
2974
2975proc tkecl:compile_pad {} {
2976
2977    set w .ec_tools
2978    if [winfo exists $w.cpad] {
2979	tkinspect:RaiseWindow $w.cpad
2980	return
2981    }
2982    set pad [toplevel $w.cpad]
2983    wm title $pad "Compile scratch-pad"
2984    text $pad.t -wrap none -bg white -yscrollcommand "$pad.vscroll set" -xscrollcommand "$pad.hscroll set"
2985    set bbar [frame $pad.bbar]
2986    pack $bbar -side bottom -fill x
2987       pack [button $bbar.com -text "Compile All" -command "tkecl:do_compile_all $pad.t"] -side left -expand 1 -fill x
2988       pack [button $bbar.sel -text "Compile Selection" -command "tkecl:do_compile_sel $pad.t"] -side left -expand 1 -fill x
2989       pack [button $bbar.end -text Close -command "wm withdraw $w.cpad"] -side left -expand 1 -fill x
2990    pack [scrollbar $pad.vscroll -command "$pad.t yview"] -side right -fill y
2991    pack [scrollbar $pad.hscroll -command "$pad.t xview" -orient horizontal] -side bottom -fill x
2992    pack $pad.t -expand 1 -fill both
2993    bind $pad <Alt-h> "tkecl:Get_helpfileinfo scra $pad"
2994    balloonhelp $bbar "Type in (short) ECLiPSe code for compilation. Can compile everything in window, or only selection."
2995    focus $pad.t
2996
2997}
2998
2999proc tkecl:do_compile_all {t} {
3000    ec_rpcq_check [list compile_string [$t get 1.0 end]] (S) tracer_tcl
3001}
3002
3003proc tkecl:do_compile_sel {t} {
3004    foreach {start end} [$t tag ranges sel] {
3005       ec_rpcq_check [list compile_string [$t get $start $end]] (S) tracer_tcl
3006    }
3007}
3008
3009
3010#----------------------------------------------------------------------
3011# Statistics display
3012#----------------------------------------------------------------------
3013proc tkecl:handle_statistics {} {
3014    global tkecl
3015
3016    tkecl:create_stat_window
3017    set data [lindex [ec_rpcq_check [list report_stats $tkecl(pref,stats_interval) _] (D_) tracer_tcl] 2]
3018    tkecl:display_stat $data
3019}
3020
3021proc tkecl:display_stat {data} {
3022    global tkecl
3023
3024    ;# colours are in pairs: dark and light versions
3025    set ec_stats .ec_tools.ec_stats
3026    if ![winfo exists $ec_stats] {
3027	return
3028    }
3029
3030    set colours [list #00d040 #00f090 #c00000 #f00000 #c0c000 #ffff00 \
3031	    #b000b0 #f000f0  #c07000 #ff9000 #50d0b0 #a0ffe0 #000090 #0000ff]
3032    set cindex 0
3033    set h 85   ;# these are for the pie charts
3034    set w 85
3035    foreach item  $data {
3036        switch -exact -- [lindex $item 0] {
3037	    times  {
3038		set user [lindex $item 1]
3039		set real [lindex $item 2]
3040		foreach {gctime ngc gccol gcratio} [lrange [lindex $item 3] 1 end] {
3041		    break
3042		}
3043		set tframe $ec_stats.times
3044		set textf $tframe.text
3045		set pie $tframe.pie
3046		if ![winfo exists $tframe] {
3047		    pack [frame $tframe] -side top
3048		    pack [canvas $pie -width [expr $w + 10] -height [expr $h + 10]] -side left
3049		    pack [frame $textf] -side right
3050		    pack [frame $textf.times -relief ridge -borderwidth 3] -side top -padx 2 -pady 2
3051		    grid [label $textf.times.a -text "total time" -width 15 -anchor e] -row 1 -column 0
3052		    grid [label $textf.times.b -text "gc time" -width 15 -anchor e] -row 1 -column 1
3053		    grid [label $textf.times.c -text "\% user" -width 10 -anchor e] -row 1 -column 2
3054		    grid [label $textf.times.user -width 15 -anchor e] -row 2 -column 0
3055		    grid [label $textf.times.gc -width 15 -anchor e] -row 2 -column 1 -padx 2 -pady 2
3056		    grid [label $textf.times.userf -width 10 -anchor e] -row 2 -column 2 -padx 2 -pady 2
3057		    grid [label $textf.times.label -text "User CPU Time"] -row 0 -column 0 -columnspan 2 -sticky news
3058		    pack [frame $textf.gc -relief ridge -borderwidth 3] -side bottom
3059		    grid [label $textf.gc.a -text "total collected" -width 16 -anchor e] -row 1 -column 0
3060		    grid [label $textf.gc.b -text "\# gc" -width 9 -anchor e] -row 1 -column 1
3061		    grid [label $textf.gc.c -text "% recovered" -width 15 -anchor e] -row 1 -column 2
3062		    grid [label $textf.gc.col -width 16 -anchor e] -row 2 -column 0
3063		    grid [label $textf.gc.ngc -width 9 -anchor e] -row 2 -column 1
3064		    grid [label $textf.gc.ratio -width 15 -anchor e] -row 2 -column 2
3065		    grid [label $textf.gc.label -text "Garbage Collection"] -row 0 -column 0 -columnspan 3 -sticky news
3066		    set tkecl(stat,times,user) 0
3067		    set tkecl(stat,times,real) 0
3068		    balloonhelp $pie "Portion of total time spent on garbage collection with respect to total user CPU time"
3069		    balloonhelp $textf.gc "Garbage collection statistics"
3070		    balloonhelp $textf.times "Timing statistics"
3071		}
3072
3073		$textf.times.user configure -text "$user"
3074		$textf.times.gc configure -text "[expr round($gctime*100)/100.0]"
3075		$textf.times.userf configure -text \
3076		    "[expr round( ($user - $tkecl(stat,times,user)) / \
3077		    ($real - $tkecl(stat,times,real)) * 10000) / 100.0]"
3078		set tkecl(stat,times,user) $user
3079		set tkecl(stat,times,real) $real
3080
3081		$textf.gc.ngc configure -text "$ngc"
3082		$textf.gc.ratio configure -text "[expr round($gcratio*100)/100.0]"
3083		$textf.gc.col configure -text "$gccol"
3084		$pie create oval 10 10 $h $w -fill white
3085		if {$ngc != 0} {
3086		    set extent [expr -360*$gctime/$user]
3087		    $pie create arc 10 10 $h $w -start 90 -extent $extent -style pieslice -fill blue
3088		}
3089	    }
3090
3091	    memory {
3092		set total [lindex $item 2]
3093		set mname [lindex $item 1]
3094		set ref   [lindex $item 3]
3095		set mframe $ec_stats.$mname
3096		set pie $mframe.pie
3097		set textf $mframe.text
3098		if ![winfo exists $mframe] {
3099		    pack [frame $mframe -relief sunken -borderwidth 2] -side top
3100		    pack [canvas $pie -width [expr $w + 20] -height [expr $h + 10]] -side left
3101		    pack [frame $textf] -side right
3102		    pack [frame $textf.headings] -side top -expand 1 -fill x
3103		    grid [label $textf.headings.main -text [string toupper $mname 0 0] -anchor w] -row 0 -column 0 -columnspan 4 -sticky news
3104		    grid [label $textf.headings.a -text {} -width 8 -anchor e] -row 1 -column 0 -sticky news
3105		    grid [label $textf.headings.b -text used -width 11 -anchor e] -row 1 -column 1 -sticky news
3106		    grid [label $textf.headings.c -text alloc -width 11 -anchor e] -row 1 -column 2 -sticky news
3107		    grid [label $textf.headings.d -text peak -width 11 -anchor e] -row 1 -column 3 -sticky news
3108
3109		    balloonhelp $textf "Memory statistics (in bytes) for the $mname memory area"
3110		    balloonhelp $pie "Proportion of memory used/allocated in the $mname area with respect to $ref"
3111
3112		}
3113		$pie create oval 10 10 $h $w -fill white
3114
3115		set direction -1.0
3116		foreach component [lrange $item 4 end] {
3117		    switch -exact -- [lindex $component 0] {
3118			stack {
3119			    foreach {cname alloc used peak} [lrange $component 1 end] {
3120				break
3121			    }
3122			    # without round() here we get funny effects with the pie charts on Windows
3123			    set startused 90
3124			    set extentused [expr round($direction*$used/$total*360)]
3125			    set startfree [expr $startused + $extentused]
3126			    set extentfree [expr round($direction*($alloc-$used)/$total*360)]
3127			    set dcol [lindex $colours $cindex]
3128			    incr cindex 1
3129			    set lcol [lindex $colours $cindex]
3130			    incr cindex 1
3131
3132			    set cframe $textf.$cname
3133			    if ![winfo exists $cframe] {
3134				pack [frame $cframe] -side bottom -expand 1 -fill x
3135				grid [label $cframe.name -text $cname -width 8 -anchor e] -row 0 -column 0 -sticky news
3136				grid [label $cframe.used -foreground $dcol -width 11 -anchor e] -row 0 -column 1 -sticky news
3137				grid [label $cframe.alloc -foreground $lcol -width 11 -anchor e] -row 0 -column 2 -sticky news
3138				grid [label $cframe.peak -width 11 -anchor e] -row 0 -column 3 -sticky news
3139			    }
3140			    $cframe.alloc configure -text $alloc
3141			    $cframe.used configure -text  $used
3142			    $cframe.peak configure -text  $peak
3143
3144			    $pie create arc 10 10 $h $w -start $startused -extent $extentused -style pieslice -fill $dcol
3145			    $pie create arc 10 10 $h $w -start $startfree -extent $extentfree -style pieslice -fill $lcol
3146			}
3147		    }
3148		    set direction [expr -$direction]
3149		}
3150	    }
3151	}
3152    }
3153}
3154
3155proc tkecl:create_stat_window {} {
3156
3157    set ec_stats .ec_tools.ec_stats
3158    if {![winfo exists $ec_stats]} {
3159	toplevel $ec_stats
3160	wm title $ec_stats "ECLiPSe statistics"
3161	wm resizable $ec_stats 0 0
3162	pack [frame $ec_stats.buttons] -side bottom -expand 1 -fill x
3163	pack [button $ec_stats.buttons.change -command "tkecl:change_stat_interval" -text "Change interval"] -side left -expand 1 -fill x
3164	pack [button $ec_stats.buttons.close -command "tkecl:kill_stat_window" -text "Close"] -side right -expand 1 -fill x
3165	bind $ec_stats <Alt-h> "tkecl:Get_helpfileinfo stat $ec_stats"
3166
3167	balloonhelp $ec_stats.buttons.change "Change the time interval with which the statistics are updated"
3168	balloonhelp $ec_stats.buttons.close "Close this window and quit monitoring statistics"
3169    } else {
3170	tkinspect:RaiseWindow $ec_stats
3171    }
3172}
3173
3174
3175proc tkecl:change_stat_interval {} {
3176    global tkecl
3177
3178    set tkecl(stats_interval1) $tkecl(pref,stats_interval)
3179    set w .ec_tools.ec_stats.interval
3180    if {![winfo exists $w]} {
3181	toplevel $w
3182	wm title $w "Statistics Reporting Interval"
3183	pack [frame $w.f] -side top
3184	pack [label $w.f.l -text "New reporting interval (sec.)"] -side left
3185	pack [entry $w.f.e -relief sunken -width 10 -textvariable tkecl(stats_interval1)] -side right -expand 1 -fill both
3186	pack [button $w.set -text "Set" -command "tkecl:set_stat_interval $w"] -side left -fill x -expand 1
3187	pack [button $w.cancel -text "Cancel" -command "destroy $w"] -side left -fill x -expand 1
3188	bind $w.f.e <Return> "tkecl:set_stat_interval $w"
3189	focus $w.f.e
3190
3191	balloonhelp $w "Change time interval at which the statistics are \
3192		updated in the statistics window.\nType in a positive number \
3193		and click `Set' to change, or `Cancel' to not change"
3194    } else {
3195	tkinspect:RaiseWindow $w
3196	focus $w.f.e
3197    }
3198}
3199
3200proc tkecl:set_stat_interval {w} {
3201    global tkecl
3202
3203    if [regexp {^([0-9]+[.][0-9]+)|([0-9]+)$} $tkecl(stats_interval1)] {
3204	set tkecl(pref,stats_interval) $tkecl(stats_interval1)
3205	ec_rpcq_check [list change_report_interval $tkecl(pref,stats_interval)] (D) tracer_tcl
3206	destroy $w
3207    } else {
3208	set tkecl(stats_interval1) $tkecl(pref,tats_interval)
3209	bell
3210    }
3211}
3212
3213proc tkecl:kill_stat_window {} {
3214    ec_rpcq stop_report_stats () tracer_tcl
3215    destroy .ec_tools.ec_stats
3216}
3217
3218proc tkecl:handle_stats_report {stream {length {}}} {
3219    tkecl:display_stat [ec_read_exdr [ec_streamnum_to_channel $stream]]
3220}
3221
3222#----------------------------------------------------------------------
3223# Grace-style term matrix display
3224#----------------------------------------------------------------------
3225proc tkecl:handle_mat_flush {stream {length {}}} {
3226    global tkecl_displayvals
3227
3228    set commandline [ec_read_exdr [ec_streamnum_to_channel $stream]]
3229    set command [lindex $commandline 0]
3230    ;#puts "line-$commandline"
3231    set name [lindex $commandline 1] ;# name is the numeric identifier for matrix
3232
3233    set ec_matdisplay .ec_tools.ec_matdisplay$name
3234    if {![winfo exists $ec_matdisplay]} {
3235	if {[string match setup $command]} { ;# initial setup
3236	    foreach {ecname row col module} [lrange $commandline 2 end] {
3237		append title $ecname "@" $module
3238		set tkecl_displayvals($name,ecname) $ecname
3239		set tkecl_displayvals($name,module) $module
3240		tkecl:setup_disptable $name $title $row $col
3241	    }
3242	    return
3243	} else {
3244	    ;# matrix display window not there, and we are not initialising
3245	    ;# been kill explicitly, do not redisplay
3246	    return
3247	}
3248    }
3249
3250    switch -exact -- $command {
3251	setup {
3252	    tk_messageBox -type ok -message "Display matrix protocol error: trying to initialise existing matrix"
3253	}
3254
3255	disp {
3256
3257	    foreach {row col new ground back} [lrange $commandline 2 end] {
3258		if {$tkecl_displayvals($name,$row,$col,stop) == 1}  {
3259		    append id r $row c $col
3260		    set tkecl_displayvals($name,$row,$col,prev) \
3261			   [lindex [$ec_matdisplay.$id config -text] end]
3262		    if {$tkecl_displayvals($name,update) == 0 && \
3263			    [string match nonground $ground]} {
3264			return
3265		    }
3266		    $ec_matdisplay.$id config -text $new
3267		    if [string match $back back] {
3268			;#set tkecl_displayvals($name,back) 1
3269			set tkecl_displayvals($name,back) [list $row $col]
3270			set colour pink
3271		    } else {
3272			;#set tkecl_displayvals($name,back) 0
3273			set colour beige
3274		    }
3275		    $ec_matdisplay.$id config -foreground black
3276		    $ec_matdisplay.$id config -background $colour
3277		    $ec_matdisplay.b.cont configure -state normal
3278		    tkinspect:RaiseWindow $ec_matdisplay
3279		    tkwait variable tkecl_displayvals($name,cont)
3280		    set tkecl_displayvals($name,back) [list 0 0]
3281		    if [winfo exists $ec_matdisplay] {
3282			$ec_matdisplay.$id config -background lightgray
3283			$ec_matdisplay.b.cont configure -state disabled
3284		    }
3285		} elseif {(($tkecl_displayvals($name,update) == 1) ||
3286		    ![string match nonground $ground])} {
3287			append id r $row c $col
3288			set tkecl_displayvals($name,$row,$col,prev) \
3289			   [lindex [$ec_matdisplay.$id config -text] end]
3290			$ec_matdisplay.$id config -text $new
3291		    if [string match $back back] {
3292			$ec_matdisplay.$id config -foreground red
3293		    } else {
3294			$ec_matdisplay.$id config -foreground black
3295		    }
3296 		}
3297	    }
3298
3299	}
3300
3301	interact {
3302	    $ec_matdisplay.b.cont configure -state normal
3303	    tkwait variable tkecl_displayvals($name,cont)
3304	    if [winfo exists $ec_matdisplay] {
3305		$ec_matdisplay.b.cont configure -state disabled
3306	    }
3307	}
3308
3309	kill {
3310	    destroy $ec_matdisplay
3311	}
3312
3313
3314    }
3315}
3316
3317proc tkecl:setup_disptable {name title row col} {
3318    global tkecl_displayvals
3319
3320    set tkecl_displayvals($name,cont) 0
3321    ;#set tkecl_displayvals($name,back) 0
3322    set tkecl_displayvals($name,back) [list 0 0]
3323    set parent [toplevel .ec_tools.ec_matdisplay$name]
3324    wm title $parent "Term display for $title"
3325    set tkecl_displayvals($name,row) $row
3326    set tkecl_displayvals($name,col) $col
3327    set tkecl_displayvals($name,update) 1
3328    bind $parent <Button-3> "tkecl:display_popup $parent %W $name $row %X %Y"
3329    bind $parent <Control-Button-1> "tkecl:display_popup $parent %W $name $row %X %Y"
3330
3331    for {set i 1} {$i <= $row} {incr i 1} {
3332	grid [label $parent.r$i -text $i -relief groove -width 5 -fg red -bg lightblue] -row $i -column 0 -sticky news
3333    }
3334    for {set i 1} {$i <= $col} {incr i 1} {
3335	grid [label $parent.c$i -text $i -relief groove -width 15 -fg red -bg lightblue] -row 0 -column $i -sticky news
3336    }
3337    for {set i 1} {$i <= $row} {incr i 1} {
3338	for {set j 1} {$j <= $col} {incr j 1} {
3339	    set id ""
3340	    append id r $i c $j
3341	    grid [label $parent.$id -text "-- unknown --" -relief ridge -width 15] -row $i -column $j -sticky news
3342	    bind $parent.$id <Double-Button-1> "tkinspect:Inspect_term_init display($name,$i,$j)"
3343	    set tkecl_displayvals($name,$i,$j,stop) 0
3344	}
3345    }
3346    grid [frame $parent.b] -row [expr $row + 1] -column 0 -columnspan [expr $col + 1] -sticky news
3347    pack [button $parent.b.cont -text "Continue" -command \
3348	    "set tkecl_displayvals($name,cont) 1"] -side left -fill x -expand 1
3349    pack [button $parent.b.kill -text "Kill display" -command "destroy $parent"] -side right -fill x
3350    pack [checkbutton $parent.b.update -text "Update on ground" -variable \
3351	    tkecl_displayvals($name,update) -onvalue 0 -offvalue 1] \
3352	    -side right -fill x
3353    pack [button $parent.b.stop -text "stop all" -command \
3354	    "tkecl:all_mat_break 1 $name $row $col"] -side right -fill x
3355    pack [button $parent.b.go -text "stop none" -command \
3356	    "tkecl:all_mat_break 0 $name $row $col"] -side right -fill x
3357
3358    bind $parent.b.kill <Destroy> "tkecl:kill_display_matrix $name"
3359
3360    for {set j 1} {$j <= $col} {incr j 1} {
3361	grid columnconfigure $parent $j -weight 1
3362    }
3363
3364    for {set j 1} {$j <= [expr $row]} {incr j 1} {
3365	grid rowconfigure $parent $j -weight 1
3366    }
3367    balloonhelp $parent "Monitor changes on terms: each matrix cell represents\
3368	     a term and show its current value.\n Right (or control-left) click on cell to get \
3369	     options. Double left click on cell to inspect\n the term in the \
3370             cell. Current and previous (pre-update) values are shown.\n \
3371             On break, changes due to forward execution shown in yellow,\
3372	    changes due to backtracking shown in pink."
3373    balloonhelp $parent.b.cont "Click to continue execution until next break-point.\n (if set, a break-point occurs when a cell is updated)"
3374    balloonhelp $parent.b.stop "Set break-points on all cells"
3375    balloonhelp $parent.b.go "Unset break-points on all cells"
3376    balloonhelp $parent.b.update "Control update events -- if set, only update when cell becomes ground.\n Otherwise, updates depends on make_display_matrix"
3377    balloonhelp $parent.b.kill "Click to kill this display matrix -- program will continue to run without the display matrix"
3378    bind $parent <Alt-h> "tkecl:Get_helpfileinfo disp $parent"
3379}
3380
3381
3382proc tkecl:kill_display_matrix {name} {
3383global tkecl_displayvals
3384# if needed, will go to ECLiPSe side to execute kill_display_matrix
3385
3386
3387  set tkecl_displayvals($name,cont) 1
3388  ;# make sure execute will continue
3389  ;# clean up and remove all Tcl vars associated with this display matrix
3390  foreach matvar [array names tkecl_displayvals $name,*] {
3391      unset tkecl_displayvals($matvar)
3392  }
3393}
3394
3395proc tkecl:all_mat_break {state name row col} {
3396    global tkecl_displayvals
3397
3398    for {set i 1} {$i <= $row} {incr i 1} {
3399	for {set j 1} {$j <= $col} {incr j 1} {
3400	    set tkecl_displayvals($name,$i,$j,stop) $state
3401	}
3402    }
3403}
3404
3405proc tkecl:display_popup {p w name nrow x y} {
3406    global tkecl_displayvals
3407
3408
3409    if [string match disabled [lindex [$p.b.cont configure -state] end]] {return}
3410    set widgetinfo [grid info $w]
3411    foreach {option value} $widgetinfo {
3412	set widget($option) $value
3413    }
3414    if {(![info exists widget(-row)] || $widget(-row) == 0 || $widget(-column) == 0)} {
3415	return
3416    }
3417    if [winfo exists $p.popup] {
3418	destroy $p.popup
3419    }
3420    set m [menu $p.popup -tearoff 0]
3421    $m add command -label "current: [lindex [$w configure -text] end]" ;#-state disabled
3422    $m add command -label "previous: $tkecl_displayvals($name,$widget(-row),$widget(-column),prev)" -state disabled
3423    $m add check -label "Break on updates" -onvalue 1 -offvalue 0 \
3424	    -variable tkecl_displayvals($name,$widget(-row),$widget(-column),stop)
3425    ;#if {$tkecl_displayvals($name,back) == 0}
3426    foreach {brow bcol} $tkecl_displayvals($name,back) {break}
3427    if {$brow != $widget(-row) || $bcol != $widget(-column)} {
3428	    $m add command -label "Inspect this term" -command \
3429		    "tkinspect:Inspect_term_init display($name,$widget(-row),$widget(-column))"
3430    }
3431
3432#    $m add command -label "row: $widget(-row) col: $widget(-column)"
3433    tk_popup $m $x $y
3434}
3435
3436#----------------------------------------------------------------------
3437# Source Display
3438#----------------------------------------------------------------------
3439
3440proc tkecl:setup_source_debug_window {} {
3441    global tkecl
3442
3443    # setup source debug window, text display for source is not packed, as
3444    # it needs to have source text added before displaying it
3445    set ec_source .ec_tools.ec_tracer.tab.source
3446    set tkecl(source_debug,file) ""
3447
3448    .ec_tools.ec_tracer.tab add "Source Context" -window [frame $ec_source]
3449#    label $ec_source.label -text "Source Context"
3450    frame $ec_source.context -relief sunken -borderwidth 1 -bg white
3451    frame $ec_source.control
3452
3453    pack $ec_source.context -side bottom -fill both -expand 1
3454#    pack $ec_source.label -side top  -fill x
3455    scrollbar $ec_source.context.vscroll -command "$ec_source.context.text yview"
3456    scrollbar $ec_source.context.hscroll -command "$ec_source.context.text xview" -orient horizontal
3457    text $ec_source.context.lineno -borderwidth 0  -bg white -width 5 -wrap none -yscrollcommand [list tkecl:vscroll-sync "$ec_source.context.status $ec_source.context.text"]
3458    text $ec_source.context.status -borderwidth 0  -bg white -width 1 -wrap none -yscrollcommand [list tkecl:vscroll-sync "$ec_source.context.lineno $ec_source.context.text"]
3459    text $ec_source.context.text -borderwidth 0  -bg white -xscrollcommand "$ec_source.context.hscroll set" -wrap none -yscrollcommand [list tkecl:vscroll-sync "$ec_source.context.lineno $ec_source.context.status"]
3460    pack $ec_source.context.vscroll -side left -fill y
3461    pack $ec_source.context.hscroll -side bottom -fill x
3462    pack $ec_source.context.lineno -side left -fill y
3463    pack $ec_source.context.status -side left -fill y
3464    pack $ec_source.context.text -side right -fill both -expand 1
3465    bind $ec_source.context.text <Double-Button-1> \
3466	"tkecl:display_source_for_callport $ec_source.context.text; break"
3467    bind $ec_source.context.lineno <Any-Key> "tkecl:readonly_keypress %A"
3468    bind $ec_source.context.lineno <ButtonRelease-2> {break}
3469
3470    bind $ec_source.context.status <Any-Key> "tkecl:readonly_keypress %A"
3471    bind $ec_source.context.status <ButtonRelease-2> {break}
3472    bind $ec_source.context.status <Button-1> "tkecl:toggle_breakpoint $ec_source.context.status; break"
3473
3474    menu $ec_source.context.text.popupmenu -tearoff 0
3475    menu $ec_source.context.text.popupmenu.predmenu
3476    bind $ec_source.context.text <Any-Key> "tkecl:readonly_keypress %A"
3477    bind $ec_source.context.text <ButtonRelease-2> {break}
3478    bind $ec_source.context.text <Button-3> "tkecl:popup_sourcetext_menu $ec_source.context.text %X %Y; break"
3479    bind $ec_source.context.text <Control-Button-1> "tkecl:popup_sourcetext_menu $ec_source.context.text %X %Y; break"
3480    $ec_source.context.text tag configure call_style -foreground #7070ff \
3481	-underline 1 -font tkeclmonobold
3482    $ec_source.context.text tag configure exit_style -foreground #00b000 \
3483	-underline 1 -font tkeclmonobold
3484    $ec_source.context.text tag configure fail_style -foreground red \
3485	-underline 1 -font tkeclmonobold
3486    $ec_source.context.text tag configure ancestor_style -background lightblue \
3487	-relief raised -borderwidth 1
3488    $ec_source.context.text tag configure debug_line -background beige -relief raised -borderwidth 1
3489    $ec_source.context.text tag configure hidden_cr -elide 1
3490    $ec_source.context.text configure -cursor left_ptr
3491
3492    $ec_source.context.status tag configure on -foreground red
3493    $ec_source.context.status tag configure off -foreground lightgray
3494    $ec_source.context.status configure -cursor left_ptr
3495    $ec_source.context.lineno configure -cursor left_ptr
3496
3497    combobox $ec_source.control.select -click single -bg white -listheight 16 -editable 0 \
3498        -postcommand [list tkecl:get_source_debug_filenames $ec_source.control.select] \
3499	-textvariable tkecl(source_debug,file) -labeltext "File:" \
3500	-command tkecl:load_source_debug_file
3501
3502    pack $ec_source.control.select -side left -fill x -expand 1
3503    pack $ec_source.control -side bottom -fill x -expand 1
3504
3505    .ec_tools.ec_tracer.tab activate "Source Context"
3506
3507    balloonhelp $ec_source.context.text "Source context for execution traced by the tracer
3508
3509 Display source file for debugging. Source line for
3510 most recent goal is highlighted, and the current
3511 goal is coloured in blue (call), green (success), or red (failure).
3512
3513 Source context for ancestor goals can also be shown,
3514 highlighted in blue. Hold right mouse button for a
3515 popup menu.
3516
3517 Double-click left mouse button on a port line to display
3518 the source for the predicate called."
3519
3520    balloonhelp $ec_source.context.status "Show port status for line in selected source file: a light gray '#' indicates a port line (not active)\n a red '#' indicates an active breakpoint\nClick left mouse button to toggle the setting of a nearby breakpoint."
3521    balloonhelp $ec_source.context.lineno "Show line numbers for selected source line"
3522    balloonhelp $ec_source.control.select "Select from popup list the source file to display"
3523
3524    # tkwait visibility $ec_source
3525
3526}
3527
3528# adapted from tkdiff
3529proc tkecl:vscroll-sync {windowlist y0 y1} {
3530    global tkecl
3531
3532    set ec_sourcecon .ec_tools.ec_tracer.tab.source.context
3533    $ec_sourcecon.vscroll set $y0 $y1
3534
3535    # if syncing is disabled, we're done. This prevents a nasty
3536    # set of recursive calls
3537    if {[info exists tkecl(disableSyncing)]} {
3538        return
3539    }
3540
3541    # set the flag; this makes sure we only get called once
3542    set tkecl(disableSyncing) 1
3543
3544    # scroll the other windows
3545    foreach window $windowlist {
3546        $window yview moveto $y0
3547    }
3548
3549    # we apparently automatically process idle events after this
3550    # proc is called. Once that is done we'll unset our flag
3551    after idle {catch {unset tkecl(disableSyncing)}}
3552}
3553
3554proc tkecl:popup_sourcetext_menu {t x y} {
3555    global tkecl
3556
3557    # return if no file loaded into source context window
3558    if {[string compare $tkecl(source_debug,file) ""] == 0} return
3559
3560    set m $t.popupmenu
3561    if [winfo exists $m] {
3562	$m delete 0 end
3563    } else {
3564	menu $m -tearoff 0
3565    }
3566
3567    set xypos [winfo pointerxy .ec_tools.ec_tracer]
3568    set line [tkecl:get_current_text_line $t]
3569    $m add command -label "Find..." -command "tkecl:show-find source_debug .ec_tools.ec_tracer.tab.source.context.text .ec_tools.ec_tracer"
3570
3571    $m add cascade -label "Display Predicate..." -menu $m.predmenu
3572    $m add separator
3573    $m add command -label "Refresh this file" -command \
3574	[list tkecl:load_source_debug_file $tkecl(source_debug,file) [$t xview] [$t yview]]
3575    $m add command -label "Edit this file" -command [list tkecl:edit_file $tkecl(source_debug,file)  $line]
3576    set callinfo [tkecl:get_nearest_port_call $tkecl(source_debug,file) $line]
3577    if {$callinfo != ""} {
3578	$m add separator
3579	set parent [lindex $callinfo 0]
3580	set callport [lindex $callinfo 1]
3581	set calldefmodule [lindex $callport 1]
3582	set callspec [lindex $callport 2]
3583	set callname [lindex $callspec 1]
3584	set callarity [lindex $callspec 2]
3585	$m add command -state disabled -label "Nearest tracable call\n$callname/$callarity in $parent"
3586	$m add command -label "Show predicate property for ths predicate" \
3587	    -command [list tkecl:show_pred_prop $calldefmodule $callspec]
3588    }
3589    tk_popup $m $x $y
3590}
3591
3592proc tkecl:show_pred_prop {module callspec} {
3593    global tkecl
3594
3595    set tkecl(predproppred) [lindex [ec_rpcq [list term_string $callspec _] {((()I)_)}] 2]
3596    set tkecl(predpropmodule) $module
3597
3598    tkecl:popup_pred_prop
3599    tkecl:display_predicates dummy
3600    tkecl:display_predprops .ec_tools.predprop.preds
3601}
3602
3603
3604proc tkecl:check_port_call_source {module callspec} {
3605
3606    if [winfo exists .ec_tools.ec_tracer] {
3607	set parent .ec_tools.ec_tracer
3608    } else {
3609	set parent .
3610    }
3611
3612    switch [ec_rpcq [list current_module $module] {(())}] {
3613	fail -
3614	throw {
3615	    tk_messageBox -parent $parent -type ok -message "Definition module $module for call $callspec does not exist"
3616	    return 0
3617	}
3618    }
3619    switch [ec_rpcatq [list is_predicate $callspec] ((()I)) $module] {
3620	fail -
3621	throw {
3622	    tk_messageBox -parent $parent -type ok -message "$callspec is not a user defined predicate in module $module"
3623	    return 0
3624	}
3625    }
3626    switch [ec_rpcatq [list get_flag $callspec source_file _] ((()I)()_) $module] {
3627	fail -
3628	throw {
3629	    tk_messageBox -parent $parent -type ok -message "Unable to access source information for $callspec defined in module $module"
3630	    return 0
3631	}
3632    }
3633
3634    return 1
3635
3636}
3637
3638proc tkecl:get_nearest_port_call {file line} {
3639
3640    set result [ec_rpcq [list find_matching_callinfo $file $line _ _] (SI__) tracer_tcl]
3641
3642    switch $result {
3643	throw -
3644	fail {
3645	    return ""
3646	}
3647	default {
3648	    return [lrange $result 3 4]
3649	}
3650    }
3651}
3652
3653proc tkecl:toggle_breakpoint {t} {
3654    global tkecl
3655
3656    set line [tkecl:get_current_text_line $t]
3657    set result [ec_rpcq [list toggle_source_breakpoint $tkecl(source_debug,file) $line _ _ _] (SI___) tracer_tcl]
3658    if [winfo exists .ec_tools.ec_tracer] {
3659	set parent .ec_tools.ec_tracer
3660    } else {
3661	set parent .
3662    }
3663
3664    switch $result {
3665	fail {
3666	    tk_messageBox  -parent $parent -type ok -message "No break ports found in file $tkecl(source_debug,file)"
3667
3668	}
3669	throw {
3670	    # shouldn't happen!
3671	    bell
3672	}
3673	default {
3674	    set breakline [lindex $result 3]
3675	    set old_style [lindex $result 4]
3676	    set new_style [lindex $result 5]
3677	    set ec_breakstatus .ec_tools.ec_tracer.tab.source.context.status
3678
3679	    $ec_breakstatus tag remove $old_style $breakline.0 $breakline.end
3680	    $ec_breakstatus tag add $new_style $breakline.0 $breakline.end
3681
3682	}
3683    }
3684}
3685
3686proc tkecl:get_source_debug_filenames {w} {
3687
3688    set source_files \
3689	[lindex [ec_rpcq [list current_files_with_port_lines _] (_) tracer_tcl] 1]
3690    foreach file $source_files {
3691	$w add [lindex $file 0]		;# $file is an atom (1-element list)
3692    }
3693
3694}
3695
3696proc tkecl:handle_source_debug_print {stream {length {}}} {
3697
3698    set ec_sourcecon .ec_tools.ec_tracer.tab.source.context
3699#    pack forget $ec_sourcecon.text ;# do not display text as it is added....
3700    set source_stream [ec_streamnum_to_channel $stream]
3701    set part [ec_read_exdr $source_stream]
3702    if {$part != ""} {
3703	$ec_sourcecon.text insert end $part
3704    } else {
3705#	pack $ec_sourcecon.text -fill both -expand 1
3706
3707	# Find and hide CR characters (for Windows) - we can't delete them
3708	# because that would break our offset-based positioning within the
3709	# file (we are getting the file in binary from ECLiPSe).
3710	set i 1.0
3711	while {1} {
3712	    set i [$ec_sourcecon.text search "\r" $i]
3713	    if {$i == ""} { break }
3714	    $ec_sourcecon.text tag add hidden_cr $i
3715	    set i "$i+1chars"
3716	}
3717
3718	# Initialise the line and breakpoint columns
3719	$ec_sourcecon.status delete 1.0 end
3720	$ec_sourcecon.lineno delete 1.0 end
3721	# find out the actual number of lines in the file.
3722	regexp {^[0-9]+} [$ec_sourcecon.text index end] lastline
3723	# check if the actual last line (lastline-1) has a newline or not.
3724	# If it does, the last char position will be 0
3725	regexp {^[0-9]+[.]([0-9]+)} [$ec_sourcecon.text index [expr $lastline-1].end] whole  lastchar
3726	# actual number of lines is one less than end if there is a newline
3727	if {$lastchar == 0} {
3728	    set terminating_nl 1
3729	    incr lastline -1
3730	} else {
3731	    set terminating_nl 0
3732	}
3733        # this only works if the source has at least 1 line!
3734	set sstuff {}
3735	set lstuff {1}
3736	for {set i 2} {$i < $lastline} {incr i} {
3737	    append sstuff "\n"
3738	    append lstuff "\n$i"
3739	}
3740	# only add a terminating  newline if the source file has one
3741	if {$terminating_nl == 1} {
3742	    append sstuff "\n"
3743	    append lstuff "\n"
3744	}
3745
3746	$ec_sourcecon.status insert end $sstuff
3747	$ec_sourcecon.lineno insert end $lstuff
3748    }
3749
3750}
3751
3752proc tkecl:show_source_context {invoc greturn} {
3753
3754    set path_info [lindex $greturn 6]
3755    set from [lindex $greturn 7]
3756    set to [lindex $greturn 8]
3757    # is_current_goal/2 must be execute when source is viewed to get
3758    # the current information
3759    set rpc_result [ec_rpcq [list is_current_goal $invoc _] (I_) tracer_tcl]
3760    if {$rpc_result != "fail"} {
3761	set gstyle [lindex $rpc_result 2]
3762    } else {
3763	set gstyle ancestor_style
3764    }
3765
3766    # path_info in quotes because it may have spaces
3767    tkecl:update_source_debug $gstyle $from $to "$path_info"
3768}
3769
3770
3771
3772proc tkecl:update_source_debug {style from to fpath_info} {
3773    global tkecl
3774
3775    set ec_source .ec_tools.ec_tracer.tab.source
3776
3777    if {![winfo exists $ec_source]} {
3778	return
3779    }
3780
3781    set ec_sourcetext $ec_source.context.text
3782    if {$style != "ancestor_style"} {
3783	# reset previous trace call annotations (except debug_line)
3784	$ec_sourcetext tag remove call_style 1.0 end
3785	$ec_sourcetext tag remove exit_style 1.0 end
3786	$ec_sourcetext tag remove fail_style 1.0 end
3787    }
3788    $ec_sourcetext tag remove ancestor_style 1.0 end
3789
3790    if {$fpath_info == "no" || $from < 0} {
3791	# .ec_tools.ec_tracer.tab itemconfigure "Source Context" -state disabled
3792	return
3793    } else {
3794	# get the pathname
3795	set fpath [lindex [lindex $fpath_info 1] 0] ;# atom type (singleton list)
3796    }
3797
3798     if {$tkecl(source_debug,file) != $fpath} {
3799	 if {[tkecl:load_source_debug_file $fpath] == 0} return
3800    } else {
3801	if {$style != "ancestor_style"} {
3802	    $ec_sourcetext tag remove debug_line 1.0 end
3803	}
3804    }
3805
3806    # assume $from, $to -- position information on an annotated term from
3807    # ECLiPSe maps into number of characters from start of file
3808    set from_idx [$ec_sourcetext index "1.0 + $from chars"]
3809    set to_idx [$ec_sourcetext index "1.0 + $to chars"]
3810    $ec_sourcetext tag add $style $from_idx $to_idx
3811    if {$style != "ancestor_style"} {
3812	$ec_sourcetext tag add debug_line "$from_idx linestart" "$to_idx lineend"
3813    }
3814    $ec_sourcetext see $from_idx
3815
3816}
3817
3818
3819proc tkecl:get_current_text_line {t} {
3820
3821    regexp {^[0-9]+} [$t index current] line
3822    return $line
3823}
3824
3825
3826proc tkecl:load_source_debug_file {fpath {xfracs "0 1"} {yfracs "0 1"}} {
3827    global tkecl
3828
3829    set ec_source .ec_tools.ec_tracer.tab.source
3830    set ec_sourcetext $ec_source.context.text
3831    set xfrac [lindex $xfracs 0]
3832    set yfrac [lindex $yfracs 0]
3833
3834    switch [ec_rpcq [list file_is_readable $fpath] (S) tracer_tcl] {
3835	    fail -
3836	    throw {
3837		# source not readable, no display
3838		return 0
3839	    }
3840     }
3841
3842    $ec_sourcetext delete 1.0 end
3843    ec_rpcq [list read_file_for_gui $fpath] (S) tracer_tcl
3844    set tkecl(source_debug,file) $fpath
3845    $ec_source.context.text xview moveto $xfrac
3846    $ec_source.context.text yview moveto $yfrac
3847
3848    set result [ec_rpcq [list breakpoints_for_file $fpath _ _ _] (S___) tracer_tcl]
3849    switch $result {
3850	fail -
3851	throw {
3852	    return 0
3853	}
3854	default {
3855	    set actives [lindex $result 2]
3856
3857	    set ports [lindex $result 3]
3858	    set predslist [lindex $result 4]
3859	    foreach line $ports {
3860		$ec_source.context.status insert $line.0 "#" off
3861	    }
3862	    foreach line $actives {
3863		$ec_source.context.status tag remove off $line.0 $line.end
3864		$ec_source.context.status tag add on $line.0 $line.end
3865	    }
3866	    set predmenu $ec_source.context.text.popupmenu.predmenu
3867	    $predmenu delete 0 end
3868	    set i 0
3869	    foreach pred $predslist {
3870		incr i
3871		if {[expr $i % 30] == 0} {
3872		    set brk 1
3873		} else {
3874		    set brk 0
3875		}
3876		$predmenu add command -label [lindex $pred 1] -command "$ec_source.context.text see [lindex $pred 2].0" -columnbreak $brk
3877	    }
3878	}
3879    }
3880
3881    return 1
3882#    $ec_source.control.load configure -state normal
3883}
3884
3885# the find code is adapted from tkdiff
3886# name is the `user' name of the text window being search. It is also used to
3887# distinguish the tkecl variables used by the find window.
3888# source is the  path to the text widget being searched
3889# top is the path of the toplevel window for source
3890proc tkecl:show-find {name source top} {
3891    global tkecl
3892
3893    set ff $source.find.content.findFrame
3894    if {![winfo exists $source.find]} {
3895        toplevel $source.find
3896        wm group $source.find $top
3897        wm transient $source.find $top
3898        wm title $source.find "$name Find"
3899
3900        # we don't want the window to be deleted, just hidden from view
3901# following lines seems to produce a collasped window - commented out
3902#        wm protocol $source.find WM_DELETE_WINDOW [list wm withdraw \
3903          $source.find]
3904
3905#        wm withdraw $source.find
3906        update idletasks
3907
3908        frame $source.find.content -bd 2 -relief groove
3909        pack $source.find.content -side top -fill both -expand y -padx 0 \
3910          -pady 5
3911
3912        frame $source.find.buttons
3913        pack $source.find.buttons -side bottom -fill x -expand n
3914
3915        button $source.find.buttons.doit -text "Find Next" -command "tkecl:do-find $name $source $top"
3916        button $source.find.buttons.dismiss -text "Dismiss" -command \
3917          "wm withdraw $source.find"
3918        pack $source.find.buttons.dismiss -side right -pady 5 -padx 0
3919        pack $source.find.buttons.doit -side right -pady 5 -padx 1
3920
3921        frame $ff -height 100 -bd 2 -relief flat
3922        pack $ff -side top -fill x -expand n -padx 0 -pady 5
3923
3924        label $ff.label -text "Find what:" -underline 2
3925
3926        entry $ff.entry -textvariable tkecl($name,findString)
3927
3928        checkbutton $ff.searchCase -text "Ignore Case" -offvalue 0 -onvalue 1 \
3929          -indicatoron true -variable tkecl($name,findIgnoreCase)
3930
3931        grid $ff.label -row 0 -column 0 -sticky e
3932        grid $ff.entry -row 0 -column 1 -sticky ew
3933        grid $ff.searchCase -row 0 -column 2 -sticky w
3934        grid columnconfigure $ff 0 -weight 0
3935        grid columnconfigure $ff 1 -weight 1
3936        grid columnconfigure $ff 2 -weight 0
3937
3938        # we need this in other places...
3939        set tkecl($name,findEntry) $ff.entry
3940
3941        bind $ff.entry <Return> "tkecl:do-find $name $source $top"
3942
3943        set of $source.find.content.optionsFrame
3944        frame $of -bd 2 -relief flat
3945        pack $of -side top -fill y -expand y -padx 10 -pady 10
3946
3947        label $of.directionLabel -text "Search Direction:" -anchor e
3948        radiobutton $of.directionForward -indicatoron true -text "Down" \
3949          -value "-forward" -variable tkecl($name,findDirection)
3950        radiobutton $of.directionBackward -text "Up" -value "-backward" \
3951          -indicatoron true -variable tkecl($name,findDirection)
3952
3953
3954        label $of.searchLabel -text "Search Type:" -anchor e
3955        radiobutton $of.searchExact -indicatoron true -text "Exact" \
3956          -value "-exact" -variable tkecl($name,findType)
3957        radiobutton $of.searchRegexp -text "Regexp" -value "-regexp" \
3958          -indicatoron true -variable tkecl($name,findType)
3959
3960        grid $of.directionLabel -row 0 -column 0 -sticky w
3961        grid $of.directionForward -row 0 -column 1 -sticky w
3962        grid $of.directionBackward -row 0 -column 2 -sticky w
3963
3964        grid $of.searchLabel -row 1 -column 0 -sticky w
3965        grid $of.searchExact -row 1 -column 1 -sticky w
3966        grid $of.searchRegexp -row 1 -column 2 -sticky w
3967
3968        grid columnconfigure $of 0 -weight 0
3969        grid columnconfigure $of 1 -weight 0
3970
3971        set tkecl($name,findDirection) "-forward"
3972        set tkecl($name,findType) "-exact"
3973        set tkecl($name,findIgnoreCase) 1
3974        set tkecl($name,lastSearch) ""
3975    }
3976
3977    wm deiconify $source.find
3978    raise $source.find
3979    after idle focus $ff.entry
3980}
3981
3982# search for the text in the find dialog
3983proc tkecl:do-find {name source top} {
3984    global tkecl
3985
3986    if {![winfo exists $source.find] || ![winfo ismapped $source.find]} {
3987        tkecl:show-find $name $source $top
3988        return
3989    }
3990
3991    if {$tkecl($name,lastSearch) != ""} {
3992        if {$tkecl($name,findDirection) == "-forward"} {
3993            set start [$source index "insert +1c"]
3994        } else {
3995            set start insert
3996        }
3997    } else {
3998        set start 1.0
3999    }
4000
4001    if {$tkecl($name,findIgnoreCase)} {
4002        set result [$source search $tkecl($name,findDirection) $tkecl($name,findType) -nocase \
4003          -- $tkecl($name,findString) $start]
4004    } else {
4005        set result [$source search $tkecl($name,findDirection) $tkecl($name,findType) \
4006          -- $tkecl($name,findString) $start]
4007    }
4008    if {[string length $result] > 0} {
4009        # if this is a regular expression search, get the whole line and try
4010        # to figure out exactly what matched; otherwise we know we must
4011        # have matched the whole string...
4012        if {$tkecl($name,findType) == "-regexp"} {
4013            set line [$source get $result "$result lineend"]
4014            regexp $tkecl($name,findString) $line matchVar
4015            set length [string length $matchVar]
4016        } else {
4017            set length [string length $tkecl($name,findString)]
4018        }
4019        set tkecl($name,lastSearch) $result
4020        $source mark set insert $result
4021        $source tag remove sel 1.0 end
4022        $source tag add sel $result "$result + ${length}c"
4023        $source see $result
4024        focus $source
4025        # should I somehow snap to the nearest diff? Probably not...
4026    } else {
4027        bell
4028
4029    }
4030}
4031
4032#---------------------------------------------------------------------
4033# Balloon Help Toggle
4034#---------------------------------------------------------------------
4035
4036trace variable tkecl(pref,balloonhelp) w tkecl:ToggleBalloonHelp
4037
4038proc tkecl:ToggleBalloonHelp {name dummy op} {
4039    global tkecl
4040
4041    if {$tkecl(pref,balloonhelp) == 1} {
4042	balloonhelp enable
4043    } else {
4044	balloonhelp disable
4045    }
4046}
4047
4048#----------------------------------------------------------------------
4049# Help Files procedures
4050#----------------------------------------------------------------------
4051
4052# find the right help file given key (four letter unique id) and display
4053# help file as a subwindow of parent
4054proc tkecl:Get_helpfileinfo {key parent} {
4055    global tkecl
4056
4057    set i [lsearch -glob $tkecl(helpfiles) $key]
4058    if {$i == -1} {
4059	tk_messageBox -type ok -message "Invalid topic name for help files"
4060	return [list $key "invalid"]
4061    }
4062    set topic [lindex $tkecl(helpfiles) [expr $i+1]]
4063    set filename [lindex $tkecl(helpfiles) [expr $i+2]]
4064    eval tkinspect:helpinfo [concat {$parent} [list $topic $filename $key]]
4065}
4066
4067#----------------------------------------------------------------------
4068# Routines for handling initial user defaults
4069#----------------------------------------------------------------------
4070
4071proc tkecl:read_defaults_file {family} {
4072    global env tkecl
4073
4074    set defaults ""
4075    set file_exists 0
4076    set filename .$family  ;# filename is the family name with leading .
4077    if [file exists $filename] {
4078	set file_exists 1
4079    } else {
4080	set filename [file join $env(HOME) $filename]  ;# check in homedir
4081	if [file exists $filename] { set file_exists 1 }
4082    }
4083    if {$file_exists == 1} {
4084	if {[catch  {open $filename r} fid]} return $defaults  ;# unable to open file
4085
4086	while {[gets $fid line] >= 0} {
4087	    set option [lindex $line 0]
4088	    if {[lsearch $tkecl(preferences) [list $option * * $family *]] != -1} {
4089
4090		;# get the part of the line from the start of the second word
4091		;# (first word is $option)
4092		set tkecl(prefset,$option) [string trimleft [string range \
4093			$line [string wordend $line [string first $option \
4094                        $line]] end]]
4095		lappend defaults $option
4096	    } else {
4097		;# not a valid option
4098		tk_messageBox -icon warning -message "$option is not a valid preference for $family"
4099	    }
4100
4101	}
4102	close $fid
4103    }
4104    return $defaults
4105}
4106
4107
4108proc tkecl:get_user_defaults {family} {
4109    global tcl_platform tkecl
4110
4111    ;# read in user defined defaults for family (tkeclipserc or tkeclipsetoolsrc)
4112    switch $tcl_platform(platform) {
4113	unix {
4114	    return [tkecl:read_defaults_file $family]
4115	}
4116
4117	windows {
4118	    package require registry
4119	    set regpath $tkecl(windows_registry_path)$family
4120	    registry set $regpath  ;# make sure the key is there
4121	    set defaults ""
4122
4123	    foreach option [registry values $regpath] {
4124		if {[lsearch $tkecl(preferences) [list $option * * $family *]] != -1} {
4125		    set tkecl(prefset,$option) [registry get $regpath $option]
4126		    lappend defaults $option
4127		} else {
4128		    ;# not a valid option
4129		    tk_messageBox -icon warning -message "$option is not a valid preference for $family"
4130		}
4131	    }
4132	    return $defaults
4133
4134	}
4135    }
4136}
4137
4138
4139proc tkecl:set_tools_defaults {} {
4140    global tkecl
4141
4142    set userdefaults [tkecl:get_user_defaults tkeclipsetoolsrc]
4143
4144    foreach preference $tkecl(preferences) {
4145	foreach {dname default type family help} $preference {
4146	    if {$family == "tkeclipsetoolsrc"} {
4147		if {[lsearch -exact $userdefaults $dname] != -1} {
4148		    set value $tkecl(prefset,$dname)
4149		} else {
4150		    set value $default
4151		}
4152		tkecl:set_one_tools_default $dname $value $type
4153	    }
4154	}
4155    }
4156}
4157
4158
4159proc tkecl:set_one_tools_default {dname dvalue type} {
4160    global tkecl
4161
4162    if {[string trimleft $dvalue] != ""} {
4163	;# only set if dvalue is not empty or whitespaces
4164	switch -- $type {
4165
4166	    boolean {
4167		;# 0 or 1 options
4168		if {$dvalue == 1 || $dvalue == 0} {
4169		    set tkecl(pref,$dname) $dvalue
4170		} else {
4171		    tk_messageBox -icon warning -message "$dvalue is an invalid value for $dname (0/1 expected)" -type ok
4172		}
4173	    }
4174
4175	    +integer {
4176		;# straight positve integers, no special routines to call
4177		if [regexp {^[0-9]+$} $dvalue size] {
4178		    set tkecl(pref,$dname) $dvalue
4179		} else {
4180		    tk_messageBox -icon warning -message "$dvalue is an invalid value for $dname (positive integer expected" -type ok
4181		}
4182	    }
4183
4184	    tracer_prdepth {
4185		if [regexp {^[0-9]+$} $dvalue size] {
4186		    set tkecl(pref,tracer_prdepth) $dvalue
4187		    ec_rpcq [list set_tracer_print_depth $tkecl(pref,tracer_prdepth)] (I) tracer_tcl
4188		} else {
4189		    tk_messageBox -icon warning -message "$dvalue is an invalid value for tracer_prdepth (positive integer expected" -type ok
4190		}
4191	    }
4192
4193	    stats_interval {
4194		if [regexp {^([0-9]+[.][0-9]+)$|^([0-9]+)$} $dvalue] {
4195		    set tkecl(pref,$dname) $dvalue
4196		    ;# interval will be set later on via rpc
4197		} else {
4198		    tk_messageBox -icon warning -message "$dvalue is an invalid value for stats_interval (number expected)"
4199		}
4200
4201	    }
4202
4203	    string {
4204		set tkecl(pref,$dname) $dvalue
4205	    }
4206
4207	    colour { ;# background colour only
4208		if [catch {tk_setPalette $dvalue}] {
4209		    tk_messageBox -icon error -type ok -message \
4210			"Unable to change default background colour to $dvalue"
4211		} else {
4212		    set tkecl(pref,$dname) $dvalue
4213		}
4214	    }
4215
4216	    fontsize  {
4217		if [regexp {^[0-9]+$} $dvalue size] {
4218		    if {[string compare $dname monofont_size] == 0} {
4219			font configure tkeclmono -size $dvalue
4220			font configure tkeclmonobold -size $dvalue
4221		    } else {
4222			font configure tkecllabel -size $dvalue
4223		    }
4224		    set tkecl(pref,$dname) $dvalue
4225		} else {
4226		    tk_messageBox -icon warning -message "$dvalue is an invalid valid for $dname (positive integer expected" -type ok
4227		}
4228	    }
4229
4230	    font {
4231		if {[string compare $dname monofont_family] == 0} {
4232		    font configure tkeclmono -family $dvalue
4233		    font configure tkeclmonobold -family $dvalue
4234		} else {
4235		    font configure tkecllabel -family $dvalue
4236		}
4237		set tkecl(pref,$dname) $dvalue
4238	    }
4239	}
4240    }
4241}
4242
4243
4244proc tkecl:popup_edit_defaults {} {
4245    global tkecl
4246
4247    set edit .ec_tools.pref_edit
4248    if {![winfo exists $edit]} {
4249	toplevel $edit
4250        wm title $edit "TkECLiPSe Preference Editor"
4251	wm resizable $edit 0 0
4252	foreach preference $tkecl(preferences) {
4253	    tkecl:display_one_default $edit $preference
4254	}
4255	pack [frame $edit.bf] -expand 1 -fill x
4256	pack [button $edit.bf.apply -text "Apply Preferences" -command tkecl:apply_prefs] -expand 1 -fill x -side left
4257	pack [button $edit.bf.save -text "Save Preferences" -command tkecl:save_prefs] -expand 1 -fill x -side left
4258	pack [button $edit.bf.close -text "Close" -command "destroy $edit"] -expand 1 -fill x -side right
4259
4260	balloonhelp $edit "Change various preference settings for TkECLiPSe"
4261	balloonhelp $edit.bf.save "Save the preferences in the editor (the values will be used for the initial settings for the next session)."
4262	balloonhelp $edit.bf.close "Close the preference editor"
4263	balloonhelp $edit.bf.apply "Apply the preferences in the editor to the current session."
4264	bind $edit <Alt-h> "tkecl:Get_helpfileinfo pref $edit"
4265    } else {
4266	tkinspect:RaiseWindow $edit
4267    }
4268}
4269
4270proc tkecl:display_one_default {w preference} {
4271    global tkecl
4272
4273    foreach {option sysdefault type family help} $preference {
4274	set default $tkecl(pref,$option)
4275	set tkecl(prefset,$option) $default
4276
4277	switch -exact -- $type {
4278	    boolean {
4279		pack [frame $w.$option]  -fill both
4280		pack [label $w.$option.l -text $help -anchor w -width 50] -side left -expand 1 -fill both
4281		pack [radiobutton $w.$option.on -text on -value 1 \
4282                    -variable tkecl(prefset,$option) -anchor w] -side left -expand 1 -fill both
4283		pack [radiobutton $w.$option.off -text off -value 0 \
4284                    -variable tkecl(prefset,$option) -anchor w] -side left -expand 1 -fill both
4285	    }
4286
4287	    fontsize  -
4288	    tracer_prdepth -
4289	    +integer {
4290		pack [ventry $w.$option -labeltext $help -labelwidth 50 \
4291                      -vcmd {regexp {^[0-9]*$} %P} -validate key -labelanchor w\
4292                      -invalidcmd bell -textvariable tkecl(prefset,$option) \
4293                     ] -fill both -expand 1
4294	    }
4295
4296	    stats_interval {
4297		pack [ventry $w.$option -labeltext $help -labelwidth 50 \
4298                      -vcmd {regexp {^([0-9]*[.][0-9]*)$|^([0-9]*)$} %P} \
4299                      -validate key -invalidcmd bell -labelanchor w \
4300                      -textvariable tkecl(prefset,$option)\
4301                     ] -fill both -expand 1
4302	    }
4303
4304	    colour -
4305	    font  -
4306	    string {
4307		pack [ventry $w.$option -labeltext $help -labelwidth 50 \
4308                     -labelanchor w -textvariable tkecl(prefset,$option)\
4309                     ] -fill both -expand 1
4310	    }
4311
4312
4313	}
4314    }
4315}
4316
4317proc tkecl:apply_prefs {} {
4318    global tkecl
4319
4320    foreach preference $tkecl(preferences) {
4321	foreach {option default type family help} $preference {
4322	    break
4323	}
4324	tkecl:set_one_tools_default $option $tkecl(prefset,$option) $type
4325    }
4326}
4327
4328proc tkecl:save_prefs {} {
4329    global tcl_platform tkecl env
4330
4331    foreach preference $tkecl(preferences) {
4332	foreach {option default type family help} $preference {
4333	    lappend group($family) $option
4334	}
4335    }
4336    switch $tcl_platform(platform) {
4337	unix {
4338	    foreach rootname [array names group] {
4339		if [file exists .$rootname] {
4340		    set filename .$rootname
4341		} else {
4342		    set filename [file join $env(HOME) .$rootname]
4343		}
4344		if {[catch {open $filename w} fid]} {
4345		    tk_messageBox -type ok -icon error -message "Unable to write the preference file. Permission problems?"
4346		    return
4347		}
4348		foreach option $group($rootname) {
4349		    if {[string trimleft $tkecl(prefset,$option)] != ""} {
4350			puts $fid "$option $tkecl(prefset,$option)"
4351		    }
4352		}
4353		close $fid
4354	    }
4355	}
4356
4357	windows {
4358	    foreach rootname [array names group] {
4359		set regpath $tkecl(windows_registry_path)$rootname
4360		foreach option $group($rootname) {
4361		    registry set $regpath $option $tkecl(prefset,$option)
4362		}
4363	    }
4364	}
4365    }
4366}
4367
4368#--------------------------------------------------------------------
4369#
4370#--------------------------------------------------------------------
4371
4372proc tkecl:listbox_search {lbox key keycode x y} {
4373    global tkecl
4374
4375    if {$key == {}} {return -code continue}  ;# return if modifier key only
4376
4377    set s $lbox.search
4378    if {![winfo exists $s]} {
4379	toplevel $s
4380	wm overrideredirect $s 1
4381        wm positionfrom $s program
4382        wm withdraw $s
4383	pack [label $s.l -highlightthickness 0 -relief raised -bd 1 \
4384		-background lightblue -textvariable tkecl(lboxstring)]
4385
4386        ;# for some reason x  position of the popup window needs to be
4387        ;# somewhat displaced from the mouse position to work
4388	set x [expr $x + 10]
4389	wm geometry $s +$x+$y
4390	wm deiconify $s
4391        raise $s
4392    } else {
4393	raise $s
4394    }
4395
4396    switch -exact  -- $keycode  {
4397	Delete    -
4398	BackSpace {
4399	    set tkecl(lboxstring) [string range "$tkecl(lboxstring)" 0 end-1]
4400	    tkecl:do_listbox_search $lbox [$lbox get 0 end] \
4401		    $tkecl(lboxstring)* 0
4402	}
4403	Escape {
4404	    tkecl:listbox_search_exit $lbox
4405	}
4406	Return {
4407	    ;# disabled because selection does not activate <<ListboxSelect>>
4408	    ;# $lbox selection set active
4409	}
4410	Control_S {
4411	    ;# search from active element
4412	    set start [expr [$lbox index active] + 1]
4413	    tkecl:do_listbox_search $lbox [$lbox get $start end] \
4414		    $tkecl(lboxstring)* $start
4415	}
4416	default {
4417	    ;# printable character
4418	    append tkecl(lboxstring) $key
4419	    tkecl:do_listbox_search $lbox [$lbox get 0 end] \
4420		    $tkecl(lboxstring)* 0
4421	}
4422    }
4423    return -code continue
4424}
4425
4426# search for string, list may be a sublist starting from start of listbox
4427proc tkecl:do_listbox_search {lbox list search_string start} {
4428    set offset [lsearch $list $search_string]
4429    if {$offset != -1} {
4430	set index [expr $offset + $start] ;# index in original list
4431	$lbox yview $index
4432	$lbox activate $index
4433    } else {
4434	bell
4435    }
4436}
4437
4438proc tkecl:listbox_search_init {lbox} {
4439    global tkecl
4440
4441    if [winfo exists $lbox.search] {
4442	destroy $lbox.search
4443    }
4444
4445    set tkecl(lboxstring) "*"
4446    focus $lbox
4447}
4448
4449proc tkecl:listbox_search_exit {lbox} {
4450    global tkecl
4451
4452    if [winfo exists $lbox.search] {
4453	destroy $lbox.search
4454    }
4455
4456    focus -lastfor $lbox
4457}
4458
4459#--------------------------------------------------------------------
4460# handling keypresses in read-only windows
4461#--------------------------------------------------------------------
4462
4463proc tkecl:readonly_keypress {keycode} {
4464
4465    switch -exact -- $keycode {
4466	"\x3" {  ;#^C -- allow default handling for window copy operation
4467	    return 0
4468	}
4469	default {
4470	    return -code break
4471	}
4472    }
4473}
4474
4475#--------------------------------------------------------------------
4476# Utility for locating the window the pointer is in
4477#--------------------------------------------------------------------
4478
4479proc tkecl:pointer_window {} {
4480
4481    set win [winfo containing -displayof . \
4482		 [winfo pointerx .] [winfo pointery .]]
4483    if {$win != ""} { ;# pointer is in a window for the application
4484	return [winfo toplevel $win] ;# we want the toplevel path only
4485    } else {
4486	return ""  ;# not in any window
4487    }
4488}
4489
4490#---------------------------------------------------------------------
4491# Handling multitasking
4492#---------------------------------------------------------------------
4493
4494proc tkecl:multi_start_handler {type} {
4495
4496    switch $type {
4497	tracer {
4498	    # only do handling of port if the tracer window exists
4499	    if [winfo exists .ec_tools.ec_tracer] {
4500		tkecl:handle_tracer_port_start
4501		set of_interest  continue
4502	    } else {
4503		set of_interest no ;# do nothing (no tracer window)
4504	    }
4505	}
4506	default {
4507	    set of_interest no
4508	    # do nothing
4509	}
4510    }
4511
4512    return $of_interest
4513}
4514
4515proc tkecl:multi_interact_handler {type} {
4516    global tkecl
4517
4518    switch $type {
4519	tracer {
4520	    tkecl:check_tracer_interaction
4521	    if [string match tkecl(tracer_state) disabled] {
4522		return terminate
4523	    } else {
4524		return continue
4525	    }
4526	}
4527	default {
4528	    # do nothing
4529	    return continue
4530	}
4531    }
4532}
4533
4534proc tkecl:multi_end_handler {type} {
4535    global tkecl
4536
4537    if {[ec_interface_type] == "remote"} {
4538	tkecl:freeze_control
4539    }
4540}
4541
4542#---------------------------------------------------------------------
4543# Visualisation client
4544#---------------------------------------------------------------------
4545
4546proc tkecl:start_vc {} {
4547    switch [ec_rpcq_check {ensure_loaded {library java_vc}} ((()))] {
4548    	fail - throw { return }
4549    }
4550    ec_rpcq_check {start_vc _} (_) java_vc
4551}
4552
4553#---------------------------------------------------------------------
4554# Viztool
4555#---------------------------------------------------------------------
4556
4557proc tkecl:start_viztool {} {
4558    switch [ec_rpcq_check {ensure_loaded {library cpviz}} ((()))] {
4559    	fail - throw { return }
4560    }
4561    ec_rpcq_check viztool () cpviz
4562}
4563
4564#----------------------------------------------------------------------
4565# Initalise and create menu/toolbar
4566#----------------------------------------------------------------------
4567
4568proc ec_tools_init {w} {
4569    global tkinspectvalues tkecl
4570
4571
4572# Init the Eclipse part (must be done after ec_init !!!)
4573    ec_rpcq {ensure_loaded {library development_support}} ((()))
4574    ec_rpcq {ensure_loaded {library tracer_tcl}} ((()))
4575    ec_rpcq install_guitools () tracer_tcl
4576    ec_queue_create debug_traceline r tkecl:handle_trace_line
4577    ec_queue_create debug_output r tkecl:handle_debug_output
4578    ec_queue_create gui_source_file r tkecl:handle_source_debug_print
4579    ec_queue_create matrix_out_queue r tkecl:handle_mat_flush
4580    ec_queue_create gui_dg_info r tkecl:handle_dg_print
4581    ec_queue_create statistics_out_queue r tkecl:handle_stats_report
4582    set tkecl(toplevel_module) [lindex [ec_rpcq_check {get_flag toplevel_module _} (()_)] 2]
4583    set tkecl(predpropmodule) $tkecl(toplevel_module)
4584
4585    ec_multi:peer_register [list interact tkecl:multi_interact_handler start tkecl:multi_start_handler end tkecl:multi_end_handler]
4586
4587# Create the tools launcher menu and set up help files
4588
4589    menu $w
4590    $w add command -label "Compile Scratch-pad" -command "tkecl:compile_pad"
4591    lappend tkecl(helpfiles) scra {Compile Scratch-Pad} scratchhelp.txt
4592    $w add command -label "Source File Manager" -command tkecl:popup_file_window
4593    lappend tkecl(helpfiles) file {Source Files Tool} sourcehelp.txt
4594    $w add command -label "Predicate Browser" -command tkecl:popup_pred_prop
4595    lappend tkecl(helpfiles) pred {Predicates Property Tool} predprophelp.txt
4596    $w add separator
4597    $w add command -label "Delayed Goals" -command tkecl:popup_dg_window
4598    lappend tkecl(helpfiles) dela {Delayed Goals Viewer} delayhelp.txt
4599    $w add command -label "Tracer" -command tkecl:popup_tracer
4600    lappend tkecl(helpfiles) trac Tracer tracerhelp.txt
4601    $w add command -label "Inspector" -command "tkinspect:Inspect_term_init current"
4602    lappend tkecl(helpfiles) insp Inspector inspecthelp.txt
4603    $w add command -label "Visualisation Client" -command "tkecl:start_vc"
4604    $w add command -label "CP-Viz Viztool" -command "tkecl:start_viztool"
4605    $w add separator
4606    $w add command -label "Global Settings" -command tkecl:popup_global_state
4607    lappend tkecl(helpfiles) glob {Global Settings Tool} globalsethelp.txt
4608    $w add command -label "Statistics" -command tkecl:handle_statistics
4609    lappend tkecl(helpfiles) stat {Statistics Window} stathelp.txt
4610    $w add command -label "Simple Query" -command tkecl:rpc
4611    lappend tkecl(helpfiles) rpc {Simple Query Tool} rpchelp.txt
4612    $w add command -label "ECLiPSe Library Browser and Help" -command tkecl:library_browser
4613    lappend tkecl(helpfiles) help {Library Browser and Help Tool} helphelp.txt
4614    $w add separator
4615#    $w add command -label "ECLiPSe Help" -command tkecl:popup_help_window
4616#    lappend tkecl(helpfiles) help {ECLiPSe Help Tool} helphelp.txt
4617    $w add command -label "TkECLiPSe Preference Editor" -command tkecl:popup_edit_defaults
4618    lappend tkecl(helpfiles) pref {Preference Editor} prefhelp.txt
4619    $w add separator
4620    $w add check -label "Balloon Help" -variable tkecl(pref,balloonhelp)
4621#    $w add command -label "Test" -command tkecl:test
4622    lappend tkecl(helpfiles) disp {Display Matrix} matdisplayhelp.txt
4623
4624    tkecl:set_tools_defaults
4625    ;# set user defined defaults for tools
4626
4627    return $w
4628}
4629
4630