# copyright (C) 1997-2006 Jean-Luc Fontaine (mailto:jfontain@free.fr)
# this program is free software: please read the COPYRIGHT file enclosed in this package or use the Help Copyright menu

# $Id: formudlg.tcl,v 1.23 2006/01/28 19:16:59 jfontain Exp $


namespace eval formulas {

    class dialog {

        set (geometry) 500x480
        set (separator) 0

        proc dialog {this args} switched {$args} viewer {} {
            set dialog [::new dialogBox .\
                -buttons hoc -default o -title [mc {moodss: Formulas}] -otherbuttons {new test delete}\
                -helpcommand {generalHelpWindow #viewers.formulas} -x [winfo pointerx .] -y [winfo pointery .]\
                -grab release -enterreturn 0 -command "formulas::dialog::validated $this" -deletecommand "delete $this"\
            ]
            lappend ($this,objects) [linkedHelpWidgetTip $composite::($dialog,help,path)]
            # configure specific buttons at the bottom of the dialog box
            composite::configure $dialog new -text [mc New] -command "formulas::dialog::new $this"
            set button $composite::($dialog,new,path)
            lappend ($this,objects) [::new widgetTip -path $button -text [mc {create a new empty formula}]]
            foreach {string underline} [underlineAmpersand [mc &Test]] {}
            composite::configure $dialog test -text $string -underline $underline -command "formulas::dialog::test $this"\
                -state disabled
            set button $composite::($dialog,test,path)
            lappend ($this,objects) [::new widgetTip -path $button -text [mc {test formula with current cell values}]]
            set ($this,testButton) $button
            foreach {string underline} [underlineAmpersand [mc &Delete]] {}
            composite::configure $dialog delete -text $string -underline $underline -command "formulas::dialog::delete $this"\
                -state disabled
            set button $composite::($dialog,delete,path)
            lappend ($this,objects) [::new widgetTip -path $button -text [mc {delete selected entry}]]
            set ($this,deleteButton) $button
            wm geometry $widget::($dialog,path) $(geometry)                     ;# use last geometry which the user may have changed
            bind $widget::($dialog,path) <Configure> "set formulas::dialog::(geometry) \[wm geometry $widget::($dialog,path)\]"
            set frame [frame $widget::($dialog,path).frame]
            set header [frame $frame.header]                                                                       ;# header section
            grid columnconfigure $header 1 -weight 1
            grid columnconfigure $header 3 -weight 2
            grid $header -row 0 -column 0 -columnspan 2 -sticky ew                                          ;# end of header section
            set table [createTable $this $frame]                                                                    ;# table section
            set ($this,formulasDrop) [::new dropSite\
                -path $selectTable::($table,tablePath) -formats FORMULAS -command "formulas::dialog::handleDrop $this"\
            ]
            grid $widget::($table,path) -row 1 -column 0 -columnspan 2 -sticky nsew
            # start of comment section
            set ($this,commentLabel) [label $frame.commentLabel -font $font::(mediumBold) -text [mc Comment:] -state disabled]
            grid $($this,commentLabel) -row 2 -column 0 -sticky nw
            set comment [::new scroll text $frame -height 100]
            lappend ($this,objects) $comment
            set ($this,commentText) $composite::($comment,scrolled,path)
            $($this,commentText) configure -state disabled -background white -font $font::(mediumNormal) -wrap word
            setupTextBindings $($this,commentText)
            grid $widget::($comment,path) -row 2 -column 1 -columnspan 2 -sticky nsew                      ;# end of comment section
            set formula [createExpressionEntry $this $frame]
            grid $formula -row 3 -column 0 -columnspan 100 -sticky nsew
            set ($this,drop) [::new dropSite\
                 -path $($this,expressionText) -formats DATACELLS -command "formulas::dialog::handleDrop $this" -state disabled\
            ]
            grid rowconfigure $frame 1 -weight 3
            grid rowconfigure $frame 2 -weight 1
            grid columnconfigure $frame 1 -weight 1
            set ($this,table) $table
            set ($this,dialog) $dialog
            switched::complete $this
            if {$switched::($this,-initial)} {set widget entry} else {set widget label}                            ;# header section
            grid [label $header.objectLabel -font $font::(mediumBold) -text [mc Object:]] -row 0 -column 0
            grid [$widget $header.objectEntry -textvariable formulas::dialog::($this,object)] -row 0 -column 1 -sticky ew
            grid [label $header.categoryLabel -font $font::(mediumBold) -text [mc Category:]] -row 0 -column 2
            grid [$widget $header.categoryEntry -textvariable formulas::dialog::($this,category)] -row 0 -column 3 -sticky ew
            if {!$switched::($this,-initial)} {
                $header.objectEntry configure -anchor w
                $header.categoryEntry configure -anchor w
            }                                                                                               ;# end of header section
            dialogBox::display $dialog $frame
            foreach formula $switched::($this,-formulas) {                                          ;# display input formulas if any
                set copy [::new $formula]; switched::configure $copy -deletecommand {}                      ;# make an inactive copy
                display $this $copy $formula
                foreach array [arrays $formula] {set arrays($array) {}}
            }
            selectTable::refreshBorders $table
            selectTable::adjustTableColumns $table
            foreach array [array names arrays] {                   ;# update immediately (as done in viewer layer for other viewers)
                update $this $array
            }
        }

        proc ~dialog {this} {                                ;# note: all data trace unregistering occurs in viewer layer destructor
            variable ${this}data
            variable number
            variable ${this}registered

            foreach {name formula} [array get ${this}data "\[0-9\]*,$number(formula)"] {     ;# get formulas from their table column
                ::delete $formula
            }
            eval ::delete $($this,table) $($this,objects) $($this,drop) $($this,formulasDrop)
            catch {unset ${this}data}
            catch {unset ${this}registered}
            if {[string length $switched::($this,-deletecommand)] > 0} {
                uplevel #0 $switched::($this,-deletecommand)                                ;# always invoke command at global level
            }
        }

        proc options {this} {
            return [list\
                [list -category {}]\
                [list -command {} {}]\
                [list -deletecommand {} {}]\
                [list -formulas {} {}]\
                [list -initial 1 1]\
                [list -object {}]\
            ]
        }

        proc set-command {this value} {}

        proc set-deletecommand {this value} {}

        proc set-formulas {this value} {                                                                   ;# input formulas to edit
            if {$switched::($this,complete)} {
                error {option -formulas cannot be set dynamically}
            }
        }

        proc set-initial {this value} {
            if {$switched::($this,complete)} {
                error {option -initial cannot be set dynamically}
            }
        }

        proc set-object {this value} {
            if {$switched::($this,complete)} {
                error {option -object cannot be set dynamically}
            }
            set ($this,object) $value
        }

        proc set-category {this value} {
            if {$switched::($this,complete)} {
                error {option -category cannot be set dynamically}
            }
            set ($this,category) $value
        }

        proc raise {this} {
            ::raise $widget::($($this,dialog),path)
        }

        proc createTable {this parentPath} {
            variable ${this}data
            variable number

            set titles [list name formula input value]
            if {![info exists help]} {
                set help(name) [mc {formula name (editable)}]
                set help(value) [mc {formula value (forcibly updated when tested)}]
                set column 0
                foreach title $titles {
                    set number($title) $column
                    incr column
                }
                set (hiddenColumns) [expr {$number(value) - $number(name) - 1}]
            }
            set column 0
            foreach title $titles {
                set ${this}data(-1,$column) $title                                                                   ;# table titles
                incr column
            }
            # keep data in a full array so that empty cells are kept when deleting rows with the table delete command
            set table [::new selectTable $parentPath -titlerows 1 -roworigin -1 -columns [llength $titles]\
                -selectcommand "formulas::dialog::selected $this" -followfocus 0 -variable formulas::dialog::${this}data\
            ]
            set path $selectTable::($table,tablePath)
            foreach {cell title} [array get ${this}data -1,*] {
                if {![info exists help($title)]} continue                                                           ;# hidden column
                set label [label $path.$cell -font $font::(mediumBold) -text [mc $title]]
                selectTable::windowConfigure $table $cell -window $label -padx 1 -pady 1 -sticky nsew
                lappend ($this,objects) [::new widgetTip -path $label -text $help($title)]
            }
            selectTable::spans $table -1,$number(name) 0,$(hiddenColumns)
            return $table
        }

        proc createExpressionEntry {this parentPath} {                                    ;# note: code adapted from thresholds code
            set panes [::new panner $parentPath -panes 2]
            set ($this,expressionLabel)\
                [label $panner::($panes,frame1).label -font $font::(mediumBold) -text [mc Expression:] -state disabled]
            pack $($this,expressionLabel) -anchor nw
            lappend ($this,objects) $panes
            set expression [::new scroll text $panner::($panes,frame1) -height 80]               ;# start of expression text section
            lappend ($this,objects) $expression
            set ($this,expressionText) $composite::($expression,scrolled,path)
            $($this,expressionText) configure -state disabled -background white -font $font::(fixedNormal)
            setupTextBindings $($this,expressionText)
            pack $widget::($expression,path) -fill both -expand 1                                  ;# end of expression text section
            set ($this,testLabel) [label $panner::($panes,frame2).testLabel\
                -font $font::(mediumBold) -text [mc {Test trace:}] -state disabled\
            ]                                                                                               ;# start of test section
            pack $($this,testLabel) -anchor nw
            set test [::new scroll text $panner::($panes,frame2) -height 120]
            lappend ($this,objects) $test
            set text $composite::($test,scrolled,path)
            $text configure -state disabled -font $font::(fixedNormal)
            # resize separators when window is resized:
            bind $text <Configure>\
                {foreach window [%W window names] {$window configure -width [expr {%w - $global::separatorCut}]}}
            set ($this,testText) $text
            pack $widget::($test,path) -fill both -expand 1                                                   ;# end of test section
            return $widget::($panes,path)
        }

        proc validated {this} {                                              ;# update input formulas with edited temporary formulas
            variable ${this}data
            variable number

            if {[string length $switched::($this,-command)] == 0} return                                            ;# nothing to do
            if {[info exists ($this,selected)]} {                                                     ;# store currently edited data
                synchronize $this [set ${this}data($($this,selected),$number(formula))]
            }
            set list {}     ;# containing edited input formulas, new formulas but not deleted formulas, all to be managed by invoker
            foreach {name formula} [array get ${this}data "\[0-9\]*,$number(formula)"] {
                scan $name %u row
                set input [set ${this}data($row,$number(input))]
                if {$input == 0} {                                                                                    ;# new formula
                    lappend list [::new $formula]       ;# pass copy since all dialog box formulas are deleted along with dialog box
                } else {                                                                                  ;# edited existing formula
                    formulas::formula::copyOptions $input $formula                                          ;# update target options
                    lappend list $input
                }
            }
            uplevel #0 $switched::($this,-command)\
                [list [string trim $($this,object)] [string trim $($this,category)] [lsort -integer $list]]
        }

        proc selected {this row} { ;# note: select table implementation insures that row differs from previously selected row if any
            variable ${this}data
            variable number

            set topPath $widget::($($this,dialog),path)
            catch {set selection [selection get]}
            if {[info exists ($this,selected)]} {                     ;# store last selected row contents and update displayed value
                set selected $($this,selected)
                synchronize $this [set formula [set ${this}data($selected,$number(formula))]]
                set value ?; catch {set value [formulas::formula::value $formula]}
                set ${this}data($selected,$number(value)) $value
            }
            set ($this,selected) $row
            set formula [set ${this}data($row,$number(formula))]
            set button $($this,testButton)
            $button configure -state normal
            bind $topPath <Alt-KeyPress-t> "$button configure -relief sunken"      ;# make sure that only this button sees the event
            bind $topPath <Alt-KeyRelease-t> "$button configure -relief raised; $button invoke"
            set button $($this,deleteButton)
            $button configure -state normal
            bind $topPath <Alt-KeyPress-d> "$button configure -relief sunken"      ;# make sure that only this button sees the event
            bind $topPath <Alt-KeyRelease-d> "$button configure -relief raised; $button invoke"
            $($this,commentLabel) configure -state normal
            $($this,commentText) configure -state normal
            $($this,commentText) delete 1.0 end
            $($this,commentText) insert 1.0 [switched::cget $formula -commenttext]
            $($this,expressionLabel) configure -state normal
            updateFormulaText $this $formula
            $($this,testLabel) configure -state normal
            $($this,testText) configure -state normal
            $($this,testText) delete 1.0 end                                                                     ;# clear test trace
            $($this,testText) configure -state disabled
            switched::configure $($this,drop) -state normal
            if {[info exists selection]} {       ;# transport selection from one entry to another (useful for copying formulas text)
                clipboard clear
                clipboard append $selection
            }
            return 1
        }

        proc deselect {this row} {
            set topPath $widget::($($this,dialog),path)
            unset ($this,selected)
            $($this,testButton) configure -state disabled
            bind $topPath <Alt-KeyPress-t> {}; bind $topPath <Alt-KeyRelease-t> {}
            $($this,deleteButton) configure -state disabled
            bind $topPath <Alt-KeyPress-d> {}; bind $topPath <Alt-KeyRelease-d> {}
            switched::configure $($this,drop) -state disabled
            $($this,commentLabel) configure -state disabled
            $($this,commentText) delete 1.0 end
            $($this,commentText) configure -state disabled
            $($this,expressionLabel) configure -state disabled
            $($this,expressionText) delete 1.0 end
            $($this,expressionText) configure -state disabled
            $($this,testLabel) configure -state disabled
            $($this,testText) configure -state normal
            $($this,testText) delete 1.0 end
            $($this,testText) configure -state disabled
        }

        proc new {this} {
            set table $($this,table)
            set formula [::new formulas::formula]
            set row [display $this $formula]
            selectTable::refreshBorders $table
            selectTable::adjustTableColumns $table
            after idle "selectTable::select $table $row"                          ;# immediately select new row for user convenience
        }

        proc display {this formula {input 0}} {
            variable ${this}data
            variable number

            set table $($this,table)
            set row [selectTable::rows $table]
            selectTable::rows $table [expr {$row + 1}]
            # row/formula mapping kept in a hidden column so that it is updated properly when deleting rows from the table
            set ${this}data($row,$number(formula)) $formula
            set ${this}data($row,$number(input)) $input                               ;# input formula mapping (0 if formula is new)
            selectTable::spans $table $row,$number(name) 0,$(hiddenColumns)
            set ${this}data($row,$number(name)) [switched::cget $formula -name]
            set cell $row,$number(name)
            set path $selectTable::($table,tablePath)
            set entry $path.$formula,name
            entry $entry -font $font::(mediumNormal) -textvariable formulas::dialog::${this}data($cell) -borderwidth 0\
                -highlightthickness 0 -width 40
            bind $entry <FocusIn> "selectTable::select $table $row"
            selectTable::windowConfigure $table $cell -window $entry -padx 1 -pady 1 -sticky nsew
            set value ?
            if {[llength [switched::cget $formula -cells]] == 0} {                                            ;# constant expression
               catch {set value [formulas::formula::value $formula]}                                                  ;# update once
            }
            set ${this}data($row,$number(value)) $value
            updateRegistration $this
            return $row
        }

        proc delete {this} {                                                                              ;# delete selected formula
            variable ${this}data
            variable number

            set table $($this,table)
            set row $($this,selected)
            deselect $this $row
            set formula [set ${this}data($row,$number(formula))]
            selectTable::delete $table $row
            ::delete $formula
            set rows [selectTable::rows $table]
            set path $selectTable::($table,tablePath)
            for {} {$row < $rows} {incr row} {                                                       ;# update entries configuration
                set formula [set ${this}data($row,$number(formula))]
                set entry $path.$formula,name
                $entry configure -textvariable formulas::dialog::${this}data($row,$number(name))
                bind $entry <FocusIn> "selectTable::select $table $row"
            }
            array unset ${this}data $rows,\[0-9\]*         ;# delete now empty last row data (all others have been moved up 1 notch)
            selectTable::clear $table
            selectTable::refreshBorders $table
            selectTable::adjustTableColumns $table
        }

        proc test {this} {                                                              ;# note: a formula is selected at this point
            variable ${this}data
            variable number

            set row $($this,selected)
            set formula [set ${this}data($row,$number(formula))]
            synchronize $this $formula
            if {[catch {set value [formulas::formula::value $formula]} message]} {
                set value ?
                set message "[mc error:] $message"
            } else {
                set message "[mc result:] $value"
            }
            set ${this}data($row,$number(value)) $value
            set text $($this,testText)
            $text configure -state normal
            $text insert end \n$message\n
            # use a unique name for separator:
            $text window create end -window [frame $text.separator$(separator)\
                -relief sunken -borderwidth 1 -height 2 -width [expr {[winfo width $text] - $global::separatorCut}]\
            ]
            incr (separator)
            $text see end
            $text configure -state disabled
        }

        proc handleDrop {this} {
            variable ${this}data
            variable number

            if {![catch {set data $dragSite::data(FORMULAS)}]} {
                set selected [selectedFormula $this]
                set formulas {}
                foreach {name formula} [array get ${this}data "\[0-9\]*,$number(formula)"] {
                    if {$formula == $selected} {                                           ;# use edited data in a temporary formula
                        synchronize $this [set formula [set temporary [::new $formula]]]
                    }
                    lappend formulas $formula
                }
                foreach formula $data {
                    set identical 0
                    foreach existing $formulas {
                        if {[formulas::formula::equal $existing $formula]} {set identical $existing; break}
                    }
                    if {$identical > 0} {
                        lifoLabel::flash $global::messenger [format $formulas::(existingMessage) [switched::cget $identical -name]]
                        continue
                    }
                    set copy [::new $formula]; switched::configure $copy -deletecommand {}   ;# make an inactive copy of new formula
                    display $this $copy                                                                         ;# display it as new
                    foreach array [arrays $formula] {set arrays($array) {}}
                }
                if {[info exists temporary]} {::delete $temporary}
                selectTable::refreshBorders $($this,table)
                selectTable::adjustTableColumns $($this,table)
                if {[info exists arrays]} {
                    foreach array [array names arrays] {                                   ;# update immediately so value is visible
                        update $this $array
                    }
                    updateRegistration $this
                }
            } elseif {![catch {set data $dragSite::data(DATACELLS)}]} {
                set path $($this,expressionText)
                set background [$path cget -background]
                foreach cell $data {
                    set label [::new label $path -background $background -cell $cell]      ;# self deleted when formula text cleared
                    switched::configure $label -deletecommand "formulas::dialog::deletedLabel $this $label"
                    $path window create insert -window $label::($label,path)
                    label::update $label
                }
                focus $path
                updateRegistration $this
            }
        }

        proc synchronize {this formula} {                                  ;# update formula with currently edited selected row data
            variable ${this}data
            variable number

            set row $($this,selected)
            set text {}; set cells {}; set indexes {}
            foreach {key value index} [$($this,expressionText) dump 1.0 end] {
                switch $key {
                    text {
                        append text $value
                    }
                    window {
                        append text $                               ;# replace windows by a character since they increment the index
                        set label [label::labelFromPath $value]
                        if {$label > 0} {                                            ;# ignore invalid windows (should never happen)
                            lappend cells [switched::cget $label -cell]
                            lappend indexes $index
                        }
                    }
                }
            }
            set name [set ${this}data($row,$number(name))]
            set comment [string trim [$($this,commentText) get 1.0 end]]
            switched::configure $formula -cells $cells -cellindexes $indexes -commenttext $comment\
                -text [string trimright $text] -name [string trim $name]                         ;# remove useless peripheral blanks
        }

        proc updateFormulaText {this formula} {
            set path $($this,expressionText)
            $path configure -state normal
            $path delete 1.0 end
            $path insert 1.0 [switched::cget $formula -text]
            set background [$path cget -background]
            foreach cell [switched::cget $formula -cells] index [switched::cget $formula -cellindexes] {
                set label [::new label $path -background $background -cell $cell]    ;# note: self deleted when formula text cleared
                switched::configure $label -deletecommand "formulas::dialog::deletedLabel $this $label"
                $path delete $index                                                             ;# delete cell replacement character
                $path window create $index -window $label::($label,path)                                      ;# insert cell display
                label::update $label
            }
        }

        proc deletedLabel {this label} {}

        proc arrays {formula} {
            foreach cell [switched::cget $formula -cells] {
                viewer::parse $cell array ignore ignore ignore
                set arrays($array) {}
            }
            return [array names arrays]
        }

        proc selectedFormula {this} {
            variable ${this}data
            variable number

            if {[info exists ($this,selected)]} {
                return [set ${this}data($($this,selected),$number(formula))]
            } else {
                return 0
            }
        }

        proc updateRegistration {this} {     ;# non optimized way of handling registration (allowed since dialog box is short lived)
            variable ${this}data
            variable number
            variable ${this}registered

            set selected [selectedFormula $this]
            foreach {name formula} [array get ${this}data "\[0-9\]*,$number(formula)"] {
                if {$formula == $selected} {
                    set arrays {}
                    foreach {key path index} [$($this,expressionText) dump -window 1.0 end] {       ;# get cells from edited formula
                        set label [label::labelFromPath $path]
                        if {$label > 0} {                                            ;# ignore invalid windows (should never happen)
                            viewer::parse [switched::cget $label -cell] array ignore ignore ignore
                            lappend arrays $array
                        }
                    }
                } else {
                    set arrays [arrays $formula]
                }
                foreach array $arrays {set current($array) {}}
            }
            foreach array [array names ${this}registered] {
                if {![info exists current($array)]} {
                    viewer::unregisterTrace $this $array
                    unset ${this}registered($array)
                }
            }
            foreach array [array names current] {
                if {![info exists ${this}registered($array)]} {
                    viewer::registerTrace $this $array
                    set ${this}registered($array) {}
                }
            }
        }

        # start of viewer layer related procedures

        proc update {this array} {                                        ;# update formulas that contain cells from specified array
            variable ${this}data
            variable number

            set selected [selectedFormula $this]
            foreach {name formula} [array get ${this}data "\[0-9\]*,$number(formula)"] {
                scan $name %u row
                set value ?
                if {$formula == $selected} {
                    foreach {key path index} [$($this,expressionText) dump -window 1.0 end] {      ;# update cells in edited formula
                        set label [label::labelFromPath $path]
                        if {$label > 0} {label::update $label}
                    }
                    set temporary [::new $formula]
                    synchronize $this $temporary
                    catch {set value [formulas::formula::value $temporary]}
                    ::delete $temporary
                } else {
                    catch {set value [formulas::formula::value $formula]}
                }
                set ${this}data($row,$number(value)) $value
            }
        }

        proc cells {this} {
            return {}                                                                           ;# contains formulas, not data cells
        }

        proc manageable {this} {return 0}

        proc saved {this} {return 0}

        # end of viewer layer related procedures

        proc select {this formula} {                                             ;# public procedure to force selection of a formula
            variable ${this}data
            variable number

            if {$formula == [selectedFormula $this]} return
            foreach {name value} [array get ${this}data "\[0-9\]*,$number(input)"] {                    ;# compare to input formulas
                if {$value == $formula} {
                    scan $name %u row
                    selectTable::select $($this,table) $row
                    return
                }
            }
        }

    }


}



namespace eval formulas {


