File: sumtable.tcl

package info (click to toggle)
moodss 9.0-2
  • links: PTS
  • area: main
  • in suites: potato
  • size: 1,540 kB
  • ctags: 609
  • sloc: sh: 8,869; tcl: 6,909; ansic: 113; makefile: 44
file content (215 lines) | stat: -rw-r--r-- 11,030 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
# copyright (C) 1997-1999 Jean-Luc Fontaine (mailto:jfontain@multimania.com)
# this program is free software: please read the COPYRIGHT file enclosed in this package or use the Help Copyright menu

set rcsId {$Id: sumtable.tcl,v 2.1 1999/08/28 09:22:49 jfontain Exp $}

class summaryTable {

    set ::summaryTable::(nextDataIndex) 0            ;# used when data array index is not specified as an option when creating table
    set ::summaryTable::(void) 000000        ;# must look void but be a valid number since it may be dropped in another viewer as is

    proc summaryTable {this parentPath args} composite {[new frame $parentPath] $args} viewer {} {
        composite::complete $this

        variable $($this,dataName)                                                   ;# after completion, data array name is defined

        array set $($this,dataName) {
            updates 0
            0,label data 0,type ascii 0,message {data cell description}
            1,label current 1,type real 1,message {current value (000000 means void)}
            2,label average 2,type real 2,message {average value since viewer creation}
            3,label minimum 3,type real 3,message {minimum value since viewer creation}
            4,label maximum 4,type real 4,message {maximum value since viewer creation}
            sort {0 increasing}
            indexColumns 0
        }
        set ($this,nextRow) 0

        # wait till after completion before creating table since some options are not dynamically settable
        # use column widths which may have been set at this summary table construction time when data table did not exist yet
        set table [new dataTable $widget::($this,path)\
            -data summaryTable::$($this,dataName) -draggable $composite::($this,-draggable)\
            -titlefont $composite::($this,-titlefont) -columnwidths $composite::($this,-columnwidths)\
        ]
        ### hack: drag and drop code should be separated from dataTable which should provide a selected member procedure ###
        # allow dropping of data cells ### use same path as drag path to avoid drops in table from table ###
        viewer::setupDropSite $this $dataTable::($table,tablePath)
        if {$composite::($this,-draggable)} {
            # extend data table drag capabilities ### hack ### also eventually allow row selection only instead of cells ###
            dragSite::provide $dataTable::($table,drag) OBJECTS "summaryTable::dragData $this"
        }
        pack $widget::($table,path) -fill both -expand 1
        set ($this,dataTable) $table
    }

    proc ~summaryTable {this} {
        variable [set dataName $($this,dataName)]
        variable ${this}cellRow

        foreach {name wish} [array get {} $this,rowLastWish,*] {                   ;# delete remaining last wishes, one for each row
            delete $wish                                                                                ;# which in turn deletes row
        }
        delete $($this,dataTable)
        catch {unset ${this}cellRow}
        incr ${dataName}(updates)                                        ;# so related viewers can eventually show disappeared cells
        unset $dataName
        if {[string length $composite::($this,-deletecommand)]>0} {
            uplevel #0 $composite::($this,-deletecommand)                                   ;# always invoke command at global level
        }
    }

    proc iconData {} {
        return {
            R0lGODdhKAAoAIQAAHt5e87PzgAAANbX1v///9/f339/fzk4OUJJQlIIY2sQe2sYe4wQpXMoe70o1qUYvbUYzrUg1msge944/60YznMwe95B/+dJ/70Y3udR
            /9YY984Y794o/wAAAAAAAAAAACwAAAAAKAAoAAAF/iAgjmRpnugYAELrvnAsz+0qBHgeDDi/6z6fbjhkBQjIJBKgbDKbyecSaTtCCVJo1ql82gZImniMpRpF
            sELBoG672e53QUCqhl9qeDy/b7MFZQRfdy58fWuHiIBeRoQtBpCRkpOUkXQigmcsLwSInZ8FnWygoH8HCAcAgwRpBAakoaGvsaSvl0x2rJyetLGjvaJzI5kC
            YLoulcnKt8Qrm4WIh3p7pggIqo3HLYZ903F/w6tp0d2J4Ji5MMrrk8xVaLu/sPK9pgep6XiusJ+z/LbhWBiDEYwfr3nC0GVTx66hO4HwoHmTI23OKXwL8ZCj
            Zi4hrowSO1Z8eMORgIYOlgPSKAjsYL05L2wkmNnKHzCbtVgpWMDTBoOfBF2WahlMQIOjDmw8gBCBIcplEo5OsEEBAoVxE/10NFqhggWqFJpqzMqNI9cKF6g6
            wIBVZDkBURt8ZYGh7pi7Mhp0zWCjrl8MXQMLHky4cGAMff8CNsy4cVfELDRs4ECZg+PLhTnYqMy5s+fPoDlvDk26tOcVRFKrXr06BAA7
        }
    }

    proc options {this} {
        # data index must be forced so that initialization always occur
        return [list\
            [list -columnwidths columnWidths ColumnWidths {} {}]\
            [list -dataindex {}]\
            [list -deletecommand {} {}]\
            [list -draggable draggable Draggable 0 0]\
            [list -titlefont titleFont TitleFont $font::(mediumBold) $font::(mediumBold)]\
        ]
    }

