source: trunk/gui/scripts/tuples.tcl @ 16

Last change on this file since 16 was 11, checked in by mmc, 19 years ago

Major reorganization of the entire package. The config.xml file
is now irrelevant. All the action is in the tool.xml file. The
main program now organizes all input into 1) side-by-side pages,
2) input/result (wizard-style) pages, or 3) a series of wizard-
style pages. The <input> can have <phase> parts representing
the various pages.

Added a new ContourResult? widget based on Swaroop's vtk plotting
code.

Also, added easymesh and showmesh to the "tools" directory.
We need these for Eric Polizzi's code.

File size: 14.7 KB
Line 
1# ----------------------------------------------------------------------
2#  COMPONENT: tuples - represents a series of tuples for arbitrary data
3#
4#  This object represents a series of tuples.  Each tuple can contain
5#  one or more elements--for example, (a) or (a,b,c).  Each column
6#  in the tuple has a well-defined name and metadata.  Columns can
7#  be added even after data has been stored in the tuple list.
8# ======================================================================
9#  AUTHOR:  Michael McLennan, Purdue University
10#  Copyright (c) 2004-2005
11#  Purdue Research Foundation, West Lafayette, IN
12# ======================================================================
13package require Itcl
14
15itcl::class Rappture::Tuples {
16    constructor {args} { # defined below }
17
18    public method column {option args}
19    public method insert {pos args}
20    public method delete {{from ""} {to ""}}
21    public method put {args}
22    public method get {args}
23    public method find {args}
24    public method size {}
25
26    protected method _range {{from ""} {to ""}}
27
28    private variable _colnames ""  ;# list of column names
29    private variable _col2info     ;# maps column name => column options
30    private variable _tuples       ;# maps index => tuple data
31
32    private common _counter 0      ;# for auto-generated column names
33}
34                                                                               
35# ----------------------------------------------------------------------
36# CONSTRUCTOR
37# ----------------------------------------------------------------------
38itcl::body Rappture::Tuples::constructor {args} {
39    eval configure $args
40}
41
42# ----------------------------------------------------------------------
43# USAGE: column insert <pos> ?-name n? ?-label l? ?-default v?
44# USAGE: column delete ?<name> <name>...?
45# USAGE: column names ?<pattern>?
46# USAGE: column info <name>
47#
48# Used by clients to manipulate the columns associated with this
49# list of tuples.  Each column is identified by a short name.  If
50# a name is not supplied when the column is created, then one is
51# generated automatically.  The column names can be queried back
52# in the order they appear in a tuple by using the "column names"
53# command.
54# ----------------------------------------------------------------------
55itcl::body Rappture::Tuples::column {option args} {
56    switch -- $option {
57        insert {
58            # parse the incoming args
59            if {[llength $args] < 1} {
60                error "wrong # args: should be \"column insert pos ?-name n? ?-label l? ?-default v?\""
61            }
62            set pos [lindex $args 0]
63            set args [lrange $args 1 end]
64            Rappture::getopts args params {
65                value -name #auto
66                value -label ""
67                value -default ""
68            }
69            if {[llength $args] != 0} {
70                error "wrong # args: should be \"column insert pos ?-name n? ?-label l? ?-default v?\""
71            }
72
73            # insert the new column
74            set cname $params(-name)
75            if {$params(-name) == "#auto"} {
76                set cname "column[incr _counter]"
77            }
78            if {[lsearch -exact $_colnames $cname] >= 0} {
79                error "column name \"$cname\" already exists"
80            }
81            set _colnames [linsert $_colnames $pos $cname]
82            set _col2info($cname-label) $params(-label)
83            set _col2info($cname-default) $params(-default)
84
85            # run through all existing tuples and insert the default val
86            set max [array size _tuples]
87            for {set i 0} {$i < $max} {incr i} {
88                set oldval $_tuples($i)
89                set _tuples($i) [linsert $oldval $pos $params(-default)]
90            }
91        }
92        delete {
93            foreach cname $args {
94                set pos [lsearch -exact $_colnames $cname]
95                if {$pos < 0} {
96                    error "bad column name \"$cname\""
97                }
98                set _colnames [lreplace $_colnames $pos $pos]
99                unset _col2info($cname-label)
100                unset _col2info($cname-default)
101
102                # run through all existing tuples and delete the column
103                set max [array size _tuples]
104                for {set i 0} {$i < $max} {incr i} {
105                    set oldval $_tuples($i)
106                    set _tuples($i) [lreplace $oldval $pos $pos]
107                }
108            }
109        }
110        names {
111            if {[llength $args] == 0} {
112                return $_colnames
113            } elseif {[llength $args] == 1} {
114                set pattern [lindex $args 0]
115                set rlist ""
116                foreach cname $_colnames {
117                    if {[string match $pattern $cname]} {
118                        lappend rlist $cname
119                    }
120                }
121                return $rlist
122            } else {
123                error "wrong # args: should be \"column names ?pattern?\""
124            }
125        }
126        info {
127            if {[llength $args] != 1} {
128                error "wrong # args: should be \"column info name\""
129            }
130            set cname [lindex $args 0]
131            set pos [lsearch -exact $_colnames $cname]
132            if {$pos < 0} {
133                error "bad column name \"$cname\""
134            }
135            return [list -label $_col2info($cname-label) -default $_col2info($cname-default)]
136        }
137        default {
138            error "bad option \"$option\": should be delete, info, insert, names"
139        }
140    }
141}
142
143# ----------------------------------------------------------------------
144# USAGE: insert <pos> ?<tuple> <tuple> ...?
145#
146# Used by clients to insert one or more tuples into this list at
147# the given position <pos>.  Each <tuple> is a Tcl list of values
148# in order corresponding to the column names.
149# ----------------------------------------------------------------------
150itcl::body Rappture::Tuples::insert {pos args} {
151    set cols [llength $_colnames]
152    set max [array size _tuples]
153
154    if {"end" == $pos} {
155        set pos $max
156    } elseif {![string is integer $pos]} {
157        error "bad position \"$pos\": should be integer or \"end\""
158    } elseif {$pos < 0} {
159        set pos 0
160    } elseif {$pos > $max} {
161        set pos $max
162    }
163
164    # make some room to insert these tuples
165    set need [llength $args]
166    for {set i [expr {$max-1}]} {$i >= $pos} {incr i -1} {
167        set _tuples([expr {$i+$need}]) $_tuples($i)
168    }
169
170    # add the tuples at the specified pos
171    foreach t $args {
172        # make sure each tuple has enough columns
173        while {[llength $t] < $cols} {
174            lappend t ""
175        }
176        set _tuples($pos) $t
177        incr pos
178    }
179}
180
181# ----------------------------------------------------------------------
182# USAGE: delete ?<from>? ?<to>?
183#
184# Used by clients to delete one or more tuples in this list.  With
185# no args, it deletes all tuples.  With a single <from> arg, it deletes
186# the tuple at that number.  With both args, it deletes tuples in the
187# specified range.
188# ----------------------------------------------------------------------
189itcl::body Rappture::Tuples::delete {{from ""} {to ""}} {
190    if {"" == $from && "" == $to} {
191        catch {unset _tuples}
192        return
193    }
194    if {[array size _tuples] == 0} {
195        return  ;# nothing to delete
196    }
197
198    set last [expr {[array size _tuples]-1}]
199    foreach {from to} [_range $from $to] break
200
201    # delete all tuples in the specified range
202    set gap [expr {$to-$from+1}]
203    for {set i $from} {$i <= $last-$gap} {incr i} {
204        set _tuples($i) $_tuples([expr {$i+$gap}])
205    }
206    for {} {$i <= $last} {incr i} {
207        unset _tuples($i)
208    }
209}
210
211# ----------------------------------------------------------------------
212# USAGE: put ?-format <columns>? <pos> <tuple>
213#
214# Used by clients to store a different tuple value at the specified
215# position <pos> in this list.  Normally, it stores the entire
216# <tuple> at the specified slot, which must already exist.  (Use
217# insert to create new slots.)  If the -format option is specified,
218# then it interprets <tuple> according to the names in the -format,
219# and updates only specific columns at that slot.
220# ----------------------------------------------------------------------
221itcl::body Rappture::Tuples::put {args} {
222    Rappture::getopts args params {
223        value -format ""
224    }
225    if {[llength $args] != 2} {
226        error "wrong # args: should be \"put ?-format cols? pos tuple\""
227    }
228    foreach {pos tuple} $args break
229    foreach {pos dummy} [_range $pos ""] break  ;# fix index
230
231    if {![info exists _tuples($pos)]} {
232        error "index $pos doesn't exist"
233    }
234
235    if {[string length $params(-format)] == 0} {
236        # no format -- add tuple as-is (with proper number of columns)
237        set cols [llength $_colnames]
238        while {[llength $tuple] < $cols} {
239            lappend tuple ""
240        }
241        set _tuples($pos) $tuple
242    } else {
243        # convert column names to indices
244        set nlist ""
245        foreach cname $params(-format) {
246            set n [lsearch -exact $_colnames $cname]
247            if {$n < 0} {
248                error "bad column name \"$cname\""
249            }
250            lappend nlist $n
251        }
252
253        # convert data only for those indices
254        set val $_tuples($pos)
255        foreach n $nlist t $tuple {
256            set val [lreplace $val $n $n $t]
257        }
258        set _tuples($pos) $val
259    }
260}
261
262# ----------------------------------------------------------------------
263# USAGE: get ?-format <columns>? ?<from>? ?<to>?
264#
265# Used by clients to query data from this list of tuples.  Returns
266# a list of tuples in the specified range, or a list of all tuples
267# if the range is not specified.
268# ----------------------------------------------------------------------
269itcl::body Rappture::Tuples::get {args} {
270    Rappture::getopts args params {
271        value -format ""
272    }
273    if {[llength $args] > 2} {
274        error "wrong # args: should be \"get ?-format cols? ?from? ?to?\""
275    }
276    set from ""
277    set to ""
278    foreach {from to} $args break
279    foreach {from to} [_range $from $to] break
280
281    # empty? then return nothing
282    if {[array size _tuples] == 0} {
283        return ""
284    }
285
286    set rlist ""
287    if {[string length $params(-format)] == 0} {
288        # no format string -- return everything as-is
289        for {set i $from} {$i <= $to} {incr i} {
290            lappend rlist $_tuples($i)
291        }
292    } else {
293        # convert column names to indices
294        set nlist ""
295        foreach cname $params(-format) {
296            set n [lsearch -exact $_colnames $cname]
297            if {$n < 0} {
298                error "bad column name \"$cname\""
299            }
300            lappend nlist $n
301        }
302        set single [expr {[llength $nlist] == 1}]
303
304        # convert data only for those indices
305        for {set i $from} {$i <= $to} {incr i} {
306            set t ""
307            foreach n $nlist {
308                if {$single} {
309                    set t [lindex $_tuples($i) $n]
310                } else {
311                    lappend t [lindex $_tuples($i) $n]
312                }
313            }
314            lappend rlist $t
315        }
316    }
317    return $rlist
318}
319
320# ----------------------------------------------------------------------
321# USAGE: find ?-format <columns>? ?<tuple>?
322#
323# Used by clients to search for all or part of a <tuple> on the
324# list.  Without the extra -format option, this searches for an
325# exact match of the <tuple> and returns a list of indices that
326# match.  With the -format option, it checks the values for only
327# the specified <columns>, and again returns a list of indices
328# with matching values.
329# ----------------------------------------------------------------------
330itcl::body Rappture::Tuples::find {args} {
331    Rappture::getopts args params {
332        value -format ""
333    }
334    if {[llength $args] > 1} {
335        error "wrong # args: should be \"find ?-format cols? ?tuple?\""
336    }
337
338    # convert column names to indices
339    set nlist ""
340    foreach cname $params(-format) {
341        set n [lsearch -exact $_colnames $cname]
342        if {$n < 0} {
343            error "bad column name \"$cname\""
344        }
345        lappend nlist $n
346    }
347
348    # scan through all entries and find matching values
349    set rlist ""
350    set last [expr {[array size _tuples]-1}]
351    if {[llength $args] == 0} {
352        # no tuple? then all match
353        for {set i 0} {$i <= $last} {incr i} {
354            lappend rlist $i
355        }
356    } else {
357        set tuple [lindex $args 0]
358        if {[llength $nlist] == 0} {
359            # no format? then look for an exact match
360            for {set i 0} {$i <= $last} {incr i} {
361                if {[string equal $tuple $_tuples($i)]} {
362                    lappend rlist $i
363                }
364            }
365        } else {
366            # match only the columns in the -format
367            for {set i 0} {$i <= $last} {incr i} {
368                set matching 1
369                foreach n $nlist t $tuple {
370                    set val [lindex $_tuples($i) $n]
371                    if {![string equal $t $val]} {
372                        set matching 0
373                        break
374                    }
375                }
376                if {$matching} {
377                    lappend rlist $i
378                }
379            }
380        }
381    }
382    return $rlist
383}
384
385# ----------------------------------------------------------------------
386# USAGE: size
387#
388# Used by clients to determine the number of tuples stored on this
389# list.  Returns the size of the list.
390# ----------------------------------------------------------------------
391itcl::body Rappture::Tuples::size {} {
392    return [array size _tuples]
393}
394
395# ----------------------------------------------------------------------
396# USAGE: _range ?<from>? ?<to>?
397#
398# Used internally to convert a <from>/<to> range to a range of real
399# number values.  If both are "", then the range is the entire range
400# of data.  The <from> and <to> values can be integers or the keyword
401# "end".
402# ----------------------------------------------------------------------
403itcl::body Rappture::Tuples::_range {{from ""} {to ""}} {
404    set last [expr {[array size _tuples]-1}]
405    if {"" == $from && "" == $to} {
406        return [list 0 $last]
407    }
408
409    if {"end" == $from} {
410        set from $last
411    } elseif {![string is integer $from]} {
412        error "bad position \"$from\": should be integer or \"end\""
413    }
414    if {$from < 0} {
415        set from 0
416    } elseif {$from > $last} {
417        set from $last
418    }
419
420    if {"" == $to} {
421        set to $from
422    } elseif {"end" == $to} {
423        set to $last
424    } elseif {![string is integer $to]} {
425        error "bad position \"$to\": should be integer or \"end\""
426    }
427    if {$to < 0} {
428        set to 0
429    } elseif {$to > $last} {
430        set to $last
431    }
432
433    if {$from > $to} {
434        # make sure to/from are in proper order
435        set tmp $from
436        set from $to
437        set to $tmp
438    }
439    return [list $from $to]
440}
Note: See TracBrowser for help on using the repository browser.