    class dialog {

        class label {

            proc label {this parentPath args} switched {$args} {
                set label [::label $parentPath.label$this\
                    -relief sunken -font $font::(mediumBold) -padx 0 -pady 0 -borderwidth 1 -cursor left_ptr\
                ]
                # keep track of label existence as it may be deleted by directly editing in the parent text widget
                bind $label <Destroy> "delete $this"
                set ($this,path) $label
                switched::complete $this
            }

            proc ~label {this} {
                bind $($this,path) <Destroy> {}                                                 ;# remove binding to avoid recursion
                catch {delete $($this,tip)}
                if {[string length $switched::($this,-deletecommand)] > 0} {
                    uplevel #0 $switched::($this,-deletecommand)                            ;# always invoke command at global level
                }
            }

            proc options {this} {
                return [list\
                    [list -background $widget::option(label,background) $widget::option(label,background)]\
                    [list -cell {} {}]\
                    [list -deletecommand {} {}]\
                ]
            }

            proc set-background {this value} {
                $($this,path) configure -background $value
            }

            proc set-cell {this value} {
                catch {delete $($this,tip)}
                if {[string length $value] == 0} return
                viewer::parse $value array row column ignore
                set ($this,tip) [new widgetTip -path $($this,path) -text [lindex [viewer::label $array $row $column] 0]]
            }

            proc set-deletecommand {this value} {}                                               ;# data is stored at switched level

            proc labelFromPath {path} {
                if {\
                    [scan [lindex [split $path .] end] label%u label] &&\
                    ![catch {set class [classof $label]}] && [string equal $class ::formulas::dialog::label]\
                } {
                    return $label
                } else {
                    return 0
                }
            }

            proc update {this} {
                set cell $switched::($this,-cell)
                if {[string length $cell] == 0} {
                    $($this,path) configure -text {}
                    return
                }
                if {[info exists $cell]} {
                    $($this,path) configure -text [set $cell]                                              ;# may be the ? character
                } else {
                    $($this,path) configure -text ?
                }

            }

        }

    }

}