    proc set-columnwidths {this value} {
        # data table may not have been built if option was passed at construction time
        if {![info exists ($this,dataTable)]} return
        composite::configure $($this,dataTable) -columnwidths $value
    }

    # data array name index must be specifiable so that data viewers depending on summary table data array name (through their
    # monitored cells) do not fail accessing that data (required when generating viewers from save file)
    proc set-dataindex {this value} {
        if {$composite::($this,complete)} {
            error {option -dataindex cannot be set dynamically}
        }
        if {[string length $value]>0} {                             ;# specified, else use internally generated next available index
            if {$value<$(nextDataIndex)} {
                error "specified data index ($value) is lower than internal summary table index"
            }
            set ::summaryTable::(nextDataIndex) $value
        }
        set ($this,dataName) $(nextDataIndex)data                                             ;# generate unique name based on index
        incr ::summaryTable::(nextDataIndex)
    }

    proc set-deletecommand {this value} {}

    foreach option {-draggable -titlefont} {
        proc set$option {this value} "
            if {\$composite::(\$this,complete)} {
                error {option $option cannot be set dynamically}
            }
        "
    }

    proc supportedTypes {this} {
        return {integer real}
    }

    proc monitorCell {this array row column} {
        variable [set dataName $($this,dataName)]
        variable ${this}cellRow

        viewer::registerTrace $this $array
        set cell ${array}($row,$column)
        if {[info exists ${this}cellRow($cell)]} return                                                  ;# already displayed, abort

        set label [viewer::label $array $row $column]

        set row $($this,nextRow)                                                                     ;# next row for this data table
        set ${dataName}($row,0) $label
        # initialize average, minimum and maximum
        array set $dataName [list $row,2 $(void) $row,3 $(void) $row,4 $(void)]
        set ${dataName}($row,sum) 0.0
        set ${this}cellRow($cell) $row                                                                          ;# remember cell row
        # setup action when a row is deleted through a cell drop in trash
        set ($this,rowLastWish,$row) [new lastWish "summaryTable::deleteRow $this $cell"]
        incr ($this,nextRow)
    }

    proc update {this array args} {
        variable [set dataName $($this,dataName)]
        variable ${this}cellRow

        foreach {cell row} [array get ${this}cellRow] {
            if {[catch {set $cell} current]||[string equal $current $(void)]} {
                # cell does not exist or is another summary table void cell, so propagate here
                set ${dataName}($row,1) $(void)                         ;# do not touch other columns as their content remains valid
            } else {                                                                                                ;# data is valid
                set ${dataName}($row,1) $current
                set ${dataName}($row,2) [format %.2f\
                    [expr\
                        {[set ${dataName}($row,sum) [expr {[set ${dataName}($row,sum)]+$current}]]/([set ${dataName}(updates)]+1)}\
                    ]\
                ]
                set value [set ${dataName}($row,3)]
                if {[string equal $value $(void)]||($current<$value)} {                             ;# eventually initialize minimum
                    set ${dataName}($row,3) $current
                }
                set value [set ${dataName}($row,4)]
                if {[string equal $value $(void)]||($current>$value)} {                             ;# eventually initialize maximum
                    set ${dataName}($row,4) $current
                }
            }
        }
        incr ${dataName}(updates)                                                                    ;# let data table update itself
    }

    proc cells {this} {
        variable ${this}cellRow

        return [array names ${this}cellRow]
    }

    proc dragData {this format} {
        variable ${this}cellRow

        foreach cell [dataTable::dragData $($this,dataTable) $format] {                 ;# gather rows with at least 1 selected cell
            regexp {\(([^,]+)} $cell dummy row
            set selected($row) {}
        }
        set lastWishes {}
        foreach row [array names selected] {
            lappend lastWishes $($this,rowLastWish,$row)
        }
        if {[llength $lastWishes]==0} {
            return $this                                                                          ;# self destruct if no rows remain
        } else {
            return $lastWishes
        }
    }

    proc deleteRow {this cell} {                                   ;# last wish object is deleted after completion of this procedure
        variable [set dataName $($this,dataName)]
        variable ${this}cellRow

        set row [set ${this}cellRow($cell)]
        unset ${dataName}($row,0) ${dataName}($row,1) ${dataName}($row,2) ${dataName}($row,3) ${dataName}($row,4)\
            ${dataName}($row,sum) ($this,rowLastWish,$row)
        unset ${this}cellRow($cell)
        dataTable::update $($this,dataTable)
    }

    # data index is needed so that data array that other eventual data viewers depend on is reused when initializing from save file
    proc initializationConfiguration {this} {
        scan $($this,dataName) %u index                                                     ;# retrieve leading index from data name
        set list [list -dataindex $index]
        foreach {option value} [dataTable::initializationConfiguration $($this,dataTable)] {                        ;# in data table
            if {[string equal $option -columnwidths]} {                                             ;# look for column widths option
                lappend list -columnwidths $value
                break                                                                                                        ;# done
            }
        }
        return $list
    }
}