00001
00002
00003 exec wish "$0" "$@"
00004
00005 if {![info exists vTcl(sourcing)]} {
00006 switch $tcl_platform(platform) {
00007 windows {
00008 }
00009 default {
00010 option add *Scrollbar.width 10
00011 }
00012 }
00013
00014 }
00015
00016
00017
00018
00019
00020
00021
00022
00023 if {![info exists vTcl(sourcing)]} {
00024 ret Window (type args) {
00025 global vTcl
00026 set cmd [lindex $args 0]
00027 set name [lindex $args 1]
00028 set newname [lindex $args 2]
00029 set rest [lrange $args 3 end]
00030 if {$name == "" || $cmd == ""} { return }
00031 if {$newname == ""} { set newname $name }
00032 if {$name == "."} { wm withdraw $name; return }
00033 set exists [winfo exists $newname]
00034 switch $cmd {
00035 show {
00036 if {$exists} { wm deiconify $newname; return }
00037 if {[info procs vTclWindow(pre)$name] != ""} {
00038 eval "vTclWindow(pre)$name $newname $rest"
00039 }
00040 if {[info procs vTclWindow$name] != ""} {
00041 eval "vTclWindow$name $newname $rest"
00042 }
00043 if {[info procs vTclWindow(post)$name] != ""} {
00044 eval "vTclWindow(post)$name $newname $rest"
00045 }
00046 }
00047 hide { if $exists {wm withdraw $newname; return} }
00048 iconify { if $exists {wm iconify $newname; return} }
00049 destroy { if $exists {destroy $newname; return} }
00050 }
00051 }
00052 }
00053
00054 if {![info exists vTcl(sourcing)]} {
00055 namespace ::mclistbox {
00056
00057 ret {::mclistbox::AdjustColumns} (type w , optional height ={)} {
00058 upvar ::mclistbox::${w}::widgets widgets
00059 upvar ::mclistbox::${w}::options options
00060 upvar ::mclistbox::${w}::misc misc
00061
00062 if {[string length $height] == 0} {
00063 height = [winfo height $widgets(text)]
00064 }
00065
00066
00067
00068 incr height -4
00069 foreach id $misc(columns) {
00070 $widgets(frame$id) configure -height $height
00071 }
00072
00073
00074 if {$options(-fillcolumn) != ""} {
00075
00076
00077 if {![info exists widgets(frame$options(-fillcolumn))]} {
00078 return
00079 }
00080 frame = $widgets(frame$options(-fillcolumn))
00081 minwidth = $misc(min-$frame)
00082
00083
00084 colwidth = 0
00085 col = 0
00086 foreach id $misc(columns) {
00087 if {![ColumnIsHidden $w $id] && $id != $options(-fillcolumn)} {
00088 incr colwidth [winfo reqwidth $widgets(frame$id)]
00089 }
00090 }
00091
00092
00093 id = $options(-fillcolumn)
00094
00095
00096 optwidth = [expr {[winfo width $widgets(text)] - (2 * [$widgets(text) cget -padx])}]
00097
00098
00099 newwidth = [expr {$optwidth - $colwidth}]
00100
00101 if {$newwidth < $minwidth} {
00102 newwidth = $minwidth
00103 }
00104
00105
00106 $widgets(frame$id) configure -width $newwidth
00107
00108 }
00109 InvalidateScrollbars $w
00110 }
00111
00112 }
00113
00114 namespace ::mclistbox {
00115
00116 ret {::mclistbox::Build} (type w , type args) {
00117 variable widgetOptions
00118
00119 # create the namespace for this instance, and define a few
00120 # variables
00121 namespace eval ::mclistbox::$w {
00122
00123 variable options
00124 variable widgets
00125 variable misc
00126 }
00127
00128 # this gives us access to the namespace variables within
00129 # this proc
00130 upvar ::mclistbox::${w}::widgets widgets
00131 upvar ::mclistbox::${w}::options options
00132 upvar ::mclistbox::${w}::misc misc
00133
00134 # initially we start out with no columns
00135 set misc(columns) {}
00136
00137 # this is our widget -- a frame of class Mclistbox. Naturally,
00138 # it will contain other widgets. We create it here because
00139 # we need it to be able to set our default options.
00140 set widgets(this) [frame $w -class Mclistbox -takefocus 1]
00141
00142 # this defines all of the default options. We get the
00143 # values from the option database. Note that if an array
00144 # value is a list of length one it is an alias to another
00145 # option, so we just ignore it
00146 foreach name [array names widgetOptions] {
00147 if {[llength $widgetOptions($name)] == 1} continue
00148 set optName [lindex $widgetOptions($name) 0]
00149 set optClass [lindex $widgetOptions($name) 1]
00150 set options($name) [option get $w $optName $optClass]
00151 }
00152
00153 # now apply any of the options supplied on the command
00154 # line. This may overwrite our defaults, which is OK
00155 if {[llength $args] > 0} {
00156 array set options $args
00157 }
00158
00159 # the columns all go into a text widget since it has the
00160 # ability to scroll.
00161 set widgets(text) [text $w.text -width 0 -height 0 -padx 0 -pady 0 -wrap none -borderwidth 0 -highlightthickness 0 -takefocus 0 -cursor {} ]
00162
00163 $widgets(text) configure -state disabled
00164
00165 # here's the tricky part (shhhh... don't tell anybody!)
00166 # we are going to create column that completely fills
00167 # the base frame. We will use it to control the sizing
00168 # of the widget. The trick is, we'll pack it in the frame
00169 # and then place the text widget over it so it is never
00170 # seen.
00171
00172 set columnWidgets [NewColumn $w {__hidden__}]
00173 set widgets(hiddenFrame) [lindex $columnWidgets 0]
00174 set widgets(hiddenListbox) [lindex $columnWidgets 1]
00175 set widgets(hiddenLabel) [lindex $columnWidgets 2]
00176
00177 # by default geometry propagation is turned off, but for this
00178 # super-secret widget we want it turned on. The idea is, we
00179 # resize the listbox which resizes the frame which resizes the
00180 # whole shibang.
00181 pack propagate $widgets(hiddenFrame) on
00182
00183 pack $widgets(hiddenFrame) -side top -fill both -expand y
00184 place $widgets(text) -x 0 -y 0 -relwidth 1.0 -relheight 1.0
00185 raise $widgets(text)
00186
00187 # we will later rename the frame's widget proc to be our
00188 # own custom widget proc. We need to keep track of this
00189 # new name, so we'll define and store it here...
00190 set widgets(frame) ::mclistbox::${w}::$w
00191
00192 # this moves the original frame widget proc into our
00193 # namespace and gives it a handy name
00194 rename ::$w $widgets(frame)
00195
00196 # now, create our widget proc. Obviously (?) it goes in
00197 # the global namespace. All mclistbox widgets will actually
00198 # share the same widget proc to cut down on the amount of
00199 # bloat.
00200 proc ::$w {command args} "eval ::mclistbox::WidgetProc {$w} \$command \$args"
00201
00202 # ok, the thing exists... let's do a bit more configuration.
00203 if {[catch "Configure $widgets(this) [array get options]" error]} {
00204 catch {destroy $w}
00205 }
00206
00207 # and be prepared to handle selections.. (this, for -exportselection
00208 # support)
00209 selection handle $w [list ::mclistbox::SelectionHandler $w get]
00210
00211 return $w
00212 }
00213
00214 }
00215
00216 namespace ::mclistbox {
00217
00218 ret {::mclistbox::Canonize} (type w , type object , type opt) {
00219 variable widgetOptions
00220 variable columnOptions
00221 variable widgetCommands
00222 variable columnCommands
00223 variable labelCommands
00224
00225 switch $object {
00226 command {
00227 if {[lsearch -exact $widgetCommands $opt] >= 0} {
00228 return $opt
00229 }
00230
00231 # command names aren't stored in an array, and there
00232 # isn't a way to get all the matches in a list, so
00233 # we'll stuff the columns in a temporary array so
00234 # we can use [array names]
00235 set list $widgetCommands
00236 foreach element $list {
00237 set tmp($element) ""
00238 }
00239 set matches [array names tmp ${opt}*]
00240 }
00241
00242 {label command} {
00243 if {[lsearch -exact $labelCommands $opt] >= 0} {
00244 return $opt
00245 }
00246
00247 # command names aren't stored in an array, and there
00248 # isn't a way to get all the matches in a list, so
00249 # we'll stuff the columns in a temporary array so
00250 # we can use [array names]
00251 set list $labelCommands
00252 foreach element $list {
00253 set tmp($element) ""
00254 }
00255 set matches [array names tmp ${opt}*]
00256 }
00257
00258 {column command} {
00259 if {[lsearch -exact $columnCommands $opt] >= 0} {
00260 return $opt
00261 }
00262
00263 # command names aren't stored in an array, and there
00264 # isn't a way to get all the matches in a list, so
00265 # we'll stuff the columns in a temporary array so
00266 # we can use [array names]
00267 set list $columnCommands
00268 foreach element $list {
00269 set tmp($element) ""
00270 }
00271 set matches [array names tmp ${opt}*]
00272 }
00273
00274 option {
00275 # JME : ajout pour Tk 8.5
00276 if {$opt == "-state"} {set opt "-relief"}
00277 if {[info exists widgetOptions($opt)] && [llength $widgetOptions($opt)] == 3} {
00278 return $opt
00279 }
00280 set list [array names widgetOptions]
00281 set matches [array names widgetOptions ${opt}*]
00282 }
00283
00284 {column option} {
00285 if {[info exists columnOptions($opt)]} {
00286 return $opt
00287 }
00288 set list [array names columnOptions]
00289 set matches [array names columnOptions ${opt}*]
00290 }
00291
00292 column {
00293 upvar ::mclistbox::${w}::misc misc
00294
00295 if {[lsearch -exact $misc(columns) $opt] != -1} {
00296 return $opt
00297 }
00298
00299 # column names aren't stored in an array, and there
00300 # isn't a way to get all the matches in a list, so
00301 # we'll stuff the columns in a temporary array so
00302 # we can use [array names]
00303 set list $misc(columns)
00304 foreach element $misc(columns) {
00305 set tmp($element) ""
00306 }
00307 set matches [array names tmp ${opt}*]
00308 }
00309 }
00310 if {[llength $matches] == 0} {
00311 set choices [HumanizeList $list]
00312 return -code error "unknown $object \"$opt\"; must be one of $choices"
00313
00314 } elseif {[llength $matches] == 1} {
00315 # deal with option aliases
00316 set opt [lindex $matches 0]
00317 switch $object {
00318 option {
00319 if {[llength $widgetOptions($opt)] == 1} {
00320 set opt $widgetOptions($opt)
00321 }
00322 }
00323
00324 {column option} {
00325 if {[llength $columnOptions($opt)] == 1} {
00326 set opt $columnOptions($opt)
00327 }
00328 }
00329 }
00330
00331 return $opt
00332
00333 } else {
00334 set choices [HumanizeList $list]
00335 return -code error "ambiguous $object \"$opt\"; must be one of $choices"
00336 }
00337 }
00338
00339 }
00340
00341 namespace ::mclistbox {
00342
00343 ret {::mclistbox::CheckColumnID} (type w , type id) {
00344 upvar ::mclistbox::${w}::misc misc
00345
00346 set id [::mclistbox::Canonize $w column $id]
00347 set index [lsearch -exact $misc(columns) $id]
00348 return $index
00349 }
00350
00351 }
00352
00353 namespace ::mclistbox {
00354
00355 ret {::mclistbox::Column-add} (type w , type args) {
00356 upvar ::mclistbox::${w}::widgets widgets
00357 upvar ::mclistbox::${w}::options options
00358 upvar ::mclistbox::${w}::misc misc
00359
00360 variable widgetOptions
00361
00362 set id "column-[llength $misc(columns)]" ;# a suitable default
00363
00364 # if the first argument doesn't have a "-" as the first
00365 # character, it is an id to associate with this column
00366 if {![string match {-*} [lindex $args 0]]} {
00367 # the first arg must be an id.
00368 set id [lindex $args 0]
00369 set args [lrange $args 1 end]
00370 if {[lsearch -exact $misc(columns) $id] != -1} {
00371 return -code error "column \"$id\" already exists"
00372 }
00373 }
00374
00375 # define some reasonable defaults, then add any specific
00376 # values supplied by the user
00377 set opts(-bitmap) {}
00378 set opts(-image) {}
00379 set opts(-visible) 1
00380 set opts(-resizable) 1
00381 set opts(-position) "end"
00382 set opts(-width) 20
00383 set opts(-background) $options(-background)
00384 set opts(-foreground) $options(-foreground)
00385 set opts(-font) $options(-font)
00386 set opts(-label) $id
00387
00388 if {[expr {[llength $args]%2}] == 1} {
00389 # hmmm. An odd number of elements in args
00390 # if the last item is a valid option we'll give a different
00391 # error than if its not
00392 set option [::mclistbox::Canonize $w "column option" [lindex $args end]]
00393 return -code error "value for \"[lindex $args end]\" missing"
00394 }
00395 array set opts $args
00396
00397 # figure out if we have any data in the listbox yet; we'll need
00398 # this information in a minute...
00399 if {[llength $misc(columns)] > 0} {
00400 set col0 [lindex $misc(columns) 0]
00401 set existingRows [$widgets(listbox$col0) size]
00402 } else {
00403 set existingRows 0
00404 }
00405
00406 # create the widget and assign the associated paths to our array
00407 set widgetlist [NewColumn $w $id]
00408
00409 set widgets(frame$id) [lindex $widgetlist 0]
00410 set widgets(listbox$id) [lindex $widgetlist 1]
00411 set widgets(label$id) [lindex $widgetlist 2]
00412
00413 # add this column to the list of known columns
00414 lappend misc(columns) $id
00415
00416 # configure the options. As a side effect, it will be inserted
00417 # in the text widget
00418 eval ::mclistbox::Column-configure {$w} {$id} [array get opts]
00419
00420 # now, if there is any data already in the listbox, we need to
00421 # add a corresponding number of blank items. At least, I *think*
00422 # that's the right thing to do.
00423 if {$existingRows > 0} {
00424 set blanks {}
00425 for {set i 0} {$i < $existingRows} {incr i} {
00426 lappend blanks {}
00427 }
00428 eval {$widgets(listbox$id)} insert end $blanks
00429 }
00430
00431 InvalidateScrollbars $w
00432 return $id
00433 }
00434
00435 }
00436
00437 namespace ::mclistbox {
00438
00439 ret {::mclistbox::Column-configure} (type w , type id , type args) {
00440 variable widgetOptions
00441 variable columnOptions
00442
00443 upvar ::mclistbox::${w}::widgets widgets
00444 upvar ::mclistbox::${w}::options options
00445 upvar ::mclistbox::${w}::misc misc
00446
00447 # bail if they gave us a bogus id
00448 set index [CheckColumnID $w $id]
00449
00450 # define some shorthand
00451 set listbox $widgets(listbox$id)
00452 set frame $widgets(frame$id)
00453 set label $widgets(label$id)
00454
00455 if {[llength $args] == 0} {
00456 # hmmm. User must be wanting all configuration information
00457 # note that if the value of an array element is of length
00458 # one it is an alias, which needs to be handled slightly
00459 # differently
00460 set results {}
00461 foreach opt [lsort [array names columnOptions]] {
00462 if {[llength $columnOptions($opt)] == 1} {
00463 set alias $columnOptions($opt)
00464 set optName $columnOptions($alias)
00465 lappend results [list $opt $optName]
00466 } else {
00467 set optName [lindex $columnOptions($opt) 0]
00468 set optClass [lindex $columnOptions($opt) 1]
00469 set default [option get $frame $optName $optClass]
00470 lappend results [list $opt $optName $optClass $default $options($id:$opt)]
00471 }
00472 }
00473
00474 return $results
00475
00476
00477 } elseif {[llength $args] == 1} {
00478
00479 # the user must be querying something... I need to get this
00480 # to return a bona fide list like the "real" configure
00481 # command, but it's not a priority at the moment. I still
00482 # have to work on the option database support foo.
00483 set option [::mclistbox::Canonize $w "column option" [lindex $args 0]]
00484
00485 set value $options($id:$option)
00486 set optName [lindex $columnOptions($option) 0]
00487 set optClass [lindex $columnOptions($option) 1]
00488 set default [option get $frame $optName $optClass]
00489 set results [list $option $optName $optClass $default $value]
00490 return $results
00491
00492 }
00493
00494 # if we have an odd number of values, bail.
00495 if {[expr {[llength $args]%2}] == 1} {
00496 # hmmm. An odd number of elements in args
00497 return -code error "value for \"[lindex $args end]\" missing"
00498 }
00499
00500 # Great. An even number of options. Let's make sure they
00501 # are all valid before we do anything. Note that Canonize
00502 # will generate an error if it finds a bogus option; otherwise
00503 # it returns the canonical option name
00504 foreach {name value} $args {
00505 set name [::mclistbox::Canonize $w "column option" $name]
00506 set opts($name) $value
00507 }
00508
00509 # if we get to here, the user is wanting to set some options
00510 foreach option [array names opts] {
00511 set value $opts($option)
00512 set options($id:$option) $value
00513
00514 switch -- $option {
00515 -label {
00516 $label configure -text $value
00517 }
00518
00519 -image -
00520 -bitmap {
00521 $label configure $option $value
00522 }
00523
00524 -width {
00525 set font [$listbox cget -font]
00526 set factor [font measure $options(-font) "0"]
00527 set width [expr {$value * $factor}]
00528
00529 $widgets(frame$id) configure -width $width
00530 set misc(min-$widgets(frame$id)) $width
00531 AdjustColumns $w
00532 }
00533 -font -
00534 -foreground -
00535 -background {
00536 if {[string length $value] == 0} {set value $options($option)}
00537 $listbox configure $option $value
00538 }
00539
00540 -labelrelief {
00541 $widgets(label$id) configure -relief $value
00542 }
00543
00544 -resizable {
00545 if {[catch {
00546 if {$value} {
00547 set options($id:-resizable) 1
00548 } else {
00549 set options($id:-resizable) 0
00550 }
00551 } msg]} {
00552 return -code error "expected boolean but got \"$value\""
00553 }
00554 }
00555
00556 -visible {
00557 if {[catch {
00558 if {$value} {
00559 set options($id:-visible) 1
00560 $widgets(text) configure -state normal
00561 $widgets(text) window configure 1.$index -window $frame
00562 $widgets(text) configure -state disabled
00563
00564 } else {
00565 set options($id:-visible) 0
00566 $widgets(text) configure -state normal
00567 $widgets(text) window configure 1.$index -window {}
00568 $widgets(text) configure -state disabled
00569 }
00570 InvalidateScrollbars $w
00571 } msg]} {
00572 return -code error "expected boolean but got \"$value\""
00573 }
00574
00575 }
00576
00577 -position {
00578 if {[string compare $value "start"] == 0} {
00579 set position 0
00580
00581 } elseif {[string compare $value "end"] == 0} {
00582
00583 set position [expr {[llength $misc(columns)] -1}]
00584 } else {
00585
00586 # ought to check for a legal value here, but I'm
00587 # lazy
00588 set position $value
00589 }
00590
00591 if {$position >= [llength $misc(columns)]} {
00592 set max [expr {[llength $misc(columns)] -1}]
00593 return -code error "bad position; must be in the range of 0-$max"
00594 }
00595
00596 # rearrange misc(columns) to reflect the new ordering
00597 set current [lsearch -exact $misc(columns) $id]
00598 set misc(columns) [lreplace $misc(columns) $current $current]
00599 set misc(columns) [linsert $misc(columns) $position $id]
00600
00601 set frame $widgets(frame$id)
00602 $widgets(text) configure -state normal
00603 $widgets(text) window create 1.$position -window $frame -stretch 1
00604 $widgets(text) configure -state disabled
00605 }
00606
00607 }
00608 }
00609 }
00610
00611 }
00612
00613 namespace ::mclistbox {
00614
00615 ret {::mclistbox::ColumnIsHidden} (type w , type id) {
00616 upvar ::mclistbox::${w}::widgets widgets
00617 upvar ::mclistbox::${w}::misc misc
00618
00619 set retval 1
00620 set col [lsearch -exact $misc(columns) $id]
00621
00622 if {$col != ""} {
00623 set index "1.$col"
00624 catch {
00625 set window [$widgets(text) window cget $index -window]
00626 if {[string length $window] > 0 && [winfo exists $window]} {
00627 set retval 0
00628 }
00629 }
00630 }
00631 return $retval
00632 }
00633
00634 }
00635
00636 namespace ::mclistbox {
00637
00638 ret {::mclistbox::Configure} (type w , type args) {
00639 variable widgetOptions
00640
00641 upvar ::mclistbox::${w}::widgets widgets
00642 upvar ::mclistbox::${w}::options options
00643 upvar ::mclistbox::${w}::misc misc
00644
00645 if {[llength $args] == 0} {
00646 # hmmm. User must be wanting all configuration information
00647 # note that if the value of an array element is of length
00648 # one it is an alias, which needs to be handled slightly
00649 # differently
00650 set results {}
00651 foreach opt [lsort [array names widgetOptions]] {
00652 if {[llength $widgetOptions($opt)] == 1} {
00653 set alias $widgetOptions($opt)
00654 set optName $widgetOptions($alias)
00655 lappend results [list $opt $optName]
00656 } else {
00657 set optName [lindex $widgetOptions($opt) 0]
00658 set optClass [lindex $widgetOptions($opt) 1]
00659 set default [option get $w $optName $optClass]
00660 lappend results [list $opt $optName $optClass $default $options($opt)]
00661 }
00662 }
00663
00664 return $results
00665 }
00666
00667 # one argument means we are looking for configuration
00668 # information on a single option
00669 if {[llength $args] == 1} {
00670 set opt [::mclistbox::Canonize $w option [lindex $args 0]]
00671
00672 set optName [lindex $widgetOptions($opt) 0]
00673 set optClass [lindex $widgetOptions($opt) 1]
00674 set default [option get $w $optName $optClass]
00675 set results [list $opt $optName $optClass $default $options($opt)]
00676 return $results
00677 }
00678
00679 # if we have an odd number of values, bail.
00680 if {[expr {[llength $args]%2}] == 1} {
00681 # hmmm. An odd number of elements in args
00682 return -code error "value for \"[lindex $args end]\" missing"
00683 }
00684
00685 # Great. An even number of options. Let's make sure they
00686 # are all valid before we do anything. Note that Canonize
00687 # will generate an error if it finds a bogus option; otherwise
00688 # it returns the canonical option name
00689 foreach {name value} $args {
00690 set name [::mclistbox::Canonize $w option $name]
00691 set opts($name) $value
00692 }
00693
00694 # process all of the configuration options
00695 foreach option [array names opts] {
00696
00697 set newValue $opts($option)
00698 if {[info exists options($option)]} {
00699 set oldValue $options($option)
00700 # set options($option) $newValue
00701 }
00702
00703 switch -- $option {
00704 -exportselection {
00705 if {$newValue} {
00706 SelectionHandler $w own
00707 set options($option) 1
00708 } else {
00709 set options($option) 0
00710 }
00711 }
00712
00713 -fillcolumn {
00714 # if the fill column changed, we need to adjust
00715 # the columns.
00716 AdjustColumns $w
00717 set options($option) $newValue
00718 }
00719
00720 -takefocus {
00721 $widgets(frame) configure -takefocus $newValue
00722 set options($option) [$widgets(frame) cget $option]
00723 }
00724
00725 -background {
00726 foreach id $misc(columns) {
00727 $widgets(listbox$id) configure -background $newValue
00728 $widgets(frame$id) configure -background $newValue
00729 }
00730 $widgets(frame) configure -background $newValue
00731
00732 $widgets(text) configure -background $newValue
00733 set options($option) [$widgets(frame) cget $option]
00734 }
00735
00736 # { the following all must be applied to each listbox }
00737 -foreground -
00738 -font -
00739 -selectborderwidth -
00740 -selectforeground -
00741 -selectbackground -
00742 -setgrid {
00743 foreach id $misc(columns) {
00744 $widgets(listbox$id) configure $option $newValue
00745 }
00746 $widgets(hiddenListbox) configure $option $newValue
00747 set options($option) [$widgets(hiddenListbox) cget $option]
00748 }
00749
00750 # { the following all must be applied to each listbox and frame }
00751 -cursor {
00752 foreach id $misc(columns) {
00753 $widgets(listbox$id) configure $option $newValue
00754 $widgets(frame$id) configure -cursor $newValue
00755 }
00756
00757 # -cursor also needs to be applied to the
00758 # frames of each column
00759 foreach id $misc(columns) {
00760 $widgets(frame$id) configure -cursor $newValue
00761 }
00762
00763 $widgets(hiddenListbox) configure $option $newValue
00764 set options($option) [$widgets(hiddenListbox) cget $option]
00765 }
00766
00767 # { this just requires to pack or unpack the labels }
00768 -labels {
00769 if {$newValue} {
00770 set newValue 1
00771 foreach id $misc(columns) {
00772 pack $widgets(label$id) -side top -fill x -expand n -before $widgets(listbox$id)
00773 }
00774 pack $widgets(hiddenLabel) -side top -fill x -expand n -before $widgets(hiddenListbox)
00775
00776 } else {
00777 set newValue
00778 foreach id $misc(columns) {
00779 pack forget $widgets(label$id)
00780 }
00781 pack forget $widgets(hiddenLabel)
00782 }
00783 set options($option) $newValue
00784 }
00785
00786 -height {
00787 $widgets(hiddenListbox) configure -height $newValue
00788 InvalidateScrollbars $w
00789 set options($option) [$widgets(hiddenListbox) cget $option]
00790 }
00791
00792 -width {
00793 if {$newValue == 0} {
00794 return -code error "a -width of zero is not supported. "
00795 }
00796
00797 $widgets(hiddenListbox) configure -width $newValue
00798 InvalidateScrollbars $w
00799 set options($option) [$widgets(hiddenListbox) cget $option]
00800 }
00801
00802 # { the following all must be applied to each column frame }
00803 -columnborderwidth -
00804 -columnrelief {
00805 regsub {column} $option {} listboxoption
00806 foreach id $misc(columns) {
00807 $widgets(listbox$id) configure $listboxoption $newValue
00808 }
00809 $widgets(hiddenListbox) configure $listboxoption $newValue
00810 set options($option) [$widgets(hiddenListbox) cget $listboxoption]
00811 }
00812
00813 -resizablecolumns {
00814 if {$newValue} {
00815 set options($option) 1
00816 } else {
00817 set options($option) 0
00818 }
00819 }
00820
00821 # { the following all must be applied to each column header }
00822 -labelimage -
00823 -labelheight -
00824 -labelrelief -
00825 -labelfont -
00826 -labelanchor -
00827 -labelbackground -
00828 -labelforeground -
00829 -labelborderwidth {
00830 regsub {label} $option {} labeloption
00831 foreach id $misc(columns) {
00832 $widgets(label$id) configure $labeloption $newValue
00833 }
00834 $widgets(hiddenLabel) configure $labeloption $newValue
00835 set options($option) [$widgets(hiddenLabel) cget $labeloption]
00836 }
00837
00838 # { the following apply only to the topmost frame}
00839 -borderwidth -
00840 -highlightthickness -
00841 -highlightcolor -
00842 -highlightbackground -
00843 -relief {
00844 $widgets(frame) configure $option $newValue
00845 set options($option) [$widgets(frame) cget $option]
00846 }
00847
00848 -selectmode {
00849 set options($option) $newValue
00850 }
00851
00852 -selectcommand {
00853 set options($option) $newValue
00854 }
00855
00856 -xscrollcommand {
00857 InvalidateScrollbars $w
00858 set options($option) $newValue
00859 }
00860
00861 -yscrollcommand {
00862 InvalidateScrollbars $w
00863 set options($option) $newValue
00864 }
00865 }
00866 }
00867 }
00868
00869 }
00870
00871 namespace ::mclistbox {
00872
00873 ret {::mclistbox::DestroyHandler} (type w) {
00874 # kill off any idle event we might have pending
00875 if {[info exists ::mclistbox::${w}::misc(afterid)]} {
00876 catch {
00877 after cancel $::mclistbox::${w}::misc(afterid)
00878 unset ::mclistbox::${w}::misc(afterid)
00879 }
00880 }
00881
00882 # if the widget actually being destroyed is of class Mclistbox,
00883 # crush the namespace and kill the proc. Get it? Crush. Kill.
00884 # Destroy. Heh. Danger Will Robinson! Oh, man! I'm so funny it
00885 # brings tears to my eyes.
00886 if {[string compare [winfo class $w] "Mclistbox"] == 0} {
00887 namespace delete ::mclistbox::$w
00888 rename $w {}
00889 }
00890 }
00891
00892 }
00893
00894 namespace ::mclistbox {
00895
00896 ret {::mclistbox::FindResizableNeighbor} (type w , type id , optional direction =right) {
00897 upvar ::mclistbox::${w}::widgets widgets
00898 upvar ::mclistbox::${w}::options options
00899 upvar ::mclistbox::${w}::misc misc
00900
00901
00902 if {$direction == "right"} {
00903 set incr 1
00904 set stop [llength $misc(columns)]
00905 set start [expr {[lsearch -exact $misc(columns) $id] + 1}]
00906 } else {
00907 set incr -1
00908 set stop -1
00909 set start [expr {[lsearch -exact $misc(columns) $id] - 1}]
00910 }
00911
00912 for {set i $start} {$i != $stop} {incr i $incr} {
00913 set col [lindex $misc(columns) $i]
00914 if {![ColumnIsHidden $w $col] && $options($col:-resizable)} {
00915 return $col
00916 }
00917 }
00918 return ""
00919 }
00920
00921 }
00922
00923 namespace ::mclistbox {
00924
00925 ret {::mclistbox::HumanizeList} (type list) {
00926 if {[llength $list] == 1} {
00927 return [lindex $list 0]
00928 } else {
00929 set list [lsort $list]
00930 set secondToLast [expr {[llength $list] -2}]
00931 set most [lrange $list 0 $secondToLast]
00932 set last [lindex $list end]
00933
00934 return "[join $most {, }] or $last"
00935 }
00936 }
00937
00938 }
00939
00940 namespace ::mclistbox {
00941
00942 ret {::mclistbox::Init} () {
00943 variable widgetOptions
00944 variable columnOptions
00945 variable widgetCommands
00946 variable columnCommands
00947 variable labelCommands
00948
00949 # here we match up command line options with option database names
00950 # and classes. As it turns out, this is a handy reference of all of the
00951 # available options. Note that if an item has a value with only one
00952 # item (like -bd, for example) it is a synonym and the value is the
00953 # actual item.
00954
00955 array set widgetOptions [list -background {background Background} -bd -borderwidth -bg -background -borderwidth {borderWidth BorderWidth} -columnbd -columnborderwidth -columnborderwidth {columnBorderWidth BorderWidth} -columnrelief {columnRelief Relief} -cursor {cursor Cursor} -exportselection {exportSelection ExportSelection} -fg -foreground -fillcolumn {fillColumn FillColumn} -font {font Font} -foreground {foreground Foreground} -height {height Height} -highlightbackground {highlightBackground HighlightBackground} -highlightcolor {highlightColor HighlightColor} -highlightthickness {highlightThickness HighlightThickness} -labelanchor {labelAnchor Anchor} -labelbackground {labelBackground Background} -labelbd -labelborderwidth -labelbg -labelbackground -labelborderwidth {labelBorderWidth BorderWidth} -labelfg -labelforeground -labelfont {labelFont Font} -labelforeground {labelForeground Foreground} -labelheight {labelHeight Height} -labelimage {labelImage Image} -labelrelief {labelRelief Relief} -labels {labels Labels} -relief {relief Relief} -resizablecolumns {resizableColumns ResizableColumns} -selectbackground {selectBackground Foreground} -selectborderwidth {selectBorderWidth BorderWidth} -selectcommand {selectCommand Command} -selectforeground {selectForeground Background} -selectmode {selectMode SelectMode} -setgrid {setGrid SetGrid} -takefocus {takeFocus TakeFocus} -width {width Width} -xscrollcommand {xScrollCommand ScrollCommand} -yscrollcommand {yScrollCommand ScrollCommand} ]
00956
00957 # and likewise for column-specific stuff.
00958 array set columnOptions [list -background {background Background} -bitmap {bitmap Bitmap} -font {font Font} -foreground {foreground Foreground} -image {image Image} -label {label Label} -position {position Position} -labelrelief {labelrelief Labelrelief} -resizable {resizable Resizable} -visible {visible Visible} -width {width Width} ]
00959
00960 # this defines the valid widget commands. It's important to
00961 # list them here; we use this list to validate commands and
00962 # expand abbreviations.
00963 set widgetCommands [list activate bbox cget column configure curselection delete get index insert label nearest scan see selection size xview yview
00964 ]
00965
00966 set columnCommands [list add cget configure delete names nearest]
00967 set labelCommands [list bind]
00968
00969 ######################################################################
00970 #- this initializes the option database. Kinda gross, but it works
00971 #- (I think).
00972 ######################################################################
00973
00974 set packages [package names]
00975
00976 # why check for the Tk package? This lets us be sourced into
00977 # an interpreter that doesn't have Tk loaded, such as the slave
00978 # interpreter used by pkg_mkIndex. In theory it should have no
00979 # side effects when run
00980 if {[lsearch -exact [package names] "Tk"] != -1} {
00981
00982 # compute a widget name we can use to create a temporary widget
00983 set tmpWidget ".__tmp__"
00984 set count 0
00985 while {[winfo exists $tmpWidget] == 1} {
00986 set tmpWidget ".__tmp__$count"
00987 incr count
00988 }
00989
00990 # steal options from the listbox
00991 # we want darn near all options, so we'll go ahead and do
00992 # them all. No harm done in adding the one or two that we
00993 # don't use.
00994 listbox $tmpWidget
00995 foreach foo [$tmpWidget configure] {
00996 if {[llength $foo] == 5} {
00997 set option [lindex $foo 1]
00998 set value [lindex $foo 4]
00999 option add *Mclistbox.$option $value widgetDefault
01000
01001 # these options also apply to the individual columns...
01002 if {[string compare $option "foreground"] == 0 || [string compare $option "background"] == 0 || [string compare $option "font"] == 0} {
01003 option add *Mclistbox*MclistboxColumn.$option $value widgetDefault
01004 }
01005 }
01006 }
01007 destroy $tmpWidget
01008
01009 # steal some options from label widgets; we only want a subset
01010 # so we'll use a slightly different method. No harm in *not*
01011 # adding in the one or two that we don't use... :-)
01012 label $tmpWidget
01013 foreach option [list Anchor Background Font Foreground Height Image ] {
01014 set values [$tmpWidget configure -[string tolower $option]]
01015 option add *Mclistbox.label$option [lindex $values 3]
01016 }
01017 destroy $tmpWidget
01018
01019 # these are unique to us...
01020 option add *Mclistbox.columnBorderWidth 0 widgetDefault
01021 option add *Mclistbox.columnRelief flat widgetDefault
01022 option add *Mclistbox.labelBorderWidth 1 widgetDefault
01023 option add *Mclistbox.labelRelief raised widgetDefault
01024 option add *Mclistbox.labels 1 widgetDefault
01025 option add *Mclistbox.resizableColumns 1 widgetDefault
01026 option add *Mclistbox.selectcommand {} widgetDefault
01027 option add *Mclistbox.fillcolumn {} widgetDefault
01028
01029 # column options
01030 option add *Mclistbox*MclistboxColumn.visible 1 widgetDefault
01031 option add *Mclistbox*MclistboxColumn.resizable 1 widgetDefault
01032 option add *Mclistbox*MclistboxColumn.position end widgetDefault
01033 option add *Mclistbox*MclistboxColumn.label "" widgetDefault
01034 option add *Mclistbox*MclistboxColumn.width 0 widgetDefault
01035 option add *Mclistbox*MclistboxColumn.bitmap "" widgetDefault
01036 option add *Mclistbox*MclistboxColumn.image "" widgetDefault
01037 }
01038
01039 ######################################################################
01040 # define the class bindings
01041 ######################################################################
01042
01043 SetClassBindings
01044 }
01045
01046 }
01047
01048 namespace ::mclistbox {
01049
01050 ret {::mclistbox::Insert} (type w , type index , type arglist) {
01051 upvar ::mclistbox::${w}::widgets widgets
01052 upvar ::mclistbox::${w}::options options
01053 upvar ::mclistbox::${w}::misc misc
01054
01055 foreach list $arglist {
01056 # make sure we have enough elements for each column
01057 for {set i [llength $list]} {$i < [llength $misc(columns)]} {incr i} {
01058 lappend list {}
01059 }
01060
01061 set column 0
01062 foreach id $misc(columns) {
01063 $widgets(listbox$id) insert $index [lindex $list $column]
01064 incr column
01065 }
01066
01067 # we also want to add a bogus item to the hidden listbox. Why?
01068 # For standard listboxes, if you specify a height of zero the
01069 # listbox will resize to be just big enough to hold all the lines.
01070 # Since we use a hidden listbox to regulate the size of the widget
01071 # and we want this same behavior, this listbox needs the same number
01072 # of elements as the visible listboxes
01073 #
01074 # (NB: we might want to make this listbox contain the contents
01075 # of all columns as a properly formatted list; then the get
01076 # command can query this listbox instead of having to query
01077 # each individual listbox. The disadvantage is that it doubles
01078 # the memory required to hold all the data)
01079 $widgets(hiddenListbox) insert $index "x"
01080 }
01081 return ""
01082 }
01083
01084 }
01085
01086 namespace ::mclistbox {
01087
01088 ret {::mclistbox::InvalidateScrollbars} (type w) {
01089 upvar ::mclistbox::${w}::widgets widgets
01090 upvar ::mclistbox::${w}::options options
01091 upvar ::mclistbox::${w}::misc misc
01092
01093 if {![info exists misc(afterid)]} {
01094 set misc(afterid) [after idle "catch {::mclistbox::UpdateScrollbars $w}"]
01095 }
01096 }
01097
01098 }
01099
01100 namespace ::mclistbox {
01101
01102 ret {::mclistbox::LabelEvent} (type w , type id , type code) {
01103 upvar ::mclistbox::${w}::widgets widgets
01104 upvar ::mclistbox::${w}::options options
01105
01106 # only fire the binding if the cursor is our default cursor
01107 # (ie: if we aren't in a "resize zone")
01108 set cursor [$widgets(label$id) cget -cursor]
01109 if {[string compare $cursor $options(-cursor)] == 0} {
01110 uplevel \#0 $code
01111 }
01112 }
01113
01114 }
01115
01116 namespace ::mclistbox {
01117
01118 ret {::mclistbox::MassageIndex} (type w , type index) {
01119 upvar ::mclistbox::${w}::widgets widgets
01120 upvar ::mclistbox::${w}::misc misc
01121
01122 if {[regexp {@([0-9]+),([0-9]+)} $index matchvar x y]} {
01123 set id [lindex $misc(columns) 0]
01124
01125 incr y -[winfo y $widgets(listbox$id)]
01126 incr y -[winfo y $widgets(frame$id)]
01127 incr x [winfo x $widgets(listbox$id)]
01128 incr x [winfo x $widgets(frame$id)]
01129
01130 set index @${x},${y}
01131 }
01132
01133 return $index
01134 }
01135
01136 }
01137
01138 namespace ::mclistbox {
01139
01140 ret {::mclistbox::NewColumn} (type w , type id) {
01141 upvar ::mclistbox::${w}::widgets widgets
01142 upvar ::mclistbox::${w}::options options
01143 upvar ::mclistbox::${w}::misc misc
01144 upvar ::mclistbox::${w}::columnID columnID
01145
01146 # the columns are all children of the text widget we created...
01147 set frame [frame $w.frame$id -takefocus 0 -highlightthickness 0 -class MclistboxColumn -background $options(-background) ]
01148
01149 set listbox [listbox $frame.listbox -takefocus 0 -bd 0 -setgrid $options(-setgrid) -exportselection false -selectmode $options(-selectmode) -highlightthickness 0 ]
01150
01151 set label [label $frame.label -takefocus 0 -relief raised -bd 1 -highlightthickness 0 ]
01152
01153 # define mappings from widgets to columns
01154 set columnID($label) $id
01155 set columnID($frame) $id
01156 set columnID($listbox) $id
01157
01158 # we're going to associate a new bindtag for the label to
01159 # handle our resize bindings. Why? We want the bindings to
01160 # be specific to this widget but we don't want to use the
01161 # widget name. If we use the widget name then the bindings
01162 # could get mixed up with user-supplied bindigs (via the
01163 # "label bind" command).
01164 set tag MclistboxLabel
01165 bindtags $label [list MclistboxMouseBindings $label]
01166
01167 # reconfigure the label based on global options
01168 foreach option [list bd image height relief font anchor background foreground borderwidth] {
01169 if {[info exists options(-label$option)] && $options(-label$option) != ""} {
01170 $label configure -$option $options(-label$option)
01171 }
01172 }
01173
01174 # reconfigure the column based on global options
01175 foreach option [list borderwidth relief] {
01176 if {[info exists options(-column$option)] && $options(-column$option) != ""} {
01177 $frame configure -$option $options(-column$option)
01178 }
01179 }
01180
01181 # geometry propagation must be off so we can control the size
01182 # of the listbox by setting the size of the containing frame
01183 pack propagate $frame off
01184
01185 pack $label -side top -fill x -expand n
01186 pack $listbox -side top -fill both -expand y -pady 2
01187
01188 # any events that happen in the listbox gets handled by the class
01189 # bindings. This has the unfortunate side effect
01190 bindtags $listbox [list $w Mclistbox all]
01191
01192 # return a list of the widgets we created.
01193 return [list $frame $listbox $label]
01194 }
01195
01196 }
01197
01198 namespace ::mclistbox {
01199
01200 ret {::mclistbox::ResizeEvent} (type w , type type , type widget , type x , type X , type Y) {
01201 upvar ::mclistbox::${w}::widgets widgets
01202 upvar ::mclistbox::${w}::options options
01203 upvar ::mclistbox::${w}::misc misc
01204 upvar ::mclistbox::${w}::columnID columnID
01205
01206 # if the widget doesn't allow resizable cursors, there's
01207 # nothing here to do...
01208 if {!$options(-resizablecolumns)} {
01209 return
01210 }
01211
01212 # this lets us keep track of some internal state while
01213 # the user is dragging the mouse
01214 variable drag
01215
01216 # this lets us define a small window around the edges of
01217 # the column.
01218 set threshold [expr {$options(-labelborderwidth) + 4}]
01219
01220 # this is what we use for the "this is resizable" cursor
01221 set resizeCursor sb_h_double_arrow
01222
01223 # if we aren't over an area that we care about, bail.
01224 if {![info exists columnID($widget)]} {
01225 return
01226 }
01227
01228 # id refers to the column name
01229 set id $columnID($widget)
01230
01231 switch $type {
01232
01233 buttonpress {
01234 # we will do all the work of initiating a drag only if
01235 # the cursor is not the defined cursor. In theory this
01236 # will only be the case if the mouse moves over the area
01237 # in which a drag can happen.
01238 if {[$widgets(label$id) cget -cursor] == $resizeCursor} {
01239 if {$x <= $threshold} {
01240 set lid [::mclistbox::FindResizableNeighbor $w $id left]
01241 if {$lid == ""} return
01242 set drag(leftFrame) $widgets(frame$lid)
01243 set drag(rightFrame) $widgets(frame$id)
01244
01245 set drag(leftListbox) $widgets(listbox$lid)
01246 set drag(rightListbox) $widgets(listbox$id)
01247
01248 } else {
01249 set rid [::mclistbox::FindResizableNeighbor $w $id right]
01250 if {$rid == ""} return
01251 set drag(leftFrame) $widgets(frame$id)
01252 set drag(rightFrame) $widgets(frame$rid)
01253
01254 set drag(leftListbox) $widgets(listbox$id)
01255 set drag(rightListbox) $widgets(listbox$rid)
01256
01257 }
01258
01259
01260 set drag(leftWidth) [winfo width $drag(leftFrame)]
01261 set drag(rightWidth) [winfo width $drag(rightFrame)]
01262
01263 # it seems to be a fact that windows can never be
01264 # less than one pixel wide. So subtract that one pixel
01265 # from our max deltas...
01266 set drag(maxDelta) [expr {$drag(rightWidth) - 1}]
01267 set drag(minDelta) -[expr {$drag(leftWidth) - 1}]
01268
01269 set drag(x) $X
01270 }
01271 }
01272
01273 motion {
01274 if {[info exists drag(x)]} {return}
01275
01276 # this is just waaaaay too much work for a motion
01277 # event, IMO.
01278
01279 set resizable 0
01280
01281 # is the column the user is over resizable?
01282 if {!$options($id:-resizable)} {return}
01283
01284 # did the user click on the left of a column?
01285 if {$x < $threshold} {
01286 set leftColumn [::mclistbox::FindResizableNeighbor $w $id left]
01287 if {$leftColumn != ""} {
01288 set resizable 1
01289 }
01290
01291 } elseif {$x > [winfo width $widget] - $threshold} {
01292 set rightColumn [::mclistbox::FindResizableNeighbor $w $id right]
01293 if {$rightColumn != ""} {
01294 set resizable 1
01295 }
01296 }
01297
01298 # if it's resizable, change the cursor
01299 set cursor [$widgets(label$id) cget -cursor]
01300 if {$resizable && $cursor != $resizeCursor} {
01301 $widgets(label$id) configure -cursor $resizeCursor
01302
01303 } elseif {!$resizable && $cursor == $resizeCursor} {
01304 $widgets(label$id) configure -cursor $options(-cursor)
01305 }
01306 }
01307
01308 drag {
01309 # if the state is set up, do the drag...
01310 if {[info exists drag(x)]} {
01311
01312 set delta [expr {$X - $drag(x)}]
01313 if {$delta >= $drag(maxDelta)} {
01314 set delta $drag(maxDelta)
01315
01316 } elseif {$delta <= $drag(minDelta)} {
01317 set delta $drag(minDelta)
01318 }
01319
01320 set lwidth [expr {$drag(leftWidth) + $delta}]
01321 set rwidth [expr {$drag(rightWidth) - $delta}]
01322
01323 $drag(leftFrame) configure -width $lwidth
01324 $drag(rightFrame) configure -width $rwidth
01325
01326 }
01327 }
01328
01329 buttonrelease {
01330 set fillColumnID $options(-fillcolumn)
01331 if {[info exists drag(x)] && $fillColumnID != {}} {
01332 set fillColumnFrame $widgets(frame$fillColumnID)
01333 if {[string compare $drag(leftFrame) $fillColumnFrame] == 0 || [string compare $drag(rightFrame) $fillColumnFrame] == 0} {
01334 set width [$fillColumnFrame cget -width]
01335 set misc(minFillColumnSize) $width
01336 }
01337 set misc(min-$drag(leftFrame)) [$drag(leftFrame) cget -width]
01338 set misc(min-$drag(rightFrame)) [$drag(rightFrame) cget -width]
01339 }
01340
01341 # reset the state and the cursor
01342 catch {unset drag}
01343 $widgets(label$id) configure -cursor $options(-cursor)
01344
01345 }
01346 }
01347 }
01348
01349 }
01350
01351 namespace ::mclistbox {
01352
01353 ret {::mclistbox::SelectionHandler} (type w , type type , optional offset ={) {length {}}} {
01354 upvar ::mclistbox::${w}::options options
01355 upvar ::mclistbox::${w}::misc misc
01356 upvar ::mclistbox::${w}::widgets widgets
01357
01358 switch -exact $type {
01359
01360 own {
01361 selection own -command [list ::mclistbox::SelectionHandler $w lose] -selection PRIMARY $w
01362 }
01363
01364 lose {
01365 if {$options(-exportselection)} {
01366 foreach id $misc(columns) {
01367 $widgets(listbox$id) selection clear 0 end
01368 }
01369 }
01370 }
01371
01372 get {
01373 end = [expr {$length + $off - 1}]
01374
01375 set = column [lindex $misc(columns) 0]
01376 curselection = [$widgets(listbox$column) curselection]
01377
01378
01379
01380
01381
01382
01383 data = ""
01384 foreach index $curselection {
01385 rowdata = [join [::mclistbox::WidgetProc-get $w $index] "\t"]
01386 lappend data $rowdata
01387 }
01388 data = [join $data "\n"]
01389 return [string range $data $off $end = ]
01390 }
01391
01392 }
01393 }
01394
01395 }
01396
01397 namespace ::mclistbox {
01398
01399 ret {::mclistbox::SetBindings} (type w) {
01400 upvar ::mclistbox::${w}::widgets widgets
01401 upvar ::mclistbox::${w}::options options
01402 upvar ::mclistbox::${w}::misc misc
01403
01404 # we must do this so that the columns fill the text widget in
01405 # the y direction
01406 bind $widgets(text) <Configure> [list ::mclistbox::AdjustColumns $w %h]
01407 }
01408
01409 }
01410
01411 namespace ::mclistbox {
01412
01413 ret {::mclistbox::SetClassBindings} () {
01414 # this allows us to clean up some things when we go away
01415 bind Mclistbox <Destroy> [list ::mclistbox::DestroyHandler %W]
01416
01417 # steal all of the standard listbox bindings. Note that if a user
01418 # clicks in a column, %W will return that column. This is bad,
01419 # so we have to make a substitution in all of the bindings to
01420 # compute the real widget name (ie: the name of the topmost
01421 # frame)
01422 foreach event [bind Listbox] {
01423 set binding [bind Listbox $event]
01424 regsub -all {%W} $binding {[::mclistbox::convert %W -W]} binding
01425 regsub -all {%x} $binding {[::mclistbox::convert %W -x %x]} binding
01426 regsub -all {%y} $binding {[::mclistbox::convert %W -y %y]} binding
01427 bind Mclistbox $event $binding
01428 }
01429
01430 # these define bindings for the column labels for resizing. Note
01431 # that we need both the name of this widget (calculated by $this)
01432 # as well as the specific widget that the event occured over.
01433 # Also note that $this is a constant string that gets evaluated
01434 # when the binding fires.
01435 # What a pain.
01436 set this {[::mclistbox::convert %W -W]}
01437 bind MclistboxMouseBindings <ButtonPress-1> "::mclistbox::ResizeEvent $this buttonpress %W %x %X %Y"
01438 bind MclistboxMouseBindings <ButtonRelease-1> "::mclistbox::ResizeEvent $this buttonrelease %W %x %X %Y"
01439 bind MclistboxMouseBindings <Enter> "::mclistbox::ResizeEvent $this motion %W %x %X %Y"
01440 bind MclistboxMouseBindings <Motion> "::mclistbox::ResizeEvent $this motion %W %x %X %Y"
01441 bind MclistboxMouseBindings <B1-Motion> "::mclistbox::ResizeEvent $this drag %W %x %X %Y"
01442 }
01443
01444 }
01445
01446 namespace ::mclistbox {
01447
01448 ret {::mclistbox::UpdateScrollbars} (type w) {
01449 upvar ::mclistbox::${w}::widgets widgets
01450 upvar ::mclistbox::${w}::options options
01451 upvar ::mclistbox::${w}::misc misc
01452
01453 if {![winfo ismapped $w]} {
01454 catch {unset misc(afterid)}
01455 return
01456 }
01457
01458 update idletasks
01459 if {[llength $misc(columns)] > 0} {
01460 if {[string length $options(-yscrollcommand)] != 0} {
01461 set col0 [lindex $misc(columns) 0]
01462 set yview [$widgets(listbox$col0) yview]
01463 eval $options(-yscrollcommand) $yview
01464 }
01465
01466 if {[string length $options(-xscrollcommand)] != 0} {
01467 set col0 [lindex $misc(columns) 0]
01468 set xview [$widgets(text) xview]
01469 eval $options(-xscrollcommand) $xview
01470 }
01471 }
01472 catch {unset misc(afterid)}
01473 }
01474
01475 }
01476
01477 namespace ::mclistbox {
01478
01479 ret {::mclistbox::WidgetProc} (type w , type command , type args) {
01480 variable widgetOptions
01481
01482 upvar ::mclistbox::${w}::widgets widgets
01483 upvar ::mclistbox::${w}::options options
01484 upvar ::mclistbox::${w}::misc misc
01485 upvar ::mclistbox::${w}::columnID columnID
01486
01487 set command [::mclistbox::Canonize $w command $command]
01488
01489 # some commands have subcommands. We'll check for that here
01490 # and mung the command and args so that we can treat them as
01491 # distinct commands in the following switch statement
01492 if {[string compare $command "column"] == 0} {
01493 set subcommand [::mclistbox::Canonize $w "column command" [lindex $args 0]]
01494 set command "$command-$subcommand"
01495 set args [lrange $args 1 end]
01496
01497 } elseif {[string compare $command "label"] == 0} {
01498 set subcommand [::mclistbox::Canonize $w "label command" [lindex $args 0]]
01499 set command "$command-$subcommand"
01500 set args [lrange $args 1 end]
01501 }
01502
01503 set result ""
01504 catch {unset priorSelection}
01505
01506 # here we go. Error checking be damned!
01507 switch $command {
01508 xview {
01509 # note that at present, "xview <index>" is broken. I'm
01510 # not even sure how to do it. Unless I attach our hidden
01511 # listbox to the scrollbar and use it. Hmmm..... I'll
01512 # try that later. (FIXME)
01513 set result [eval {$widgets(text)} xview $args]
01514 InvalidateScrollbars $w
01515 }
01516
01517 yview {
01518 if {[llength $args] == 0} {
01519 # length of zero means to fetch the yview; we can
01520 # get this from a single listbox
01521 set result [$widgets(hiddenListbox) yview]
01522
01523 } else {
01524
01525 # if it's one argument, it's an index. We'll pass that
01526 # index through the index command to properly translate
01527 # @x,y indicies, and place the value back in args
01528 if {[llength $args] == 1} {
01529 set index [::mclistbox::MassageIndex $w [lindex $args 0]]
01530 set args [list $index]
01531 }
01532
01533 # run the yview command on every column.
01534 foreach id $misc(columns) {
01535 eval {$widgets(listbox$id)} yview $args
01536 }
01537 eval {$widgets(hiddenListbox)} yview $args
01538
01539 InvalidateScrollbars $w
01540
01541 set result ""
01542 }
01543 }
01544
01545 activate {
01546 if {[llength $args] != 1} {
01547 return -code error "wrong \# of args: should be $w activate index"
01548 }
01549 set index [::mclistbox::MassageIndex $w [lindex $args 0]]
01550
01551 foreach id $misc(columns) {
01552 $widgets(listbox$id) activate $index
01553 }
01554 set result ""
01555 }
01556
01557 bbox {
01558 if {[llength $args] != 1} {
01559 return -code error "wrong \# of args: should be $w bbox index"
01560 }
01561 # get a real index. This will adjust @x,y indicies
01562 # to account for the label, if any.
01563 set index [::mclistbox::MassageIndex $w [lindex $args 0]]
01564
01565 set id [lindex $misc(columns) 0]
01566
01567 # we can get the x, y, and height from the first
01568 # column.
01569 set bbox [$widgets(listbox$id) bbox $index]
01570 if {[string length $bbox] == 0} {return ""}
01571
01572 foreach {x y w h} $bbox {}
01573
01574 # the x and y coordinates have to be adjusted for the
01575 # fact that the listbox is inside a frame, and the
01576 # frame is inside a text widget. All of those add tiny
01577 # offsets. Feh.
01578 incr y [winfo y $widgets(listbox$id)]
01579 incr y [winfo y $widgets(frame$id)]
01580 incr x [winfo x $widgets(listbox$id)]
01581 incr x [winfo x $widgets(frame$id)]
01582
01583 # we can get the width by looking at the relative x
01584 # coordinate of the right edge of the last column
01585 set id [lindex $misc(columns) end]
01586 set w [expr {[winfo width $widgets(frame$id)] + [winfo x $widgets(frame$id)]}]
01587 set bbox [list $x $y [expr {$x + $w}] $h]
01588 set result $bbox
01589 }
01590
01591 label-bind {
01592 # we are just too clever for our own good. (that's a
01593 # polite way of saying this is more complex than it
01594 # needs to be)
01595
01596 set id [lindex $args 0]
01597 set index [CheckColumnID $w $id]
01598
01599 set args [lrange $args 1 end]
01600 if {[llength $args] == 0} {
01601 set result [bind $widgets(label$id)]
01602 } else {
01603
01604 # when we create a binding, we'll actually have the
01605 # binding run our own command with the user's command
01606 # as an argument. This way we can do some sanity checks
01607 # before running the command. So, when querying a binding
01608 # we need to only return the user's code
01609 set sequence [lindex $args 0]
01610 if {[llength $args] == 1} {
01611 set result [lindex [bind $widgets(label$id) $sequence] end]
01612 } else {
01613
01614 # replace %W with our toplevel frame, then
01615 # do the binding
01616 set code [lindex $args 1]
01617 regsub -all {%W} $code $w code
01618
01619 set result [bind $widgets(label$id) $sequence [list ::mclistbox::LabelEvent $w $id $code]]
01620 }
01621 }
01622 }
01623
01624 column-add {
01625 eval ::mclistbox::Column-add {$w} $args
01626 AdjustColumns $w
01627 set result ""
01628 }
01629
01630 column-delete {
01631 foreach id $args {
01632 set index [CheckColumnID $w $id]
01633
01634 # remove the reference from our list of columns
01635 set misc(columns) [lreplace $misc(columns) $index $index]
01636
01637 # whack the widget
01638 destroy $widgets(frame$id)
01639
01640 # clear out references to the individual widgets
01641 unset widgets(frame$id)
01642 unset widgets(listbox$id)
01643 unset widgets(label$id)
01644 }
01645 InvalidateScrollbars $w
01646 set result ""
01647 }
01648
01649 column-cget {
01650 if {[llength $args] != 2} {
01651 return -code error "wrong # of args: should be \"$w column cget name option\""
01652 }
01653 set id [::mclistbox::Canonize $w column [lindex $args 0]]
01654 set option [lindex $args 1]
01655 set data [::mclistbox::Column-configure $w $id $option]
01656 set result [lindex $data 4]
01657 }
01658
01659 column-configure {
01660 set id [::mclistbox::Canonize $w column [lindex $args 0]]
01661 set args [lrange $args 1 end]
01662 set result [eval ::mclistbox::Column-configure {$w} {$id} $args]
01663 }
01664
01665 column-names {
01666 if {[llength $args] != 0} {
01667 return -code error "wrong # of args: should be \"$w column names\""
01668 }
01669 set result $misc(columns)
01670 }
01671
01672 column-nearest {
01673 if {[llength $args] != 1} {
01674 return -code error "wrong # of args: should be \"$w column nearest x\""
01675 }
01676
01677 set x [lindex $args 0]
01678 set tmp [$widgets(text) index @$x,0]
01679 set tmp [split $tmp "."]
01680 set index [lindex $tmp 1]
01681
01682 set result [lindex $misc(columns) $index]
01683 }
01684
01685 cget {
01686 if {[llength $args] != 1} {
01687 return -code error "wrong # args: should be $w cget option"
01688 }
01689 set opt [::mclistbox::Canonize $w option [lindex $args 0]]
01690
01691 set result $options($opt)
01692 }
01693
01694
01695 configure {
01696 set result [eval ::mclistbox::Configure {$w} $args]
01697
01698 }
01699
01700 curselection {
01701 set id [lindex $misc(columns) 0]
01702 set result [$widgets(listbox$id) curselection]
01703 }
01704
01705 delete {
01706 if {[llength $args] < 1 || [llength $args] > 2} {
01707 return -code error "wrong \# of args: should be $w delete first ?last?"
01708 }
01709
01710 # it's possible that the selection will change because
01711 # of something we do. So, grab the current selection before
01712 # we do anything. Just before returning we'll see if the
01713 # selection has changed. If so, we'll call our selectcommand
01714 if {$options(-selectcommand) != ""} {
01715 set col0 [lindex $misc(columns) 0]
01716 set priorSelection [$widgets(listbox$col0) curselection]
01717 }
01718
01719 set index1 [::mclistbox::MassageIndex $w [lindex $args 0]]
01720 if {[llength $args] == 2} {
01721 set index2 [::mclistbox::MassageIndex $w [lindex $args 1]]
01722 } else {
01723 set index2 ""
01724 }
01725
01726 # note we do an eval here to make index2 "disappear" if it
01727 # is set to an empty string.
01728 foreach id $misc(columns) {
01729 eval {$widgets(listbox$id)} delete $index1 $index2
01730 }
01731 eval {$widgets(hiddenListbox)} delete $index1 $index2
01732
01733 InvalidateScrollbars $w
01734
01735 set result ""
01736 }
01737
01738 get {
01739 if {[llength $args] < 1 || [llength $args] > 2} {
01740 return -code error "wrong \# of args: should be $w get first ?last?"
01741 }
01742 set index1 [::mclistbox::MassageIndex $w [lindex $args 0]]
01743 if {[llength $args] == 2} {
01744 set index2 [::mclistbox::MassageIndex $w [lindex $args 1]]
01745 } else {
01746 set index2 ""
01747 }
01748
01749 set result [eval ::mclistbox::WidgetProc-get {$w} $index1 $index2]
01750
01751 }
01752
01753 index {
01754
01755 if {[llength $args] != 1} {
01756 return -code error "wrong \# of args: should be $w index index"
01757 }
01758
01759 set index [::mclistbox::MassageIndex $w [lindex $args 0]]
01760 set id [lindex $misc(columns) 0]
01761
01762 set result [$widgets(listbox$id) index $index]
01763 }
01764
01765 insert {
01766 if {[llength $args] < 1} {
01767 return -code error "wrong \# of args: should be $w insert ?element element...?"
01768 }
01769
01770 # it's possible that the selection will change because
01771 # of something we do. So, grab the current selection before
01772 # we do anything. Just before returning we'll see if the
01773 # selection has changed. If so, we'll call our selectcommand
01774 if {$options(-selectcommand) != ""} {
01775 set col0 [lindex $misc(columns) 0]
01776 set priorSelection [$widgets(listbox$col0) curselection]
01777 }
01778
01779 set index [::mclistbox::MassageIndex $w [lindex $args 0]]
01780
01781 ::mclistbox::Insert $w $index [lrange $args 1 end]
01782
01783 InvalidateScrollbars $w
01784 set result ""
01785 }
01786
01787 nearest {
01788 if {[llength $args] != 1} {
01789 return -code error "wrong \# of args: should be $w nearest y"
01790 }
01791
01792 # translate the y coordinate into listbox space
01793 set id [lindex $misc(columns) 0]
01794 set y [lindex $args 0]
01795 incr y -[winfo y $widgets(listbox$id)]
01796 incr y -[winfo y $widgets(frame$id)]
01797
01798 set col0 [lindex $misc(columns) 0]
01799
01800 set result [$widgets(listbox$col0) nearest $y]
01801 }
01802
01803 scan {
01804 foreach {subcommand x y} $args {}
01805 switch $subcommand {
01806 mark {
01807 # we have to treat scrolling in x and y differently;
01808 # scrolling in the y direction affects listboxes and
01809 # scrolling in the x direction affects the text widget.
01810 # to facilitate that, we need to keep a local copy
01811 # of the scan mark.
01812 set misc(scanmarkx) $x
01813 set misc(scanmarky) $y
01814
01815 # set the scan mark for each column
01816 foreach id $misc(columns) {
01817 $widgets(listbox$id) scan mark $x $y
01818 }
01819
01820 # we can't use the x coordinate given us, since it
01821 # is relative to whatever column we are over. So,
01822 # we'll just usr the results of [winfo pointerx].
01823 $widgets(text) scan mark [winfo pointerx $w] $y
01824 }
01825 dragto {
01826 # we want the columns to only scan in the y direction,
01827 # so we'll force the x componant to remain constant
01828 foreach id $misc(columns) {
01829 $widgets(listbox$id) scan dragto $misc(scanmarkx) $y
01830 }
01831
01832 # since the scan mark of the text widget was based
01833 # on the pointer location, so must be the x
01834 # coordinate to the dragto command. And since we
01835 # want the text widget to only scan in the x
01836 # direction, the y componant will remain constant
01837 $widgets(text) scan dragto [winfo pointerx $w] $misc(scanmarky)
01838
01839 # make sure the scrollbars reflect the changes.
01840 InvalidateScrollbars $w
01841 }
01842
01843 set result ""
01844 }
01845 }
01846
01847 see {
01848 if {[llength $args] != 1} {
01849 return -code error "wrong \# of args: should be $w see index"
01850 }
01851 set index [::mclistbox::MassageIndex $w [lindex $args 0]]
01852
01853 foreach id $misc(columns) {
01854 $widgets(listbox$id) see $index
01855 }
01856 InvalidateScrollbars $w
01857 set result {}
01858 }
01859
01860 selection {
01861 # it's possible that the selection will change because
01862 # of something we do. So, grab the current selection before
01863 # we do anything. Just before returning we'll see if the
01864 # selection has changed. If so, we'll call our selectcommand
01865 if {$options(-selectcommand) != ""} {
01866 set col0 [lindex $misc(columns) 0]
01867 set priorSelection [$widgets(listbox$col0) curselection]
01868 }
01869
01870 set subcommand [lindex $args 0]
01871 set args [lrange $args 1 end]
01872
01873 set prefix "wrong \# of args: should be $w"
01874 switch $subcommand {
01875 includes {
01876 if {[llength $args] != 1} {
01877 return -code error "$prefix selection $subcommand index"
01878 }
01879 set index [::mclistbox::MassageIndex $w [lindex $args 0]]
01880 set id [lindex $misc(columns) 0]
01881 set result [$widgets(listbox$id) selection includes $index]
01882 }
01883
01884 set {
01885 switch [llength $args] {
01886 1 {
01887 set index1 [::mclistbox::MassageIndex $w [lindex $args 0]]
01888 set index2 ""
01889 }
01890 2 {
01891 set index1 [::mclistbox::MassageIndex $w [lindex $args 0]]
01892 set index2 [::mclistbox::MassageIndex $w [lindex $args 1]]
01893 }
01894 default {
01895 return -code error "$prefix selection clear first ?last?"
01896 }
01897 }
01898
01899 if {$options(-exportselection)} {
01900 SelectionHandler $w own
01901 }
01902 if {$index1 != ""} {
01903 foreach id $misc(columns) {
01904 eval {$widgets(listbox$id)} selection set $index1 $index2
01905 }
01906 }
01907
01908 set result ""
01909 }
01910
01911 anchor {
01912 if {[llength $args] != 1} {
01913 return -code error "$prefix selection $subcommand index"
01914 }
01915 set index [::mclistbox::MassageIndex $w [lindex $args 0]]
01916
01917 if {$options(-exportselection)} {
01918 SelectionHandler $w own
01919 }
01920 foreach id $misc(columns) {
01921 $widgets(listbox$id) selection anchor $index
01922 }
01923 set result ""
01924 }
01925
01926 clear {
01927 switch [llength $args] {
01928 1 {
01929 set index1 [::mclistbox::MassageIndex $w [lindex $args 0]]
01930 set index2 ""
01931 }
01932 2 {
01933 set index1 [::mclistbox::MassageIndex $w [lindex $args 0]]
01934 set index2 [::mclistbox::MassageIndex $w [lindex $args 1]]
01935 }
01936 default {
01937 return -code error "$prefix selection clear first ?last?"
01938 }
01939 }
01940
01941 if {$options(-exportselection)} {
01942 SelectionHandler $w own
01943 }
01944 foreach id $misc(columns) {
01945 eval {$widgets(listbox$id)} selection clear $index1 $index2
01946 }
01947 set result ""
01948 }
01949 }
01950 }
01951
01952 size {
01953 set id [lindex $misc(columns) 0]
01954 set result [$widgets(listbox$id) size]
01955 }
01956 }
01957
01958 # if the user has a selectcommand defined and the selection changed,
01959 # run the selectcommand
01960 if {[info exists priorSelection] && $options(-selectcommand) != ""} {
01961 set column [lindex $misc(columns) 0]
01962 set currentSelection [$widgets(listbox$column) curselection]
01963 if {[string compare $priorSelection $currentSelection] != 0} {
01964 # this logic keeps us from getting into some sort of
01965 # infinite loop of the selectcommand changes the selection
01966 # (not particularly well tested, but it seems like the
01967 # right thing to do...)
01968 if {![info exists misc(skipRecursiveCall)]} {
01969 set misc(skipRecursiveCall) 1
01970 uplevel \#0 $options(-selectcommand) $currentSelection
01971 catch {unset misc(skipRecursiveCall)}
01972 }
01973 }
01974 }
01975
01976 return $result
01977 }
01978
01979 }
01980
01981 namespace ::mclistbox {
01982
01983 ret {::mclistbox::WidgetProc-get} (type w , type args) {
01984 upvar ::mclistbox::${w}::widgets widgets
01985 upvar ::mclistbox::${w}::options options
01986 upvar ::mclistbox::${w}::misc misc
01987
01988 set returnType "list"
01989 # the listbox "get" command returns different things
01990 # depending on whether it has one or two args. Internally
01991 # we *always* want a valid list, so we'll force a second
01992 # arg which in turn forces the listbox to return a list,
01993 # even if its a list of one element
01994 if {[llength $args] == 1} {
01995 lappend args [lindex $args 0]
01996 set returnType "listOfLists"
01997 }
01998
01999 # get all the data from each column
02000 foreach id $misc(columns) {
02001 set data($id) [eval {$widgets(listbox$id)} get $args]
02002 }
02003
02004 # now join the data together one row at a time. Ugh.
02005 set result {}
02006 set rows [llength $data($id)]
02007 for {set i 0} {$i < $rows} {incr i} {
02008 set this {}
02009 foreach column $misc(columns) {
02010 lappend this [lindex $data($column) $i]
02011 }
02012 lappend result $this
02013 }
02014
02015 # now to unroll the list if necessary. If the user gave
02016 # us only one indicie we want to return a single list
02017 # of values. If they gave use two indicies we want to return
02018 # a list of lists.
02019 if {[string compare $returnType "list"] == 0} {
02020 return $result
02021 } else {
02022 return [lindex $result 0]
02023 }
02024 }
02025
02026 }
02027
02028 namespace ::mclistbox {
02029
02030 ret {::mclistbox::convert} (type w , type args) {
02031 set result {}
02032 if {![winfo exists $w]} {
02033 return -code error "window \"$w\" doesn't exist"
02034 }
02035
02036 while {[llength $args] > 0} {
02037 set option [lindex $args 0]
02038 set args [lrange $args 1 end]
02039
02040 switch -exact -- $option {
02041 -x {
02042 set value [lindex $args 0]
02043 set args [lrange $args 1 end]
02044 set win $w
02045 while {[winfo class $win] != "Mclistbox"} {
02046 incr value [winfo x $win]
02047 set win [winfo parent $win]
02048 if {$win == "."} break
02049 }
02050 lappend result $value
02051 }
02052
02053 -y {
02054 set value [lindex $args 0]
02055 set args [lrange $args 1 end]
02056 set win $w
02057 while {[winfo class $win] != "Mclistbox"} {
02058 incr value [winfo y $win]
02059 set win [winfo parent $win]
02060 if {$win == "."} break
02061 }
02062 lappend result $value
02063 }
02064
02065 -w -
02066 -W {
02067 set win $w
02068 while {[winfo class $win] != "Mclistbox"} {
02069 set win [winfo parent $win]
02070 if {$win == "."} break;
02071 }
02072 lappend result $win
02073 }
02074 }
02075 }
02076 return $result
02077 }
02078
02079 }
02080
02081 namespace ::mclistbox {
02082
02083 ret {::mclistbox::mclistbox} (type args) {
02084 variable widgetOptions
02085
02086 # perform a one time initialization
02087 if {![info exists widgetOptions]} {
02088 __mclistbox_Setup
02089 Init
02090 }
02091
02092 # make sure we at least have a widget name
02093 if {[llength $args] == 0} {
02094 return -code error "wrong # args: should be \"mclistbox pathName ?options?\""
02095 }
02096
02097 # ... and make sure a widget doesn't already exist by that name
02098 if {[winfo exists [lindex $args 0]]} {
02099 return -code error "window name \"[lindex $args 0]\" already exists"
02100 }
02101
02102 # and check that all of the args are valid
02103 foreach {name value} [lrange $args 1 end] {
02104 Canonize [lindex $args 0] option $name
02105 }
02106
02107 # build it...
02108 set w [eval Build $args]
02109
02110 # set some bindings...
02111 SetBindings $w
02112
02113 # and we are done!
02114 return $w
02115 }
02116
02117 }
02118
02119 ret {__mclistbox_Setup} () {
02120 namespace eval ::mclistbox {
02121
02122 # this is the public interface
02123 namespace export mclistbox
02124
02125 # these contain references to available options
02126 variable widgetOptions
02127 variable columnOptions
02128
02129 # these contain references to available commands and subcommands
02130 variable widgetCommands
02131 variable columnCommands
02132 variable labelCommands
02133 }
02134 }
02135
02136 ret {vTcl:DefineAlias} (type target , type alias , type widgetProc , type top_, type or_, type alias , type cmdalias) {
02137 global widget
02138
02139 set widget($alias) $target
02140 set widget(rev,$target) $alias
02141
02142 if {$cmdalias} {
02143 interp alias {} $alias {} $widgetProc $target
02144 }
02145
02146 if {$top_or_alias != ""} {
02147 set widget($top_or_alias,$alias) $target
02148
02149 if {$cmdalias} {
02150 interp alias {} $top_or_alias.$alias {} $widgetProc $target
02151 }
02152 }
02153 }
02154
02155 ret {vTcl:Toplevel:WidgetProc} (type w , type args) {
02156 if {[llength $args] == 0} {
02157 return -code error "wrong # args: should be \"$w option ?arg arg ...?\""
02158 }
02159
02160 ## The first argument is a switch, they must be doing a configure.
02161 if {[string index $args 0] == "-"} {
02162 set command configure
02163
02164 ## There's only one argument, must be a cget.
02165 if {[llength $args] == 1} {
02166 set command cget
02167 }
02168 } else {
02169 set command [lindex $args 0]
02170 set args [lrange $args 1 end]
02171 }
02172
02173 switch -- $command {
02174 "hide" -
02175 "Hide" {
02176 Window hide $w
02177 }
02178
02179 "show" -
02180 "Show" {
02181 Window show $w
02182 }
02183
02184 "ShowModal" {
02185 Window show $w
02186 raise $w
02187 grab $w
02188 tkwait window $w
02189 grab release $w
02190 }
02191
02192 default {
02193 eval $w $command $args
02194 }
02195 }
02196 }
02197
02198 ret {vTcl:WidgetProc} (type w , type args) {
02199 if {[llength $args] == 0} {
02200 return -code error "wrong # args: should be \"$w option ?arg arg ...?\""
02201 }
02202
02203 ## The first argument is a switch, they must be doing a configure.
02204 if {[string index $args 0] == "-"} {
02205 set command configure
02206
02207 ## There's only one argument, must be a cget.
02208 if {[llength $args] == 1} {
02209 set command cget
02210 }
02211 } else {
02212 set command [lindex $args 0]
02213 set args [lrange $args 1 end]
02214 }
02215
02216 eval $w $command $args
02217 }
02218 }
02219
02220 if {[info exists vTcl(sourcing)]} {
02221 ret vTcl:project:info () {
02222 namespace eval ::widgets::.gui {
02223 array set save {}
02224 }
02225 namespace eval ::widgets::.gui.cpd17 {
02226 array set save {-background 1 -borderwidth 1 -height 1 -relief 1 -width 1}
02227 }
02228 namespace eval ::widgets::.gui.cpd17.01 {
02229 array set save {-anchor 1 -borderwidth 1 -font 1 -menu 1 -padx 1 -pady 1 -text 1 -underline 1 -width 1}
02230 }
02231 namespace eval ::widgets::.gui.cpd17.01.02 {
02232 array set save {-cursor 1 -tearoff 1}
02233 }
02234 namespace eval ::widgets::.gui.cpd17.settingbutton {
02235 array set save {-font 1 -menu 1 -padx 1 -pady 1 -text 1 -underline 1}
02236 }
02237 namespace eval ::widgets::.gui.cpd17.settingbutton.m {
02238 array set save {}
02239 }
02240 namespace eval ::widgets::.gui.pr {
02241 array set save {-borderwidth 1 -height 1 -relief 1 -width 1}
02242 }
02243 namespace eval ::widgets::.gui.pr.tools {
02244 array set save {-height 1 -width 1}
02245 }
02246 namespace eval ::widgets::.gui.pr.tools.infolabel {
02247 array set save {-anchor 1 -background 1 -borderwidth 1 -font 1 -relief 1 -text 1}
02248 }
02249 namespace eval ::widgets::.gui.pr.tools.resizescrl {
02250 array set save {-bigincrement 1 -borderwidth 1 -command 1 -from 1 -highlightthickness 1 -orient 1 -relief 1 -resolution 1 -showvalue 1 -sliderlength 1 -tickinterval 1 -to 1 -troughcolor 1 -variable 1 -width 1}
02251 }
02252 namespace eval ::widgets::.gui.pr.toolframe {
02253 array set save {-borderwidth 1 -height 1 -relief 1 -width 1}
02254 }
02255 namespace eval ::widgets::.gui.pr.toolframe.toolsbox {
02256 array set save {-background 1 -height 1 -highlightbackground 1 -highlightcolor 1 -relief 1 -width 1}
02257 }
02258 namespace eval ::widgets::.gui.pr.toolframe.toolsbox.fobt {
02259 array set save {-borderwidth 1 -command 1 -text 1}
02260 }
02261 namespace eval ::widgets::.gui.pr.toolframe.toolsbox.but34 {
02262 array set save {-command 1 -padx 1 -text 1}
02263 }
02264 namespace eval ::widgets::.gui.pr.toolframe.toolsbox.but35 {
02265 array set save {-command 1 -padx 1 -text 1}
02266 }
02267 namespace eval ::widgets::.gui.pr.toolframe.toolsbox.but32 {
02268 array set save {-anchor 1 -borderwidth 1 -command 1}
02269 }
02270 namespace eval ::widgets::.gui.pr.toolframe.entityframe {
02271 array set save {-borderwidth 1 -height 1 -width 1}
02272 }
02273 namespace eval ::widgets::.gui.pr.toolframe.entityframe.comprb {
02274 array set save {-anchor 1 -borderwidth 1 -command 1 -font 1 -highlightthickness 1 -padx 1 -pady 1 -selectcolor 1 -text 1 -value 1 -variable 1 -width 1}
02275 }
02276 namespace eval ::widgets::.gui.pr.toolframe.entityframe.ficrb {
02277 array set save {-anchor 1 -command 1 -font 1 -highlightthickness 1 -padx 1 -pady 1 -text 1 -value 1 -variable 1}
02278 }
02279 namespace eval ::widgets::.gui.pr.toolframe.entityframe.cnxrb {
02280 array set save {-anchor 1 -command 1 -font 1 -highlightthickness 1 -padx 1 -pady 1 -text 1 -value 1 -variable 1}
02281 }
02282 namespace eval ::widgets::.gui.pr.toolframe.entityframe.fieldsrb {
02283 array set save {-anchor 1 -command 1 -font 1 -highlightthickness 1 -padx 1 -pady 1 -text 1 -value 1 -variable 1 -width 1}
02284 }
02285 namespace eval ::widgets::.gui.pr.toolframe.buttonfrc {
02286 array set save {-height 1 -width 1}
02287 }
02288 namespace eval ::widgets::.gui.pr.toolframe.buttonfrc.editb {
02289 array set save {-command 1 -font 1 -padx 1 -pady 1 -text 1}
02290 }
02291 namespace eval ::widgets::.gui.pr.toolframe.buttonfrc.deleteb {
02292 array set save {-command 1 -font 1 -padx 1 -pady 1 -state 1 -text 1}
02293 }
02294 namespace eval ::widgets::.gui.pr.toolframe.cpd18 {
02295 array set save {-borderwidth 1 -height 1 -relief 1 -width 1}
02296 }
02297 namespace eval ::widgets::.gui.pr.toolframe.cpd18.02 {
02298 array set save {-borderwidth 1 -command 1 -orient 1 -width 1}
02299 }
02300 namespace eval ::widgets::.gui.pr.toolframe.cpd18.03 {
02301 array set save {-borderwidth 1 -command 1 -width 1}
02302 }
02303 namespace eval ::widgets::.gui.pr.toolframe.cpd18.01 {
02304 array set save {-background 1 -borderwidth 1 -font 1 -height 1 -labelanchor 1 -labelborderwidth 1 -labelrelief 1 -relief 1 -selectborderwidth 1 -selectmode 1 -width 1 -xscrollcommand 1 -yscrollcommand 1}
02305 }
02306 namespace eval ::widgets::.gui.pr.zoomframe {
02307 array set save {-height 1 -relief 1 -width 1}
02308 }
02309 namespace eval ::widgets::.gui.pr.zoomframe.viewframe {
02310 array set save {-borderwidth 1 -height 1 -relief 1 -width 1}
02311 }
02312 namespace eval ::widgets::.gui.pr.zoomframe.viewframe.viewcommcheck {
02313 array set save {-command 1 -font 1 -pady 1 -text 1 -variable 1}
02314 }
02315 namespace eval ::widgets::.gui.pr.zoomframe.zm {
02316 array set save {-borderwidth 1 -command 1 -padx 1 -pady 1 -relief 1 -text 1}
02317 }
02318 namespace eval ::widgets::.gui.pr.zoomframe.zp {
02319 array set save {-borderwidth 1 -command 1 -padx 1 -pady 1 -relief 1 -text 1}
02320 }
02321 namespace eval ::widgets::.gui.pr.cpd22 {
02322 array set save {-borderwidth 1 -height 1 -relief 1 -width 1}
02323 }
02324 namespace eval ::widgets::.gui.pr.cpd22.01 {
02325 array set save {-borderwidth 1 -command 1 -jump 1 -orient 1 -width 1}
02326 }
02327 namespace eval ::widgets::.gui.pr.cpd22.02 {
02328 array set save {-borderwidth 1 -command 1 -jump 1 -width 1}
02329 }
02330 namespace eval ::widgets::.gui.pr.cpd22.03 {
02331 array set save {-background 1 -borderwidth 1 -closeenough 1 -height 1 -relief 1 -scrollregion 1 -width 1 -xscrollcommand 1 -yscrollcommand 1}
02332 }
02333 namespace eval ::widgets::.ballon_object {
02334 array set save {-borderwidth 1}
02335 }
02336 namespace eval ::widgets::.ballon_object.text {
02337 array set save {-background 1 -font 1 -foreground 1}
02338 }
02339 namespace eval ::widgets_bindings {
02340 set tagslist {}
02341 }
02342 }
02343 }
02344
02345
02346
02347
02348 namespace ::combobox {
02349
02350 ret {::combobox::Build} (type w , type args) {
02351 variable widgetOptions
02352
02353 if {[winfo exists $w]} {
02354 error "window name \"$w\" already exists"
02355 }
02356
02357 # create the namespace for this instance, and define a few
02358 # variables
02359 namespace eval ::combobox::$w {
02360
02361 variable ignoreTrace 0
02362 variable oldFocus {}
02363 variable oldGrab {}
02364 variable oldValue {}
02365 variable options
02366 variable this
02367 variable widgets
02368
02369 set widgets(foo) foo ;# coerce into an array
02370 set options(foo) foo ;# coerce into an array
02371
02372 unset widgets(foo)
02373 unset options(foo)
02374 }
02375
02376 # import the widgets and options arrays into this proc so
02377 # we don't have to use fully qualified names, which is a
02378 # pain.
02379 upvar ::combobox::${w}::widgets widgets
02380 upvar ::combobox::${w}::options options
02381
02382 # this is our widget -- a frame of class Combobox. Naturally,
02383 # it will contain other widgets. We create it here because
02384 # we need it in order to set some default options.
02385 set widgets(this) [frame $w -class Combobox -takefocus 0]
02386 set widgets(entry) [entry $w.entry -takefocus 1]
02387 set widgets(button) [label $w.button -takefocus 0]
02388
02389 # this defines all of the default options. We get the
02390 # values from the option database. Note that if an array
02391 # value is a list of length one it is an alias to another
02392 # option, so we just ignore it
02393 foreach name [array names widgetOptions] {
02394 if {[llength $widgetOptions($name)] == 1} continue
02395
02396 set optName [lindex $widgetOptions($name) 0]
02397 set optClass [lindex $widgetOptions($name) 1]
02398
02399 set value [option get $w $optName $optClass]
02400 set options($name) $value
02401 }
02402
02403 # a couple options aren't available in earlier versions of
02404 # tcl, so we'll set them to sane values. For that matter, if
02405 # they exist but are empty, set them to sane values.
02406 if {[string length $options(-disabledforeground)] == 0} {
02407 set options(-disabledforeground) $options(-foreground)
02408 }
02409 if {[string length $options(-disabledbackground)] == 0} {
02410 set options(-disabledbackground) $options(-background)
02411 }
02412
02413 # if -value is set to null, we'll remove it from our
02414 # local array. The assumption is, if the user sets it from
02415 # the option database, they will set it to something other
02416 # than null (since it's impossible to determine the difference
02417 # between a null value and no value at all).
02418 if {[info exists options(-value)] && [string length $options(-value)] == 0} {
02419 unset options(-value)
02420 }
02421
02422 # we will later rename the frame's widget proc to be our
02423 # own custom widget proc. We need to keep track of this
02424 # new name, so we'll define and store it here...
02425 set widgets(frame) ::combobox::${w}::$w
02426
02427 # gotta do this sooner or later. Might as well do it now
02428 pack $widgets(entry) -side left -fill both -expand yes
02429 pack $widgets(button) -side right -fill y -expand no
02430
02431 # I should probably do this in a catch, but for now it's
02432 # good enough... What it does, obviously, is put all of
02433 # the option/values pairs into an array. Make them easier
02434 # to handle later on...
02435 array set options $args
02436
02437 # now, the dropdown list... the same renaming nonsense
02438 # must go on here as well...
02439 set widgets(dropdown) [toplevel $w.top]
02440 set widgets(listbox) [listbox $w.top.list]
02441 set widgets(vsb) [scrollbar $w.top.vsb]
02442
02443 pack $widgets(listbox) -side left -fill both -expand y
02444
02445 # fine tune the widgets based on the options (and a few
02446 # arbitrary values...)
02447
02448 # NB: we are going to use the frame to handle the relief
02449 # of the widget as a whole, so the entry widget will be
02450 # flat. This makes the button which drops down the list
02451 # to appear "inside" the entry widget.
02452
02453 $widgets(vsb) configure -command "$widgets(listbox) yview" -highlightthickness 0
02454
02455 $widgets(button) configure -highlightthickness 0 -borderwidth 1 -relief raised -width [expr {[winfo reqwidth $widgets(vsb)] - 2}]
02456
02457 $widgets(entry) configure -borderwidth 0 -relief flat -highlightthickness 0
02458
02459 $widgets(dropdown) configure -borderwidth 1 -relief sunken
02460
02461 $widgets(listbox) configure -selectmode browse -background [$widgets(entry) cget -bg] -yscrollcommand "$widgets(vsb) set" -exportselection false -borderwidth 0
02462
02463
02464 # trace variable ::combobox::${w}::entryTextVariable w # [list ::combobox::EntryTrace $w]
02465
02466 # do some window management foo on the dropdown window
02467 wm overrideredirect $widgets(dropdown) 1
02468 wm transient $widgets(dropdown) [winfo toplevel $w]
02469 wm group $widgets(dropdown) [winfo parent $w]
02470 wm resizable $widgets(dropdown) 0 0
02471 wm withdraw $widgets(dropdown)
02472
02473 # this moves the original frame widget proc into our
02474 # namespace and gives it a handy name
02475 rename ::$w $widgets(frame)
02476
02477 # now, create our widget proc. Obviously (?) it goes in
02478 # the global namespace. All combobox widgets will actually
02479 # share the same widget proc to cut down on the amount of
02480 # bloat.
02481 proc ::$w {command args} "eval ::combobox::WidgetProc $w \$command \$args"
02482
02483
02484 # ok, the thing exists... let's do a bit more configuration.
02485 if {[catch "::combobox::Configure [list $widgets(this)] [array get options]" error]} {
02486 catch {destroy $w}
02487 error "internal error: $error"
02488 }
02489
02490 return ""
02491 }
02492
02493 }
02494
02495 namespace ::combobox {
02496
02497 ret {::combobox::CallCommand} (type w , type newValue) {
02498 upvar ::combobox::${w}::widgets widgets
02499 upvar ::combobox::${w}::options options
02500
02501 # call the associated command, if defined and -commandstate is
02502 # set to "normal"
02503 if {$options(-commandstate) == "normal" && [string length $options(-command)] > 0} {
02504 set args [list $widgets(this) $newValue]
02505 uplevel \#0 $options(-command) $args
02506 }
02507 }
02508
02509 }
02510
02511 namespace ::combobox {
02512
02513 ret {::combobox::Canonize} (type w , type object , type opt) {
02514 variable widgetOptions
02515 variable columnOptions
02516 variable widgetCommands
02517 variable listCommands
02518 variable scanCommands
02519
02520 switch $object {
02521 command {
02522 if {[lsearch -exact $widgetCommands $opt] >= 0} {
02523 return $opt
02524 }
02525
02526 # command names aren't stored in an array, and there
02527 # isn't a way to get all the matches in a list, so
02528 # we'll stuff the commands in a temporary array so
02529 # we can use [array names]
02530 set list $widgetCommands
02531 foreach element $list {
02532 set tmp($element) ""
02533 }
02534 set matches [array names tmp ${opt}*]
02535 }
02536
02537 {list command} {
02538 if {[lsearch -exact $listCommands $opt] >= 0} {
02539 return $opt
02540 }
02541
02542 # command names aren't stored in an array, and there
02543 # isn't a way to get all the matches in a list, so
02544 # we'll stuff the commands in a temporary array so
02545 # we can use [array names]
02546 set list $listCommands
02547 foreach element $list {
02548 set tmp($element) ""
02549 }
02550 set matches [array names tmp ${opt}*]
02551 }
02552
02553 {scan command} {
02554 if {[lsearch -exact $scanCommands $opt] >= 0} {
02555 return $opt
02556 }
02557
02558 # command names aren't stored in an array, and there
02559 # isn't a way to get all the matches in a list, so
02560 # we'll stuff the commands in a temporary array so
02561 # we can use [array names]
02562 set list $scanCommands
02563 foreach element $list {
02564 set tmp($element) ""
02565 }
02566 set matches [array names tmp ${opt}*]
02567 }
02568
02569 option {
02570 if {[info exists widgetOptions($opt)] && [llength $widgetOptions($opt)] == 2} {
02571 return $opt
02572 }
02573 set list [array names widgetOptions]
02574 set matches [array names widgetOptions ${opt}*]
02575 }
02576
02577 }
02578
02579 if {[llength $matches] == 0} {
02580 set choices [HumanizeList $list]
02581 error "unknown $object \"$opt\"; must be one of $choices"
02582
02583 } elseif {[llength $matches] == 1} {
02584 set opt [lindex $matches 0]
02585
02586 # deal with option aliases
02587 switch $object {
02588 option {
02589 set opt [lindex $matches 0]
02590 if {[llength $widgetOptions($opt)] == 1} {
02591 set opt $widgetOptions($opt)
02592 }
02593 }
02594 }
02595
02596 return $opt
02597
02598 } else {
02599 set choices [HumanizeList $list]
02600 error "ambiguous $object \"$opt\"; must be one of $choices"
02601 }
02602 }
02603
02604 }
02605
02606 namespace ::combobox {
02607
02608 ret {::combobox::ComputeGeometry} (type w) {
02609 upvar ::combobox::${w}::widgets widgets
02610 upvar ::combobox::${w}::options options
02611
02612 if {$options(-height) == 0 && $options(-maxheight) != "0"} {
02613 # if this is the case, count the items and see if
02614 # it exceeds our maxheight. If so, set the listbox
02615 # size to maxheight...
02616 set nitems [$widgets(listbox) size]
02617 if {$nitems > $options(-maxheight)} {
02618 # tweak the height of the listbox
02619 $widgets(listbox) configure -height $options(-maxheight)
02620 } else {
02621 # un-tweak the height of the listbox
02622 $widgets(listbox) configure -height 0
02623 }
02624 update idletasks
02625 }
02626
02627 # compute height and width of the dropdown list
02628 set bd [$widgets(dropdown) cget -borderwidth]
02629 set height [expr {[winfo reqheight $widgets(dropdown)] + $bd + $bd}]
02630 if {[string length $options(-dropdownwidth)] == 0 ||
02631 $options(-dropdownwidth) == 0} {
02632 set width [winfo width $widgets(this)]
02633 } else {
02634 set m [font measure [$widgets(listbox) cget -font] "m"]
02635 set width [expr {$options(-dropdownwidth) * $m}]
02636 }
02637
02638 # figure out where to place it on the screen, trying to take into
02639 # account we may be running under some virtual window manager
02640 set screenWidth [winfo screenwidth $widgets(this)]
02641 set screenHeight [winfo screenheight $widgets(this)]
02642 set rootx [winfo rootx $widgets(this)]
02643 set rooty [winfo rooty $widgets(this)]
02644 set vrootx [winfo vrootx $widgets(this)]
02645 set vrooty [winfo vrooty $widgets(this)]
02646
02647 # the x coordinate is simply the rootx of our widget, adjusted for
02648 # the virtual window. We won't worry about whether the window will
02649 # be offscreen to the left or right -- we want the illusion that it
02650 # is part of the entry widget, so if part of the entry widget is off-
02651 # screen, so will the list. If you want to change the behavior,
02652 # simply change the if statement... (and be sure to update this
02653 # comment!)
02654 set x [expr {$rootx + $vrootx}]
02655 if {0} {
02656 set rightEdge [expr {$x + $width}]
02657 if {$rightEdge > $screenWidth} {
02658 set x [expr {$screenWidth - $width}]
02659 }
02660 if {$x < 0} {set x 0}
02661 }
02662
02663 # the y coordinate is the rooty plus vrooty offset plus
02664 # the height of the static part of the widget plus 1 for a
02665 # tiny bit of visual separation...
02666 set y [expr {$rooty + $vrooty + [winfo reqheight $widgets(this)] + 1}]
02667 set bottomEdge [expr {$y + $height}]
02668
02669 if {$bottomEdge >= $screenHeight} {
02670 # ok. Fine. Pop it up above the entry widget isntead of
02671 # below.
02672 set y [expr {($rooty - $height - 1) + $vrooty}]
02673
02674 if {$y < 0} {
02675 # this means it extends beyond our screen. How annoying.
02676 # Now we'll try to be real clever and either pop it up or
02677 # down, depending on which way gives us the biggest list.
02678 # then, we'll trim the list to fit and force the use of
02679 # a scrollbar
02680
02681 # (sadly, for windows users this measurement doesn't
02682 # take into consideration the height of the taskbar,
02683 # but don't blame me -- there isn't any way to detect
02684 # it or figure out its dimensions. The same probably
02685 # applies to any window manager with some magic windows
02686 # glued to the top or bottom of the screen)
02687
02688 if {$rooty > [expr {$screenHeight / 2}]} {
02689 # we are in the lower half of the screen --
02690 # pop it up. Y is zero; that parts easy. The height
02691 # is simply the y coordinate of our widget, minus
02692 # a pixel for some visual separation. The y coordinate
02693 # will be the topof the screen.
02694 set y 1
02695 set height [expr {$rooty - 1 - $y}]
02696
02697 } else {
02698 # we are in the upper half of the screen --
02699 # pop it down
02700 set y [expr {$rooty + $vrooty + [winfo reqheight $widgets(this)] + 1}]
02701 set height [expr {$screenHeight - $y}]
02702
02703 }
02704
02705 # force a scrollbar
02706 HandleScrollbar $widgets(this) crop
02707 }
02708 }
02709
02710 if {$y < 0} {
02711 # hmmm. Bummer.
02712 set y 0
02713 set height $screenheight
02714 }
02715
02716 set geometry [format "=%dx%d+%d+%d" $width $height $x $y]
02717
02718 return $geometry
02719 }
02720
02721 }
02722
02723 namespace ::combobox {
02724
02725 ret {::combobox::Configure} (type w , type args) {
02726 variable widgetOptions
02727 variable defaultEntryCursor
02728
02729 upvar ::combobox::${w}::widgets widgets
02730 upvar ::combobox::${w}::options options
02731
02732 if {[llength $args] == 0} {
02733 # hmmm. User must be wanting all configuration information
02734 # note that if the value of an array element is of length
02735 # one it is an alias, which needs to be handled slightly
02736 # differently
02737 set results {}
02738 foreach opt [lsort [array names widgetOptions]] {
02739 if {[llength $widgetOptions($opt)] == 1} {
02740 set alias $widgetOptions($opt)
02741 set optName $widgetOptions($alias)
02742 lappend results [list $opt $optName]
02743 } else {
02744 set optName [lindex $widgetOptions($opt) 0]
02745 set optClass [lindex $widgetOptions($opt) 1]
02746 set default [option get $w $optName $optClass]
02747 if {[info exists options($opt)]} {
02748 lappend results [list $opt $optName $optClass $default $options($opt)]
02749 } else {
02750 lappend results [list $opt $optName $optClass $default ""]
02751 }
02752 }
02753 }
02754
02755 return $results
02756 }
02757
02758 # one argument means we are looking for configuration
02759 # information on a single option
02760 if {[llength $args] == 1} {
02761 set opt [::combobox::Canonize $w option [lindex $args 0]]
02762
02763 set optName [lindex $widgetOptions($opt) 0]
02764 set optClass [lindex $widgetOptions($opt) 1]
02765 set default [option get $w $optName $optClass]
02766 set results [list $opt $optName $optClass $default $options($opt)]
02767 return $results
02768 }
02769
02770 # if we have an odd number of values, bail.
02771 if {[expr {[llength $args]%2}] == 1} {
02772 # hmmm. An odd number of elements in args
02773 error "value for \"[lindex $args end]\" missing"
02774 }
02775
02776 # Great. An even number of options. Let's make sure they
02777 # are all valid before we do anything. Note that Canonize
02778 # will generate an error if it finds a bogus option; otherwise
02779 # it returns the canonical option name
02780 foreach {name value} $args {
02781 set name [::combobox::Canonize $w option $name]
02782 set opts($name) $value
02783 }
02784
02785 # process all of the configuration options
02786 # some (actually, most) options require us to
02787 # do something, like change the attributes of
02788 # a widget or two. Here's where we do that...
02789 #
02790 # note that the handling of disabledforeground and
02791 # disabledbackground is a little wonky. First, we have
02792 # to deal with backwards compatibility (ie: tk 8.3 and below
02793 # didn't have such options for the entry widget), and
02794 # we have to deal with the fact we might want to disable
02795 # the entry widget but use the normal foreground/background
02796 # for when the combobox is not disabled, but not editable either.
02797
02798 set updateVisual 0
02799 foreach option [array names opts] {
02800 set newValue $opts($option)
02801 if {[info exists options($option)]} {
02802 set oldValue $options($option)
02803 }
02804
02805 switch -- $option {
02806 -background {
02807 set updateVisual 1
02808 set options($option) $newValue
02809 }
02810
02811 -borderwidth {
02812 $widgets(frame) configure -borderwidth $newValue
02813 set options($option) $newValue
02814 }
02815
02816 -command {
02817 # nothing else to do...
02818 set options($option) $newValue
02819 }
02820
02821 -commandstate {
02822 # do some value checking...
02823 if {$newValue != "normal" && $newValue != "disabled"} {
02824 set options($option) $oldValue
02825 set message "bad state value \"$newValue\";"
02826 append message " must be normal or disabled"
02827 error $message
02828 }
02829 set options($option) $newValue
02830 }
02831
02832 -cursor {
02833 $widgets(frame) configure -cursor $newValue
02834 $widgets(entry) configure -cursor $newValue
02835 $widgets(listbox) configure -cursor $newValue
02836 set options($option) $newValue
02837 }
02838
02839 -disabledforeground {
02840 set updateVisual 1
02841 set options($option) $newValue
02842 }
02843
02844 -disabledbackground {
02845 set updateVisual 1
02846 set options($option) $newValue
02847 }
02848
02849 -dropdownwidth {
02850 set options($option) $newValue
02851 }
02852
02853 -editable {
02854 set updateVisual 1
02855 if {$newValue} {
02856 # it's editable...
02857 $widgets(entry) configure -state normal -cursor $defaultEntryCursor
02858 } else {
02859 $widgets(entry) configure -state disabled -cursor $options(-cursor)
02860 }
02861 set options($option) $newValue
02862 }
02863
02864 -font {
02865 $widgets(entry) configure -font $newValue
02866 $widgets(listbox) configure -font $newValue
02867 set options($option) $newValue
02868 }
02869
02870 -foreground {
02871 set updateVisual 1
02872 set options($option) $newValue
02873 }
02874
02875 -height {
02876 $widgets(listbox) configure -height $newValue
02877 HandleScrollbar $w
02878 set options($option) $newValue
02879 }
02880
02881 -highlightbackground {
02882 $widgets(frame) configure -highlightbackground $newValue
02883 set options($option) $newValue
02884 }
02885
02886 -highlightcolor {
02887 $widgets(frame) configure -highlightcolor $newValue
02888 set options($option) $newValue
02889 }
02890
02891 -highlightthickness {
02892 $widgets(frame) configure -highlightthickness $newValue
02893 set options($option) $newValue
02894 }
02895
02896 -image {
02897 if {[string length $newValue] > 0} {
02898 $widgets(button) configure -image $newValue
02899 } else {
02900 $widgets(button) configure -image ::combobox::bimage
02901 }
02902 set options($option) $newValue
02903 }
02904
02905 -maxheight {
02906 # ComputeGeometry may dork with the actual height
02907 # of the listbox, so let's undork it
02908 $widgets(listbox) configure -height $options(-height)
02909 HandleScrollbar $w
02910 set options($option) $newValue
02911 }
02912
02913 -opencommand {
02914 # nothing else to do...
02915 set options($option) $newValue
02916 }
02917
02918 -relief {
02919 $widgets(frame) configure -relief $newValue
02920 set options($option) $newValue
02921 }
02922
02923 -selectbackground {
02924 $widgets(entry) configure -selectbackground $newValue
02925 $widgets(listbox) configure -selectbackground $newValue
02926 set options($option) $newValue
02927 }
02928
02929 -selectborderwidth {
02930 $widgets(entry) configure -selectborderwidth $newValue
02931 $widgets(listbox) configure -selectborderwidth $newValue
02932 set options($option) $newValue
02933 }
02934
02935 -selectforeground {
02936 $widgets(entry) configure -selectforeground $newValue
02937 $widgets(listbox) configure -selectforeground $newValue
02938 set options($option) $newValue
02939 }
02940
02941 -state {
02942 if {$newValue == "normal"} {
02943 set updateVisual 1
02944 # it's enabled
02945
02946 set editable [::combobox::GetBoolean $options(-editable)]
02947 if {$editable} {
02948 $widgets(entry) configure -state normal
02949 $widgets(entry) configure -takefocus 1
02950 }
02951
02952 # note that $widgets(button) is actually a label,
02953 # not a button. And being able to disable labels
02954 # wasn't possible until tk 8.3. (makes me wonder
02955 # why I chose to use a label, but that answer is
02956 # lost to antiquity)
02957 if {[info patchlevel] >= 8.3} {
02958 $widgets(button) configure -state normal
02959 }
02960
02961 } elseif {$newValue == "disabled"} {
02962 set updateVisual 1
02963 # it's disabled
02964 $widgets(entry) configure -state disabled
02965 $widgets(entry) configure -takefocus 0
02966 # note that $widgets(button) is actually a label,
02967 # not a button. And being able to disable labels
02968 # wasn't possible until tk 8.3. (makes me wonder
02969 # why I chose to use a label, but that answer is
02970 # lost to antiquity)
02971 if {$::tcl_version >= 8.3} {
02972 $widgets(button) configure -state disabled
02973 }
02974
02975 } else {
02976 set options($option) $oldValue
02977 set message "bad state value \"$newValue\";"
02978 append message " must be normal or disabled"
02979 error $message
02980 }
02981
02982 set options($option) $newValue
02983 }
02984
02985 -takefocus {
02986 $widgets(entry) configure -takefocus $newValue
02987 set options($option) $newValue
02988 }
02989
02990 -textvariable {
02991 $widgets(entry) configure -textvariable $newValue
02992 set options($option) $newValue
02993 }
02994
02995 -value {
02996 ::combobox::SetValue $widgets(this) $newValue
02997 set options($option) $newValue
02998 }
02999
03000 -width {
03001 $widgets(entry) configure -width $newValue
03002 $widgets(listbox) configure -width $newValue
03003 set options($option) $newValue
03004 }
03005
03006 -xscrollcommand {
03007 $widgets(entry) configure -xscrollcommand $newValue
03008 set options($option) $newValue
03009 }
03010 }
03011
03012 if {$updateVisual} {UpdateVisualAttributes $w}
03013 }
03014 }
03015
03016 }
03017
03018 namespace ::combobox {
03019
03020 ret {::combobox::DestroyHandler} (type w) {
03021 # if the widget actually being destroyed is of class Combobox,
03022 # crush the namespace and kill the proc. Get it? Crush. Kill.
03023 # Destroy. Heh. Danger Will Robinson! Oh, man! I'm so funny it
03024 # brings tears to my eyes.
03025 if {[string compare [winfo class $w] "Combobox"] == 0} {
03026 upvar ::combobox::${w}::widgets widgets
03027 upvar ::combobox::${w}::options options
03028
03029 # delete the namespace and the proc which represents
03030 # our widget
03031 namespace delete ::combobox::$w
03032 rename $w {}
03033 }
03034
03035 return ""
03036 }
03037
03038 }
03039
03040 namespace ::combobox {
03041
03042 ret {::combobox::DoInternalWidgetCommand} (type w , type subwidget , type command , type args) {
03043 upvar ::combobox::${w}::widgets widgets
03044 upvar ::combobox::${w}::options options
03045
03046 set subcommand $command
03047 set command [concat $widgets($subwidget) $command $args]
03048 if {[catch $command result]} {
03049 # replace the subwidget name with the megawidget name
03050 regsub $widgets($subwidget) $result $widgets(this) result
03051
03052 # replace specific instances of the subwidget command
03053 # with out megawidget command
03054 switch $subwidget,$subcommand {
03055 listbox,index {regsub "index" $result "list index" result}
03056 listbox,insert {regsub "insert" $result "list insert" result}
03057 listbox,delete {regsub "delete" $result "list delete" result}
03058 listbox,get {regsub "get" $result "list get" result}
03059 listbox,size {regsub "size" $result "list size" result}
03060 }
03061 error $result
03062
03063 } else {
03064 return $result
03065 }
03066 }
03067
03068 }
03069
03070 namespace ::combobox {
03071
03072 ret {::combobox::Find} (type w , optional exact =0) {
03073 upvar ::combobox::${w}::widgets widgets
03074 upvar ::combobox::${w}::options options
03075
03076 ## *sigh* this logic is rather gross and convoluted. Surely
03077 ## there is a more simple, straight-forward way to implement
03078 ## all this. As the saying goes, I lack the time to make it
03079 ## shorter...
03080
03081 # use what is already in the entry widget as a pattern
03082 set pattern [$widgets(entry) get]
03083
03084 if {[string length $pattern] == 0} {
03085 # clear the current selection
03086 $widgets(listbox) see 0
03087 $widgets(listbox) selection clear 0 end
03088 $widgets(listbox) selection anchor 0
03089 $widgets(listbox) activate 0
03090 return
03091 }
03092
03093 # we're going to be searching this list...
03094 set list [$widgets(listbox) get 0 end]
03095
03096 # if we are doing an exact match, try to find,
03097 # well, an exact match
03098 set exactMatch -1
03099 if {$exact} {
03100 set exactMatch [lsearch -exact $list $pattern]
03101 }
03102
03103 # search for it. We'll try to be clever and not only
03104 # search for a match for what they typed, but a match for
03105 # something close to what they typed. We'll keep removing one
03106 # character at a time from the pattern until we find a match
03107 # of some sort.
03108 set index -1
03109 while {$index == -1 && [string length $pattern]} {
03110 set index [lsearch -glob $list "$pattern*"]
03111 if {$index == -1} {
03112 regsub {.$} $pattern {} pattern
03113 }
03114 }
03115
03116 # this is the item that most closely matches...
03117 set thisItem [lindex $list $index]
03118
03119 # did we find a match? If so, do some additional munging...
03120 if {$index != -1} {
03121
03122 # we need to find the part of the first item that is
03123 # unique WRT the second... I know there's probably a
03124 # simpler way to do this...
03125
03126 set nextIndex [expr {$index + 1}]
03127 set nextItem [lindex $list $nextIndex]
03128
03129 # we don't really need to do much if the next
03130 # item doesn't match our pattern...
03131 if {[string match $pattern* $nextItem]} {
03132 # ok, the next item matches our pattern, too
03133 # now the trick is to find the first character
03134 # where they *don't* match...
03135 set marker [string length $pattern]
03136 while {$marker <= [string length $pattern]} {
03137 set a [string index $thisItem $marker]
03138 set b [string index $nextItem $marker]
03139 if {[string compare $a $b] == 0} {
03140 append pattern $a
03141 incr marker
03142 } else {
03143 break
03144 }
03145 }
03146 } else {
03147 set marker [string length $pattern]
03148 }
03149
03150 } else {
03151 set marker end
03152 set index 0
03153 }
03154
03155 # ok, we know the pattern and what part is unique;
03156 # update the entry widget and listbox appropriately
03157 if {$exact && $exactMatch == -1} {
03158 # this means we didn't find an exact match
03159 $widgets(listbox) selection clear 0 end
03160 $widgets(listbox) see $index
03161
03162
03163 } elseif {!$exact} {
03164 # this means we found something, but it isn't an exact
03165 # match. If we find something that *is* an exact match we
03166 # don't need to do the following, since it would merely
03167 # be replacing the data in the entry widget with itself
03168 set oldstate [$widgets(entry) cget -state]
03169 $widgets(entry) configure -state normal
03170 $widgets(entry) delete 0 end
03171 $widgets(entry) insert end $thisItem
03172 $widgets(entry) selection clear
03173 $widgets(entry) selection range $marker end
03174 $widgets(listbox) activate $index
03175 $widgets(listbox) selection clear 0 end
03176 $widgets(listbox) selection anchor $index
03177 $widgets(listbox) selection set $index
03178 $widgets(listbox) see $index
03179 $widgets(entry) configure -state $oldstate
03180 }
03181 }
03182
03183 }
03184
03185 namespace ::combobox {
03186
03187 ret {::combobox::GetBoolean} (type value , optional errorValue =1) {
03188 if {[catch {expr {([string trim $value])?1:0}} res]} {
03189 return $errorValue
03190 } else {
03191 return $res
03192 }
03193 }
03194
03195 }
03196
03197 namespace ::combobox {
03198
03199 ret {::combobox::HandleEvent} (type w , type event , type args) {
03200 upvar ::combobox::${w}::widgets widgets
03201 upvar ::combobox::${w}::options options
03202 upvar ::combobox::${w}::oldValue oldValue
03203
03204 # for all of these events, if we have a special action we'll
03205 # do that and do a "return -code break" to keep additional
03206 # bindings from firing. Otherwise we'll let the event fall
03207 # on through.
03208 switch $event {
03209
03210 "<MouseWheel>" {
03211 if {[winfo ismapped $widgets(dropdown)]} {
03212 set D [lindex $args 0]
03213 # the '120' number in the following expression has
03214 # it's genesis in the tk bind manpage, which suggests
03215 # that the smallest value of %D for mousewheel events
03216 # will be 120. The intent is to scroll one line at a time.
03217 $widgets(listbox) yview scroll [expr {-($D/120)}] units
03218 }
03219 }
03220
03221 "<Any-KeyPress>" {
03222 # if the widget is editable, clear the selection.
03223 # this makes it more obvious what will happen if the
03224 # user presses <Return> (and helps our code know what
03225 # to do if the user presses return)
03226 if {$options(-editable)} {
03227 $widgets(listbox) see 0
03228 $widgets(listbox) selection clear 0 end
03229 $widgets(listbox) selection anchor 0
03230 $widgets(listbox) activate 0
03231 }
03232 }
03233
03234 "<FocusIn>" {
03235 set oldValue [$widgets(entry) get]
03236 }
03237
03238 "<FocusOut>" {
03239 if {![winfo ismapped $widgets(dropdown)]} {
03240 # did the value change?
03241 set newValue [$widgets(entry) get]
03242 if {$oldValue != $newValue} {
03243 CallCommand $widgets(this) $newValue
03244 }
03245 }
03246 }
03247
03248 "<1>" {
03249 set editable [::combobox::GetBoolean $options(-editable)]
03250 if {!$editable} {
03251 if {[winfo ismapped $widgets(dropdown)]} {
03252 $widgets(this) close
03253 return -code break;
03254
03255 } else {
03256 if {$options(-state) != "disabled"} {
03257 $widgets(this) open
03258 return -code break;
03259 }
03260 }
03261 }
03262 }
03263
03264 "<Double-1>" {
03265 if {$options(-state) != "disabled"} {
03266 $widgets(this) toggle
03267 return -code break;
03268 }
03269 }
03270
03271 "<Tab>" {
03272 if {[winfo ismapped $widgets(dropdown)]} {
03273 ::combobox::Find $widgets(this) 0
03274 return -code break;
03275 } else {
03276 ::combobox::SetValue $widgets(this) [$widgets(this) get]
03277 }
03278 }
03279
03280 "<Escape>" {
03281 # $widgets(entry) delete 0 end
03282 # $widgets(entry) insert 0 $oldValue
03283 if {[winfo ismapped $widgets(dropdown)]} {
03284 $widgets(this) close
03285 return -code break;
03286 }
03287 }
03288
03289 "<Return>" {
03290 # did the value change?
03291 set newValue [$widgets(entry) get]
03292 if {$oldValue != $newValue} {
03293 CallCommand $widgets(this) $newValue
03294 }
03295
03296 if {[winfo ismapped $widgets(dropdown)]} {
03297 ::combobox::Select $widgets(this) [$widgets(listbox) curselection]
03298 return -code break;
03299 }
03300
03301 }
03302
03303 "<Next>" {
03304 $widgets(listbox) yview scroll 1 pages
03305 set index [$widgets(listbox) index @0,0]
03306 $widgets(listbox) see $index
03307 $widgets(listbox) activate $index
03308 $widgets(listbox) selection clear 0 end
03309 $widgets(listbox) selection anchor $index
03310 $widgets(listbox) selection set $index
03311
03312 }
03313
03314 "<Prior>" {
03315 $widgets(listbox) yview scroll -1 pages
03316 set index [$widgets(listbox) index @0,0]
03317 $widgets(listbox) activate $index
03318 $widgets(listbox) see $index
03319 $widgets(listbox) selection clear 0 end
03320 $widgets(listbox) selection anchor $index
03321 $widgets(listbox) selection set $index
03322 }
03323
03324 "<Down>" {
03325 if {[winfo ismapped $widgets(dropdown)]} {
03326 ::combobox::tkListboxUpDown $widgets(listbox) 1
03327 return -code break;
03328
03329 } else {
03330 if {$options(-state) != "disabled"} {
03331 $widgets(this) open
03332 return -code break;
03333 }
03334 }
03335 }
03336 "<Up>" {
03337 if {[winfo ismapped $widgets(dropdown)]} {
03338 ::combobox::tkListboxUpDown $widgets(listbox) -1
03339 return -code break;
03340
03341 } else {
03342 if {$options(-state) != "disabled"} {
03343 $widgets(this) open
03344 return -code break;
03345 }
03346 }
03347 }
03348 }
03349
03350 return ""
03351 }
03352
03353 }
03354
03355 namespace ::combobox {
03356
03357 ret {::combobox::HandleScrollbar} (type w , optional action =unknown) {
03358 upvar ::combobox::${w}::widgets widgets
03359 upvar ::combobox::${w}::options options
03360
03361 if {$options(-height) == 0} {
03362 set hlimit $options(-maxheight)
03363 } else {
03364 set hlimit $options(-height)
03365 }
03366
03367 switch $action {
03368 "grow" {
03369 if {$hlimit > 0 && [$widgets(listbox) size] > $hlimit} {
03370 pack $widgets(vsb) -side right -fill y -expand n
03371 }
03372 }
03373
03374 "shrink" {
03375 if {$hlimit > 0 && [$widgets(listbox) size] <= $hlimit} {
03376 pack forget $widgets(vsb)
03377 }
03378 }
03379
03380 "crop" {
03381 # this means the window was cropped and we definitely
03382 # need a scrollbar no matter what the user wants
03383 pack $widgets(vsb) -side right -fill y -expand n
03384 }
03385
03386 default {
03387 if {$hlimit > 0 && [$widgets(listbox) size] > $hlimit} {
03388 pack $widgets(vsb) -side right -fill y -expand n
03389 } else {
03390 pack forget $widgets(vsb)
03391 }
03392 }
03393 }
03394
03395 return ""
03396 }
03397
03398 }
03399
03400 namespace ::combobox {
03401
03402 ret {::combobox::HumanizeList} (type list) {
03403 if {[llength $list] == 1} {
03404 return [lindex $list 0]
03405 } else {
03406 set list [lsort $list]
03407 set secondToLast [expr {[llength $list] -2}]
03408 set most [lrange $list 0 $secondToLast]
03409 set last [lindex $list end]
03410
03411 return "[join $most {, }] or $last"
03412 }
03413 }
03414
03415 }
03416
03417 namespace ::combobox {
03418
03419 ret {::combobox::Init} () {
03420 variable widgetOptions
03421 variable widgetCommands
03422 variable scanCommands
03423 variable listCommands
03424 variable defaultEntryCursor
03425
03426 array set widgetOptions [list -background {background Background} -bd -borderwidth -bg -background -borderwidth {borderWidth BorderWidth} -command {command Command} -commandstate {commandState State} -cursor {cursor Cursor} -disabledbackground {disabledBackground DisabledBackground} -disabledforeground {disabledForeground DisabledForeground} -dropdownwidth {dropdownWidth DropdownWidth} -editable {editable Editable} -fg -foreground -font {font Font} -foreground {foreground Foreground} -height {height Height} -highlightbackground {highlightBackground HighlightBackground} -highlightcolor {highlightColor HighlightColor} -highlightthickness {highlightThickness HighlightThickness} -image {image Image} -maxheight {maxHeight Height} -opencommand {opencommand Command} -relief {relief Relief} -selectbackground {selectBackground Foreground} -selectborderwidth {selectBorderWidth BorderWidth} -selectforeground {selectForeground Background} -state {state State} -takefocus {takeFocus TakeFocus} -textvariable {textVariable Variable} -value {value Value} -width {width Width} -xscrollcommand {xScrollCommand ScrollCommand} ]
03427
03428
03429 set widgetCommands [list bbox cget configure curselection delete get icursor index insert list scan selection xview select toggle open close ]
03430
03431 set listCommands [list delete get index insert size ]
03432
03433 set scanCommands [list mark dragto]
03434
03435 # why check for the Tk package? This lets us be sourced into
03436 # an interpreter that doesn't have Tk loaded, such as the slave
03437 # interpreter used by pkg_mkIndex. In theory it should have no
03438 # side effects when run
03439 if {[lsearch -exact [package names] "Tk"] != -1} {
03440
03441 ##################################################################
03442 #- this initializes the option database. Kinda gross, but it works
03443 #- (I think).
03444 ##################################################################
03445
03446 # the image used for the button...
03447 if {$::tcl_platform(platform) == "windows"} {
03448 image create bitmap ::combobox::bimage -data {
03449 #define down_arrow_width 12
03450 #define down_arrow_height 12
03451 static char down_arrow_bits[] = {
03452 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
03453 0xfc,0xf1,0xf8,0xf0,0x70,0xf0,0x20,0xf0,
03454 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00;
03455 }
03456 }
03457 } else {
03458 image create bitmap ::combobox::bimage -data {
03459 #define down_arrow_width 15
03460 #define down_arrow_height 15
03461 static char down_arrow_bits[] = {
03462 0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,
03463 0x00,0x80,0xf8,0x8f,0xf0,0x87,0xe0,0x83,
03464 0xc0,0x81,0x80,0x80,0x00,0x80,0x00,0x80,
03465 0x00,0x80,0x00,0x80,0x00,0x80
03466 }
03467 }
03468 }
03469
03470 # compute a widget name we can use to create a temporary widget
03471 set tmpWidget ".__tmp__"
03472 set count 0
03473 while {[winfo exists $tmpWidget] == 1} {
03474 set tmpWidget ".__tmp__$count"
03475 incr count
03476 }
03477
03478 # get the scrollbar width. Because we try to be clever and draw our
03479 # own button instead of using a tk widget, we need to know what size
03480 # button to create. This little hack tells us the width of a scroll
03481 # bar.
03482 #
03483 # NB: we need to be sure and pick a window that doesn't already
03484 # exist...
03485 scrollbar $tmpWidget
03486 set sb_width [winfo reqwidth $tmpWidget]
03487 destroy $tmpWidget
03488
03489 # steal options from the entry widget
03490 # we want darn near all options, so we'll go ahead and do
03491 # them all. No harm done in adding the one or two that we
03492 # don't use.
03493 entry $tmpWidget
03494 foreach foo [$tmpWidget configure] {
03495 # the cursor option is special, so we'll save it in
03496 # a special way
03497 if {[lindex $foo 0] == "-cursor"} {
03498 set defaultEntryCursor [lindex $foo 4]
03499 }
03500 if {[llength $foo] == 5} {
03501 set option [lindex $foo 1]
03502 set value [lindex $foo 4]
03503 option add *Combobox.$option $value widgetDefault
03504
03505 # these options also apply to the dropdown listbox
03506 if {[string compare $option "foreground"] == 0 || [string compare $option "background"] == 0 || [string compare $option "font"] == 0} {
03507 option add *Combobox*ComboboxListbox.$option $value widgetDefault
03508 }
03509 }
03510 }
03511 destroy $tmpWidget
03512
03513 # these are unique to us...
03514 option add *Combobox.dropdownWidth {} widgetDefault
03515 option add *Combobox.openCommand {} widgetDefault
03516 option add *Combobox.cursor {} widgetDefault
03517 option add *Combobox.commandState normal widgetDefault
03518 option add *Combobox.editable 1 widgetDefault
03519 option add *Combobox.maxHeight 10 widgetDefault
03520 option add *Combobox.height 0
03521 }
03522
03523 # set class bindings
03524 SetClassBindings
03525 }
03526
03527 }
03528
03529 namespace ::combobox {
03530
03531 ret {::combobox::Select} (type w , type index) {
03532 upvar ::combobox::${w}::widgets widgets
03533 upvar ::combobox::${w}::options options
03534
03535 # the catch is because I'm sloppy -- presumably, the only time
03536 # an error will be caught is if there is no selection.
03537 if {![catch {set data [$widgets(listbox) get [lindex $index 0]]}]} {
03538 ::combobox::SetValue $widgets(this) $data
03539
03540 $widgets(listbox) selection clear 0 end
03541 $widgets(listbox) selection anchor $index
03542 $widgets(listbox) selection set $index
03543
03544 }
03545 $widgets(entry) selection range 0 end
03546
03547 $widgets(this) close
03548
03549 return ""
03550 }
03551
03552 }
03553
03554 namespace ::combobox {
03555
03556 ret {::combobox::SetBindings} (type w) {
03557 upvar ::combobox::${w}::widgets widgets
03558 upvar ::combobox::${w}::options options
03559
03560 # juggle the bindtags. The basic idea here is to associate the
03561 # widget name with the entry widget, so if a user does a bind
03562 # on the combobox it will get handled properly since it is
03563 # the entry widget that has keyboard focus.
03564 bindtags $widgets(entry) [concat $widgets(this) [bindtags $widgets(entry)]]
03565
03566 bindtags $widgets(button) [concat $widgets(this) [bindtags $widgets(button)]]
03567
03568 # override the default bindings for tab and shift-tab. The
03569 # focus procs take a widget as their only parameter and we
03570 # want to make sure the right window gets used (for shift-
03571 # tab we want it to appear as if the event was generated
03572 # on the frame rather than the entry.
03573 bind $widgets(entry) <Tab> "::combobox::tkTabToWindow \[tk_focusNext $widgets(entry)\]; break"
03574 bind $widgets(entry) <Shift-Tab> "::combobox::tkTabToWindow \[tk_focusPrev $widgets(this)\]; break"
03575
03576 # this makes our "button" (which is actually a label)
03577 # do the right thing
03578 bind $widgets(button) <ButtonPress-1> [list $widgets(this) toggle]
03579
03580 # this lets the autoscan of the listbox work, even if they
03581 # move the cursor over the entry widget.
03582 bind $widgets(entry) <B1-Enter> "break"
03583
03584 bind $widgets(listbox) <ButtonRelease-1> "::combobox::Select [list $widgets(this)] \[$widgets(listbox) nearest %y\]; break"
03585
03586 bind $widgets(vsb) <ButtonPress-1> {continue}
03587 bind $widgets(vsb) <ButtonRelease-1> {continue}
03588
03589 bind $widgets(listbox) <Any-Motion> {
03590 %W selection clear 0 end
03591 %W activate @%x,%y
03592 %W selection anchor @%x,%y
03593 %W selection set @%x,%y @%x,%y
03594 # need to do a yview if the cursor goes off the top
03595 # or bottom of the window... (or do we?)
03596 }
03597
03598 # these events need to be passed from the entry widget
03599 # to the listbox, or otherwise need some sort of special
03600 # handling.
03601 foreach event [list <Up> <Down> <Tab> <Return> <Escape> <Next> <Prior> <Double-1> <1> <Any-KeyPress> <FocusIn> <FocusOut>] {
03602 bind $widgets(entry) $event [list ::combobox::HandleEvent $widgets(this) $event]
03603 }
03604
03605 # like the other events, <MouseWheel> needs to be passed from
03606 # the entry widget to the listbox. However, in this case we
03607 # need to add an additional parameter
03608 catch {
03609 bind $widgets(entry) <MouseWheel> [list ::combobox::HandleEvent $widgets(this) <MouseWheel> %D]
03610 }
03611 }
03612
03613 }
03614
03615 namespace ::combobox {
03616
03617 ret {::combobox::SetClassBindings} () {
03618 # make sure we clean up after ourselves...
03619 bind Combobox <Destroy> [list ::combobox::DestroyHandler %W]
03620
03621 # this will (hopefully) close (and lose the grab on) the
03622 # listbox if the user clicks anywhere outside of it. Note
03623 # that on Windows, you can click on some other app and
03624 # the listbox will still be there, because tcl won't see
03625 # that button click
03626 set this {[::combobox::convert %W -W]}
03627 bind Combobox <Any-ButtonPress> "$this close"
03628 bind Combobox <Any-ButtonRelease> "$this close"
03629
03630 # this helps (but doesn't fully solve) focus issues. The general
03631 # idea is, whenever the frame gets focus it gets passed on to
03632 # the entry widget
03633 bind Combobox <FocusIn> {::combobox::tkTabToWindow [::combobox::convert %W -W].entry}
03634
03635 # this closes the listbox if we get hidden
03636 bind Combobox <Unmap> {[::combobox::convert %W -W] close}
03637
03638 return ""
03639 }
03640
03641 }
03642
03643 namespace ::combobox {
03644
03645 ret {::combobox::SetValue} (type w , type newValue) {
03646 upvar ::combobox::${w}::widgets widgets
03647 upvar ::combobox::${w}::options options
03648 upvar ::combobox::${w}::ignoreTrace ignoreTrace
03649 upvar ::combobox::${w}::oldValue oldValue
03650
03651 if {[info exists options(-textvariable)] && [string length $options(-textvariable)] > 0} {
03652 set variable ::$options(-textvariable)
03653 set $variable $newValue
03654 } else {
03655 set oldstate [$widgets(entry) cget -state]
03656 $widgets(entry) configure -state normal
03657 $widgets(entry) delete 0 end
03658 $widgets(entry) insert 0 $newValue
03659 $widgets(entry) configure -state $oldstate
03660 }
03661
03662 # set our internal textvariable; this will cause any public
03663 # textvariable (ie: defined by the user) to be updated as
03664 # well
03665 # set ::combobox::${w}::entryTextVariable $newValue
03666
03667 # redefine our concept of the "old value". Do it before running
03668 # any associated command so we can be sure it happens even
03669 # if the command somehow fails.
03670 set oldValue $newValue
03671
03672
03673 # call the associated command. The proc will handle whether or
03674 # not to actually call it, and with what args
03675 CallCommand $w $newValue
03676
03677 return ""
03678 }
03679
03680 }
03681
03682 namespace ::combobox {
03683
03684 ret {::combobox::UpdateVisualAttributes} (type w) {
03685 upvar ::combobox::${w}::widgets widgets
03686 upvar ::combobox::${w}::options options
03687
03688 if {$options(-state) == "normal"} {
03689
03690 set foreground $options(-foreground)
03691 set background $options(-background)
03692
03693 } elseif {$options(-state) == "disabled"} {
03694
03695 set foreground $options(-disabledforeground)
03696 set background $options(-disabledbackground)
03697 }
03698
03699 $widgets(entry) configure -foreground $foreground -background $background
03700 $widgets(listbox) configure -foreground $foreground -background $background
03701 $widgets(button) configure -foreground $foreground
03702 $widgets(vsb) configure -background $background -troughcolor $background
03703 $widgets(frame) configure -background $background
03704
03705 # we need to set the disabled colors in case our widget is disabled.
03706 # We could actually check for disabled-ness, but we also need to
03707 # check whether we're enabled but not editable, in which case the
03708 # entry widget is disabled but we still want the enabled colors. It's
03709 # easier just to set everything and be done with it.
03710
03711 if {$::tcl_version >= 8.4} {
03712 $widgets(entry) configure -disabledforeground $foreground -disabledbackground $background
03713 $widgets(button) configure -disabledforeground $foreground
03714 $widgets(listbox) configure -disabledforeground $foreground
03715 }
03716 }
03717
03718 }
03719
03720 namespace ::combobox {
03721
03722 ret {::combobox::WidgetProc} (type w , type command , type args) {
03723 upvar ::combobox::${w}::widgets widgets
03724 upvar ::combobox::${w}::options options
03725 upvar ::combobox::${w}::oldFocus oldFocus
03726 upvar ::combobox::${w}::oldFocus oldGrab
03727
03728 set command [::combobox::Canonize $w command $command]
03729
03730 # this is just shorthand notation...
03731 set doWidgetCommand [list ::combobox::DoInternalWidgetCommand $widgets(this)]
03732
03733 if {$command == "list"} {
03734 # ok, the next argument is a list command; we'll
03735 # rip it from args and append it to command to
03736 # create a unique internal command
03737 #
03738 # NB: because of the sloppy way we are doing this,
03739 # we'll also let the user enter our secret command
03740 # directly (eg: listinsert, listdelete), but we
03741 # won't document that fact
03742 set command "list-[lindex $args 0]"
03743 set args [lrange $args 1 end]
03744 }
03745
03746 set result ""
03747
03748 # many of these commands are just synonyms for specific
03749 # commands in one of the subwidgets. We'll get them out
03750 # of the way first, then do the custom commands.
03751 switch $command {
03752 bbox -
03753 delete -
03754 get -
03755 icursor -
03756 index -
03757 insert -
03758 scan -
03759 selection -
03760 xview {
03761 set result [eval $doWidgetCommand entry $command $args]
03762 }
03763 list-get {set result [eval $doWidgetCommand listbox get $args]}
03764 list-index {set result [eval $doWidgetCommand listbox index $args]}
03765 list-size {set result [eval $doWidgetCommand listbox size $args]}
03766
03767 select {
03768 if {[llength $args] == 1} {
03769 set index [lindex $args 0]
03770 set result [Select $widgets(this) $index]
03771 } else {
03772 error "usage: $w select index"
03773 }
03774 }
03775
03776 subwidget {
03777 set knownWidgets [list button entry listbox dropdown vsb]
03778 if {[llength $args] == 0} {
03779 return $knownWidgets
03780 }
03781
03782 set name [lindex $args 0]
03783 if {[lsearch $knownWidgets $name] != -1} {
03784 set result $widgets($name)
03785 } else {
03786 error "unknown subwidget $name"
03787 }
03788 }
03789
03790 curselection {
03791 set result [eval $doWidgetCommand listbox curselection]
03792 }
03793
03794 list-insert {
03795 eval $doWidgetCommand listbox insert $args
03796 set result [HandleScrollbar $w "grow"]
03797 }
03798
03799 list-delete {
03800 eval $doWidgetCommand listbox delete $args
03801 set result [HandleScrollbar $w "shrink"]
03802 }
03803
03804 toggle {
03805 # ignore this command if the widget is disabled...
03806 if {$options(-state) == "disabled"} return
03807
03808 # pops down the list if it is not, hides it
03809 # if it is...
03810 if {[winfo ismapped $widgets(dropdown)]} {
03811 set result [$widgets(this) close]
03812 } else {
03813 set result [$widgets(this) open]
03814 }
03815 }
03816
03817 open {
03818
03819 # if this is an editable combobox, the focus should
03820 # be set to the entry widget
03821 if {$options(-editable)} {
03822 focus $widgets(entry)
03823 $widgets(entry) select range 0 end
03824 $widgets(entry) icur end
03825 }
03826
03827 # if we are disabled, we won't allow this to happen
03828 if {$options(-state) == "disabled"} {
03829 return 0
03830 }
03831
03832 # if there is a -opencommand, execute it now
03833 if {[string length $options(-opencommand)] > 0} {
03834 # hmmm... should I do a catch, or just let the normal
03835 # error handling handle any errors? For now, the latter...
03836 uplevel \#0 $options(-opencommand)
03837 }
03838
03839 # compute the geometry of the window to pop up, and set
03840 # it, and force the window manager to take notice
03841 # (even if it is not presently visible).
03842 #
03843 # this isn't strictly necessary if the window is already
03844 # mapped, but we'll go ahead and set the geometry here
03845 # since its harmless and *may* actually reset the geometry
03846 # to something better in some weird case.
03847 set geometry [::combobox::ComputeGeometry $widgets(this)]
03848 wm geometry $widgets(dropdown) $geometry
03849 update idletasks
03850
03851 # if we are already open, there's nothing else to do
03852 if {[winfo ismapped $widgets(dropdown)]} {
03853 return 0
03854 }
03855
03856 # save the widget that currently has the focus; we'll restore
03857 # the focus there when we're done
03858 set oldFocus [focus]
03859
03860 # ok, tweak the visual appearance of things and
03861 # make the list pop up
03862 $widgets(button) configure -relief sunken
03863 raise $widgets(dropdown) [winfo parent $widgets(this)]
03864 wm deiconify $widgets(dropdown)
03865 raise $widgets(dropdown)
03866
03867 # force focus to the entry widget so we can handle keypress
03868 # events for traversal
03869 focus -force $widgets(entry)
03870
03871 # select something by default, but only if its an
03872 # exact match...
03873 ::combobox::Find $widgets(this) 1
03874
03875 # save the current grab state for the display containing
03876 # this widget. We'll restore it when we close the dropdown
03877 # list
03878 set status "none"
03879 set grab [grab current $widgets(this)]
03880 if {$grab != ""} {set status [grab status $grab]}
03881 set oldGrab [list $grab $status]
03882 unset grab status
03883
03884 # *gasp* do a global grab!!! Mom always told me not to
03885 # do things like this, but sometimes a man's gotta do
03886 # what a man's gotta do.
03887 grab -global $widgets(this)
03888
03889 # fake the listbox into thinking it has focus. This is
03890 # necessary to get scanning initialized properly in the
03891 # listbox.
03892 event generate $widgets(listbox) <B1-Enter>
03893
03894 return 1
03895 }
03896
03897 close {
03898 # if we are already closed, don't do anything...
03899 if {![winfo ismapped $widgets(dropdown)]} {
03900 return 0
03901 }
03902
03903 # restore the focus and grab, but ignore any errors...
03904 # we're going to be paranoid and release the grab before
03905 # trying to set any other grab because we really really
03906 # really want to make sure the grab is released.
03907 catch {focus $oldFocus} result
03908 catch {grab release $widgets(this)}
03909 catch {
03910 set status [lindex $oldGrab 1]
03911 if {$status == "global"} {
03912 grab -global [lindex $oldGrab 0]
03913 } elseif {$status == "local"} {
03914 grab [lindex $oldGrab 0]
03915 }
03916 unset status
03917 }
03918
03919 # hides the listbox
03920 $widgets(button) configure -relief raised
03921 wm withdraw $widgets(dropdown)
03922
03923 # select the data in the entry widget. Not sure
03924 # why, other than observation seems to suggest that's
03925 # what windows widgets do.
03926 set editable [::combobox::GetBoolean $options(-editable)]
03927 if {$editable} {
03928 $widgets(entry) selection range 0 end
03929 $widgets(button) configure -relief raised
03930 }
03931
03932
03933 # magic tcl stuff (see tk.tcl in the distribution
03934 # lib directory)
03935 ::combobox::tkCancelRepeat
03936
03937 return 1
03938 }
03939
03940 cget {
03941 if {[llength $args] != 1} {
03942 error "wrong # args: should be $w cget option"
03943 }
03944 set opt [::combobox::Canonize $w option [lindex $args 0]]
03945
03946 if {$opt == "-value"} {
03947 set result [$widgets(entry) get]
03948 } else {
03949 set result $options($opt)
03950 }
03951 }
03952
03953 configure {
03954 set result [eval ::combobox::Configure {$w} $args]
03955 }
03956
03957 default {
03958 error "bad option \"$command\""
03959 }
03960 }
03961
03962 return $result
03963 }
03964
03965 }
03966
03967 namespace ::combobox {
03968
03969 ret {::combobox::combobox} (type w , type args) {
03970 variable widgetOptions
03971 variable widgetCommands
03972 variable scanCommands
03973 variable listCommands
03974
03975 # perform a one time initialization
03976 if {![info exists widgetOptions]} {
03977 Init
03978 }
03979
03980 # build it...
03981 eval Build $w $args
03982
03983 # set some bindings...
03984 SetBindings $w
03985
03986 # and we are done!
03987 return $w
03988 }
03989
03990 }
03991
03992 namespace ::combobox {
03993
03994 ret {::combobox::convert} (type w , type args) {
03995 set result {}
03996 if {![winfo exists $w]} {
03997 error "window \"$w\" doesn't exist"
03998 }
03999
04000 while {[llength $args] > 0} {
04001 set option [lindex $args 0]
04002 set args [lrange $args 1 end]
04003
04004 switch -exact -- $option {
04005 -x {
04006 set value [lindex $args 0]
04007 set args [lrange $args 1 end]
04008 set win $w
04009 while {[winfo class $win] != "Combobox"} {
04010 incr value [winfo x $win]
04011 set win [winfo parent $win]
04012 if {$win == "."} break
04013 }
04014 lappend result $value
04015 }
04016
04017 -y {
04018 set value [lindex $args 0]
04019 set args [lrange $args 1 end]
04020 set win $w
04021 while {[winfo class $win] != "Combobox"} {
04022 incr value [winfo y $win]
04023 set win [winfo parent $win]
04024 if {$win == "."} break
04025 }
04026 lappend result $value
04027 }
04028
04029 -w -
04030 -W {
04031 set win $w
04032 while {[winfo class $win] != "Combobox"} {
04033 set win [winfo parent $win]
04034 if {$win == "."} break;
04035 }
04036 lappend result $win
04037 }
04038 }
04039 }
04040 return $result
04041 }
04042
04043 }
04044
04045 namespace ::dom::libxml2 {
04046
04047 ret {::dom::libxml2::parse} (type xml , type args) {
04048 array set options {
04049 -keep normal
04050 -retainpath
04051
04052
04053
04054
04055
04056
04057
04058
04059
04060
04061
04062
04063
04064
04065
04066
04067
04068
04069
04070
04071
04072
04073
04074
04075
04076
04077
04078
04079
04080
04081
04082
04083
04084
04085
04086
04087
04088
04089
04090
04091
04092
04093
04094
04095
04096
04097
04098
04099
04100
04101
04102
04103
04104
04105
04106
04107
04108
04109
04110
04111
04112
04113
04114
04115
04116
04117
04118
04119
04120
04121
04122
04123
04124
04125
04126
04127
04128
04129
04130
04131
04132
04133
04134
04135
04136
04137
04138
04139
04140
04141
04142
04143
04144
04145
04146
04147
04148
04149
04150
04151
04152
04153
04154
04155
04156
04157
04158
04159
04160
04161
04162
04163
04164
04165
04166
04167
04168
04169
04170
04171
04172
04173
04174
04175
04176
04177
04178
04179
04180
04181
04182
04183
04184
04185
04186
04187
04188
04189
04190
04191
04192
04193
04194
04195
04196
04197
04198
04199
04200
04201
04202
04203
04204
04205
04206
04207
04208
04209
04210
04211
04212
04213
04214
04215
04216
04217
04218
04219
04220
04221
04222
04223
04224
04225
04226
04227
04228
04229
04230
04231
04232
04233
04234
04235
04236
04237
04238
04239
04240
04241
04242
04243
04244
04245
04246
04247
04248
04249
04250
04251
04252
04253
04254
04255
04256
04257
04258
04259
04260
04261
04262
04263
04264
04265
04266
04267
04268
04269
04270
04271
04272
04273
04274
04275
04276
04277
04278
04279
04280
04281
04282
04283
04284
04285
04286
04287
04288
04289
04290
04291
04292
04293
04294
04295
04296
04297
04298
04299
04300
04301
04302
04303
04304
04305
04306
04307
04308
04309
04310
04311
04312
04313
04314
04315
04316
04317
04318
04319
04320
04321
04322
04323
04324
04325
04326
04327
04328
04329
04330
04331
04332
04333
04334
04335
04336
04337
04338
04339
04340
04341
04342
04343
04344
04345
04346
04347
04348
04349
04350
04351
04352
04353
04354
04355
04356
04357
04358
04359
04360
04361
04362
04363
04364
04365
04366
04367
04368
04369
04370
04371
04372
04373
04374
04375
04376
04377
04378
04379
04380
04381
04382
04383
04384
04385
04386
04387
04388
04389
04390
04391
04392
04393
04394
04395
04396
04397
04398
04399
04400
04401
04402
04403
04404
04405
04406
04407
04408
04409
04410
04411
04412
04413
04414
04415
04416
04417
04418
04419
04420
04421
04422
04423
04424
04425
04426
04427
04428
04429
04430
04431
04432
04433
04434
04435
04436
04437
04438
04439
04440
04441
04442
04443
04444
04445
04446
04447
04448
04449
04450
04451
04452
04453
04454
04455
04456
04457
04458
04459
04460
04461
04462
04463
04464
04465
04466
04467
04468
04469
04470
04471
04472
04473
04474
04475
04476
04477
04478
04479
04480
04481
04482
04483
04484
04485
04486
04487
04488
04489
04490
04491
04492
04493
04494
04495
04496
04497
04498
04499
04500
04501
04502
04503
04504
04505
04506
04507
04508
04509
04510
04511
04512
04513
04514
04515
04516
04517
04518
04519
04520
04521
04522
04523
04524
04525
04526
04527
04528
04529
04530
04531
04532
04533
04534
04535
04536
04537
04538
04539
04540
04541
04542
04543
04544
04545
04546
04547
04548
04549
04550
04551
04552
04553
04554
04555
04556
04557
04558
04559
04560
04561
04562
04563
04564
04565
04566
04567
04568
04569
04570
04571
04572
04573
04574
04575
04576
04577
04578
04579
04580
04581
04582
04583
04584
04585
04586
04587
04588
04589
04590
04591
04592
04593
04594
04595
04596
04597
04598
04599
04600
04601
04602
04603
04604
04605
04606
04607
04608
04609
04610
04611
04612
04613
04614
04615
04616
04617
04618
04619
04620
04621
04622
04623
04624
04625
04626
04627
04628
04629
04630
04631
04632
04633
04634
04635
04636
04637
04638
04639
04640
04641
04642
04643
04644
04645
04646
04647
04648
04649
04650
04651
04652
04653
04654
04655
04656
04657
04658
04659
04660
04661
04662
04663
04664
04665
04666
04667
04668
04669
04670
04671
04672
04673
04674
04675
04676
04677
04678
04679
04680
04681
04682
04683
04684
04685
04686
04687
04688
04689
04690
04691
04692
04693
04694
04695
04696
04697
04698
04699
04700
04701
04702
04703
04704
04705
04706
04707
04708
04709
04710
04711
04712
04713
04714
04715
04716
04717
04718
04719
04720
04721
04722
04723
04724
04725
04726
04727
04728
04729
04730
04731
04732
04733
04734
04735
04736
04737
04738
04739
04740
04741
04742
04743
04744
04745
04746
04747
04748
04749
04750
04751
04752
04753
04754
04755
04756
04757
04758
04759
04760
04761
04762
04763
04764
04765
04766
04767
04768
04769
04770
04771
04772
04773
04774
04775
04776
04777
04778
04779
04780
04781
04782
04783
04784
04785
04786
04787
04788
04789
04790
04791
04792
04793
04794
04795
04796
04797
04798
04799
04800
04801
04802
04803
04804
04805
04806
04807
04808
04809
04810
04811
04812
04813
04814
04815
04816
04817
04818
04819
04820
04821
04822
04823
04824
04825
04826
04827
04828
04829
04830
04831
04832
04833
04834
04835
04836
04837
04838
04839
04840
04841
04842
04843
04844
04845
04846
04847
04848
04849
04850
04851
04852
04853
04854
04855
04856
04857
04858
04859
04860
04861
04862
04863
04864
04865
04866
04867
04868
04869
04870
04871
04872
04873
04874
04875
04876
04877
04878
04879
04880
04881
04882
04883
04884
04885
04886
04887
04888
04889
04890
04891
04892
04893
04894
04895
04896
04897
04898
04899
04900
04901
04902
04903
04904
04905
04906
04907
04908
04909
04910
04911
04912
04913
04914
04915
04916
04917
04918
04919
04920
04921
04922
04923
04924
04925
04926
04927
04928
04929
04930
04931
04932
04933
04934
04935
04936
04937
04938
04939
04940
04941
04942
04943
04944
04945
04946
04947
04948
04949
04950
04951
04952
04953
04954
04955
04956
04957
04958
04959
04960
04961
04962
04963
04964
04965
04966
04967
04968
04969
04970
04971
04972
04973
04974
04975
04976
04977
04978
04979
04980
04981
04982
04983
04984
04985
04986
04987
04988
04989
04990
04991
04992
04993
04994
04995
04996
04997
04998
04999
05000
05001
05002
05003
05004
05005
05006
05007
05008
05009
05010
05011
05012
05013
05014
05015
05016
05017
05018
05019
05020
05021
05022
05023
05024
05025
05026
05027
05028
05029
05030
05031
05032
05033
05034
05035
05036
05037
05038
05039
05040
05041
05042
05043
05044
05045
05046
05047
05048
05049
05050
05051
05052
05053
05054
05055
05056
05057
05058
05059
05060
05061
05062
05063
05064
05065
05066
05067
05068
05069
05070
05071
05072
05073
05074
05075
05076
05077
05078
05079
05080
05081
05082
05083
05084
05085
05086
05087
05088
05089
05090
05091
05092
05093
05094
05095
05096
05097
05098
05099
05100
05101
05102
05103
05104
05105
05106
05107
05108
05109
05110
05111
05112
05113
05114
05115
05116
05117
05118
05119
05120
05121
05122
05123
05124
05125
05126
05127
05128
05129
05130
05131
05132
05133
05134
05135
05136
05137
05138
05139
05140
05141
05142
05143
05144
05145
05146
05147
05148
05149
05150
05151
05152
05153
05154
05155
05156
05157
05158
05159
05160
05161
05162
05163
05164
05165
05166
05167
05168
05169
05170
05171
05172
05173
05174
05175
05176
05177
05178
05179
05180
05181
05182
05183
05184
05185
05186
05187
05188
05189
05190
05191
05192
05193
05194
05195
05196
05197
05198
05199
05200
05201
05202
05203
05204
05205
05206
05207
05208
05209
05210
05211
05212
05213
05214
05215
05216
05217
05218
05219
05220
05221
05222
05223
05224
05225
05226
05227
05228
05229
05230
05231
05232
05233
05234
05235
05236
05237
05238
05239
05240
05241
05242
05243
05244
05245
05246
05247
05248
05249
05250
05251
05252
05253
05254
05255
05256
05257
05258
05259
05260
05261
05262
05263
05264
05265
05266
05267
05268
05269
05270
05271
05272
05273
05274
05275
05276
05277
05278
05279
05280
05281
05282
05283
05284
05285
05286
05287
05288
05289
05290
05291
05292
05293
05294
05295
05296
05297
05298
05299
05300
05301
05302
05303
05304
05305
05306
05307
05308
05309
05310
05311
05312
05313
05314
05315
05316
05317
05318
05319
05320
05321
05322
05323
05324
05325
05326
05327
05328
05329
05330
05331
05332
05333
05334
05335
05336
05337
05338
05339
05340
05341
05342
05343
05344
05345
05346
05347
05348
05349
05350
05351
05352
05353
05354
05355
05356
05357
05358
05359
05360
05361
05362
05363
05364
05365
05366
05367
05368
05369
05370
05371
05372
05373
05374
05375
05376
05377
05378
05379
05380
05381
05382
05383
05384
05385
05386
05387
05388
05389
05390
05391
05392
05393
05394
05395
05396
05397
05398
05399
05400
05401
05402
05403
05404
05405
05406
05407
05408
05409
05410
05411
05412
05413
05414
05415
05416
05417
05418
05419
05420
05421
05422
05423 [string trimright $remattlist]]} {
05424 set remattlist [string range $remattlist 0 end-1]
05425 set handleEmpty 1
05426 set cfg(-empty) 1
05427 }
05428
05429 append attvalue >$remattvalue
05430 lappend attlist $attname $attvalue
05431
05432 # Complete parsing the attribute list
05433 if {[catch {uplevel #0 $options(-parseattributelistcommand) [list $options(-statevariable) $remattlist]} attr]} {
05434 uplevel #0 $options(-errorcommand) [list unterminatedattribute "$attr around line $state(line)"]
05435 set attr {}
05436 set attlist {}
05437 } else {
05438 eval lappend attlist $attr
05439 }
05440
05441 set attr $attlist
05442
05443 } else {
05444 uplevel #0 $options(-errorcommand) [list unterminatedattribute "$attr around line $state(line)"]
05445 set attr {}
05446 }
05447 }
05448 }
05449 }
05450
05451 set empty {}
05452 if {$cfg(-empty) && $options(-reportempty)} {
05453 set empty {-empty 1}
05454 }
05455
05456 # Check for namespace declarations
05457 upvar #0 $options(namespaces) namespaces
05458 set nsdecls {}
05459 if {[llength $attr]} {
05460 array set attrlist $attr
05461 foreach {attrName attrValue} [array get attrlist xmlns*] {
05462 unset attrlist($attrName)
05463 set colon [set prefix {}]
05464 if {[regexp {^xmlns(:(.+))?$} $attrName discard colon prefix]} {
05465 switch -glob [string length $colon],[string length $prefix] {
05466 0,0 {
05467 # default NS declaration
05468 lappend state(defaultNSURI) $attrValue
05469 lappend state(defaultNS) [llength $state(stack)]
05470 lappend nsdecls $attrValue {}
05471 }
05472 0,* {
05473 # Huh?
05474 }
05475 *,0 {
05476 # Error
05477 uplevel #0 $state(-warningcommand) "no prefix specified for namespace URI \"$attrValue\" in element \"$tag\""
05478 }
05479 default {
05480 set namespaces($prefix,[llength $state(stack)]) $attrValue
05481 lappend nsdecls $attrValue $prefix
05482 }
05483 }
05484 }
05485 }
05486 if {[llength $nsdecls]} {
05487 set nsdecls [list -namespacedecls $nsdecls]
05488 }
05489 set attr [array get attrlist]
05490 }
05491
05492 # Check whether this element has an expanded name
05493 set ns {}
05494 if {[regexp {([^:]+):(.*)$} $tag discard prefix tag]} {
05495 set nsspec [lsort -dictionary -decreasing [array names namespaces $prefix,*]]
05496 if {[llength $nsspec]} {
05497 set nsuri $namespaces([lindex $nsspec 0])
05498 set ns [list -namespace $nsuri]
05499 } else {
05500 uplevel #0 $options(-errorcommand) [list namespaceundeclared "no namespace declared for prefix \"$prefix\" in element $tag"]
05501 }
05502 } elseif {[llength $state(defaultNSURI)]} {
05503 set ns [list -namespace [lindex $state(defaultNSURI) end]]
05504 }
05505
05506 # Invoke callback
05507 set code [catch {uplevel #0 $options(-elementstartcommand) [list $tag $attr] $empty $ns $nsdecls} msg]
05508
05509 # Sometimes empty elements must be handled here (see above)
05510 if {$code == 0 && $handleEmpty} {
05511 ParseEvent:ElementClose $tag $opts -empty 1
05512 }
05513
05514 return -code $code -errorinfo $::errorInfo $msg
05515 }
05516
05517 }
05518
05519 namespace ::sgml {
05520
05521 ret {::sgml::ParserDelete} (type var) {
05522 upvar #0 $var state
05523
05524 if {![info exists state]} {
05525 return -code error "unknown parser"
05526 }
05527
05528 catch {unset $state(entities)}
05529 catch {unset $state(parameterentities)}
05530 catch {unset $state(elementdecls)}
05531 catch {unset $state(attlistdecls)}
05532 catch {unset $state(notationdecls)}
05533 catch {unset $state(namespaces)}
05534
05535 unset state
05536
05537 return {}
05538 }
05539
05540 }
05541
05542 namespace ::sgml {
05543
05544 ret {::sgml::ResolveEntity} (type cmd , type base , type sysId , type pubId) {
05545 variable ParseEventNum
05546
05547 if {[catch {uri::resolve $base $sysId} url]} {
05548 return -code error "unable to resolve system identifier \"$sysId\""
05549 }
05550 if {[catch {uri::geturl $url} token]} {
05551 return -code error "unable to retrieve external entity \"$url\" for system identifier \"$sysId\""
05552 }
05553
05554 upvar #0 $token data
05555
05556 set parser [uplevel #0 $cmd entityparser]
05557
05558 set body {}
05559 catch {set body $data(body)}
05560 catch {set body $data(data)}
05561 if {[string length $body]} {
05562 uplevel #0 $parser parse [list $body] -dtdsubset external
05563 }
05564 $parser free
05565
05566 return {}
05567 }
05568
05569 }
05570
05571 namespace ::sgml {
05572
05573 ret {::sgml::TraverseDepth1st} (type state , type t , type leaf , type nonTerm) {
05574 upvar #0 $state var
05575
05576 set nullable {}
05577 set firstpos {}
05578 set lastpos {}
05579
05580 switch -- [lindex [lindex $t 1] 0] {
05581 :seq -
05582 :choice {
05583 set rep [lindex $t 0]
05584 set cs [lindex [lindex $t 1] 0]
05585
05586 foreach child [lrange [lindex $t 1] 1 end] {
05587 foreach {childNullable childFirstpos childLastpos} [TraverseDepth1st $state $child $leaf $nonTerm] break
05588 lappend nullable $childNullable
05589 lappend firstpos $childFirstpos
05590 lappend lastpos $childLastpos
05591 }
05592
05593 eval $nonTerm
05594 }
05595 default {
05596 incr var(number)
05597 set rep [lindex [lindex $t 0] 0]
05598 set name [lindex [lindex $t 1] 0]
05599 eval $leaf
05600 }
05601 }
05602
05603 return [list $nullable $firstpos $lastpos]
05604 }
05605
05606 }
05607
05608 namespace ::sgml {
05609
05610 ret {::sgml::cl} (type x) {
05611 return "\[$x\]"
05612 }
05613
05614 }
05615
05616 namespace ::sgml {
05617
05618 ret {::sgml::firstpos} (type cs , type firstpos , type nullable) {
05619 switch -- $cs {
05620 :seq {
05621 set result [lindex [lindex $firstpos 0] 1]
05622 for {set i 0} {$i < [llength $nullable]} {incr i} {
05623 if {[lindex [lindex $nullable $i] 1]} {
05624 eval lappend result [lindex [lindex $firstpos [expr $i + 1]] 1]
05625 } else {
05626 break
05627 }
05628 }
05629 }
05630 :choice {
05631 foreach child $firstpos {
05632 eval lappend result $child
05633 }
05634 }
05635 }
05636
05637 return [list $firstpos [makeSet $result]]
05638 }
05639
05640 }
05641
05642 namespace ::sgml {
05643
05644 ret {::sgml::followpos} (type state , type st , type firstpos , type lastpos) {
05645 upvar #0 $state var
05646
05647 switch -- [lindex [lindex $st 1] 0] {
05648 :seq {
05649 for {set i 1} {$i < [llength [lindex $st 1]]} {incr i} {
05650 followpos $state [lindex [lindex $st 1] $i] [lindex [lindex $firstpos 0] [expr $i - 1]] [lindex [lindex $lastpos 0] [expr $i - 1]]
05651 foreach pos [lindex [lindex [lindex $lastpos 0] [expr $i - 1]] 1] {
05652 eval lappend var($pos) [lindex [lindex [lindex $firstpos 0] $i] 1]
05653 set var($pos) [makeSet $var($pos)]
05654 }
05655 }
05656 }
05657 :choice {
05658 for {set i 1} {$i < [llength [lindex $st 1]]} {incr i} {
05659 followpos $state [lindex [lindex $st 1] $i] [lindex [lindex $firstpos 0] [expr $i - 1]] [lindex [lindex $lastpos 0] [expr $i - 1]]
05660 }
05661 }
05662 default {
05663 # No action at leaf nodes
05664 }
05665 }
05666
05667 switch -- [lindex $st 0] {
05668 ? {
05669 # We having nothing to do here ! Doing the same as
05670 # for * effectively converts this qualifier into the other.
05671 }
05672 * {
05673 foreach pos [lindex $lastpos 1] {
05674 eval lappend var($pos) [lindex $firstpos 1]
05675 set var($pos) [makeSet $var($pos)]
05676 }
05677 }
05678 }
05679 }
05680
05681 }
05682
05683 namespace ::sgml {
05684
05685 ret {::sgml::identity} (type a) {
05686 return $a
05687 }
05688
05689 }
05690
05691 namespace ::sgml {
05692
05693 ret {::sgml::lastpos} (type cs , type lastpos , type nullable) {
05694 switch -- $cs {
05695 :seq {
05696 set result [lindex [lindex $lastpos end] 1]
05697 for {set i [expr [llength $nullable] - 1]} {$i >= 0} {incr i -1} {
05698 if {[lindex [lindex $nullable $i] 1]} {
05699 eval lappend result [lindex [lindex $lastpos $i] 1]
05700 } else {
05701 break
05702 }
05703 }
05704 }
05705 :choice {
05706 foreach child $lastpos {
05707 eval lappend result $child
05708 }
05709 }
05710 }
05711
05712 return [list $lastpos [makeSet $result]]
05713 }
05714
05715 }
05716
05717 namespace ::sgml {
05718
05719 ret {::sgml::makeSet} (type s) {
05720 foreach r $s {
05721 if {[llength $r]} {
05722 set unique($r) {}
05723 }
05724 }
05725 return [array names unique]
05726 }
05727
05728 }
05729
05730 namespace ::sgml {
05731
05732 ret {::sgml::noop} (type args) {
05733 return 0
05734 }
05735
05736 }
05737
05738 namespace ::sgml {
05739
05740 ret {::sgml::nullable} (type nodeType , type rep , type name , optional subtree ={)} {
05741 switch -glob -- $rep:$nodeType {
05742 :leaf -
05743 +:leaf {
05744 return [list {} 0]
05745 }
05746 \\*:leaf -
05747 \\?:leaf {
05748 return [list {} 1]
05749 }
05750 \\*:nonterm -
05751 \\?:nonterm {
05752 return [list $subtree 1]
05753 }
05754 :nonterm -
05755 +:nonterm {
05756 switch -- $name {
05757 :choice {
05758 set result 0
05759 foreach child $subtree {
05760 set result [expr $result || [lindex $child 1]]
05761 }
05762 }
05763 :seq {
05764 set result 1
05765 foreach child $subtree {
05766 set result [expr $result && [lindex $child 1]]
05767 }
05768 }
05769 }
05770 return [list $subtree $result]
05771 }
05772 }
05773 }
05774
05775 }
05776
05777 namespace ::sgml {
05778
05779 ret {::sgml::parseEvent} (type sgml , type args) {
05780 variable Wsp
05781 variable noWsp
05782 variable Nmtoken
05783 variable Name
05784 variable ParseEventNum
05785 variable StdOptions
05786
05787 array set options [array get StdOptions]
05788 catch {array set options $args}
05789
05790 # Mats:
05791 # If the data is not final then there must be a variable to persistently store the parse state.
05792 if {!$options(-final) && ![info exists options(-statevariable)]} {
05793 return -code error {option "-statevariable" required if not final}
05794 }
05795
05796 foreach {opt value} [array get options *command] {
05797 if {[string compare $opt "-externalentitycommand"] && ![string length $value]} {
05798 set options($opt) [namespace current]::noop
05799 }
05800 }
05801
05802 if {![info exists options(-statevariable)]} {
05803 set options(-statevariable) [namespace current]::ParseEvent[incr ParseEventNum]
05804 }
05805 if {![info exists options(entities)]} {
05806 set options(entities) [namespace current]::Entities$ParseEventNum
05807 array set $options(entities) [array get [namespace current]::EntityPredef]
05808 }
05809 if {![info exists options(extentities)]} {
05810 set options(extentities) [namespace current]::ExtEntities$ParseEventNum
05811 }
05812 if {![info exists options(parameterentities)]} {
05813 set options(parameterentities) [namespace current]::ParamEntities$ParseEventNum
05814 }
05815 if {![info exists options(externalparameterentities)]} {
05816 set options(externalparameterentities) [namespace current]::ExtParamEntities$ParseEventNum
05817 }
05818 if {![info exists options(elementdecls)]} {
05819 set options(elementdecls) [namespace current]::ElementDecls$ParseEventNum
05820 }
05821 if {![info exists options(attlistdecls)]} {
05822 set options(attlistdecls) [namespace current]::AttListDecls$ParseEventNum
05823 }
05824 if {![info exists options(notationdecls)]} {
05825 set options(notationdecls) [namespace current]::NotationDecls$ParseEventNum
05826 }
05827 if {![info exists options(namespaces)]} {
05828 set options(namespaces) [namespace current]::Namespaces$ParseEventNum
05829 }
05830
05831 # For backward-compatibility
05832 catch {set options(-baseuri) $options(-baseurl)}
05833
05834 # Choose an external entity resolver
05835
05836 if {![string length $options(-externalentitycommand)]} {
05837 if {$options(-validate)} {
05838 set options(-externalentitycommand) [namespace code ResolveEntity]
05839 } else {
05840 set options(-externalentitycommand) [namespace code noop]
05841 }
05842 }
05843
05844 upvar #0 $options(-statevariable) state
05845 upvar #0 $options(entities) entities
05846
05847 # Mats:
05848 # The problem is that the state is not maintained when -final 0 !
05849 # I've switched back to an older version here.
05850
05851 if {![info exists state(line)]} {
05852 # Initialise the state variable
05853 array set state {
05854 mode normal
05855 haveXMLDecl 0
05856 haveDocElement 0
05857 inDTD 0
05858 context {}
05859 stack {}
05860 line 0
05861 defaultNS {}
05862 defaultNSURI {}
05863 }
05864 }
05865
05866 foreach {tag close param text} $sgml {
05867
05868 # Keep track of lines in the input
05869 incr state(line) [regsub -all \n $param {} discard]
05870 incr state(line) [regsub -all \n $text {} discard]
05871
05872 # If the current mode is cdata or comment then we must undo what the
05873 # regsub has done to reconstitute the data
05874
05875 set empty {}
05876 switch $state(mode) {
05877 comment {
05878 # This had "[string length $param] && " as a guard -
05879 # can't remember why :-(
05880 if {[regexp ([cl ^-]*)--\$ $tag discard comm1]} {
05881 # end of comment (in tag)
05882 set tag {}
05883 set close {}
05884 set state(mode) normal
05885 DeProtect1 $options(-commentcommand) $state(commentdata)<$comm1
05886 unset state(commentdata)
05887 } elseif {[regexp ([cl ^-]*)--\$ $param discard comm1]} {
05888 # end of comment (in attributes)
05889 DeProtect1 $options(-commentcommand) $state(commentdata)<$close$tag>$comm1
05890 unset state(commentdata)
05891 set tag {}
05892 set param {}
05893 set close {}
05894 set state(mode) normal
05895 } elseif {[regexp ([cl ^-]*)-->(.*) $text discard comm1 text]} {
05896 # end of comment (in text)
05897 DeProtect1 $options(-commentcommand) $state(commentdata)<$close$tag$param>$comm1
05898 unset state(commentdata)
05899 set tag {}
05900 set param {}
05901 set close {}
05902 set state(mode) normal
05903 } else {
05904 # comment continues
05905 append state(commentdata) <$close$tag$param>$text
05906 continue
05907 }
05908 }
05909 cdata {
05910 if {[string length $param] && [regexp ([cl ^\]]*)\]\][cl $Wsp]*\$ $tag discard cdata1]} {
05911 # end of CDATA (in tag)
05912 PCDATA [array get options] $state(cdata)<[subst -nocommand -novariable $close$cdata1]
05913 set text [subst -novariable -nocommand $text]
05914 set tag {}
05915 unset state(cdata)
05916 set state(mode) normal
05917 } elseif {[regexp ([cl ^\]]*)\]\][cl $Wsp]*\$ $param discard cdata1]} {
05918 # end of CDATA (in attributes)
05919 PCDATA [array get options] $state(cdata)<[subst -nocommand -novariable $close$tag$cdata1]
05920 set text [subst -novariable -nocommand $text]
05921 set tag {}
05922 set param {}
05923 unset state(cdata)
05924 set state(mode) normal
05925 } elseif {[regexp (.*)\]\][cl $Wsp]*>(.*) $text discard cdata1 text]} {
05926 # end of CDATA (in text)
05927 PCDATA [array get options] $state(cdata)<[subst -nocommand -novariable $close$tag$param>$cdata1]
05928 set text [subst -novariable -nocommand $text]
05929 set tag {}
05930 set param {}
05931 set close {}
05932 unset state(cdata)
05933 set state(mode) normal
05934 } else {
05935 # CDATA continues
05936 append state(cdata) [subst -nocommand -novariable <$close$tag$param>$text]
05937 continue
05938 }
05939 }
05940 continue {
05941 # We're skipping elements looking for the close tag
05942 switch -glob -- [string length $tag],[regexp {^\?|!.*} $tag],$close {
05943 0,* {
05944 continue
05945 }
05946 *,0, {
05947 if {![string compare $tag $state(continue:tag)]} {
05948 set empty [uplevel #0 $options(-emptyelement) [list $tag $param $empty]]
05949 if {![string length $empty]} {
05950 incr state(continue:level)
05951 }
05952 }
05953 continue
05954 }
05955 *,0,/ {
05956 if {![string compare $tag $state(continue:tag)]} {
05957 incr state(continue:level) -1
05958 }
05959 if {!$state(continue:level)} {
05960 unset state(continue:tag)
05961 unset state(continue:level)
05962 set state(mode) {}
05963 }
05964 }
05965 default {
05966 continue
05967 }
05968 }
05969 }
05970 default {
05971 # The trailing slash on empty elements can't be automatically separated out
05972 # in the RE, so we must do it here.
05973 regexp (.*)(/)[cl $Wsp]*$ $param discard param empty
05974 }
05975 }
05976
05977 # default: normal mode
05978
05979 # Bug: if the attribute list has a right angle bracket then the empty
05980 # element marker will not be seen
05981
05982 set empty [uplevel #0 $options(-emptyelement) [list $tag $param $empty]]
05983
05984 switch -glob -- [string length $tag],[regexp {^\?|!.*} $tag],$close,$empty {
05985
05986 0,0,, {
05987 # Ignore empty tag - dealt with non-normal mode above
05988 }
05989 *,0,, {
05990
05991 # Start tag for an element.
05992
05993 # Check if the internal DTD entity is in an attribute value
05994 regsub -all &xml:intdtd\; $param \[$options(-internaldtd)\] param
05995
05996 set code [catch {ParseEvent:ElementOpen $tag $param [array get options]} msg]
05997 set state(haveDocElement) 1
05998 switch $code {
05999 0 {# OK}
06000 3 {
06001 # break
06002 return {}
06003 }
06004 4 {
06005 # continue
06006 # Remember this tag and look for its close
06007 set state(continue:tag) $tag
06008 set state(continue:level) 1
06009 set state(mode) continue
06010 continue
06011 }
06012 default {
06013 return -code $code -errorinfo $::errorInfo $msg
06014 }
06015 }
06016
06017 }
06018
06019 *,0,/, {
06020
06021 # End tag for an element.
06022
06023 set code [catch {ParseEvent:ElementClose $tag [array get options]} msg]
06024 switch $code {
06025 0 {# OK}
06026 3 {
06027 # break
06028 return {}
06029 }
06030 4 {
06031 # continue
06032 # skip sibling nodes
06033 set state(continue:tag) [lindex $state(stack) end]
06034 set state(continue:level) 1
06035 set state(mode) continue
06036 continue
06037 }
06038 default {
06039 return -code $code -errorinfo $::errorInfo $msg
06040 }
06041 }
06042
06043 }
06044
06045 *,0,,/ {
06046
06047 # Empty element
06048
06049 # The trailing slash sneaks through into the param variable
06050 regsub -all /[cl $::sgml::Wsp]*\$ $param {} param
06051
06052 set code [catch {ParseEvent:ElementOpen $tag $param [array get options] -empty 1} msg]
06053 set state(haveDocElement) 1
06054 switch $code {
06055 0 {# OK}
06056 3 {
06057 # break
06058 return {}
06059 }
06060 4 {
06061 # continue
06062 # Pretty useless since it closes straightaway
06063 }
06064 default {
06065 return -code $code -errorinfo $::errorInfo $msg
06066 }
06067 }
06068 set code [catch {ParseEvent:ElementClose $tag [array get options] -empty 1} msg]
06069 switch $code {
06070 0 {# OK}
06071 3 {
06072 # break
06073 return {}
06074 }
06075 4 {
06076 # continue
06077 # skip sibling nodes
06078 set state(continue:tag) [lindex $state(stack) end]
06079 set state(continue:level) 1
06080 set state(mode) continue
06081 continue
06082 }
06083 default {
06084 return -code $code -errorinfo $::errorInfo $msg
06085 }
06086 }
06087
06088 }
06089
06090 *,1,* {
06091 # Processing instructions or XML declaration
06092 switch -glob -- $tag {
06093
06094 {\?xml} {
06095 # XML Declaration
06096 if {$state(haveXMLDecl)} {
06097 uplevel #0 $options(-errorcommand) [list illegalcharacter "unexpected characters \"<$tag\" around line $state(line)"]
06098 } elseif {![regexp {\?$} $param]} {
06099 uplevel #0 $options(-errorcommand) [list missingcharacters "XML Declaration missing characters \"?>\" around line $state(line)"]
06100 } else {
06101
06102 # We can do the parsing in one step with Tcl 8.1 RE's
06103 # This has the benefit of performing better WF checking
06104
06105 set adv_re [format {^[%s]*version[%s]*=[%s]*("|')(-+|[a-zA-Z0-9_.:]+)\1([%s]+encoding[%s]*=[%s]*("|')([A-Za-z][-A-Za-z0-9._]*)\4)?([%s]*standalone[%s]*=[%s]*("|')(yes|no)\7)?[%s]*\?$} $::sgml::Wsp $::sgml::Wsp $::sgml::Wsp $::sgml::Wsp $::sgml::Wsp $::sgml::Wsp $::sgml::Wsp $::sgml::Wsp $::sgml::Wsp $::sgml::Wsp]
06106
06107 if {[catch {regexp $adv_re $param discard delimiter version discard delimiter encoding discard delimiter standalone} matches]} {
06108 # Otherwise we must fallback to 8.0.
06109 # This won't detect certain well-formedness errors
06110
06111 # Get the version number
06112 if {[regexp [format {[%s]*version[%s]*=[%s]*"(-+|[a-zA-Z0-9_.:]+)"[%s]*} $::sgml::Wsp $::sgml::Wsp $::sgml::Wsp $::sgml::Wsp] $param discard version] || [regexp [format {[%s]*version[%s]*=[%s]*'(-+|[a-zA-Z0-9_.:]+)'[%s]*} $::sgml::Wsp $::sgml::Wsp $::sgml::Wsp $::sgml::Wsp] $param discard version]} {
06113 if {[string compare $version "1.0"]} {
06114 # Should we support future versions?
06115 # At least 1.X?
06116 uplevel #0 $options(-errorcommand) [list versionincompatibility "document XML version \"$version\" is incompatible with XML version 1.0"]
06117 }
06118 } else {
06119 uplevel #0 $options(-errorcommand) [list missingversion "XML Declaration missing version information around line $state(line)"]
06120 }
06121
06122 # Get the encoding declaration
06123 set encoding {}
06124 regexp [format {[%s]*encoding[%s]*=[%s]*"([A-Za-z]([A-Za-z0-9._]|-)*)"[%s]*} $::sgml::Wsp $::sgml::Wsp $::sgml::Wsp $::sgml::Wsp] $param discard encoding
06125 regexp [format {[%s]*encoding[%s]*=[%s]*'([A-Za-z]([A-Za-z0-9._]|-)*)'[%s]*} $::sgml::Wsp $::sgml::Wsp $::sgml::Wsp $::sgml::Wsp] $param discard encoding
06126
06127 # Get the standalone declaration
06128 set standalone {}
06129 regexp [format {[%s]*standalone[%s]*=[%s]*"(yes|no)"[%s]*} $::sgml::Wsp $::sgml::Wsp $::sgml::Wsp $::sgml::Wsp] $param discard standalone
06130 regexp [format {[%s]*standalone[%s]*=[%s]*'(yes|no)'[%s]*} $::sgml::Wsp $::sgml::Wsp $::sgml::Wsp $::sgml::Wsp] $param discard standalone
06131
06132 # Invoke the callback
06133 uplevel #0 $options(-xmldeclcommand) [list $version $encoding $standalone]
06134
06135 } elseif {$matches == 0} {
06136 uplevel #0 $options(-errorcommand) [list illformeddeclaration "XML Declaration not well-formed around line $state(line)"]
06137 } else {
06138
06139 # Invoke the callback
06140 uplevel #0 $options(-xmldeclcommand) [list $version $encoding $standalone]
06141
06142 }
06143
06144 }
06145
06146 }
06147
06148 {\?*} {
06149 # Processing instruction
06150 set tag [string range $tag 1 end]
06151 if {[regsub {\?$} $tag {} tag]} {
06152 if {[string length [string trim $param]]} {
06153 uplevel #0 $options(-errorcommand) [list unexpectedtext "unexpected text \"$param\" in processing instruction around line $state(line)"]
06154 }
06155 } elseif {![regexp ^$Name\$ $tag]} {
06156 uplevel #0 $options(-errorcommand) [list illegalcharacter "illegal character in processing instruction target \"$tag\""]
06157 } elseif {[regexp {[xX][mM][lL]} $tag]} {
06158 uplevel #0 $options(-errorcommand) [list illegalcharacters "characters \"xml\" not permitted in processing instruction target \"$tag\""]
06159 } elseif {![regsub {\?$} $param {} param]} {
06160 uplevel #0 $options(-errorcommand) [list missingquestion "PI: expected '?' character around line $state(line)"]
06161 }
06162 set code [catch {uplevel #0 $options(-processinginstructioncommand) [list $tag [string trimleft $param]]} msg]
06163 switch $code {
06164 0 {# OK}
06165 3 {
06166 # break
06167 return {}
06168 }
06169 4 {
06170 # continue
06171 # skip sibling nodes
06172 set state(continue:tag) [lindex $state(stack) end]
06173 set state(continue:level) 1
06174 set state(mode) continue
06175 continue
06176 }
06177 default {
06178 return -code $code -errorinfo $::errorInfo $msg
06179 }
06180 }
06181 }
06182
06183 !DOCTYPE {
06184 # External entity reference
06185 # This should move into xml.tcl
06186 # Parse the params supplied. Looking for Name, ExternalID and MarkupDecl
06187 set matched [regexp ^[cl $Wsp]*($Name)[cl $Wsp]*(.*) $param x state(doc_name) param]
06188 set state(doc_name) [Normalize $state(doc_name) $options(-normalize)]
06189 set externalID {}
06190 set pubidlit {}
06191 set systemlit {}
06192 set externalID {}
06193 if {[regexp -nocase ^[cl $Wsp]*(SYSTEM|PUBLIC)(.*) $param x id param]} {
06194 switch [string toupper $id] {
06195 SYSTEM {
06196 if {[regexp ^[cl $Wsp]+"([cl ^"]*)"(.*) $param x systemlit param] || [regexp ^[cl $Wsp]+'([cl ^']*)'(.*) $param x systemlit param]} {
06197 set externalID [list SYSTEM $systemlit] ;# "
06198 } else {
06199 uplevel #0 $options(-errorcommand) {syntaxerror {syntax error: SYSTEM identifier not followed by literal}}
06200 }
06201 }
06202 PUBLIC {
06203 if {[regexp ^[cl $Wsp]+"([cl ^"]*)"(.*) $param x pubidlit param] || [regexp ^[cl $Wsp]+'([cl ^']*)'(.*) $param x pubidlit param]} {
06204 if {[regexp ^[cl $Wsp]+"([cl ^"]*)"(.*) $param x systemlit param] || [regexp ^[cl $Wsp]+'([cl ^']*)'(.*) $param x systemlit param]} {
06205 set externalID [list PUBLIC $pubidlit $systemlit]
06206 } else {
06207 uplevel #0 $options(-errorcommand) [list syntaxerror "syntax error: PUBLIC identifier not followed by system literal around line $state(line)"]
06208 }
06209 } else {
06210 uplevel #0 $options(-errorcommand) [list syntaxerror "syntax error: PUBLIC identifier not followed by literal around line $state(line)"]
06211 }
06212 }
06213 }
06214 if {[regexp -nocase ^[cl $Wsp]+NDATA[cl $Wsp]+($Name)(.*) $param x notation param]} {
06215 lappend externalID $notation
06216 }
06217 }
06218
06219 set state(inDTD) 1
06220
06221 ParseEvent:DocTypeDecl [array get options] $state(doc_name) $pubidlit $systemlit $options(-internaldtd)
06222
06223 set state(inDTD) 0
06224
06225 }
06226
06227 !--* {
06228
06229 # Start of a comment
06230 # See if it ends in the same tag, otherwise change the
06231 # parsing mode
06232
06233 regexp {!--(.*)} $tag discard comm1
06234 if {[regexp ([cl ^-]*)--[cl $Wsp]*\$ $comm1 discard comm1_1]} {
06235 # processed comment (end in tag)
06236 uplevel #0 $options(-commentcommand) [list $comm1_1]
06237 } elseif {[regexp ([cl ^-]*)--[cl $Wsp]*\$ $param discard comm2]} {
06238 # processed comment (end in attributes)
06239 uplevel #0 $options(-commentcommand) [list $comm1$comm2]
06240 } elseif {[regexp ([cl ^-]*)-->(.*) $text discard comm2 text]} {
06241 # processed comment (end in text)
06242 uplevel #0 $options(-commentcommand) [list $comm1$param$empty>$comm2]
06243 } else {
06244 # start of comment
06245 set state(mode) comment
06246 set state(commentdata) "$comm1$param$empty>$text"
06247 continue
06248 }
06249 }
06250
06251 {!\[CDATA\[*} {
06252
06253 regexp {!\[CDATA\[(.*)} $tag discard cdata1
06254 if {[regexp {(.*)]]$} $cdata1 discard cdata2]} {
06255 # processed CDATA (end in tag)
06256 PCDATA [array get options] [subst -novariable -nocommand $cdata2]
06257 set text [subst -novariable -nocommand $text]
06258 } elseif {[regexp {(.*)]]$} $param discard cdata2]} {
06259 # processed CDATA (end in attribute)
06260 # Backslashes in param are quoted at this stage
06261 PCDATA [array get options] $cdata1[subst -novariable -nocommand $cdata2]
06262 set text [subst -novariable -nocommand $text]
06263 } elseif {[regexp {(.*)]]>(.*)} $text discard cdata2 text]} {
06264 # processed CDATA (end in text)
06265 # Backslashes in param and text are quoted at this stage
06266 PCDATA [array get options] $cdata1[subst -novariable -nocommand $param]$empty>[subst -novariable -nocommand $cdata2]
06267 set text [subst -novariable -nocommand $text]
06268 } else {
06269 # start CDATA
06270 set state(cdata) "$cdata1$param>$text"
06271 set state(mode) cdata
06272 continue
06273 }
06274
06275 }
06276
06277 !ELEMENT -
06278 !ATTLIST -
06279 !ENTITY -
06280 !NOTATION {
06281 uplevel #0 $options(-errorcommand) [list illegaldeclaration "[string range $tag 1 end] declaration not expected in document instance around line $state(line)"]
06282 }
06283
06284 default {
06285 uplevel #0 $options(-errorcommand) [list unknowninstruction "unknown processing instruction \"<$tag>\" around line $state(line)"]
06286 }
06287 }
06288 }
06289 *,1,* -
06290 *,0,/,/ {
06291 # Syntax error
06292 uplevel #0 $options(-errorcommand) [list syntaxerror "syntax error: closed/empty tag: tag $tag param $param empty $empty close $close around line $state(line)"]
06293 }
06294 }
06295
06296 # Process character data
06297
06298 if {$state(haveDocElement) && [llength $state(stack)]} {
06299
06300 # Check if the internal DTD entity is in the text
06301 regsub -all &xml:intdtd\; $text \[$options(-internaldtd)\] text
06302
06303 # Look for entity references
06304 if {([array size entities] || [string length $options(-entityreferencecommand)]) && $options(-defaultexpandinternalentities) && [regexp {&[^;]+;} $text]} {
06305
06306 # protect Tcl specials
06307 # NB. braces and backslashes may already be protected
06308 regsub -all {\\({|}|\\)} $text {\1} text
06309 regsub -all {([][$\\{}])} $text {\\\1} text
06310
06311 # Mark entity references
06312 regsub -all {&([^;]+);} $text [format {%s; %s {\1} ; %s %s} \}\} [namespace code [list Entity [array get options] $options(-entityreferencecommand) [namespace code [list PCDATA [array get options]]] $options(entities)]] [namespace code [list DeProtect [namespace code [list PCDATA [array get options]]]]] \{\{] text
06313 set text "uplevel #0 [namespace code [list DeProtect1 [namespace code [list PCDATA [array get options]]]]] {{$text}}"
06314 eval $text
06315 } else {
06316
06317 # Restore protected special characters
06318 regsub -all {\\([][{}\\])} $text {\1} text
06319 PCDATA [array get options] $text
06320 }
06321 } elseif {[string length [string trim $text]]} {
06322 uplevel #0 $options(-errorcommand) [list unexpectedtext "unexpected text \"$text\" in document prolog around line $state(line)"]
06323 }
06324
06325 }
06326
06327 # If this is the end of the document, close all open containers
06328 if {$options(-final) && [llength $state(stack)]} {
06329 eval $options(-errorcommand) [list unclosedelement "element [lindex $state(stack) end] remains unclosed around line $state(line)"]
06330 }
06331
06332 return {}
06333 }
06334
06335 }
06336
06337 namespace ::sgml {
06338
06339 ret {::sgml::tokenise} (type sgml , type elemExpr , type elemSub , type args) {
06340 array set options {-final 1}
06341 array set options $args
06342 set options(-final) [Boolean $options(-final)]
06343
06344 # If the data is not final then there must be a variable to store
06345 # unused data.
06346 if {!$options(-final) && ![info exists options(-statevariable)]} {
06347 return -code error {option "-statevariable" required if not final}
06348 }
06349
06350 # Pre-process stage
06351 #
06352 # Extract the internal DTD subset, if any
06353
06354 catch {upvar #0 $options(-internaldtdvariable) dtd}
06355 if {[regexp {<!DOCTYPE[^[<]+\[([^]]+)\]} $sgml discard dtd]} {
06356 regsub {(<!DOCTYPE[^[<]+)(\[[^]]+\])} $sgml {\1\&xml:intdtd;} sgml
06357 }
06358
06359 # Protect Tcl special characters
06360 regsub -all {([{}\\])} $sgml {\\\1} sgml
06361
06362 # Do the translation
06363
06364 if {[info exists options(-statevariable)]} {
06365 # Mats: Several rewrites here to handle -final 0 option.
06366 # If any cached unparsed xml (state(leftover)), prepend it.
06367 upvar #0 $options(-statevariable) state
06368 if {[string length $state(leftover)]} {
06369 regsub -all $elemExpr $state(leftover)$sgml $elemSub sgml
06370 set state(leftover) {}
06371 } else {
06372 regsub -all $elemExpr $sgml $elemSub sgml
06373 }
06374 set sgml "{} {} {} \{$sgml\}"
06375
06376 # Performance note (Tcl 8.0):
06377 # Use of lindex, lreplace will cause parsing to list object
06378
06379 # This RE only fixes chopped inside tags, not chopped text.
06380 if {[regexp {^([^<]*)(<[^>]*$)} [lindex $sgml end] x text rest]} {
06381 set sgml [lreplace $sgml end end $text]
06382 # Mats: unmatched stuff means that it is chopped off. Cache it for next round.
06383 set state(leftover) $rest
06384 }
06385
06386 # Patch from bug report #596959, Marshall Rose
06387 if {[string compare [lindex $sgml 4] ""]} {
06388 set sgml [linsert $sgml 0 {} {} {} {} {}]
06389 }
06390
06391 } else {
06392
06393 # Performance note (Tcl 8.0):
06394 # In this case, no conversion to list object is performed
06395
06396 # Mats: This fails if not -final and $sgml is chopped off right in a tag.
06397 regsub -all $elemExpr $sgml $elemSub sgml
06398 set sgml "{} {} {} \{$sgml\}"
06399 }
06400
06401 return $sgml
06402 }
06403
06404 }
06405
06406 namespace ::sgml {
06407
06408 ret {::sgml::zapWhite} (type data) {
06409 regsub -all "\[ \t\r\n\]+" $data { } data
06410 return $data
06411 }
06412
06413 }
06414
06415 namespace ::uri {
06416
06417 ret {::uri::GetHostPort} (type urlvar) {
06418 # @c Parse host and port out of the url stored in variable <a urlvar>.
06419 # @d Side effect: The extracted information is removed from the given url.
06420 # @r List containing the extracted information in a format suitable for
06421 # @r 'array set'.
06422 # @a urlvar: Name of the variable containing the url to parse.
06423
06424 upvar #0 [namespace current]::basic::hostname hostname
06425 upvar #0 [namespace current]::basic::hostnumber hostnumber
06426 upvar #0 [namespace current]::basic::port port
06427
06428 upvar $urlvar url
06429
06430 set pattern "^(${hostname}|${hostnumber})(:(${port}))?"
06431
06432 if {[regexp -indices -- $pattern $url match host c d e f g h thePort]} {
06433 set fromHost [lindex $host 0]
06434 set toHost [lindex $host 1]
06435
06436 set fromPort [lindex $thePort 0]
06437 set toPort [lindex $thePort 1]
06438
06439 set parts(host) [string range $url $fromHost $toHost]
06440 set parts(port) [string range $url $fromPort $toPort]
06441
06442 set matchEnd [lindex $match 1]
06443 incr matchEnd
06444
06445 set url [string range $url $matchEnd end]
06446 }
06447
06448 return [array get parts]
06449 }
06450
06451 }
06452
06453 namespace ::uri {
06454
06455 ret {::uri::GetUPHP} (type urlvar) {
06456 # @c Parse user, password host and port out of the url stored in
06457 # @c variable <a urlvar>.
06458 # @d Side effect: The extracted information is removed from the given url.
06459 # @r List containing the extracted information in a format suitable for
06460 # @r 'array set'.
06461 # @a urlvar: Name of the variable containing the url to parse.
06462
06463 upvar \#0 [namespace current]::basic::user user
06464 upvar \#0 [namespace current]::basic::password password
06465 upvar \#0 [namespace current]::basic::hostname hostname
06466 upvar \#0 [namespace current]::basic::hostnumber hostnumber
06467 upvar \#0 [namespace current]::basic::port port
06468
06469 upvar $urlvar url
06470
06471 array set parts {user {} pwd {} host {} port {}}
06472
06473 # syntax
06474 # "//" [ <user> [":" <password> ] "@"] <host> [":" <port>] "/"
06475 # "//" already cut off by caller
06476
06477 set upPattern "^(${user})(:(${password}))?@"
06478
06479 if {[regexp -indices -- $upPattern $url match theUser c d thePassword]} {
06480 set fu [lindex $theUser 0]
06481 set tu [lindex $theUser 1]
06482
06483 set fp [lindex $thePassword 0]
06484 set tp [lindex $thePassword 1]
06485
06486 set parts(user) [string range $url $fu $tu]
06487 set parts(pwd) [string range $url $fp $tp]
06488
06489 set matchEnd [lindex $match 1]
06490 incr matchEnd
06491
06492 set url [string range $url $matchEnd end]
06493 }
06494
06495 set hpPattern "^($hostname|$hostnumber)(:($port))?"
06496
06497 if {[regexp -indices -- $hpPattern $url match theHost c d e f g h thePort]} {
06498 set fh [lindex $theHost 0]
06499 set th [lindex $theHost 1]
06500
06501 set fp [lindex $thePort 0]
06502 set tp [lindex $thePort 1]
06503
06504 set parts(host) [string range $url $fh $th]
06505 set parts(port) [string range $url $fp $tp]
06506
06507 set matchEnd [lindex $match 1]
06508 incr matchEnd
06509
06510 set url [string range $url $matchEnd end]
06511 }
06512
06513 return [array get parts]
06514 }
06515
06516 }
06517
06518 namespace ::uri {
06519
06520 ret {::uri::JoinFile} (type args) {
06521 array set components {
06522 host {} port {} path {}
06523 }
06524 array set components $args
06525
06526 switch -exact -- $::tcl_platform(platform) {
06527 windows {
06528 if {[string length $components(host)]} {
06529 return file://$components(host):$components(path)
06530 } else {
06531 return file://$components(path)
06532 }
06533 }
06534 default {
06535 return file://$components(host)$components(path)
06536 }
06537 }
06538 }
06539
06540 }
06541
06542 namespace ::uri {
06543
06544 ret {::uri::JoinFtp} (type args) {
06545 array set components {
06546 user {} pwd {} host {} port {}
06547 path {} type {}
06548 }
06549 array set components $args
06550
06551 set userPwd {}
06552 if {[string length $components(user)] || [string length $components(pwd)]} {
06553 set userPwd $components(user)[expr {[string length $components(pwd)] ? ":$components(pwd)" : {}}]@
06554 }
06555
06556 set port {}
06557 if {[string length $components(port)]} {
06558 set port :$components(port)
06559 }
06560
06561 set type {}
06562 if {[string length $components(type)]} {
06563 set type \;type=$components(type)
06564 }
06565
06566 return ftp://${userPwd}$components(host)${port}/[string trimleft $components(path) /]$type
06567 }
06568
06569 }
06570
06571 namespace ::uri {
06572
06573 ret {::uri::JoinHttp} (type args) {
06574 return [eval [linsert $args 0 ::uri::JoinHttpInner http 80]]
06575 }
06576
06577 }
06578
06579 namespace ::uri {
06580
06581 ret {::uri::JoinHttpInner} (type scheme , type defport , type args) {
06582 array set components {host {} path {} query {}}
06583 set components(port) $defport
06584 array set components $args
06585
06586 set port {}
06587 if {[string length $components(port)] && $components(port) != $defport} {
06588 set port :$components(port)
06589 }
06590
06591 set query {}
06592 if {[string length $components(query)]} {
06593 set query ?$components(query)
06594 }
06595
06596 regsub -- {^/} $components(path) {} components(path)
06597
06598 if { [info exists components(fragment)] && $components(fragment) != "" } {
06599 set components(fragment) "#$components(fragment)"
06600 } else {
06601 set components(fragment) ""
06602 }
06603
06604 return $scheme://$components(host)$port/$components(path)$components(fragment)$query
06605 }
06606
06607 }
06608
06609 namespace ::uri {
06610
06611 ret {::uri::JoinHttps} (type args) {
06612 return [eval [linsert $args 0 ::uri::JoinHttpInner https 443]]
06613 }
06614
06615 }
06616
06617 namespace ::uri {
06618
06619 ret {::uri::JoinLdap} (type args) {
06620 return [eval [linsert $args 0 ::uri::JoinLdapInner ldap 389]]
06621 }
06622
06623 }
06624
06625 namespace ::uri {
06626
06627 ret {::uri::JoinLdapInner} (type scheme , type defport , type args) {
06628 array set components {host {} port {} dn {} attrs {} scope {} filter {} extensions {}}
06629 set components(port) $defport
06630 array set components $args
06631
06632 set port {}
06633 if {[string length $components(port)] && $components(port) != $defport} {
06634 set port :$components(port)
06635 }
06636
06637 set url "$scheme://$components(host)$port"
06638
06639 set components(attrs) [::join $components(attrs) ","]
06640
06641 set s ""
06642 foreach c {dn attrs scope filter extensions} {
06643 if {[string equal $c "dn"]} then {
06644 append s "/"
06645 } else {
06646 append s "?"
06647 }
06648 if {! [string equal $components($c) ""]} then {
06649 append url "${s}$components($c)"
06650 set s ""
06651 }
06652 }
06653
06654 return $url
06655 }
06656
06657 }
06658
06659 namespace ::uri {
06660
06661 ret {::uri::JoinLdaps} (type args) {
06662 return [eval [linsert $args 0 ::uri::JoinLdapInner ldaps 636]]
06663 }
06664
06665 }
06666
06667 namespace ::uri {
06668
06669 ret {::uri::JoinMailto} (type args) {
06670 array set components {
06671 user {} host {}
06672 }
06673 array set components $args
06674
06675 return mailto:$components(user)@$components(host)
06676 }
06677
06678 }
06679
06680 namespace ::uri {
06681
06682 ret {::uri::JoinNews} (type args) {
06683 array set components {
06684 message-id {} newsgroup-name {}
06685 }
06686 array set components $args
06687 return news:$components(message-id)$components(newsgroup-name)
06688 }
06689
06690 }
06691
06692 namespace ::uri {
06693
06694 ret {::uri::SplitFile} (type url) {
06695 # @c Splits the given file-<a url> into its constituents.
06696 # @a url: The url to split, without! scheme specification.
06697 # @r List containing the constituents, suitable for 'array set'.
06698
06699 upvar #0 [namespace current]::basic::hostname hostname
06700 upvar #0 [namespace current]::basic::hostnumber hostnumber
06701
06702 if {[string match "//*" $url]} {
06703 set url [string range $url 2 end]
06704
06705 set hostPattern "^($hostname|$hostnumber)"
06706 switch -exact -- $::tcl_platform(platform) {
06707 windows {
06708 # Catch drive letter
06709 append hostPattern :?
06710 }
06711 default {
06712 # Proceed as usual
06713 }
06714 }
06715
06716 if {[regexp -indices -- $hostPattern $url match host]} {
06717 set fh [lindex $host 0]
06718 set th [lindex $host 1]
06719
06720 set parts(host) [string range $url $fh $th]
06721
06722 set matchEnd [lindex $match 1]
06723 incr matchEnd
06724
06725 set url [string range $url $matchEnd end]
06726 }
06727 }
06728
06729 set parts(path) $url
06730
06731 return [array get parts]
06732 }
06733
06734 }
06735
06736 namespace ::uri {
06737
06738 ret {::uri::SplitFtp} (type url) {
06739 # @c Splits the given ftp-<a url> into its constituents.
06740 # @a url: The url to split, without! scheme specification.
06741 # @r List containing the constituents, suitable for 'array set'.
06742
06743 # general syntax:
06744 # //<user>:<password>@<host>:<port>/<cwd1>/.../<cwdN>/<name>;type=<typecode>
06745 #
06746 # additional rules:
06747 #
06748 # <user>:<password> are optional, detectable by presence of @.
06749 # <password> is optional too.
06750 #
06751 # "//" [ <user> [":" <password> ] "@"] <host> [":" <port>] "/"
06752 # <cwd1> "/" ..."/" <cwdN> "/" <name> [";type=" <typecode>]
06753
06754 upvar \#0 [namespace current]::ftp::typepart ftptype
06755
06756 array set parts {user {} pwd {} host {} port {} path {} type {}}
06757
06758 # slash off possible type specification
06759
06760 if {[regexp -indices -- "${ftptype}$" $url dummy ftype]} {
06761
06762 set from [lindex $ftype 0]
06763 set to [lindex $ftype 1]
06764
06765 set parts(type) [string range $url $from $to]
06766
06767 set from [lindex $dummy 0]
06768 set url [string replace $url $from end]
06769 }
06770
06771 # Handle user, password, host and port
06772
06773 if {[string match "//*" $url]} {
06774 set url [string range $url 2 end]
06775
06776 array set parts [GetUPHP url]
06777 }
06778
06779 set parts(path) [string trimleft $url /]
06780
06781 return [array get parts]
06782 }
06783
06784 }
06785
06786 namespace ::uri {
06787
06788 ret {::uri::SplitHttp} (type url) {
06789 # @c Splits the given http-<a url> into its constituents.
06790 # @a url: The url to split, without! scheme specification.
06791 # @r List containing the constituents, suitable for 'array set'.
06792
06793 # general syntax:
06794 # //<host>:<port>/<path>?<searchpart>
06795 #
06796 # where <host> and <port> are as described in Section 3.1. If :<port>
06797 # is omitted, the port defaults to 80. No user name or password is
06798 # allowed. <path> is an HTTP selector, and <searchpart> is a query
06799 # string. The <path> is optional, as is the <searchpart> and its
06800 # preceding "?". If neither <path> nor <searchpart> is present, the "/"
06801 # may also be omitted.
06802 #
06803 # Within the <path> and <searchpart> components, "/", ";", "?" are
06804 # reserved. The "/" character may be used within HTTP to designate a
06805 # hierarchical structure.
06806 #
06807 # path == <cwd1> "/" ..."/" <cwdN> "/" <name> ["#" <fragment>]
06808
06809 upvar #0 [namespace current]::http::search search
06810 upvar #0 [namespace current]::http::segment segment
06811
06812 array set parts {host {} port {} path {} query {}}
06813
06814 set searchPattern "\\?(${search})\$"
06815 set fragmentPattern "#(${segment})\$"
06816
06817 # slash off possible query. the 'search' regexp, while official,
06818 # is not good enough. We have apparently lots of urls in the wild
06819 # which contain unquoted urls with queries in a query. The RE
06820 # finds the embedded query, not the actual one. Using string first
06821 # now instead of a RE
06822
06823 if {[set pos [string first ? $url]] >= 0} {
06824 incr pos
06825 set parts(query) [string range $url $pos end]
06826 incr pos -1
06827 set url [string replace $url $pos end]
06828 }
06829
06830 # slash off possible fragment
06831
06832 if {[regexp -indices -- $fragmentPattern $url match fragment]} {
06833 set from [lindex $fragment 0]
06834 set to [lindex $fragment 1]
06835
06836 set parts(fragment) [string range $url $from $to]
06837
06838 set url [string replace $url [lindex $match 0] end]
06839 }
06840
06841 if {[string match "//*" $url]} {
06842 set url [string range $url 2 end]
06843
06844 array set parts [GetUPHP url]
06845 }
06846
06847 set parts(path) [string trimleft $url /]
06848
06849 return [array get parts]
06850 }
06851
06852 }
06853
06854 namespace ::uri {
06855
06856 ret {::uri::SplitHttps} (type url) {
06857 return [SplitHttp $url]
06858 }
06859
06860 }
06861
06862 namespace ::uri {
06863
06864 ret {::uri::SplitLdap} (type url) {
06865 # @c Splits the given Ldap-<a url> into its constituents.
06866 # @a url: The url to split, without! scheme specification.
06867 # @r List containing the constituents, suitable for 'array set'.
06868
06869 # general syntax:
06870 # //<host>:<port>/<dn>?<attrs>?<scope>?<filter>?<extensions>
06871 #
06872 # where <host> and <port> are as described in Section 5 of RFC 1738.
06873 # No user name or password is allowed.
06874 # If omitted, the port defaults to 389 for ldap, 636 for ldaps
06875 # <dn> is the base DN for the search
06876 # <attrs> is a comma separated list of attributes description
06877 # <scope> is either "base", "one" or "sub".
06878 # <filter> is a RFC 2254 filter specification
06879 # <extensions> are documented in RFC 2255
06880 #
06881
06882 array set parts {host {} port {} dn {} attrs {} scope {} filter {} extensions {}}
06883
06884 # host port dn attrs scope filter extns
06885 set re {//([^:?/]+)(?::([0-9]+))?(?:/([^?]+)(?:\?([^?]*)(?:\?(base|one|sub)?(?:\?([^?]*)(?:\?(.*))?)?)?)?)?}
06886
06887 if {! [regexp $re $url match parts(host) parts(port) parts(dn) parts(attrs) parts(scope) parts(filter) parts(extensions)]} then {
06888 return -code error "unable to match URL \"$url\""
06889 }
06890
06891 set parts(attrs) [::split $parts(attrs) ","]
06892
06893 return [array get parts]
06894 }
06895
06896 }
06897
06898 namespace ::uri {
06899
06900 ret {::uri::SplitLdaps} (type url) {
06901 ::uri::SplitLdap $url
06902 }
06903
06904 }
06905
06906 namespace ::uri {
06907
06908 ret {::uri::SplitMailto} (type url) {
06909 # @c Splits the given mailto-<a url> into its constituents.
06910 # @a url: The url to split, without! scheme specification.
06911 # @r List containing the constituents, suitable for 'array set'.
06912
06913 if {[string match "*@*" $url]} {
06914 set url [::split $url @]
06915 return [list user [lindex $url 0] host [lindex $url 1]]
06916 } else {
06917 return [list user $url]
06918 }
06919 }
06920
06921 }
06922
06923 namespace ::uri {
06924
06925 ret {::uri::SplitNews} (type url) {
06926 if { [string first @ $url] >= 0 } {
06927 return [list message-id $url]
06928 } else {
06929 return [list newsgroup-name $url]
06930 }
06931 }
06932
06933 }
06934
06935 namespace ::uri {
06936
06937 ret {::uri::canonicalize} (type uri) {
06938 # Make uri canonical with respect to dots (path changing commands)
06939 #
06940 # Remove single dots (.) => pwd not changing
06941 # Remove double dots (..) => gobble previous segment of path
06942 #
06943 # Fixes for this command:
06944 #
06945 # * Ignore any url which cannot be split into components by this
06946 # module. Just assume that such urls do not have a path to
06947 # canonicalize.
06948 #
06949 # * Ignore any url which could be split into components, but does
06950 # not have a path component.
06951 #
06952 # In the text above 'ignore' means
06953 # 'return the url unchanged to the caller'.
06954
06955 if {[catch {array set u [::uri::split $uri]}]} {
06956 return $uri
06957 }
06958 if {![info exists u(path)]} {
06959 return $uri
06960 }
06961
06962 set uri $u(path)
06963
06964 # Remove leading "./" "../" "/.." (and "/../")
06965 regsub -all -- {^(\./)+} $uri {} uri
06966 regsub -all -- {^/(\.\./)+} $uri {/} uri
06967 regsub -all -- {^(\.\./)+} $uri {} uri
06968
06969 # Remove inner /./ and /../
06970 while {[regsub -all -- {/\./} $uri {/} uri]} {}
06971 while {[regsub -all -- {/[^/]+/\.\./} $uri {/} uri]} {}
06972 while {[regsub -all -- {^[^/]+/\.\./} $uri {} uri]} {}
06973 # Munge trailing /..
06974 while {[regsub -all -- {/[^/]+/\.\.} $uri {/} uri]} {}
06975 if { $uri == ".." } { set uri "/" }
06976
06977 set u(path) $uri
06978 set uri [eval [linsert [array get u] 0 ::uri::join]]
06979
06980 return $uri
06981 }
06982
06983 }
06984
06985 namespace ::uri {
06986
06987 ret {::uri::file_geturl} (type url , type args) {
06988 variable file:counter
06989
06990 set var [namespace current]::file[incr file:counter]
06991 upvar #0 $var state
06992 array set state {data {}}
06993
06994 array set parts [split $url]
06995
06996 set ch [open $parts(path)]
06997 # Could determine text/binary from file extension,
06998 # except on Macintosh
06999 # fconfigure $ch -translation binary
07000 set state(data) [read $ch]
07001 close $ch
07002
07003 return $var
07004 }
07005
07006 }
07007
07008 namespace ::uri {
07009
07010 ret {::uri::geturl} (type url , type args) {
07011 array set urlparts [split $url]
07012
07013 switch -- $urlparts(scheme) {
07014 file {
07015 return [eval [linsert $args 0 file_geturl $url]]
07016 }
07017 default {
07018 # Load a geturl package for the scheme first and only if
07019 # that fails the scheme package itself. This prevents
07020 # cyclic dependencies between packages.
07021 if {[catch {package require $urlparts(scheme)::geturl}]} {
07022 package require $urlparts(scheme)
07023 }
07024 return [eval [linsert $args 0 $urlparts(scheme)::geturl $url]]
07025 }
07026 }
07027 }
07028
07029 }
07030
07031 namespace ::uri {
07032
07033 ret {::uri::isrelative} (type url) {
07034 return [expr {![regexp -- {^[a-z0-9+-.][a-z0-9+-.]*:} $url]}]
07035 }
07036
07037 }
07038
07039 namespace ::uri {
07040
07041 ret {::uri::join} (type args) {
07042 array set components $args
07043
07044 return [eval [linsert $args 0 Join[string totitle $components(scheme)]]]
07045 }
07046
07047 }
07048
07049 namespace ::uri {
07050
07051 ret {::uri::register} (type schemeList , type script) {
07052 variable schemes
07053 variable schemePattern
07054 variable url
07055 variable url2part
07056
07057 # Check scheme and its aliases for existence.
07058 foreach scheme $schemeList {
07059 if {[lsearch -exact $schemes $scheme] >= 0} {
07060 return -code error "trying to register scheme (\"$scheme\") which is already known"
07061 }
07062 }
07063
07064 # Get the main scheme
07065 set scheme [lindex $schemeList 0]
07066
07067 if {[catch {namespace eval $scheme $script} msg]} {
07068 catch {namespace delete $scheme}
07069 return -code error "error while evaluating scheme script: $msg"
07070 }
07071
07072 if {![info exists ${scheme}::schemepart]} {
07073 namespace delete $scheme
07074 return -code error "Variable \"schemepart\" is missing."
07075 }
07076
07077 # Now we can extend the variables which keep track of the registered schemes.
07078
07079 eval [linsert $schemeList 0 lappend schemes]
07080 set schemePattern "([::join $schemes |]):"
07081
07082 foreach s $schemeList {
07083 # FRINK: nocheck
07084 set url2part($s) "${s}:[set ${scheme}::schemepart]"
07085 # FRINK: nocheck
07086 append url "(${s}:[set ${scheme}::schemepart])|"
07087 }
07088 set url [string trimright $url |]
07089 return
07090 }
07091
07092 }
07093
07094 namespace ::uri {
07095
07096 ret {::uri::resolve} (type base , type url) {
07097 if {[string length $url]} {
07098 if {[isrelative $url]} {
07099
07100 array set baseparts [split $base]
07101
07102 switch -- $baseparts(scheme) {
07103 http -
07104 https -
07105 ftp -
07106 file {
07107 array set relparts [split $url]
07108 if { [string match /* $url] } {
07109 catch { set baseparts(path) $relparts(path) }
07110 } elseif { [string match */ $baseparts(path)] } {
07111 set baseparts(path) "$baseparts(path)$relparts(path)"
07112 } else {
07113 if { [string length $relparts(path)] > 0 } {
07114 set path [lreplace [::split $baseparts(path) /] end end]
07115 set baseparts(path) "[::join $path /]/$relparts(path)"
07116 }
07117 }
07118 catch { set baseparts(query) $relparts(query) }
07119 catch { set baseparts(fragment) $relparts(fragment) }
07120 return [eval [linsert [array get baseparts] 0 join]]
07121 }
07122 default {
07123 return -code error "unable to resolve relative URL \"$url\""
07124 }
07125 }
07126
07127 } else {
07128 return $url
07129 }
07130 } else {
07131 return $base
07132 }
07133 }
07134
07135 }
07136
07137 namespace ::uri {
07138
07139 ret {::uri::split} (type url , optional defaultscheme =http) {
07140 set url [string trim $url]
07141 set scheme {}
07142
07143 # RFC 1738: scheme = 1*[ lowalpha | digit | "+" | "-" | "." ]
07144 regexp -- {^([a-z0-9+.-][a-z0-9+.-]*):} $url dummy scheme
07145
07146 if {$scheme == {}} {
07147 set scheme $defaultscheme
07148 }
07149
07150 # ease maintenance: dynamic dispatch, able to handle all schemes
07151 # added in future!
07152
07153 if {[::info procs Split[string totitle $scheme]] == {}} {
07154 error "unknown scheme '$scheme' in '$url'"
07155 }
07156
07157 regsub -- "^${scheme}:" $url {} url
07158
07159 set parts(scheme) $scheme
07160 array set parts [Split[string totitle $scheme] $url]
07161
07162 # should decode all encoded characters!
07163
07164 return [array get parts]
07165 }
07166
07167 }
07168
07169 namespace ::xml {
07170
07171 ret {::xml::cl} (type x) {
07172 return "\[$x\]"
07173 }
07174
07175 }
07176
07177 namespace ::xml {
07178
07179 ret {::xml::qnamesplit} (type qname) {
07180 variable NCName
07181 variable Name
07182
07183 set prefix {}
07184 set localname $qname
07185 if {[regexp : $qname]} {
07186 if {![regexp ^($NCName)?:($NCName)\$ $qname discard prefix localname]} {
07187 return -code error "name \"$qname\" is not a valid QName"
07188 }
07189 } elseif {![regexp ^$Name\$ $qname]} {
07190 return -code error "name \"$qname\" is not a valid Name"
07191 }
07192
07193 return [list $prefix $localname]
07194 }
07195
07196 }
07197
07198 namespace ::xml::tclparser {
07199
07200 ret {::xml::tclparser::NormalizeAttValue} (type opts , type value) {
07201 # sgmlparser already has backslashes protected
07202 # Protect Tcl specials
07203 regsub -all {([][$])} $value {\\\1} value
07204
07205 # Deal with white space
07206 regsub -all "\[$::xml::Wsp\]" $value { } value
07207
07208 # Find entity refs
07209 regsub -all {&([^;]+);} $value {[NormalizeAttValue:DeRef $opts {\1}]} value
07210
07211 return [subst $value]
07212 }
07213
07214 }
07215
07216 namespace ::xml::tclparser {
07217
07218 ret {::xml::tclparser::NormalizeAttValue:DeRef} (type opts , type ref) {
07219 switch -glob -- $ref {
07220 #x* {
07221 scan [string range $ref 2 end] %x value
07222 set char [format %c $value]
07223 # Check that the char is legal for XML
07224 if {[regexp [format {^[%s]$} $::xml::Char] $char]} {
07225 return $char
07226 } else {
07227 return -code error "illegal character"
07228 }
07229 }
07230 #* {
07231 scan [string range $ref 1 end] %d value
07232 set char [format %c $value]
07233 # Check that the char is legal for XML
07234 if {[regexp [format {^[%s]$} $::xml::Char] $char]} {
07235 return $char
07236 } else {
07237 return -code error "illegal character"
07238 }
07239 }
07240 lt -
07241 gt -
07242 amp -
07243 quot -
07244 apos {
07245 array set map {lt < gt > amp & quot \" apos '}
07246 return $map($ref)
07247 }
07248 default {
07249 # A general entity. Must resolve to a text value - no element structure.
07250
07251 array set options $opts
07252 upvar #0 $options(entities) map
07253
07254 if {[info exists map($ref)]} {
07255
07256 if {[regexp < $map($ref)]} {
07257 return -code error "illegal character \"<\" in attribute value"
07258 }
07259
07260 if {![regexp & $map($ref)]} {
07261 # Simple text replacement
07262 return $map($ref)
07263 }
07264
07265 # There are entity references in the replacement text.
07266 # Can't use child entity parser since must catch element structures
07267
07268 return [NormalizeAttValue $opts $map($ref)]
07269
07270 } elseif {[string compare $options(-entityreferencecommand) "::sgml::noop"]} {
07271
07272 set result [uplevel #0 $options(-entityreferencecommand) [list $ref]]
07273
07274 return $result
07275
07276 } else {
07277 return -code error "unable to resolve entity reference \"$ref\""
07278 }
07279 }
07280 }
07281 }
07282
07283 }
07284
07285 namespace ::xml::tclparser {
07286
07287 ret {::xml::tclparser::ParseAttrs} (type opts , type attrs) {
07288 set result {}
07289
07290 while {[string length [string trim $attrs]]} {
07291 if {[regexp [::sgml::cl $::xml::Wsp]*($::xml::Name)[::sgml::cl $::xml::Wsp]*=[::sgml::cl $::xml::Wsp]*("|')([::sgml::cl ^<]*?)\\2(.*) $attrs discard attrName delimiter value attrs]} {
07292 lappend result $attrName [NormalizeAttValue $opts $value]
07293 } elseif {[regexp [::sgml::cl $::xml::Wsp]*$::xml::Name[::sgml::cl $::xml::Wsp]*=[::sgml::cl $::xml::Wsp]*("|')[::sgml::cl ^<]*\$ $attrs]} {
07294 return -code error [list {unterminated attribute value} $result $attrs]
07295 } else {
07296 return -code error "invalid attribute list"
07297 }
07298 }
07299
07300 return $result
07301 }
07302
07303 }
07304
07305 namespace ::xml::tclparser {
07306
07307 ret {::xml::tclparser::ParseEmpty} (type tag , type attr , type e) {
07308 switch -glob [string length $e],[regexp "/[::xml::cl $::xml::Wsp]*$" $attr] {
07309 0,0 {
07310 return {}
07311 }
07312 0,* {
07313 return /
07314 }
07315 default {
07316 return $e
07317 }
07318 }
07319 }
07320
07321 }
07322
07323 namespace ::xml::tclparser {
07324
07325 ret {::xml::tclparser::ParseEntity} (type data) {
07326 set data [string trim $data]
07327 if {[regexp $::sgml::ExternalEntityExpr $data discard type delimiter1 id1 discard delimiter2 id2 optNDATA ndata]} {
07328 switch $type {
07329 PUBLIC {
07330 return [list external $id2 $id1 $ndata]
07331 }
07332 SYSTEM {
07333 return [list external $id1 {} $ndata]
07334 }
07335 }
07336 } elseif {[regexp {^("|')(.*?)\1$} $data discard delimiter value]} {
07337 return [list internal $value]
07338 } else {
07339 return -code error "badly formed entity declaration"
07340 }
07341 }
07342
07343 }
07344
07345 namespace ::xml::tclparser {
07346
07347 ret {::xml::tclparser::configure} (type name , type args) {
07348 upvar \#0 [namespace current]::$name parser
07349
07350 # BUG: very crude, no checks for illegal args
07351 # Mats: Should be synced with sgmlparser.tcl
07352 set options {-elementstartcommand -elementendcommand -characterdatacommand -processinginstructioncommand -externalentitycommand -xmldeclcommand -doctypecommand -commentcommand -entitydeclcommand -unparsedentitydeclcommand -parameterentitydeclcommand -notationdeclcommand -elementdeclcommand -attlistdeclcommand -paramentityparsing -defaultexpandinternalentities -startdoctypedeclcommand -enddoctypedeclcommand -entityreferencecommand -warningcommand -defaultcommand -unknownencodingcommand -notstandalonecommand -startcdatasectioncommand -endcdatasectioncommand -errorcommand -final -validate -baseuri -baseurl -name -cmd -emptyelement -parseattributelistcommand -parseentitydeclcommand -normalize -internaldtd -dtdsubset -reportempty -ignorewhitespace -reportempty }
07353 set usage [join $options ", "]
07354 regsub -all -- - $options {} options
07355 set pat ^-([join $options |])$
07356 foreach {flag value} $args {
07357 if {[regexp $pat $flag]} {
07358 # Validate numbers
07359 if {[info exists parser($flag)] && [string is integer -strict $parser($flag)] && ![string is integer -strict $value]} {
07360 return -code error "Bad value for $flag ($value), must be integer"
07361 }
07362 set parser($flag) $value
07363 } else {
07364 return -code error "Unknown option $flag, can be: $usage"
07365 }
07366 }
07367
07368 # Backward-compatibility: -baseuri is a synonym for -baseurl
07369 catch {set parser(-baseuri) $parser(-baseurl)}
07370
07371 return {}
07372 }
07373
07374 }
07375
07376 namespace ::xml::tclparser {
07377
07378 ret {::xml::tclparser::create} (type name) {
07379 # Initialise state variable
07380 upvar \#0 [namespace current]::$name parser
07381 array set parser [list -name $name -cmd [uplevel 3 namespace current]::$name -final 1 -validate 0 -statevariable [namespace current]::$name -baseuri {} internaldtd {} entities [namespace current]::Entities$name extentities [namespace current]::ExtEntities$name parameterentities [namespace current]::PEntities$name externalparameterentities [namespace current]::ExtPEntities$name elementdecls [namespace current]::ElDecls$name attlistdecls [namespace current]::AttlistDecls$name notationdecls [namespace current]::NotDecls$name depth 0 leftover {} ]
07382
07383 # Initialise entities with predefined set
07384 array set [namespace current]::Entities$name [array get ::sgml::EntityPredef]
07385
07386 return $parser(-cmd)
07387 }
07388
07389 }
07390
07391 namespace ::xml::tclparser {
07392
07393 ret {::xml::tclparser::createentityparser} (type parent , type name) {
07394 upvar #0 [namespace current]::$parent p
07395
07396 # Initialise state variable
07397 upvar \#0 [namespace current]::$name external
07398 array set external [array get p]
07399
07400 regsub $parent $p(-cmd) {} parentns
07401
07402 array set external [list -name $name -cmd $parentns$name -statevariable [namespace current]::$name internaldtd {} line 0 ]
07403 incr external(depth)
07404
07405 return $external(-cmd)
07406 }
07407
07408 }
07409
07410 namespace ::xml::tclparser {
07411
07412 ret {::xml::tclparser::delete} (type name) {
07413 upvar \#0 [namespace current]::$name parser
07414 catch {::sgml::ParserDelete $parser(-statevariable)}
07415 catch {unset parser}
07416 return {}
07417 }
07418
07419 }
07420
07421 namespace ::xml::tclparser {
07422
07423 ret {::xml::tclparser::get} (type name , type method , type args) {
07424 upvar #0 [namespace current]::$name parser
07425
07426 switch -- $method {
07427
07428 elementdecl {
07429 switch [llength $args] {
07430
07431 0 {
07432 # Return all element declarations
07433 upvar #0 $parser(elementdecls) elements
07434 return [array get elements]
07435 }
07436
07437 1 {
07438 # Return specific element declaration
07439 upvar #0 $parser(elementdecls) elements
07440 if {[info exists elements([lindex $args 0])]} {
07441 return [array get elements [lindex $args 0]]
07442 } else {
07443 return -code error "element \"[lindex $args 0]\" not declared"
07444 }
07445 }
07446
07447 default {
07448 return -code error "wrong number of arguments: should be \"elementdecl ?element?\""
07449 }
07450 }
07451 }
07452
07453 attlist {
07454 if {[llength $args] != 1} {
07455 return -code error "wrong number of arguments: should be \"get attlist element\""
07456 }
07457
07458 upvar #0 $parser(attlistdecls)
07459
07460 return {}
07461 }
07462
07463 entitydecl {
07464 }
07465
07466 parameterentitydecl {
07467 }
07468
07469 notationdecl {
07470 }
07471
07472 default {
07473 return -code error "unknown method \"$method\""
07474 }
07475 }
07476
07477 return {}
07478 }
07479
07480 }
07481
07482 namespace ::xml::tclparser {
07483
07484 ret {::xml::tclparser::parse} (type name , type xml , type args) {
07485 array set options $args
07486 upvar \#0 [namespace current]::$name parser
07487 variable tokExpr
07488 variable substExpr
07489
07490 # Mats:
07491 if {[llength $args]} {
07492 eval {configure $name} $args
07493 }
07494
07495 set parseOptions [list -emptyelement [namespace code ParseEmpty] -parseattributelistcommand [namespace code ParseAttrs] -parseentitydeclcommand [namespace code ParseEntity] -normalize 0]
07496 eval lappend parseOptions [array get parser -*command] [array get parser -reportempty] [array get parser -ignorewhitespace] [array get parser -name] [array get parser -cmd] [array get parser -baseuri] [array get parser -validate] [array get parser -final] [array get parser -defaultexpandinternalentities] [array get parser entities] [array get parser extentities] [array get parser parameterentities] [array get parser externalparameterentities] [array get parser elementdecls] [array get parser attlistdecls] [array get parser notationdecls]
07497
07498 # Mats:
07499 # If -final 0 we also need to maintain the state with a -statevariable !
07500 if {!$parser(-final)} {
07501 eval lappend parseOptions [array get parser -statevariable]
07502 }
07503
07504 set dtdsubset no
07505 catch {set dtdsubset $options(-dtdsubset)}
07506 switch -- $dtdsubset {
07507 internal {
07508 # Bypass normal parsing
07509 lappend parseOptions -statevariable $parser(-statevariable)
07510 array set intOptions [array get ::sgml::StdOptions]
07511 array set intOptions $parseOptions
07512 ::sgml::ParseDTD:Internal [array get intOptions] $xml
07513 return {}
07514 }
07515 external {
07516 # Bypass normal parsing
07517 lappend parseOptions -statevariable $parser(-statevariable)
07518 array set intOptions [array get ::sgml::StdOptions]
07519 array set intOptions $parseOptions
07520 ::sgml::ParseDTD:External [array get intOptions] $xml
07521 return {}
07522 }
07523 default {
07524 # Pass through to normal processing
07525 }
07526 }
07527
07528 lappend tokenOptions -internaldtdvariable [namespace current]::${name}(internaldtd)
07529
07530 # Mats: If -final 0 we also need to maintain the state with a -statevariable !
07531 if {!$parser(-final)} {
07532 eval lappend tokenOptions [array get parser -statevariable] [array get parser -final]
07533 }
07534
07535 # Mats:
07536 # Why not the first four? Just padding? Lrange undos \n interp.
07537 # It is necessary to have the first four as well if chopped off in
07538 # middle of pcdata.
07539 set tokenised [lrange [eval {::sgml::tokenise $xml $tokExpr $substExpr} $tokenOptions] 0 end]
07540
07541 lappend parseOptions -internaldtd [list $parser(internaldtd)]
07542 eval ::sgml::parseEvent [list $tokenised] $parseOptions
07543
07544 return {}
07545 }
07546
07547 }
07548
07549 namespace ::xml::tclparser {
07550
07551 ret {::xml::tclparser::reset} (type name) {
07552 upvar \#0 [namespace current]::$name parser
07553
07554 # Has this parser object been properly initialised?
07555 if {![info exists parser] || ![info exists parser(-name)]} {
07556 return [create $name]
07557 }
07558
07559 array set parser {
07560 -final 1
07561 depth 0
07562 leftover {}
07563 }
07564
07565 foreach var {Entities ExtEntities PEntities ExtPEntities ElDecls AttlistDecls NotDecls} {
07566 catch {unset [namespace current]::${var}$name}
07567 }
07568
07569 # Initialise entities with predefined set
07570 array set [namespace current]::Entities$name [array get ::sgml::EntityPredef]
07571
07572 return {}
07573 }
07574
07575 }
07576
07577 namespace ::xml {
07578
07579 ret {::xml::zapWhite} (type data) {
07580 regsub -all "\[ \t\r\n\]+" $data { } data
07581 return $data
07582 }
07583
07584 }
07585
07586 ret {Draw_comm} (optional unitd =all) {
07587 # Raffiche les connexions d'un composant (entrantes ou sortantes)
07588 # ou toutes les connexions (unitd == "all")
07589
07590 #** global variables
07591 global liste_cnx_in dico_cnx_out dico_caract_cnx dico_units
07592 global viewcommcheck
07593 #** Variables specifiques pour le dessin
07594 global plot
07595 global coord_points_X coord_points_Y
07596
07597 global coordunit
07598 global DRAW
07599 global zoomfactor
07600
07601 set w $DRAW(window)
07602 set info .gui.pr.tools.infolabel
07603 set ray $DRAW(ray)
07604
07605 #================================================================
07606 #=== destruction des communications
07607 #================================================================
07608
07609 if {$unitd == "all"} {
07610 $w delete COMM_tag(all)
07611 $w dtag COMM_tag(all)
07612 } else {
07613 $w delete COMM_tag($unitd)
07614 $w dtag COMM_tag($unitd)
07615 }
07616 # S'il ne faut pas dessiner les connexions, c'est fini
07617 if {$viewcommcheck == 0} {return}
07618
07619 #================================================================
07620 #=== Etablissement de la liste des couples de composants
07621 #=== et établissement de la liste des communications de chaque couple
07622 #================================================================
07623
07624 set liste_couples {}
07625
07626 foreach clef_cnx $liste_cnx_in {
07627 set appli_source $dico_caract_cnx($clef_cnx.app_source)
07628 set appli_cible $dico_caract_cnx($clef_cnx.app_cible)
07629 set comp_source $dico_caract_cnx($clef_cnx.comp_source)
07630 set comp_cible $dico_caract_cnx($clef_cnx.comp_cible)
07631
07632 set clef_comp_source $appli_source.$comp_source
07633 set clef_comp_cible $appli_cible.$comp_cible
07634
07635 if {$unitd != "all"} {if {$unitd != $clef_comp_source && $unitd != $clef_comp_cible } {continue}}
07636
07637 # Si on n'a pas encore vu ce couple de composants
07638 if { ! [info exists nbcom_parcouple_unite($clef_comp_source.$clef_comp_cible)] } {
07639 # Ajoute le couple à la liste
07640 lappend liste_couples $clef_comp_source.$clef_comp_cible
07641 # Initialise le nb de comm total
07642 set nbcom_parcouple_unite($clef_comp_source.$clef_comp_cible) 0
07643 }
07644 # Ajoute la connexion à la liste pour ce couple
07645 lappend table_liste_cnx($clef_comp_source.$clef_comp_cible) $clef_cnx
07646 }
07647
07648 # Pour tous les couples d'unités
07649 foreach couple $liste_couples {
07650 # Compte le nombre total de connexions
07651 set nbcom_parcouple_unite($couple) [llength table_liste_cnx($couple)]
07652 }
07653
07654 #================================================================
07655 #=== établissement de la liste des paires de composants
07656 #=== et établissement de la liste des communications de chaque paire dans chaque sens (montant ou descendant)
07657 #================================================================
07658
07659 # Un couple : (a,b) est différent de (b,a)
07660 # Une paire : (a,b) similaire à (b,a)
07661 set liste_paires {}
07662
07663 # Pour tous les couples de composants
07664 foreach couple $liste_couples {
07665 # Si le couple n'a pas déjà été traité
07666 if { [info exists table_liste_cnx($couple)] } {
07667 # Enregistre la paire dans la liste
07668 lappend liste_paires $couple
07669
07670 # Crée la liste des connexions pour cette paire : cnx dans un sens et dans l'autre
07671 # ---------------------------------------------
07672
07673 # Regarde la première connexion
07674 set clef_cnx [lindex $table_liste_cnx($couple) 0]
07675 set appli_source $dico_caract_cnx($clef_cnx.app_source)
07676 set appli_cible $dico_caract_cnx($clef_cnx.app_cible)
07677 set comp_source $dico_caract_cnx($clef_cnx.comp_source)
07678 set comp_cible $dico_caract_cnx($clef_cnx.comp_cible)
07679 set clef_comp_source $appli_source.$comp_source
07680 set clef_comp_cible $appli_cible.$comp_cible
07681
07682 # Regarde quelle unité est le plus bas dans le graphe
07683 set y_source $dico_units($clef_comp_source.coor_y)
07684 set y_cible $dico_units($clef_comp_cible.coor_y)
07685
07686 # Si l'unité source est la plus haute
07687 if { $y_source < $y_cible } {
07688 # Mémorise le sens
07689 set sens descend
07690 set sens_inverse monte
07691 } else {
07692 set sens monte
07693 set sens_inverse descend
07694 }
07695 # Mémorise la liste des cnx dans une nouvelle table
07696 set liste_cnx($clef_comp_source.$clef_comp_cible.$sens) $table_liste_cnx($clef_comp_source.$clef_comp_cible)
07697 # Elimine la liste des cnx dans ce sens
07698 unset table_liste_cnx($clef_comp_source.$clef_comp_cible)
07699
07700 # S'il existe des connexions dans l'autre sens
07701 if { [info exists table_liste_cnx($clef_comp_cible.$clef_comp_source)] } {
07702 # Mémorise la liste des cnx dans une nouvelle table
07703 set liste_cnx($clef_comp_source.$clef_comp_cible.$sens_inverse) $table_liste_cnx($clef_comp_cible.$clef_comp_source)
07704 # Elimine la liste des cnx dans le sens inverse
07705 unset table_liste_cnx($clef_comp_cible.$clef_comp_source)
07706 } else {
07707 # Aucune connexion dans l'autre sens
07708 set liste_cnx($clef_comp_source.$clef_comp_cible.$sens_inverse) {}
07709 }
07710 }
07711 }
07712 array unset table_liste_cnx
07713
07714 #================================================================
07715 # Determine le point milieu de chaque fil de communication
07716 #================================================================
07717
07718 # Pour toutes les paires d'unités
07719 foreach paire $liste_paires {
07720 # 1ère étape : étudier l'espace total occcupé par tous les points milieu
07721 # ----------------------------------------------------------------------
07722
07723 # Détermine le nombre max de pictogrammes de transformations dans chaque sens
07724 set nbmax_transfo(descend) 0
07725 set nbmax_transfo(monte) 0
07726
07727 # Pour les sens montant et descendant
07728 foreach sens {monte descend} {
07729 # Nombre de connexions dans ce sens entre les deux composants de la paire
07730 set nb_cnx($sens) [llength $liste_cnx($paire.$sens)]
07731
07732 # Pour toutes les connexions dans ce sens entre les deux composants de la paire
07733 foreach clef_cnx $liste_cnx($paire.$sens) {
07734 # Transformations de la connexions
07735 set src_time_op $dico_caract_cnx($clef_cnx.src_time_op)
07736 set src_add_val $dico_caract_cnx($clef_cnx.src_add_val)
07737 set src_mult_val $dico_caract_cnx($clef_cnx.src_mult_val)
07738 set tgt_time_op $dico_caract_cnx($clef_cnx.tgt_time_op)
07739 set tgt_add_val $dico_caract_cnx($clef_cnx.tgt_add_val)
07740 set tgt_mult_val $dico_caract_cnx($clef_cnx.tgt_mult_val)
07741 set remail $dico_caract_cnx($clef_cnx.remail)
07742
07743 # Détermine la liste des pictogrammes de transformations
07744 # dans l'ordre où elles sont effectivement appliquées :
07745 # -1- source local transf. -2- middle transf. -3- target local transf.
07746
07747 set liste_transfo($clef_cnx) {}
07748 if { $src_add_val != 0 } { lappend liste_transfo($clef_cnx) add }
07749 if { $src_mult_val != 1 } { lappend liste_transfo($clef_cnx) multiply }
07750 switch $src_time_op {
07751 taverage {lappend liste_transfo($clef_cnx) average}
07752 accumul {lappend liste_transfo($clef_cnx) accumulate}
07753 }
07754 if { $remail != "" } { lappend liste_transfo($clef_cnx) remaillage }
07755 if { $tgt_time_op == "time_linear"} { lappend liste_transfo($clef_cnx) interpol }
07756 if { $tgt_add_val != 0 } { lappend liste_transfo($clef_cnx) add }
07757 if { $tgt_mult_val != 1 } { lappend liste_transfo($clef_cnx) multiply }
07758 # Calcule le nombre total de pictogrammes de transformations
07759 set nb_transfo($clef_cnx) [llength $liste_transfo($clef_cnx)]
07760
07761 # Détermine le nombre max de pictogrammes de transformations dans chaque sens
07762 if { $nb_transfo($clef_cnx) > $nbmax_transfo($sens) } {
07763 set nbmax_transfo($sens) $nb_transfo($clef_cnx)
07764 }
07765 }
07766 }
07767
07768 # Les pictogrammes de transformations des cnx descendantes sont alignés horizontalement
07769 # Ceux des connexions montantes sont alignés verticalement
07770
07771 # Hauteur totale de la zone des points milieu :
07772 # hauteur des pictogrm alignés verticalement plus nbre de lignes
07773 set hauteur [expr ($nbmax_transfo(monte) + $nb_cnx(descend)) * 30]
07774 # Largeur totale de la zone des points milieu
07775 # largeur des pictogrm alignés horizontalement plus nbre de colonnes
07776 set largeur [expr ($nbmax_transfo(descend) + $nb_cnx(monte)) * 25]
07777 # 30 et 25 pixels sont les dimensions d'un pictogramme
07778
07779 # 2ème étape : définir la position de tous les points milieu
07780 # ----------------------------------------------------------
07781
07782 # Indicateur d'initialisation
07783 set initial 1
07784
07785 # Pour toutes les connexions descendantes entre les deux composants de la paire
07786 foreach clef_cnx $liste_cnx($paire.descend) {
07787
07788 # Si première cnx de la liste
07789 if { $initial } {
07790 set initial 0
07791
07792 # Lit les données de la connexion
07793 set appli_source $dico_caract_cnx($clef_cnx.app_source)
07794 set appli_cible $dico_caract_cnx($clef_cnx.app_cible)
07795 set comp_source $dico_caract_cnx($clef_cnx.comp_source)
07796 set comp_cible $dico_caract_cnx($clef_cnx.comp_cible)
07797 set clef_comp_source $appli_source.$comp_source
07798 set clef_comp_cible $appli_cible.$comp_cible
07799
07800 # Si un des deux composants est rétréci
07801 if { $dico_units($clef_comp_source.expand) == 0
07802 || $dico_units($clef_comp_cible.expand) == 0} {
07803 # Rien à calculer car on ne dessinera pas les connexions une à une
07804 break;
07805 }
07806 # Détermine le milieu du composant source
07807 set mil_source_x [expr $dico_units($clef_comp_source.coor_x) + $dico_units($clef_comp_source.largeur) / 2]
07808 set mil_source_y [expr $dico_units($clef_comp_source.coor_y) + $DRAW(heigthunit) / 2]
07809 # Détermine le milieu du composant cible
07810 set mil_cible_x [expr $dico_units($clef_comp_cible.coor_x) + $dico_units($clef_comp_cible.largeur) / 2]
07811 set mil_cible_y [expr $dico_units($clef_comp_cible.coor_y) + $DRAW(heigthunit) / 2]
07812
07813 # Détermine le milieu géométrique entre les deux composants
07814 set milieu_comp_x [expr ($mil_source_x + $mil_cible_x) / 2]
07815 set milieu_comp_y [expr ($mil_source_y + $mil_cible_y) / 2]
07816
07817 # Ordonnée du point milieu pour la 1ère connexion : tout en haut
07818 # mais en dessous des pictogrammes des connexions montantes
07819 set point_milieu_y [expr round( $milieu_comp_y - ($hauteur - 30) / 2 + 30 * $nbmax_transfo(monte) )]
07820 # Abscisse du point milieu pour toutes les connexions descendantes : à gauche des connexions montantes
07821 set point_milieu_x_general [expr round( $milieu_comp_x + ($largeur - 25) / 2 - 25 * $nb_cnx(monte) )]
07822 }
07823
07824 # Abscisse du point milieu pour cette connexion : à gauche du point milieu general
07825 set point_milieu_x [expr round( $point_milieu_x_general - 25 * $nb_transfo($clef_cnx) / 2 )]
07826
07827 # Mémorise les coordonnées du point milieu de la cnx
07828 set table_points_milieu($clef_cnx.x) $point_milieu_x
07829 set table_points_milieu($clef_cnx.y) $point_milieu_y
07830
07831 # Calcule l'ordonnée du point milieu pour la connexion suivante
07832 incr point_milieu_y 30
07833 }
07834
07835 # Indicateur d'initialisation
07836 set initial 1
07837
07838 # Pour toutes les connexions montantes entre les deux composants de la paire
07839 foreach clef_cnx $liste_cnx($paire.monte) {
07840
07841 # Si première cnx de la liste
07842 if { $initial } {
07843 set initial 0
07844
07845 # Lit les données de la connexion
07846 set appli_source $dico_caract_cnx($clef_cnx.app_source)
07847 set appli_cible $dico_caract_cnx($clef_cnx.app_cible)
07848 set comp_source $dico_caract_cnx($clef_cnx.comp_source)
07849 set comp_cible $dico_caract_cnx($clef_cnx.comp_cible)
07850 set clef_comp_source $appli_source.$comp_source
07851 set clef_comp_cible $appli_cible.$comp_cible
07852
07853 # Si un des deux composants est rétréci
07854 if { $dico_units($clef_comp_source.expand) == 0
07855 || $dico_units($clef_comp_cible.expand) == 0} {
07856 # Rien à calculer car on ne dessinera pas les connexions une à une
07857 break;
07858 }
07859 # Détermine le milieu du composant source
07860 set mil_source_x [expr $dico_units($clef_comp_source.coor_x) + $dico_units($clef_comp_source.largeur) / 2]
07861 set mil_source_y [expr $dico_units($clef_comp_source.coor_y) + $DRAW(heigthunit) / 2]
07862 # Détermine le milieu du composant cible
07863 set mil_cible_x [expr $dico_units($clef_comp_cible.coor_x) + $dico_units($clef_comp_cible.largeur) / 2]
07864 set mil_cible_y [expr $dico_units($clef_comp_cible.coor_y) + $DRAW(heigthunit) / 2]
07865
07866 # Détermine le milieu géométrique entre les deux composants
07867 set milieu_comp_x [expr ($mil_source_x + $mil_cible_x) / 2]
07868 set milieu_comp_y [expr ($mil_source_y + $mil_cible_y) / 2]
07869
07870 # Abscisse du point milieu pour la 1ère connexion : tout à fait à gauche
07871 # mais à droite des pictogrammes des connexions descendantes
07872 set point_milieu_x [expr round( $milieu_comp_x - ($largeur - 25) / 2 + 25 * $nbmax_transfo(descend))]
07873 # Ordonnée du point milieu pour toutes les connexions montantes : au dessus des connexions descendantes
07874 set point_milieu_y_general [expr round( $milieu_comp_y + ($hauteur - 30) / 2 - 30 * $nb_cnx(descend) )]
07875 }
07876
07877 # Ordonnée du point milieu pour cette connexion : au dessous du point milieu general
07878 set point_milieu_y [expr round( $point_milieu_y_general - 30 * $nb_transfo($clef_cnx) / 2 )]
07879
07880 # Mémorise les coordonnées du point milieu de la cnx
07881 set table_points_milieu($clef_cnx.x) $point_milieu_x
07882 set table_points_milieu($clef_cnx.y) $point_milieu_y
07883
07884 # Calcule l'abscisse du point milieu pour la connexion suivante
07885 incr point_milieu_x 25
07886 }
07887
07888 }
07889
07890 #================================================================
07891 #=== affichage des communications
07892 #================================================================
07893
07894 # Pour toutes les paires de composants
07895 foreach paire $liste_paires {
07896
07897 # Pour les sens montant et descendant
07898 foreach sens {monte descend} {
07899 # Pour toutes les connexions entre les deux composants de la paire
07900 foreach clef_cnx $liste_cnx($paire.$sens) {
07901
07902 set appli_source $dico_caract_cnx($clef_cnx.app_source)
07903 set appli_cible $dico_caract_cnx($clef_cnx.app_cible)
07904 set comp_source $dico_caract_cnx($clef_cnx.comp_source)
07905 set comp_cible $dico_caract_cnx($clef_cnx.comp_cible)
07906 set clef_comp_source $appli_source.$comp_source
07907 set clef_comp_cible $appli_cible.$comp_cible
07908
07909 # Determine la clef des points de couplage source et cible
07910 set champ_source $dico_caract_cnx($clef_cnx.champ_source)
07911 set champ_cible $dico_caract_cnx($clef_cnx.champ_cible)
07912 set clef_point_source $clef_comp_source.$champ_source.o
07913 set clef_point_cible $clef_comp_cible.$champ_cible.i
07914
07915 # Si un des deux composants est rétréci
07916 if { $dico_units($clef_comp_source.expand) == 0
07917 || $dico_units($clef_comp_cible.expand) == 0} {
07918
07919 # Si les deux composants sont rétrécis
07920 if { $dico_units($clef_comp_source.expand) == 0
07921 && $dico_units($clef_comp_cible.expand) == 0} {
07922
07923 set x1 [expr $coord_points_X($clef_point_source)+$dico_units($clef_comp_source.coor_x)]
07924 set y1 [expr $coord_points_Y($clef_point_source)+$ray+$dico_units($clef_comp_source.coor_y)]
07925 set x2 [expr $coord_points_X($clef_point_cible)+$dico_units($clef_comp_cible.coor_x)]
07926 set y2 [expr $coord_points_Y($clef_point_cible)-$ray+$dico_units($clef_comp_cible.coor_y)]
07927 if {$y1 < $y2 } {
07928 set x3 [expr $x1+($x2-$x1)/10 ]
07929 set x4 [expr $x2-($x2-$x1)/10 ]
07930 set y3 [expr $y1+($y2-$y1)/10 +12]
07931 set y4 [expr $y2-($y2-$y1)/10 -12]
07932 set midleX [expr $x3+($x4-$x3)/3]
07933 set midleY [expr $y3+($y4-$y3)/3]
07934 } else {
07935 set midleX [expr ($x1+$x2)/2]
07936 set midleY [expr ($y1+$y2)/2]
07937 }
07938 if {[distming $x1 $y1 $x2 $y2]} {
07939 set itemcom [$w create line [chemin $x1 $y1 $x2 $y2] -smooth 1 -fill grey80 -width 3]
07940 $w addtag COMM_tag(all) withtag $itemcom
07941 $w addtag COMM_tag($clef_comp_source) withtag $itemcom
07942 $w addtag COMM_tag($clef_comp_cible) withtag $itemcom
07943 set itemcom [$w create rectangle [expr $midleX-8] [expr $midleY-6] [expr $midleX+8] [expr $midleY+5] -fill white -outline white ]
07944 $w addtag COMM_tag(all) withtag $itemcom
07945 $w addtag COMM_tag($clef_comp_source) withtag $itemcom
07946 $w addtag COMM_tag($clef_comp_cible) withtag $itemcom
07947 set itemcom [$w create text $midleX $midleY -text "$nbcom_parcouple_unite($clef_comp_source.$clef_comp_cible)" -font {helvetica -10 bold} -fill black ]
07948 $w addtag COMM_tag(all) withtag $itemcom
07949 $w addtag COMM_tag($clef_comp_source) withtag $itemcom
07950 $w addtag COMM_tag($clef_comp_cible) withtag $itemcom
07951 }
07952 } else {
07953
07954 # Un seul des deux composants est rétréci
07955 # --> on n'affiche aucun fil de connexion
07956 }
07957 # Ne traite pas les autres cnx de la paire
07958 break
07959
07960 } else {
07961 # Aucun des deux composants n'est rétréci
07962 #=====affichage liaison
07963
07964 #===type de trait
07965 set dash {2 2}
07966 #===epaisseur
07967 set wid 1
07968 #====couleur
07969 set colorcom [color_rgb 128 80 0]
07970
07971 # Point de départ de la liaison
07972 set x1 [expr $coord_points_X($clef_point_source)+$dico_units($clef_comp_source.coor_x)]
07973 set y1 [expr $coord_points_Y($clef_point_source)+$ray+$dico_units($clef_comp_source.coor_y)]
07974
07975 # Point d'arrivée
07976 set x2 [expr $coord_points_X($clef_point_cible)+$dico_units($clef_comp_cible.coor_x)]
07977 set y2 [expr $coord_points_Y($clef_point_cible)-$ray+$dico_units($clef_comp_cible.coor_y)]
07978
07979 # Si liaison entre deux points du même composant
07980 if {$clef_comp_source == $clef_comp_cible} {
07981 set itemcom [$w create line $x1 [expr $y1-2*$ray] $x2 [expr $y2+2*$ray] -fill $colorcom -width $wid -dash $dash]
07982 $w addtag COMM_tag(all) withtag $itemcom
07983 $w addtag COMM_tag($clef_comp_source) withtag $itemcom
07984 $w addtag COMM_tag($clef_comp_cible) withtag $itemcom
07985 $w addtag tag_connexions($clef_cnx) withtag $itemcom
07986 $w addtag tag_fils_connexions($clef_cnx) withtag $itemcom
07987
07988 } else {
07989
07990 # Si la distance entre le départ et l'arrivée n'est pas trop grande
07991 if {[distmin $x1 $y1 $x2 $y2]} {
07992
07993 # Si la cnx a des transformations
07994 if { $nb_transfo($clef_cnx) != "0" } {
07995 # Affiche la liaison en deux morceaux :
07996 # 1 : du composant source au point milieu
07997 # 2 : du point milieu au composant cible
07998
07999 # Si on va de source dessus à cible dessous
08000 # if $y2 > $y1
08001 if { $dico_units($clef_comp_source.coor_y) < $dico_units($clef_comp_cible.coor_y) } {
08002 # On traverse le point milieu par l'horizontale
08003 # demi-largeur de l'ensemble des pictogrammes des transformations
08004 set demi_largeur [expr 25 * $nb_transfo($clef_cnx) / 2]
08005 set agauche_milieu_x [expr $table_points_milieu($clef_cnx.x) - $demi_largeur]
08006 set adroite_milieu_x [expr $table_points_milieu($clef_cnx.x) + $demi_largeur]
08007 # Si on va de gauche à droite
08008 if { $x1 < $x2 } {
08009 set cote_approche gauche
08010 set avant_milieu_x $agauche_milieu_x
08011 set apres_milieu_x $adroite_milieu_x
08012 } else {
08013 set cote_approche droit
08014 set avant_milieu_x $adroite_milieu_x
08015 set apres_milieu_x $agauche_milieu_x
08016 }
08017 set avant_milieu_y $table_points_milieu($clef_cnx.y)
08018 set apres_milieu_y $table_points_milieu($clef_cnx.y)
08019 } else {
08020 set cote_approche bas
08021 # On traverse le point milieu par la verticale (et par dessous)
08022 # demi-hauteur de l'ensemble des pictogrammes des transformations
08023 set demi_hauteur [expr 30 * $nb_transfo($clef_cnx) / 2]
08024 set avant_milieu_y [expr $table_points_milieu($clef_cnx.y) + $demi_hauteur]
08025 set apres_milieu_y [expr $table_points_milieu($clef_cnx.y) - $demi_hauteur]
08026
08027 set avant_milieu_x $table_points_milieu($clef_cnx.x)
08028 set apres_milieu_x $table_points_milieu($clef_cnx.x)
08029 }
08030
08031 # 1er morceau : du composant source au point milieu
08032 # ----------------------------------------------------
08033
08034 set demi_chemin [demi_chemin_1 $x1 $y1 $avant_milieu_x $avant_milieu_y $cote_approche $clef_comp_source]
08035 set itemcom [$w create line $demi_chemin -smooth 1 -fill $colorcom -width $wid -dash $dash]
08036 $w addtag COMM_tag(all) withtag $itemcom
08037 $w addtag COMM_tag($clef_comp_source) withtag $itemcom
08038 $w addtag COMM_tag($clef_comp_cible) withtag $itemcom
08039 $w addtag tag_connexions($clef_cnx) withtag $itemcom
08040 $w addtag tag_fils_connexions($clef_cnx) withtag $itemcom
08041
08042 # 2ème morceau : du point milieu au composant cible
08043 # ----------------------------------------------------
08044
08045 set demi_chemin [demi_chemin_2 $apres_milieu_x $apres_milieu_y $x2 $y2 $cote_approche $clef_comp_cible]
08046 set itemcom [$w create line $demi_chemin -smooth 1 -fill $colorcom -width $wid -dash $dash]
08047 $w addtag COMM_tag(all) withtag $itemcom
08048 $w addtag COMM_tag($clef_comp_source) withtag $itemcom
08049 $w addtag COMM_tag($clef_comp_cible) withtag $itemcom
08050 $w addtag tag_connexions($clef_cnx) withtag $itemcom
08051 $w addtag tag_fils_connexions($clef_cnx) withtag $itemcom
08052
08053 # 3eme : Affiche les symboles (pictogrammes) des transformations
08054 # --------------------------------------------------------------
08055
08056 # Si la connexion est "montante"
08057 if { $cote_approche == "bas" } {
08058 # Dispose les pictogrammes sur une colonne en partant du bas
08059 set offset_1ere_tranfo_y [expr 30 * ($nb_transfo($clef_cnx) - 1) / 2]
08060 set pos_tranfo_y [expr $table_points_milieu($clef_cnx.y) + $offset_1ere_tranfo_y]
08061 set increment_y -30
08062 set pos_tranfo_x $table_points_milieu($clef_cnx.x)
08063 set increment_x 0
08064 } else {
08065 # Dispose les pictogrammes sur une ligne
08066 set offset_1ere_tranfo_x [expr 25 * ($nb_transfo($clef_cnx) - 1) / 2]
08067 # Si on va de source à gauche à cible à droite
08068 if { $x1 < $x2 } {
08069 # Dispose les pictogrammes sur une ligne en partant de la gauche
08070 set pos_tranfo_x [expr $table_points_milieu($clef_cnx.x) - $offset_1ere_tranfo_x]
08071 set increment_x 25
08072 } else {
08073 # Dispose les pictogrammes sur une ligne en partant de la droite
08074 set pos_tranfo_x [expr $table_points_milieu($clef_cnx.x) + $offset_1ere_tranfo_x]
08075 set increment_x -25
08076 }
08077 set pos_tranfo_y $table_points_milieu($clef_cnx.y)
08078 set increment_y 0
08079 }
08080
08081 # Pour toutes les tranformations existantes
08082 foreach transfo $liste_transfo($clef_cnx) {
08083 # Met un pictogramme dans le graphe
08084 set itemcom [$w create image $pos_tranfo_x $pos_tranfo_y -image img_$transfo]
08085 $w addtag COMM_tag(all) withtag $itemcom
08086 $w addtag COMM_tag($clef_comp_source) withtag $itemcom
08087 $w addtag COMM_tag($clef_comp_cible) withtag $itemcom
08088 $w addtag tag_connexions($clef_cnx) withtag $itemcom
08089 # Calcule les coordonnées de la transfo suivante
08090 incr pos_tranfo_x $increment_x
08091 incr pos_tranfo_y $increment_y
08092 }
08093 } else {
08094 # S'il y a au moins un pictogramme de transformation dans ce sens
08095 if { $nbmax_transfo($sens) > 0 } {
08096 # Affiche la liaison en un seul morceau forcé de passer par le point milieu
08097 set milieu_x $table_points_milieu($clef_cnx.x)
08098 set milieu_y $table_points_milieu($clef_cnx.y)
08099 set itemcom [$w create line [chemin_force $x1 $y1 $x2 $y2 $milieu_x $milieu_y] -smooth 1 -fill $colorcom -width $wid -dash $dash]
08100 } else {
08101 # Affiche la liaison en un seul morceau
08102 set itemcom [$w create line [chemin $x1 $y1 $x2 $y2] -smooth 1 -fill $colorcom -width $wid -dash $dash]
08103 }
08104 $w addtag COMM_tag(all) withtag $itemcom
08105 $w addtag COMM_tag($clef_comp_source) withtag $itemcom
08106 $w addtag COMM_tag($clef_comp_cible) withtag $itemcom
08107 $w addtag tag_connexions($clef_cnx) withtag $itemcom
08108 $w addtag tag_fils_connexions($clef_cnx) withtag $itemcom
08109 }
08110
08111 } else {
08112 # Les deux composants sont trop éloignés l'un de l'autre
08113 # On trace juste le départ et l'arrivée de la liaison : le milieu est caché
08114
08115 set itemcom [$w create line $x1 $y1 $x1 [expr $y1+20] -fill $colorcom -width $wid -dash $dash]
08116 $w addtag COMM_tag(all) withtag $itemcom
08117 $w addtag COMM_tag($clef_comp_source) withtag $itemcom
08118 $w addtag COMM_tag($clef_comp_cible) withtag $itemcom
08119 $w addtag tag_connexions($clef_cnx) withtag $itemcom
08120 $w addtag tag_fils_connexions($clef_cnx) withtag $itemcom
08121 set itemcom [$w create line $x2 $y2 $x2 [expr $y2-20] -fill $colorcom -width $wid -dash $dash]
08122 $w addtag COMM_tag(all) withtag $itemcom
08123 $w addtag COMM_tag($clef_comp_source) withtag $itemcom
08124 $w addtag COMM_tag($clef_comp_cible) withtag $itemcom
08125 $w addtag tag_connexions($clef_cnx) withtag $itemcom
08126 $w addtag tag_fils_connexions($clef_cnx) withtag $itemcom
08127 # Le fil central qui relie les deux extrémités est caché
08128 # Il n'est révélé que lorsque la souris survole l'une des extrémité
08129 set itemcom [$w create line $x1 [expr $y1+20] $x2 [expr $y2-20] -fill $colorcom -width $wid -dash $dash -state hidden]
08130 $w addtag COMM_tag(all) withtag $itemcom
08131 $w addtag COMM_tag($clef_comp_source) withtag $itemcom
08132 $w addtag COMM_tag($clef_comp_cible) withtag $itemcom
08133 $w addtag tag_fils_connexions($clef_cnx) withtag $itemcom
08134 $w addtag liaison($clef_cnx) withtag $itemcom
08135 }
08136 }
08137 #=====bind evenements comm
08138 $w bind tag_connexions($clef_cnx) <Any-Enter> " $w itemconfigure liaison($clef_cnx) -state normal ;help_communication %X %Y $clef_cnx
08139 $info configure -text {Double click to edit the connection}"
08140 $w bind tag_connexions($clef_cnx) <Any-Leave> " $w itemconfigure liaison($clef_cnx) -state hidden ;help_object_hide
08141 $info configure -text {}"
08142 $w bind tag_connexions($clef_cnx) <Button-1> " minimenu_comm $clef_cnx"
08143 $w bind tag_connexions($clef_cnx) <Double-Button-1> "control_edit_entity"
08144 $w bind tag_connexions($clef_cnx) <Key-Delete> "control_delete_entity"
08145 }
08146 }
08147 }
08148 }
08149
08150 #-------------------------------------
08151 #** zoom
08152 #-------------------------------------
08153 if {$unitd == "all"} {
08154 $w scale COMM_tag(all) 0 0 $zoomfactor $zoomfactor
08155 } else {
08156 $w scale COMM_tag($unitd) 0 0 $zoomfactor $zoomfactor
08157 }
08158 }
08159
08160 ret {Draw_drawunit} () {
08161 #
08162 global dico_applis liste_fichiers
08163 #** Variables specifiques pour le dessin
08164 global DRAW
08165
08166 # Efface toutes les unités affichées
08167 set w $DRAW(window)
08168 $w delete UNIT_tag(all)
08169 $w dtag UNIT_tag(all)
08170
08171 # Détermine la liste des applications chargées en mémoire
08172 set liste_applis ""
08173 catch {set liste_applis $dico_applis(lapplis)}
08174 # Pour toutes les applications chargées en mémoire
08175 foreach nom_appli $liste_applis {
08176 # Pour tous les composants de cette application
08177 foreach nom_composant $dico_applis(app.$nom_appli.lcomp) {
08178 Draw_one_unit $nom_appli.$nom_composant
08179 }
08180 }
08181
08182 # Pour tous les fichiers
08183 foreach id_fichier $liste_fichiers {
08184 Draw_one_unit
08185 }
08186
08187 return
08188 }
08189
08190 ret {Draw_one_unit} (type clef_, type unit) {
08191 # affiche une unité dans le canvas
08192 # clef_unit :
08193 # - si c'est un composant d'application : clef du composant, composée ainsi <nom_application>.<nom_composant>
08194 # - si c'est un fichier NetCDF : clef du fichier, composée ainsi
08195 #
08196 # gere les procedures d'evenement
08197
08198 global dico_applis dico_caract_fichiers
08199 global dico_units
08200 global liste_points_i liste_points_o
08201 global dico_caract_points
08202
08203 global coord_points_X coord_points_Y
08204 global plot
08205
08206 # Renomme le paramètre
08207 set i $clef_unit
08208
08209 #** Variables specifiques pour le dessin
08210 global DRAW
08211 global zoomfactor
08212 set w $DRAW(window)
08213 set ray $DRAW(ray)
08214 set info .gui.pr.tools.infolabel
08215
08216 $w delete UNIT_tag($i)
08217 $w dtag UNIT_tag($i)
08218 $w delete UNIT_texttag($i)
08219 $w dtag UNIT_texttag($i)
08220 $w delete UNIT_expand_tag($i)
08221 $w dtag UNIT_expand_tag($i)
08222
08223 #================================================================
08224 #=== affichage des unites
08225 #================================================================
08226 #================================================================
08227 set id_unit $dico_units($i)
08228 # Extrait de la clef le nom de l'appli
08229 set len_unit [string length $id_unit]
08230 incr len_unit
08231 set nom_appli [string range $i 0 end-$len_unit]
08232
08233 # S'il s'agit d'un fichier NetCDF
08234 if { $nom_appli == "///file///" } {
08235 set si_fichier 1
08236 set id_fichier $id_unit
08237 # Le nom du fichier
08238 set nom_unit $dico_caract_fichiers($id_fichier.name)
08239 set nom_long_unit ""
08240
08241 # il s'agit d'un composant d'une application
08242 } else {
08243 set si_fichier 0
08244 # Nom du composant
08245 set nom_unit $id_unit
08246 # Clef d'acces au composant dans le dictionnaire dico_applis
08247 set clef_comp_2 app.$nom_appli.comp.$nom_unit
08248 # Nom long du composant
08249 set nom_long_unit ""
08250 catch {set nom_long_unit $dico_applis($clef_comp_2.long_name)}
08251 }
08252
08253 # Titres de l'unité à afficher
08254 set text1 $nom_unit
08255 if { [string length $text1] > 20 } {
08256 set text1 [string range $text1 0 20]
08257 set text1 "$text1..."
08258 }
08259 set text2 $nom_long_unit
08260 if { [string length $text2] > 30 } {
08261 set text2 [string range $text2 0 30]
08262 set text2 "$text2..."
08263 }
08264
08265 set coor_x $dico_units($i.coor_x)
08266 set coor_y $dico_units($i.coor_y)
08267
08268 # Nombre de points en entrée et en sortie de l'unité
08269 set liste_clefs_points_i [lsearch -glob -all -inline $liste_points_i "$i.*"]
08270 set liste_clefs_points_o [lsearch -glob -all -inline $liste_points_o "$i.*"]
08271 set nbget [llength $liste_clefs_points_i]
08272 set nbput [llength $liste_clefs_points_o]
08273
08274 #== calcul largeur boite
08275 set nbb $nbput
08276 if {$nbget > $nbb} {set nbb $nbget}
08277 set widthtot [expr ($nbb + 2) * $DRAW(widthcombox)]
08278 set wrefp [expr $nbput * $DRAW(widthcombox)]
08279 set wrefg [expr $nbget * $DRAW(widthcombox)]
08280 if {$widthtot < $DRAW(widthminunit)} {set widthtot $DRAW(widthminunit)}
08281 set widthtex [expr [string length $text1] *8]
08282 if {$widthtot < $widthtex} {set widthtot $widthtex}
08283 set widthtex [expr [string length $text2] *6]
08284 if {$widthtot < $widthtex} {set widthtot $widthtex}
08285
08286 # Mémorise la largeur de la boite
08287 set dico_units($i.largeur) $widthtot
08288 if { $si_fichier } {
08289 # Tient compte des deux bords verticaux de la boite
08290 set widthtot [expr $widthtot + 2 * $DRAW(hcont)]
08291 }
08292 set midle_x [expr $coor_x + $widthtot/2]
08293
08294 #===couleurs de l'unité
08295 set colorunit $dico_units($i.colour)
08296 set colortext [color_white_or_black $colorunit]
08297 set pastel [color_pastelise $colorunit]
08298 set fonce [color_fonce $colorunit]
08299
08300
08301 #===boite extérieure
08302
08303 # Si c'est un fichier NetCDF
08304 if { $si_fichier } {
08305 # Dessine deux bandes verticales à gauche et à droite du rectangle principal
08306 set hauteur [expr $DRAW(heigthunit) + 2 * $DRAW(hcont)]
08307 set bord_gauche [$w create rectangle $coor_x $coor_y [expr $coor_x + $DRAW(hcont)] [expr $coor_y + $hauteur] -fill $pastel -outline $pastel]
08308 $w addtag unitpoint($i) withtag $bord_gauche
08309 $w addtag UNIT_tag($i) withtag $bord_gauche
08310 $w addtag UNIT_tag(all) withtag $bord_gauche
08311 set bord_droit [$w create rectangle [expr $coor_x + $widthtot - $DRAW(hcont)] $coor_y [expr $coor_x + $widthtot] [expr $coor_y + $hauteur] -fill $pastel -outline $pastel]
08312 $w addtag unitpoint($i) withtag $bord_droit
08313 $w addtag UNIT_tag($i) withtag $bord_droit
08314 $w addtag UNIT_tag(all) withtag $bord_droit
08315 } else {
08316 # Dessine deux bandes horizontales au dessus et dessous du rectangle principal
08317 set containerput [$w create rectangle $coor_x [expr $coor_y + $DRAW(heigthunit) + $DRAW(hcont)] [expr $coor_x + $widthtot] [expr $coor_y + $DRAW(heigthunit) + 2*$DRAW(hcont)] -fill $pastel -outline $pastel]
08318 $w addtag unitpoint($i) withtag $containerput
08319 $w addtag UNIT_tag($i) withtag $containerput
08320 $w addtag UNIT_tag(all) withtag $containerput
08321 set containerget [$w create rectangle $coor_x $coor_y [expr $coor_x + $widthtot] [expr $coor_y + $DRAW(hcont)] -fill $pastel -outline $pastel]
08322 $w addtag unitpoint($i) withtag $containerget
08323 $w addtag UNIT_tag($i) withtag $containerget
08324 $w addtag UNIT_tag(all) withtag $containerget
08325 }
08326
08327 #===bouton expand
08328 set colorbout white
08329 if {$dico_units($i.expand) == 0} {set colorbout grey80}
08330 set bexp [$w create rectangle [expr $coor_x+$widthtot -12] [expr $coor_y + $DRAW(hcont) - 2] [expr $coor_x + $widthtot-2] [expr $coor_y + $DRAW(hcont) - 9] -fill $colorbout -outline grey50]
08331 $w addtag UNIT_tag($i) withtag $bexp
08332 $w addtag UNIT_tag(all) withtag $bexp
08333 $w addtag UNIT_expand_tag($i) withtag $bexp
08334 if {$dico_units($i.expand) == 0} {
08335 $w bind UNIT_expand_tag($i) <1> "global dico_units; set dico_units($i.expand) 1; Draw_one_unit $i;Draw_comm $i;.gui configure -cursor {}"
08336 $w bind UNIT_expand_tag($i) <Any-Enter> ".gui configure -cursor sb_h_double_arrow"
08337 $w bind UNIT_expand_tag($i) <Any-Leave> ".gui configure -cursor {}"
08338 } else {
08339 $w bind UNIT_expand_tag($i) <1> "global dico_units; set dico_units($i.expand) 0; Draw_one_unit $i; Draw_comm $i;.gui configure -cursor {}"
08340 $w bind UNIT_expand_tag($i) <Any-Enter> ".gui configure -cursor sb_left_arrow"
08341 $w bind UNIT_expand_tag($i) <Any-Leave> ".gui configure -cursor {}"
08342 }
08343
08344 #===boite intérieure
08345
08346 # Si c'est un fichier NetCDF
08347 if { $si_fichier } {
08348 set itemunit [$w create rectangle [expr $coor_x + $DRAW(hcont)] $coor_y [expr $coor_x + $widthtot - $DRAW(hcont)] [expr $coor_y + 2 * $DRAW(hcont) + $DRAW(heigthunit)] -fill $colorunit -outline $colorunit]
08349 } else {
08350 set itemunit [$w create rectangle $coor_x [expr $coor_y + $DRAW(hcont)] [expr $coor_x + $widthtot] [expr $coor_y + $DRAW(hcont) + $DRAW(heigthunit)] -fill $colorunit -outline $colorunit]
08351 }
08352 $w addtag UNIT_tag($i) withtag $itemunit
08353 $w addtag UNIT_tag(all) withtag $itemunit
08354 $w addtag unitpoint($i) withtag $itemunit
08355 $w addtag unitpoint_color($i) withtag $itemunit
08356
08357 if { $text2 == "" } {
08358 # Un seul texte place au centre de la boite
08359 set pos_text1 12
08360 } else {
08361 set pos_text1 7
08362 }
08363
08364 set itemunit [$w create text [expr $coor_x+$widthtot/2] [expr $coor_y + $DRAW(hcont) + $pos_text1] -text $text1 -font "helvetica -[expr int(12*$zoomfactor)] bold" -fill $colortext]
08365 $w addtag unitpoint($i) withtag $itemunit
08366 $w addtag UNIT_tag($i) withtag $itemunit
08367 $w addtag UNIT_tag(all) withtag $itemunit
08368 $w addtag UNIT_texttag($i) withtag $itemunit
08369 if { $text2 != "" } {
08370 set itemunit [$w create text [expr $coor_x+$widthtot/2] [expr $coor_y + $DRAW(hcont) + 19] -text $text2 -font "helvetica -[expr int(10*$zoomfactor)] bold" -fill $colortext]
08371 $w addtag unitpoint($i) withtag $itemunit
08372 $w addtag UNIT_tag($i) withtag $itemunit
08373 $w addtag UNIT_tag(all) withtag $itemunit
08374 $w addtag UNIT_texttag($i) withtag $itemunit
08375 }
08376
08377 # Si c'est un composant d'une application
08378 if { ! $si_fichier } {
08379 set itemunit [$w create text [expr $coor_x+$widthtot+12] [expr $coor_y + $DRAW(hcont) + 28] -text "0" -font "helvetica -[expr int(12*$zoomfactor)] bold" -fill white -anchor w -state hidden]
08380 $w addtag unitpoint($i) withtag $itemunit
08381 $w addtag UNIT_tag($i) withtag $itemunit
08382 $w addtag UNIT_tag(all) withtag $itemunit
08383 }
08384 #=======================================
08385 #==== gros rond pour les unites fermees
08386 #=======================================
08387 if {$dico_units($i.expand) == 0} {
08388 set x1 $midle_x
08389 set y1 [expr int([expr $coor_y + $DRAW(hcont)/2])]
08390 if {$nbget > 0} {
08391 set item [$w create oval [expr $x1-2*$ray] [expr $y1 -$ray] [expr $x1+2*$ray] [expr $y1+$ray] -fill grey80]
08392 $w addtag UNIT_tag($i) withtag $item
08393 $w addtag UNIT_tag(all) withtag $item
08394 }
08395 foreach clef_point $liste_clefs_points_i {
08396 set coord_points_X($clef_point) [expr $x1 - $coor_x]
08397 set coord_points_Y($clef_point) [expr $y1 - $coor_y]
08398 }
08399 if {$nbput > 0} {
08400 set y1 [expr int([expr $coor_y+$DRAW(heigthunit) + 3*$DRAW(hcont)/2])]
08401 set item [$w create oval [expr $x1-2*$ray] [expr $y1 -$ray] [expr $x1+2*$ray] [expr $y1+$ray] -fill grey80]
08402 $w addtag UNIT_tag($i) withtag $item
08403 $w addtag UNIT_tag(all) withtag $item
08404 }
08405 foreach clef_point $liste_clefs_points_o {
08406 set coord_points_X($clef_point) [expr $x1 - $coor_x]
08407 set coord_points_Y($clef_point) [expr $y1 - $coor_y]
08408 }
08409 } else {
08410 #=================================
08411 #====les petits ronds du haut et du bas
08412 #================================
08413 Draw_points_de_couplage in $liste_clefs_points_i $nom_appli $id_unit $coor_x $coor_y [expr ($wrefg - $widthtot) / 2]
08414 Draw_points_de_couplage out $liste_clefs_points_o $nom_appli $id_unit $coor_x $coor_y [expr ($wrefp - $widthtot) / 2]
08415 }
08416 set txt1 "{double click to edit the unit, left click to move the unit icon}"
08417
08418
08419 #==== bind evenement unit
08420 $w bind unitpoint($i) <Any-Enter> "$info configure -text $txt1 "
08421 $w bind unitpoint($i) <Any-Leave> "$info configure -text {}"
08422
08423 $w bind unitpoint($i) <Button-1> "minimenu_unit $i"
08424 $w bind unitpoint($i) <Button-1> "+ .gui configure -cursor fleur; unitplotdown $w %x %y $i"
08425 $w bind unitpoint($i) <ButtonRelease-1> ".gui configure -cursor {}; unitplotrelease $w %x %y $i"
08426
08427 $w bind unitpoint($i) <Double-Button-1> "unit_edit $i"
08428 $w bind unitpoint($i) <Key-Delete> "unit_delete $i"
08429
08430 $w scale UNIT_tag($i) 0 0 $zoomfactor $zoomfactor
08431 set plot(lastX) 0
08432 set plot(lastY) 0
08433 set plot(firstX) 0
08434 set plot(firstY) 0
08435 }
08436
08437 ret {Draw_points_de_couplage} (type direction , type liste_, type clefs_, type points , type nom_, type appli , type nom_, type unit , type coor_, type x , type coor_, type y , type offset) {
08438 # affiche une rangée de points de couplage sous forme de petits ronds
08439 #
08440 # Si points de couplage en entrée : il sont au sommet de la boite
08441 # Si points de couplage en sortie : il sont au fond de la boite
08442 #
08443 # Paramètres d'entrée :
08444 # - direction : "in" ou "out"
08445 # - liste_clefs_points : liste des points de couplage a représenter
08446 # - nom_appli : nom de l'application ou "
08447 # - nom_unit : nom du composant ou identifiant du fichier
08448 # - coor_x coor_y : coordonnées de l'unité (composant ou fichier)
08449 # - offset : offset horizontal du premier petit rond par rapport au milieu de la boite
08450 #
08451 global DRAW
08452 global dico_applis dico_caract_fichiers dico_caract_points
08453 global coord_points_X coord_points_Y
08454
08455 # wnd : le canevas
08456 set wnd $DRAW(window)
08457 set ray $DRAW(ray)
08458 set info .gui.pr.tools.infolabel
08459
08460 if { $direction == "in" } {
08461 set y1 [expr int([expr $coor_y + $DRAW(hcont)/2])]
08462 # Un point pas connecté apparait plus haut
08463 set offset_point_pas_connecte -10
08464 set endpoint_type target
08465 } else {
08466 set y1 [expr int($coor_y + $DRAW(heigthunit) + 3*$DRAW(hcont)/2)]
08467 # Un point pas connecté apparait plus bas
08468 set offset_point_pas_connecte 10
08469 set endpoint_type source
08470 }
08471
08472 # Pour tous les points de couplage
08473 set j 0
08474 foreach clef_point $liste_clefs_points {
08475 set x1 [expr int($coor_x+ ($j+.5)*$DRAW(widthcombox) - $offset)]
08476 set coord_points_X($clef_point) [expr $x1 - $coor_x]
08477 set coord_points_Y($clef_point) [expr $y1 - $coor_y]
08478
08479 # Si c'est un fichier NetCDF
08480 if { $nom_appli == "///file///" } {
08481 # Identifiant du fichier
08482 set id_fichier $nom_unit
08483 # Identifiant du champ
08484 set id_champ $dico_caract_points($clef_point.champ)
08485 # Nom du champ
08486 if { $direction == "in" } {
08487 # C'est un fichier de sortie : normalement $id_champ vaut "field"
08488 set nom_champ $dico_caract_fichiers($id_fichier.$id_champ.name)
08489 } else {
08490 # C'est un fichier d'entrée (entrée de données pour un composant)
08491 # L'identifiant est le nom
08492 set nom_champ $id_champ
08493 }
08494 # info bulle
08495 set txt "{Field: $nom_champ"
08496
08497 # Pour tous les parametres du champ, ajoute à l'info bulle
08498 foreach {name param} {Datatype type Packing packing Scaling scaling Adding adding "Fill value" fill_value} {
08499 if { [info exists dico_caract_fichiers($id_fichier.$id_champ.$param)] } {
08500 set value $dico_caract_fichiers($id_fichier.$id_champ.$param)
08501 if { $value != "" } {
08502 set txt "$txt\n$name: $value"
08503 }
08504 }
08505 }
08506 # Ajoute une parenthese fermante
08507 set txt "$txt}"
08508
08509 # c'est un composant d'une application
08510 } else {
08511 # Nom du composant
08512 set nom_composant $nom_unit
08513 # Nom du champ
08514 set nom_champ $dico_caract_points($clef_point.champ)
08515 # Clef d'accès aux caractéristiques du champ
08516 set clef_champ "app.$nom_appli.comp.$nom_composant.champ.$nom_champ"
08517 # Nom long du champ, si présent
08518 set nom_long ""
08519 if { [info exists dico_applis($clef_champ.long_name)] } {
08520 set nom_long $dico_applis($clef_champ.long_name)
08521 }
08522 # Type numérique
08523 set type_num $dico_applis($clef_champ.datatype)
08524 # Type dimensionel du champ (single ou vector)
08525 set type_dim $dico_applis($clef_champ.type)
08526
08527 # info bulle
08528 set txt "{Field: $nom_champ\nType: $type_dim\nDatatype: $type_num\nLong name: $nom_long}"
08529 }
08530
08531 # Liste des connexions à ce point de couplage
08532 set liste_cnx ""
08533 if { [info exists dico_caract_points($clef_point.lcnx)] } {
08534 set liste_cnx $dico_caract_points($clef_point.lcnx)
08535 }
08536
08537 set coloro \#eeee55
08538 set bordcolor black
08539
08540 # Si le point n'est pas connecté
08541 if { $liste_cnx == "" } {
08542 set y2 [expr $y1 + $offset_point_pas_connecte]
08543 } else {
08544 set y2 $y1
08545 }
08546 set item [$wnd create oval [expr $x1-$ray] [expr $y2 -$ray] [expr $x1+$ray] [expr $y2+$ray] -fill $coloro -outline $bordcolor]
08547 $wnd addtag UNIT_tag($nom_appli.$nom_unit) withtag $item
08548 $wnd addtag UNIT_tag(all) withtag $item
08549
08550 $wnd bind $item <Any-Enter> "help_object %W $txt label %X %Y \; $info configure -text {Click to set the $endpoint_type of a new connection }"
08551 $wnd bind $item <Button-1> "comm_new $direction $clef_point"
08552 $wnd bind $item <Any-Leave> "help_object_hide;$info configure -text {}"
08553 incr j 1
08554 }
08555 }
08556
08557 ret {Draw_set_init_variables} (optional default =no_default) {
08558 #================================================================
08559 #=== set des variables pour le dessin (valeurs par default)
08560 #================================================================
08561 global DRAW palm_param
08562
08563 set DRAW(init) 1
08564 set DRAW(window) .gui.pr.cpd22.03
08565 set DRAW(widthminunit) 60
08566
08567 if {$default == "default"} {
08568 set oasis_GUI_param(MAXIMUN_LINE_SIZE) 1000
08569 set oasis_GUI_param(GROUPED_MAXIMUN_LINE_SIZE) 1000
08570 set oasis_GUI_param(PLUGS_RADIUS) 4
08571 set oasis_GUI_param(HEIGHT_UNIT) 25
08572 }
08573 set DRAW(maxi_line_size) 1000
08574 set DRAW(grouped_maxi_line_size) 1000
08575 set DRAW(heigthunit) 25
08576 set DRAW(heightfile) 50
08577 set DRAW(ray) 4
08578
08579
08580 catch {set DRAW(maxi_line_size) $oasis_GUI_param(MAXIMUN_LINE_SIZE)}
08581 catch {set DRAW(grouped_maxi_line_size) $oasis_GUI_param(GROUPED_MAXIMUN_LINE_SIZE)}
08582 catch {set DRAW(heigthunit) $oasis_GUI_param(HEIGHT_UNIT)}
08583 catch {set DRAW(ray) $oasis_GUI_param(PLUGS_RADIUS)}
08584
08585 set DRAW(widthcombox) [expr $DRAW(ray)*2+1]
08586 set DRAW(hcont) [expr $DRAW(ray)*2+2]
08587 }
08588
08589 ret {Draw_settings} () {
08590 # boite de dialogue pour gerer les parametres du dessin dans le
08591 # cannevas
08592
08593
08594 proc resize_draw {w} {
08595 global DRAW oasis_GUI_param
08596
08597 set oasis_GUI_param(MAXIMUN_LINE_SIZE) $DRAW(maxi_line_size)
08598 set oasis_GUI_param(GROUPED_MAXIMUN_LINE_SIZE) $DRAW(grouped_maxi_line_size)
08599 set oasis_GUI_param(PLUGS_RADIUS) $DRAW(ray)
08600 set oasis_GUI_param(HEIGHT_UNIT) $DRAW(heigthunit)
08601 set DRAW(widthcombox) [expr $DRAW(ray)*2+1]
08602 set DRAW(hcont) [expr $DRAW(ray)*2+2]
08603 drawall
08604 destroy $w
08605 }
08606
08607 global DRAW
08608 global global_font
08609
08610
08611 set w .setting
08612 catch {destroy $w}
08613 toplevel $w
08614 wm title $w "Canvas settings"
08615 wm iconname $w "settings"
08616 window_position $w 200 200
08617
08618
08619
08620 frame $w.fr1
08621 pack $w.fr1 -side bottom -fill x -pady 2m -padx 2m
08622 button $w.fr1.ok -font $global_font -text ok -command "resize_draw $w"
08623 pack $w.fr1.ok -side left -expand 1
08624 button $w.fr1.defaut -font $global_font -text Default -command "global DRAW; catch {unset DRAW(init)};Draw_set_init_variables default; destroy $w; drawall"
08625 pack $w.fr1.defaut -side left -expand 1
08626 frame $w.sep -width 100 -height 2 -borderwidth 1 -relief sunken
08627 pack $w.sep -side bottom
08628
08629 frame $w.fr7 -borderwidth 1 -relief sunken
08630 pack $w.fr7 -side top -expand 1 -pady 10 -padx 10
08631
08632 grid [label $w.fr7.v1 -font $global_font -text "Maximun line size for communications:"] -row 0 -column 0 -sticky w
08633 grid [scale $w.fr7.e1 -variable DRAW(maxi_line_size) -font $global_font -orient horizontal -from 0 -to 2000] -row 0 -column 1 -sticky w
08634 grid [label $w.fr7.v5 -font $global_font -text "Maximun line size for grouped communications:"] -row 1 -column 0 -sticky w
08635 grid [scale $w.fr7.e5 -variable DRAW(grouped_maxi_line_size) -font $global_font -orient horizontal -from 0 -to 2000] -row 1 -column 1 -sticky w
08636 grid [label $w.fr7.v2 -font $global_font -text "Radius of plugs:"] -row 2 -column 0 -sticky w
08637 grid [scale $w.fr7.e2 -variable DRAW(ray) -font $global_font -orient horizontal -from 2 -to 6] -row 2 -column 1 -sticky w
08638 grid [label $w.fr7.v3 -font $global_font -text "Unit height:"] -row 3 -column 0 -sticky w
08639 grid [scale $w.fr7.e3 -variable DRAW(heigthunit) -font $global_font -orient horizontal -from 25 -to 60] -row 3 -column 1 -sticky w
08640 }
08641
08642 ret {HOSTOS} () {
08643 # retourne l'operating systeme
08644 # sert pour le lancement de la bonne version de steplang
08645 # selon la machine sur laquelle tourne PrePALM
08646
08647 set machine [string toupper [exec uname -s]]
08648 switch $machine {
08649 SunOS {return "-sun"}
08650 IRIX64 {return "-sgi"}
08651 Linux {return "-i386"}
08652 }
08653 puts "Unknown architecture $machine"
08654 exit
08655 }
08656
08657 ret {Help_legend} () {
08658 # affiche la legende du canevas de Prepalm
08659 # contenue dan le fichier legend.gif
08660
08661 if {![winfo exists .help_legend]} {
08662 set w .help_legend
08663 toplevel $w -background white
08664 wm title $w "Legend"
08665 wm iconname $w "Legend"
08666
08667 frame $w.buttons
08668 pack $w.buttons -side bottom -fill x -pady 0
08669 button $w.buttons.dismiss -text Ok -command "destroy $w"
08670 pack $w.buttons.dismiss
08671 frame $w.sep -width 100 -height 2 -borderwidth 1 -relief sunken
08672 pack $w.sep -side bottom -fill x -pady 0
08673
08674 set win $w.frsc
08675 frame $win
08676 scrollbar $win.sbar -command "$win.vport yview"
08677 pack $win.sbar -side right -fill y
08678 canvas $win.vport -yscrollcommand "$win.sbar set" -background white -width 590 -height 750 -scrollregion {0 0 0 750}
08679 pack $win.vport -side left -fill both -expand true
08680 pack $win -expand yes -fill both -side top
08681 } else {
08682 set w .help_legend
08683 wm deiconify $w
08684 raise $w
08685 set win $w.frsc
08686 $win.vport delete all
08687 }
08688 set font1 "helvetica 14 bold"
08689 set font2 "helvetica 11 bold"
08690 set font3 "helvetica 12"
08691 global env
08692 global OASIS_GUI_DIR
08693
08694 # creation image et insertion dans le canvas
08695 set w $win.vport
08696
08697
08698 image create photo im1 -file [file join $OASIS_GUI_DIR IMAGES legend.gif]
08699 $w create image 295 375 -image im1
08700 }
08701
08702 ret {MOD} (type i , type j) {
08703 # retourne le modulo de deux entiers
08704 set mod [expr $i - $j*(int($i/$j))]
08705 return $mod
08706 }
08707
08708 ret {NetCDF_file_add_new} (optional filename ={)} {
08709 #
08710 global liste_fichiers dico_caract_fichiers
08711 global liste_points_i dico_caract_points
08712 global dico_units
08713
08714 # Ferme la boite de dialogue précédente
08715 destroy .load_dir
08716
08717 # Détermine un identifiant automatique pour ce nouveau fichier
08718 set file_id [NetCDF_file_cree_nouvel_id]
08719 set clef_unit "
08720
08721 # Choisit une couleur pour le composant
08722 set dico_units($clef_unit.colour) [color_rgb [expr int(rand()*254)] [expr int(rand()*254)] [expr int(rand()*254)]]
08723 # Permet la modification de ces attributs
08724 NetCDF_file_edit $file_id $filename
08725 tkwait window .mod_file
08726
08727 # Si l'utilisateur a validé la saisie
08728 if { [info exists dico_caract_fichiers($file_id.field.name)] } {
08729
08730
08731 clef = _point $clef_unit.field.i
08732 lappend liste_points_i $clef_point
08733 dico = _caract_points($clef_point.appli) "///file///"
08734 dico = _caract_points($clef_point.comp) $file_id
08735 dico = _caract_points($clef_point.champ) field
08736
08737
08738 dico = _caract_fichiers($file_id.field.type) undefined
08739
08740 dico = _units($clef_unit) $file_id
08741 dico = _units($clef_unit.coor_x) 80
08742 dico = _units($clef_unit.coor_y) 25
08743
08744 dico = _units($clef_unit.expand) 1
08745
08746
08747 Draw_one_unit $clef_unit
08748
08749
08750
08751 minimenu_unit $clef_unit
08752 }
08753 }
08754
08755 ret {NetCDF_file_cree_nouvel_id} () {
08756 # Détermine automatiquement et retourne un identifiant
08757 # pour un nouveau fichier NetCDF en output
08758
08759 global liste_fichiers
08760 # Liste actuelle des identifiants de fichiers en output
08761 set liste_fic_output [lsearch -glob -all -inline $liste_fichiers "///outNetCDFfile///_*"]
08762 if { $liste_fic_output != "" } {
08763 # Numero du dernier identifiant
08764 set dernier [lindex $liste_fic_output end]
08765 set dernier_num [string range $dernier [string length
08766 # Nouvel identifiant
08767 incr dernier_num
08768 } else {
08769 set dernier_num 1
08770 }
08771 return "///outNetCDFfile///_$dernier_num"
08772 }
08773
08774 ret {NetCDF_file_delete} (type clef_, type fichier) {
08775 # Suppression d'un fichier par appui sur la bouton <DELETE>
08776 global liste_fichiers dico_caract_fichiers dico_units
08777 global liste_points_i liste_points_o dico_caract_points
08778 global dico_cnx_out dico_caract_cnx
08779 global DRAW tagselected
08780
08781 # Identifiant du fichier
08782 set file_id $dico_units($clef_fichier)
08783 set clef_fichier
08784
08785 # Supprime toutes les connexions vers ce fichier
08786 # ----------------------------------------------
08787
08788 # Si le fichier est en "output"
08789 if { $dico_caract_fichiers($file_id.dir) == "output" } {
08790 # Point de couplage du champ unique du fichier
08791 set clef_point $clef_fichier.field.i
08792 # Teste si le champ est connecté
08793 set cnx ""
08794 catch {set cnx $dico_caract_points($clef_point.lcnx)}
08795
08796 # Si le champ est connecté
08797 if { $cnx != ""} {
08798 # Supprime la connexion
08799 comm_remove $clef_point
08800 }
08801
08802 # Le fichier est en "input"
08803 } else {
08804 # Pour tous les champs du fichier
08805 foreach field_id $dico_caract_fichiers($file_id.lchamps) {
08806 # Identifiant de ce point de couplage
08807 set clef_point $clef_fichier.$field_id
08808 # Teste si le champ est connecté
08809 set lcnx ""
08810 catch {set lcnx $dico_caract_points($clef_point.o.lcnx)}
08811 # Pour toutes les connexions sortant de ce point
08812 foreach num_cnx $lcnx {
08813 # Clef de la cnx sortante
08814 set clef_cnx_out $clef_point.$num_cnx
08815 # Clef de la connexion : point de couplage cible de la connexion
08816 set clef_cnx_in $dico_cnx_out($clef_cnx_out)
08817 # Supprime la connexion
08818 comm_remove $clef_cnx_in
08819 }
08820 }
08821 }
08822
08823 # Supprime tous les points de couplage de ce fichier
08824 # --------------------------------------------------
08825
08826 # Points en entrée
08827 set liste_points_i [lsearch -not -all -inline -glob $liste_points_i "$clef_fichier.*"]
08828 # Points en sortie
08829 set liste_points_o [lsearch -not -all -inline -glob $liste_points_o "$clef_fichier.*"]
08830 # Caractéristiques des points
08831 array unset dico_caract_points "$clef_fichier.*"
08832
08833 # Supprime le fichier de la liste
08834 set liste_fichiers [lsearch -not -all -inline $liste_fichiers $file_id]
08835 # Supprime toutes ses caractéristiques
08836 array unset dico_caract_fichiers "$file_id.*"
08837
08838 # Raffraichit l'écran
08839 # -------------------
08840
08841 # Efface et redessine tous les composants
08842 Draw_drawunit
08843 # Efface et redessine toutes les connexions
08844 Draw_comm all
08845
08846 # Affiche la liste des fichiers
08847 control_entity FILE
08848
08849 # Si ce fichier était sélectionné (a priori OUI)
08850 if {$tagselected == "unitpoint_color($clef_fichier)"} {
08851 # Oublie l'objet sélectionné
08852 set tagselected ""
08853 }
08854 }
08855
08856 ret {NetCDF_file_edit} (type file_, type id , optional new_filename ={)} {
08857 #
08858 global liste_fichiers dico_caract_fichiers dico_units
08859
08860 # Extrait les informations pertinentes
08861 # ------------------------------------
08862
08863 # Si le fichier n'existe pas encore
08864 if { ! [info exists dico_caract_fichiers($file_id.dir)] } {
08865 io = _direction output
08866 access = _mode iosingle
08867 suffix = no
08868 fieldname = ""
08869
08870 filename = $new_filename
08871
08872 } else {
08873 io = _direction $dico_caract_fichiers($file_id.dir)
08874 access = _mode ""
08875 catch { access = _mode $dico_caract_fichiers($file_id.io_mode)}
08876 suffix = ""
08877 catch { suffix = $dico_caract_fichiers($file_id.suffix) }
08878 fieldname = ""
08879 catch { fieldname = $dico_caract_fichiers($file_id.field.name)}
08880 filename = $dico_caract_fichiers($file_id.name)
08881
08882 time = _unit ""
08883 catch { time = _unit $dico_caract_fichiers($file_id.time_unit)}
08884 time = _values "unknown"
08885 catch { time = _values $dico_caract_fichiers($file_id.time_values)}
08886 if { $suffix == "true" } { suffix = yes} else { suffix = no}
08887 }
08888
08889
08890
08891
08892 u = .mod_file
08893 catch {destroy $u}
08894 toplevel $u
08895 wm title $u "Edit NetCDF file"
08896 wm iconname $u "Mod_NetCDF"
08897 window_position $u 20 20
08898
08899 w = $u.menu
08900 frame $w
08901 grid $w -row 2 -column 0
08902 grid configure $w -columnspan 2 -padx 4 -pady 4
08903
08904 frame $w.buttons
08905 pack $w.buttons -side bottom -fill x -pady 2m
08906
08907 button $w.buttons.dismiss -text Cancel -command "destroy $u"
08908 button $w.buttons.ok -text Ok -command "NetCDF_file_update $u $file_id $io_direction"
08909
08910 pack $w.buttons.dismiss -side left -expand 1 -padx 10
08911 pack $w.buttons.ok -side left -expand 1 -padx 10
08912
08913 frame $w.sep1 -width 200 -height 2 -borderwidth 1 -relief sunken
08914 pack $w.sep1 -side bottom -fill x -pady 2m -expand 1
08915
08916 w = $u.char
08917 frame $w
08918 grid $w -row 0 -column 1
08919 grid configure $w -padx 4 -pady 4
08920 r = 1
08921
08922
08923 label $w.label1 -text "Name :"
08924 global filename_m
08925 filename = _m $filename
08926 entry $w.entry1 -textvariable filename_m -width 40 -background white
08927 grid $w.label1 $w.entry1 -row $r -sticky w
08928 incr r
08929
08930 help = _text {Enter here a file name, without suffix, if any.}
08931 entry_help_balloon $w.entry1 $help_text
08932
08933
08934 label $w.label12 -text "I/O direction :"
08935 label $w.label13 -text $io_direction -relief sunken
08936 grid $w.label12 $w.label13 -row $r -sticky w
08937 incr r
08938
08939
08940 label $w.label2 -text "Access mode :"
08941 combobox_lim $w.cmb2 {iosingle distributed parallel} {} access_mode_m 30 $access_mode
08942 grid $w.label2 $w.cmb2 -row $r -sticky w
08943 incr r
08944
08945 help = _text {The mode iosingle means that the whole file is written or read only by the master ret ess;
08946
08947 distributed means that each process writes or reads its part of the field to a different partial file. Note that if OASIS is linked against the parallel NetCDF library (7), the parallel mode will automatically be used; in this case each process writes its part of the field to one parallel file (see Oasis User Guide on page 26).}
08948 entry_help_balloon $w.cmb2 $help_text
08949
08950 #== Suffix option
08951 label $w.label3 -text "Suffix :"
08952 combobox_lim $w.cmb3 (type yes , type no) {} suffix_m 30 $suffix
08953 grid $w.label3 $w.cmb3 -row $r -sticky w
08954 incr r
08955
08956 help = _text {If yes, a suffix is appended to file name.
08957
08958 When the file is opened for writing, the suffix will be “ out.<job-startdate>.nc”, where <job-startdate> is the start date of the job.
08959
08960 When the file is opened for reading, the suffix should be “ in.<start-date>.nc”, where <start-date> is the date of the first time stamp in that file.
08961 When reading an input from a file, OASIS will automatically match the requested date of the input with the appropiate file if it falls into the time interval covered by that file. The <job-startdate> and <start-date> must be written according to the ISO format yyyy-mm-ddTHH:MM:SS. The date/time string in the file name must have to format yyyy-mmddTHH.MM.SS since the colon is already used in other context for file systems.}
08962 entry_help_balloon $w.cmb3 $help_text
08963
08964 grid [ frame $w.sep1 -width 430 -height 2 -borderwidth 1 -relief sunken] -row $r -column 0 -pady 5 -columnspan 2
08965 incr r
08966
08967
08968 if { $io_direction == "output" } {
08969
08970
08971 label $w.label4 -text "Field name :" -fg
08972 global fieldname_m
08973 fieldname = _m $fieldname
08974 entry $w.entry4 -textvariable fieldname_m -width 40 -background white
08975 grid $w.label4 $w.entry4 -row $r -sticky w
08976 incr r
08977
08978 help = _text {Enter here the name of NetCDF file variable.}
08979 entry_help_balloon $w.entry4 $help_text
08980 } else {
08981
08982
08983
08984 label $w.label31 -text "Time values :"
08985 label $w.label32 -text "$time_values $time_unit" -relief sunken -wraplength 450 -justify left
08986 grid $w.label31 $w.label32 -row $r -sticky w
08987 incr r
08988 }
08989
08990
08991 global color_m
08992 clef = _comp
08993 color = _m $dico_units($clef_comp.colour)
08994 label $w.label5 -text "Color :"
08995 button $w.entry5 -relief sunken -width 20 -text $color_m -background $color_m -command {
08996 global color_m
08997 color = _m [tk_chooseColor -initialcolor $color_m]
08998 catch {.mod_file.char.entry5 configure -background $color_m}
08999 }
09000 grid $w.label5 $w.entry5 -row $r -sticky w
09001
09002 global no_help_balloon
09003 if { $no_help_balloon == 0 } {
09004 help = _text {Click here to change the color of the component.}
09005 help = _action "help_object %W [list $help_text] message"
09006 bind $w.entry5 <Any-Enter> $help_action
09007 bind $w.entry5 <FocusIn> $help_action
09008 bind $w.entry5 <Any-Leave> "help_object_hide"
09009 bind $w.entry5 <FocusOut> "help_object_hide"
09010 bind $w.entry5 <ButtonPress> "help_object_hide"
09011 }
09012 }
09013
09014 ret {NetCDF_file_maj} (type file_, type list , type nom_, type dico_, type ajout , type option_, type redraw) {
09015 # Met à jour les données en mémoire avec les fichiers ajoutés :
09016 # en particulierm la liste des points de couplage
09017 # Ajoute les fichiers sur le graphe
09018 #
09019 # Tient compte du fait que des fichiers sont en fait chargés pour la deuxième fois en mémoire.
09020 # Les fichiers ne sont alors pas ajoutés mais remis à jour.
09021 # Dans ce cas, on supprime les points de couplage qui n'existent plus et les éventuelles connexions
09022 # qui leur sont attachées.
09023 #
09024
09025 upvar 1 $nom_dico_ajout dico_ajout
09026 global liste_fichiers dico_caract_fichiers dico_units
09027 global liste_points_o dico_cnx_out dico_caract_points dico_caract_cnx
09028
09029 # Position initiale du fichier ajouté sur le graphe : en haut à gauche
09030 set position_x 80
09031 set position_y 25
09032
09033 foreach nom_fichier $file_list {
09034 set clef_comp
09035
09036 # Si fichier en entrée dont l'attribut 'suffix' n'est pas encore défini
09037 if {$dico_ajout($nom_fichier.dir) == "input" &&
09038 ![info exists dico_ajout($nom_fichier.suffix)]} {
09039
09040 # Si le nom du fichier comprend un suffixe _out<date>.nc
09041 if {[regexp -nocase {_in\.[1-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]T[0-9][0-9][._][0-9][0-9][._][0-9][0-9].nc$} $nom_fichier]} {
09042 set dico_ajout($nom_fichier.suffix) true
09043 # Garde le nom sans le suffixe
09044 set dico_ajout($nom_fichier.name) [string range $dico_ajout($nom_fichier.name) 0 end-26]
09045 } else {
09046 set dico_ajout($nom_fichier.suffix) false
09047 }
09048 }
09049
09050 # Si le fichier n'existait pas déja en mémoire (il a bien été ajouté)
09051 if { [lsearch $liste_fichiers $nom_fichier] == -1 } {
09052
09053 # Ajoute le fichier a la liste
09054 lappend liste_fichiers $nom_fichier
09055 # Ajoute toutes ses infos au dictionnaire global des fichiers
09056 array set dico_caract_fichiers [array get dico_ajout "$nom_fichier.*"]
09057
09058 # Nouvelle unité sur le graphe de couplage
09059 set dico_units($clef_comp) $nom_fichier
09060 # Détermine les coordonnées du fichier sur le graphe
09061 set dico_units($clef_comp.coor_x) $position_x
09062 set dico_units($clef_comp.coor_y) $position_y
09063 incr position_y 80
09064 # Met le composant dans l'état "connexions visibles"
09065 set dico_units($clef_comp.expand) 1
09066 # Choisit une couleur pour le composant
09067 set dico_units($clef_comp.colour) [color_rgb [expr int(rand()*254)] [expr int(rand()*254)] [expr int(rand()*254)]]
09068
09069 # Pour toutes ses variables
09070 foreach nom_var $dico_ajout($nom_fichier.lchamps) {
09071 # Ajoute un point de couplage
09072 set clef_point $clef_comp.$nom_var.o
09073 lappend liste_points_o $clef_point
09074
09075 set dico_caract_points($clef_point.appli)
09076 set dico_caract_points($clef_point.comp) $nom_fichier
09077 set dico_caract_points($clef_point.champ) $nom_var
09078 }
09079 # Affiche le fichier sur le graphe
09080 Draw_one_unit $clef_comp
09081
09082 } else { # Le fichier a été rechargé avec des changements possibles
09083
09084 # Mémorise l'axe des temps
09085 if {$dico_ajout($nom_fichier.time_name) != ""} {
09086 array set dico_caract_fichiers [array get dico_ajout "$nom_fichier.time_*"]
09087 } else {
09088 array unset dico_caract_fichiers $nom_fichier.time_unit
09089 array unset dico_caract_fichiers $nom_fichier.time_values
09090 }
09091
09092 # Vérifie la liste des champs et cherche des champs supprimés ou ajoutés
09093 # ----------------------------------------------------------------------
09094
09095 # Pour toutes les variables du fichier chargé en mémoire
09096 foreach nom_var $dico_ajout($nom_fichier.lchamps) {
09097 # Si la variable n'existait pas auparavant
09098 if { [lsearch $dico_caract_fichiers($nom_fichier.lchamps) $nom_var] == -1} {
09099 # Ajoute un point de couplage
09100 set clef_point $clef_comp.$nom_var.o
09101 lappend liste_points_o $clef_point
09102
09103 set dico_caract_points($clef_point.appli)
09104 set dico_caract_points($clef_point.comp) $nom_fichier
09105 set dico_caract_points($clef_point.champ) $nom_var
09106 }
09107 # Met a jour en mémoire les attributs de cette var. du fichier
09108 array set dico_caract_fichiers [array get dico_ajout "$nom_fichier.$nom_var.*"]
09109 }
09110
09111 # Init liste des composants touchés par les conexions supprimées
09112 set liste_comp_touches {}
09113 # Pour toutes les variables qui existaient auparavant
09114 foreach nom_var $dico_caract_fichiers($nom_fichier.lchamps) {
09115 # Si la variable n'existe plus
09116 if { [lsearch $dico_ajout($nom_fichier.lchamps) $nom_var] == -1} {
09117 # Identifiant de ce point de couplage
09118 set clef_point $clef_comp.$nom_var
09119 # Teste si le champ est connecté
09120 set lcnx ""
09121 catch {set lcnx $dico_caract_points($clef_point.o.lcnx)}
09122 # Pour toutes les connexions sortant de ce point
09123 foreach num_cnx $lcnx {
09124 # Clef de la cnx sortante
09125 set clef_cnx_out $clef_point.$num_cnx
09126 # Clef de la connexion : point de couplage cible de la connexion
09127 set clef_cnx_in $dico_cnx_out($clef_cnx_out)
09128 # Memorise le composant cible de la connexion
09129 set appli_cible $dico_caract_cnx($clef_cnx_in.app_cible)
09130 set comp_cible $dico_caract_cnx($clef_cnx_in.comp_cible)
09131 lappend liste_comp_touches $appli_cible.$comp_cible
09132 # Supprime la connexion
09133 comm_remove $clef_cnx_in
09134 }
09135
09136 # Met a jour la liste des points en sortie
09137 set liste_points_o [lsearch -not -all -inline -glob $liste_points_o "$clef_point.o"]
09138 # Supprime les caractéristiques du point
09139 array unset dico_caract_points "$clef_point.o.*"
09140 # Supprime les infos concernant ce champ
09141 array unset dico_caract_fichiers "$nom_fichier.$nom_var.*"
09142 }
09143 }
09144
09145 # Met a jour en mémoire la liste des champs du fichier
09146 set dico_caract_fichiers($nom_fichier.lchamps) $dico_ajout($nom_fichier.lchamps)
09147
09148 if {$option_redraw} {
09149 # Pour tous les composants touchés
09150 foreach composant $liste_comp_touches {
09151 # Redessine le composant
09152 Draw_one_unit $composant
09153 }
09154
09155 # Affiche le fichier sur le graphe
09156 Draw_one_unit $clef_comp
09157 # Redessine les connexions du fichier
09158 Draw_comm $clef_comp
09159 }
09160 }
09161 }
09162 }
09163
09164 ret {NetCDF_file_read} (type nom_, type dico_, type ajout , type nom_, type fichier) {
09165 # Lit les caracteristiques d'un fichier NetCDF
09166 # et les enregistre dans le dictionnaire "nom_dico_ajout"
09167 #
09168 # Retourne le nom court du fichier si ce fichier a été lu correctement
09169 #
09170 upvar 1 $nom_dico_ajout dico_ajout
09171
09172 # Ecriture de l'en-tete du fichier netCDF dans un autre ficher
09173 exec ncdump -h $nom_fichier > ".dmp"
09174
09175
09176 # Lecture et stockage des informations de l'en-tete
09177 #--------------------------------------------------
09178
09179 set status "rien"
09180
09181 if { [file exists .dmp] } {
09182 set f [open .dmp r]
09183
09184 # Mémorise le fichier sans son chemin
09185 set nom_fichier [file tail $nom_fichier]
09186 set dico_ajout($nom_fichier.dir) input
09187 # Le nom du fichier est editable : par défaut, c'est celui du fichier lu
09188 set dico_ajout($nom_fichier.name) $nom_fichier
09189 # Initialise certains attributs du fichier
09190 set dico_ajout($nom_fichier.io_mode) iosingle
09191
09192 set time_dim_var ""
09193 set unlimited_dim ""
09194 while {![eof $f]} {
09195 gets $f line
09196 set line [string trim $line]
09197 # On regarde dans quelle partie declarative on se trouve
09198 if {$line == "dimensions:"} {
09199 set status "on_dim"
09200 continue
09201 }
09202 if {$line == "variables:"} {
09203 set status "on_var"
09204 continue
09205 }
09206 if {$line == "// global attributes:"} {
09207 set status "on_ga"
09208 continue
09209 }
09210 # On collecte les donnees en fonction du statut courant
09211 # GESTION DES DIMENSIONS
09212 if {$status == "on_dim"} {
09213 set dim [lindex $line 0]
09214 # Recherche la dimension "temps" : par son nom (time)
09215 if {[string toupper $dim] == "TIME"} {
09216 set time_dim_var $dim
09217 }
09218 # Recherche la dimension dont la taille n'est pas fixe
09219 set valeur [lindex $line 2]
09220 if {$valeur == "UNLIMITED"} {
09221 # Memorise la variable
09222 set unlimited_dim $dim
09223 }
09224 continue
09225 }
09226 # GESTION DES VARIABLES
09227 if {$status == "on_var"} {
09228 set item1 [lindex $line 0]
09229 # gestion des attributs des variables
09230 if { $item1 == "double" || $item1 == "float" || $item1 == "int" || $item1 == "short" || $item1 == "char" || $item1 == "byte"} {
09231 set type_var $item1
09232 set debut_nom_var [string length $type_var]
09233 incr debut_nom_var
09234 set par_ouv [string first "(" $line]
09235 set par_fer [string first ")" $line]
09236 set nom_var [string range $line $debut_nom_var [expr $par_ouv -1 ]]
09237 set dim_var [string range $line [expr $par_ouv+1] [expr $par_fer-1]]
09238
09239 # Si la variable porte le nom de ses dimensions, c'est que c'est une dimension
09240 # On ne l'ajoutera pas à la liste
09241 if { $nom_var != $dim_var } {
09242 lappend dico_ajout($nom_fichier.lchamps) $nom_var
09243 set dico_ajout($nom_fichier.$nom_var.type) $type_var
09244 }
09245 } else {
09246 if { $item1 == "$nom_var:_FillValue" } {
09247 set fill_value [lindex $line 2]
09248 set dico_ajout($nom_fichier.$nom_var.fill_value) $fill_value
09249 }
09250 if { $item1 == "$nom_var:long_name" } {
09251 set long_name [lindex $line 2]
09252 set dico_ajout($nom_fichier.$nom_var.long_name) $long_name
09253 }
09254 }
09255 continue
09256 }
09257 # GESTION DES ATTRIBUTS GLOBAUX
09258 if {$status == "on_ga"} {continue}
09259 }
09260
09261 # On ferme le fichier .dump dont on a lu le nécessaire
09262 close $f
09263 file delete .dmp
09264
09265 # Si la dimension 'temps' n'est pas connue
09266 if {$time_dim_var == ""} {
09267 # La dimension temps est a priori celle qui est de taille illimitée
09268 set time_dim_var $unlimited_dim
09269 # A ce stade, il se peut que la dimension temps soit encore inconue
09270 }
09271 set dico_ajout($nom_fichier.time_name) $time_dim_var
09272
09273 return $nom_fichier
09274 } else {
09275 notice_show "'ncdump' not found !\nPlease, install NetCDF support utilities." error
09276 return ""
09277 }
09278 }
09279
09280 ret {NetCDF_file_read_time} (type nom_, type dico_, type ajout , type nom_, type fichier , type nom_, type axe_, type temps) {
09281 # Lit les caractéristiques de l'axe des temps d'un fichier NetCDF
09282 # et les enregistre dans le dictionnaire "nom_dico_ajout"
09283 #
09284 upvar 1 $nom_dico_ajout dico_ajout
09285
09286 # Ecriture de l'en-tête du fichier netCDF suivie des données de la dimension temps
09287 # dans un autre ficher de type texte
09288 exec ncdump -v $nom_axe_temps $nom_fichier > ".dmp"
09289
09290
09291 # Lecture et stockage des informations du fichier texte
09292 #------------------------------------------------------
09293
09294 set status "rien"
09295
09296 if { [file exists .dmp] } {
09297 set f [open .dmp r]
09298
09299 # Mémorise le fichier sans son chemin
09300 set nom_fichier [file tail $nom_fichier]
09301 # Lit toutes les lignes du fichier une à une
09302 while {![eof $f]} {
09303 gets $f line
09304 set line [string trim $line]
09305 # On regarde dans quelle partie declarative on se trouve
09306 if {$line == "dimensions:"} {
09307 set status "on_dim"
09308 continue
09309 }
09310 if {$line == "variables:"} {
09311 set status "on_var"
09312 continue
09313 }
09314 if {$line == "// global attributes:"} {
09315 set status "on_ga"
09316 continue
09317 }
09318 if {$line == "data:"} {
09319 set status "on_data"
09320 continue
09321 }
09322 # On collecte les donnees en fonction du statut courant
09323 # GESTION DES DIMENSIONS
09324 if {$status == "on_dim"} {continue}
09325
09326 # GESTION DES VARIABLES
09327 if {$status == "on_var"} {
09328 set item1 [lindex $line 0]
09329 # si attribut 'units' de la dimension temps
09330 if { $item1 == "$nom_axe_temps:units" } {
09331 set units [lindex $line 2]
09332 set dico_ajout($nom_fichier.time_unit) $units
09333 }
09334 continue
09335 }
09336 # GESTION DES ATTRIBUTS GLOBAUX
09337 if {$status == "on_ga"} {continue}
09338
09339 # GESTION DES données de l'axe des temps : 1ère ligne
09340 if {$status == "on_data"} {
09341 set item1 [lindex $line 0]
09342 # Si première ligne des données de la dimension temps
09343 if { $item1 == "$nom_axe_temps" } {
09344 # Lit les premières données
09345 set liste_valeurs [lrange $line 2 end]
09346 # Si la ligne finit par un point-virgule
09347 if {[lindex $liste_valeurs end] == ";"} {
09348 set status "end"
09349 } else {
09350 set status "on_time"
09351 }
09352 }
09353 continue
09354 }
09355 # GESTION DES données de l'axe des temps : lignes suivantes
09356 if {$status == "on_time"} {
09357 # Lit les données
09358 set liste_valeurs [concat $liste_valeurs $line]
09359 # Si la ligne finit par un point-virgule
09360 if {[lindex $liste_valeurs end] == ";"} {
09361 set status "end"
09362 }
09363 continue
09364 }
09365 }
09366
09367 # On ferme le fichier .dump dont on a lu le nécessaire
09368 close $f
09369 file delete .dmp
09370
09371 # Memrise les attributs de l'axe des temps
09372 set dico_ajout($nom_fichier.time_values) [lrange $liste_valeurs 0 end-1]
09373
09374 } else {
09375 notice_show "'ncdump' not found !\nPlease, install NetCDF support utilities." error
09376 }
09377 }
09378
09379 ret {NetCDF_file_read_files} (type file_, type list) {
09380 global tagselected oldcolor
09381
09382 # Dictionnaire des fichiers ajoutés
09383 array set dico_ajout {}
09384 # Init de la liste des fichiers ajoutés
09385 set liste_fic_ajoutes {}
09386
09387 foreach file $file_list {
09388 if {$file != ""} {
09389 set fic_ajoute [NetCDF_file_read dico_ajout $file]
09390 if {$fic_ajoute != ""} {
09391 lappend liste_fic_ajoutes $fic_ajoute
09392 set nom_fichier [file tail $file]
09393 # Si le fichier comporte une dimension "temps" clairement reconnaissable
09394 set nom_axe_temps $dico_ajout($nom_fichier.time_name)
09395 if {$nom_axe_temps != ""} {
09396 # Lit les caractéristiques de l'axe des temps
09397 NetCDF_file_read_time dico_ajout $file $nom_axe_temps
09398 }
09399 }
09400 }
09401 }
09402 # Met à jour les données et le graphe avec les fichiers ajoutés
09403 NetCDF_file_maj $liste_fic_ajoutes dico_ajout 1
09404
09405 # Affiche la liste des fichiers
09406 control_entity "FILE"
09407
09408 # S'il n'y a qu'un seul fichier ajouté
09409 if { [llength $file_list] == 1 } {
09410 set nom_fichier [lindex $file_list 0]
09411 # Permet la modification des attributs de ce fichier
09412 set file_id [file tail $nom_fichier]
09413 NetCDF_file_edit $file_id
09414 tkwait window .mod_file
09415
09416 # Raffiche le fichier sur le graphe
09417 set clef
09418 Draw_one_unit $clef
09419
09420 # Si ce fichier était sélectionné
09421 if {$tagselected == "unitpoint_color($clef)"} {
09422 # Change la couleur de l'objet sélectionné
09423 set w .gui.pr.cpd22.03
09424 set oldcolor [$w itemcget $tagselected -fill ]
09425 $w itemconfigure $tagselected -fill red
09426 }
09427 }
09428 }
09429
09430 ret {NetCDF_file_update} (type win , type file_, type id , type io_, type direction) {
09431 # Procedure appelee lors de la validation de la boite de dialogue de saisie des parametres
09432 # d'un fichier NetCDF.
09433 #
09434 # Variables globales
09435 global liste_fichiers dico_caract_fichiers dico_units
09436 # Varaibles globales des champs saisis
09437 global filename_m access_mode_m suffix_m fieldname_m
09438
09439 # Validation du nom de fichier
09440 if { $filename_m == "" } {
09441 notice_show "File name not filled !" error
09442 focus .mod_file.char.entry1
09443 return error
09444 }
09445
09446 # Si le fichier est un fichier en sortie
09447 if { $io_direction == "output" } {
09448 # Validation du nom de champ
09449 if { $fieldname_m == "" } {
09450 notice_show "Field name not filled !" error
09451 focus .mod_file.char.entry4
09452 return error
09453 }
09454 }
09455
09456 # Réinterprète les booléens
09457 if {$suffix_m == "yes"} {set suffix_m true} else {set suffix_m false}
09458
09459 # Si le fichier n'existe pas encore en mémoire
09460 if { ! [info exists dico_caract_fichiers($file_id.dir)] } {
09461 # Ajoute l'identifiant à la liste
09462 lappend liste_fichiers $file_id
09463
09464 # Saisit les caracteristiques du nouveau fichier
09465 set dico_caract_fichiers($file_id.dir) output
09466 set dico_caract_fichiers($file_id.lchamps) field
09467 }
09468
09469 # Enregistre les attributs du fichier
09470 set dico_caract_fichiers($file_id.suffix) $suffix_m
09471 set dico_caract_fichiers($file_id.io_mode) $access_mode_m
09472 unset suffix_m access_mode_m
09473 # Enregistre le nom du fichier
09474 set dico_caract_fichiers($file_id.name) $filename_m
09475 unset filename_m
09476
09477 # Si le fichier est un fichier en sortie
09478 if { $io_direction == "output"} {
09479 # Enregistre le nom du champ
09480 set dico_caract_fichiers($file_id.field.name) $fieldname_m
09481 unset fieldname_m
09482 # Enregistre les attributs du champ NetCDF
09483 # set dico_caract_fichiers($filename_m.$fieldname_m.....) ....
09484 }
09485
09486 # Met a jour la couleur
09487 global color_m
09488 set clef_comp
09489 set dico_units($clef_comp.colour) $color_m
09490 unset color_m
09491
09492 destroy $win
09493 }
09494
09495 ret {application_edit} (type nom_, type appli) {
09496 ##################################################
09497 # menu d'edition d'une application
09498 ##################################################
09499 global dico_applis
09500
09501 # Extrait les informations concernant l'application
09502 global exe_name_m args_m redirect_m
09503
09504 set exe_name_m ""
09505 catch { set exe_name_m $dico_applis(app.$nom_appli.executable_name) }
09506 set args_m ""
09507 catch { set args_m $dico_applis(app.$nom_appli.args) }
09508 set redirect_m "true"
09509 catch { set redirect_m $dico_applis(app.$nom_appli.redirect) }
09510 if { $redirect_m == "true" } {
09511 set redirect_m "yes"
09512 } else {
09513 set redirect_m "no"
09514 }
09515
09516 #== number of processes
09517 set min_proc $dico_applis(app.$nom_appli.proc.min_value)
09518 set max_proc $dico_applis(app.$nom_appli.proc.max_value)
09519 set increment $dico_applis(app.$nom_appli.proc.increment)
09520
09521 # Start mode
09522 set start_mode $dico_applis(app.$nom_appli.start_mode)
09523 array set translation_dict { spawn Spawn notspawn {Not spawn} notspawn_or_spawn {Either spawn or not spawn}}
09524 set start_mode $translation_dict($start_mode)
09525
09526 # Recopie les infos concernant les ordinateurs hosts de l'application
09527 global hosts_m
09528 array set hosts_m {}
09529 if { [info exists dico_applis(app.$nom_appli.lhosts)] && $dico_applis(app.$nom_appli.lhosts) != "" } {
09530 set hosts_m(lhosts) $dico_applis(app.$nom_appli.lhosts)
09531 foreach id_host $dico_applis(app.$nom_appli.lhosts) {
09532 set clef app.$nom_appli.host.$id_host
09533 set hosts_m(host.$id_host.name) $dico_applis($clef.name)
09534 set hosts_m(host.$id_host.nb_procs) $dico_applis($clef.nb_procs)
09535 }
09536 } else {
09537 # Definit un "host" arbitraire avec N processus
09538 set hosts_m(lhosts) "1"
09539 set hosts_m(host.1.name) "Enter name..."
09540 set hosts_m(host.1.nb_procs) $max_proc
09541 if {$max_proc == 0} {inc hosts_m(host.1.nb_procs)}
09542 }
09543
09544 # un toplevel
09545 set u .mod_appli
09546 catch {destroy $u}
09547 toplevel $u
09548 wm title $u "Edit Application"
09549 wm iconname $u "Mod_Appli"
09550 window_position $u 100 100
09551
09552 set w $u.menu
09553 frame $w
09554 grid $w -row 2 -column 0
09555 grid configure $w -columnspan 2 -padx 4 -pady 4
09556
09557 frame $w.buttons
09558 pack $w.buttons -side bottom -fill x -pady 2m
09559
09560 button $w.buttons.dismiss -text Cancel -command "destroy $u"
09561 button $w.buttons.ok -text Ok -command "application_update $u $nom_appli \$exe_name_m \$args_m \$redirect_m hosts_m"
09562
09563 pack $w.buttons.dismiss -side left -expand 1 -padx 10
09564 pack $w.buttons.ok -side left -expand 1 -padx 10
09565
09566 frame $w.sep1 -width 200 -height 2 -borderwidth 1 -relief sunken
09567 pack $w.sep1 -side bottom -fill x -pady 2m -expand 1
09568
09569 set w $u.char
09570 frame $w
09571 grid $w -row 0 -column 1
09572 grid configure $w -padx 4 -pady 4
09573 set r 1
09574
09575 #== nom
09576 label $w.label1 -text "Name: "
09577 label $w.label11 -relief sunken -text $nom_appli
09578 grid $w.label1 $w.label11 -row $r -sticky w
09579 incr r
09580
09581 #== number of processes
09582 label $w.label2 -text "Number of processes : "
09583 label $w.label21 -relief sunken -text "$min_proc to $max_proc step $increment"
09584 grid $w.label2 $w.label21 -row $r -sticky w
09585 incr r
09586
09587 #== start mode
09588 label $w.label20 -text "Allowed start mode : "
09589 label $w.label201 -relief sunken -text "$start_mode"
09590 grid $w.label20 $w.label201 -row $r -sticky w
09591 incr r
09592
09593 # Séparateur
09594 frame $w.sep1 -width 200 -height 2 -borderwidth 1 -relief sunken
09595 grid $w.sep1 -row $r -columnspan 2 -pady 5
09596 incr r
09597
09598 #== executable
09599 label $w.label3 -text "Executable name : " -fg #ee3333
09600 entry $w.entry3 -textvariable exe_name_m -width 25 -background white
09601 grid $w.label3 $w.entry3 -row $r -sticky w
09602 incr r
09603
09604 # Ajoute une bulle d'aide pour 'Executable name'
09605 set help_text {Enter here the application executable name, defined by the compiling environment (used only in spawn mode as argument of the MPI_Comm_Spawn_Multiple).}
09606 entry_help_balloon $w.entry3 $help_text
09607
09608 #== Executable arguments
09609 label $w.label4 -text "Executable args : "
09610 entry $w.entry4 -textvariable args_m -width 25 -background white
09611 grid $w.label4 $w.entry4 -row $r -sticky w
09612 incr r
09613
09614 # Ajoute une bulle d'aide pour 'Executable args'
09615 set help_text {Enter here a list of launching arguments for the application executable}
09616 entry_help_balloon $w.entry4 $help_text
09617
09618 #== redirect stdout
09619 label $w.label5 -text "Redirect stdout : "
09620 combobox_lim $w.cmb5 {yes no} {} redirect_m 10 $redirect_m
09621 grid $w.label5 $w.cmb5 -row $r -sticky w
09622 incr r
09623
09624 # Ajoute une bulle d'aide pour 'redirect stdout'
09625 set help_text {Enter here whether the application stdout shall be redirected or not.}
09626 entry_help_balloon $w.cmb5 $help_text
09627
09628 # Séparateur
09629 frame $w.sep2 -width 200 -height 2 -borderwidth 1 -relief sunken
09630 grid $w.sep2 -row $r -columnspan 2 -pady 5
09631 incr r
09632
09633 #== Hosts
09634 label $w.label6 -text "Hosts : "
09635 scrollform_create $w.sform
09636 set form [scrollform_interior $w.sform]
09637 button $w.insert_host -text "Add" -command "host_insert $form"
09638 grid $w.label6 $w.insert_host -row $r -sticky w
09639 incr r
09640
09641 # une frame et un label pour le titre
09642 frame $w.fr2
09643 grid $w.fr2 -row $r -sticky w -columnspan 2
09644 label $w.fr2.title1 -text " Name Nb processes " -borderwidth 1 -justify left
09645 pack $w.fr2.title1 -anchor w
09646 incr r
09647
09648 # une frame scrollable pour les "hosts"
09649 grid $w.sform -row $r -columnspan 2 -sticky ew
09650 $form configure -borderwidth 1 -relief sunken
09651 # grid columnconfigure $form 0 -minsize 15 -weight 15
09652 # grid columnconfigure $form 1 -minsize 10 -weight 10
09653
09654 # insertion des boutons pour les hosts existant
09655 set nb_hosts 0
09656 foreach id_host $hosts_m(lhosts) {
09657 host_boutons_insert $form $id_host $nb_hosts
09658 incr nb_hosts
09659 }
09660
09661 # Ajoute une bulle d'aide pour le bouton 'Add Host'
09662 global no_help_balloon
09663 if { $no_help_balloon == 0 } {
09664 set help_text {Click here to add a host to the list.}
09665 set help_action "help_object %W [list $help_text] message"
09666 bind $w.insert_host <Any-Enter> $help_action
09667 bind $w.insert_host <FocusIn> $help_action
09668 bind $w.insert_host <Any-Leave> "help_object_hide"
09669 bind $w.insert_host <FocusOut> "help_object_hide"
09670 bind $w.insert_host <ButtonPress> "help_object_hide"
09671 }
09672
09673 # Ajoute une bulle d'aide pour la liste des 'hosts'
09674 set help_text {Enter here a list of hosts; for each host:
09675
09676 1) the host name (used only in spawn mode as argument of the MPI_Comm_Spawn_Multiple).
09677
09678 2) the number of processes to run this host (used in the not spawn method to split the global communicator; for the spawn method, used as argument in MPI_Comm_Spawn_Multiple ).}
09679 entry_help_balloon $w.sform $help_text
09680
09681 # Si fermeture de la fenêtre, cache la bulle d'aide
09682 bind $u <Destroy> "help_object_hide"
09683 }
09684
09685 ret {application_update} (type win , type nom_, type appli , type exe_, type name , type args , type redirect , type hosts_, type list) {
09686 # Validation de saisie des parametres d'une application
09687 global dico_applis
09688
09689 upvar 1 $hosts_list hosts
09690
09691 # Si l'application doit être lancée par OASIS
09692 set start_mode $dico_applis(app.$nom_appli.start_mode)
09693 if {$start_mode != "notspawn"} {
09694 # Vérifie le nom du prog. exe
09695 if { $exe_name == "" } {
09696 notice_show "Please, enter an executable file name !" error
09697 focus .mod_appli.char.entry3
09698 return error
09699 }
09700 }
09701
09702 # Vérifie le nombre des ordinateurs hosts de l'application
09703 # --------------------------------------------------------
09704
09705 if { [llength $hosts(lhosts)] != 0 } {
09706
09707 set nb_proc_total 0
09708 foreach id_host $hosts(lhosts) {
09709 # Si le nom ou le nombre de processus de l'ordinateur host est defini
09710 if {$hosts(host.$id_host.name) != "" || $hosts(host.$id_host.nb_procs) != ""} {
09711 # Si le nbre de processus est défini
09712 if { [regexp {^[0-9]+$} $hosts(host.$id_host.nb_procs)] } {
09713 # Additionne au total
09714 incr nb_proc_total $hosts(host.$id_host.nb_procs)
09715 }
09716 }
09717 }
09718
09719 # Verifie que le nombre de processus est dans la fourchette acceptable pour l'appli
09720 set min_proc $dico_applis(app.$nom_appli.proc.min_value)
09721 set max_proc $dico_applis(app.$nom_appli.proc.max_value)
09722 set increment $dico_applis(app.$nom_appli.proc.increment)
09723 if {$max_proc != 0} {
09724 if { $nb_proc_total >= $min_proc && $nb_proc_total <= $max_proc } {
09725
09726 # Vérifie que le nombre est un multiple attendu
09727 if {[expr ($nb_proc_total - $min_proc) % $increment] == 0} {
09728 # OK
09729 } else {
09730 notice_show "Total number of processes ($nb_proc_total) out of the arithmetic series : \[$min_proc to $max_proc\] step $increment !" error
09731 return error
09732 }
09733 } else {
09734 notice_show "Total number of processes ($nb_proc_total) out of the range \[$min_proc, $max_proc\]!" error
09735 return error
09736 }
09737 }
09738
09739 # Recopie les infos concernant l'application
09740 set dico_applis(app.$nom_appli.executable_name) $exe_name
09741 set dico_applis(app.$nom_appli.args) $args
09742 if { $redirect == "yes" } {
09743 set redirect "true"
09744 } else {
09745 set redirect "false"
09746 }
09747 set dico_applis(app.$nom_appli.redirect) $redirect
09748
09749 # Recopie les infos concernant les ordinateurs hosts de l'application
09750 set dico_applis(app.$nom_appli.lhosts) {}
09751 array unset dico_applis app.$nom_appli.host.*
09752 foreach id_host $hosts(lhosts) {
09753 # Si le nom de l'ordinateur host est defini
09754 if {$hosts(host.$id_host.name) != ""} {
09755 # Si le nbre de processus est défini
09756 if { [regexp {^[0-9]+$} $hosts(host.$id_host.nb_procs)] } {
09757 lappend dico_applis(app.$nom_appli.lhosts) $id_host
09758 set clef app.$nom_appli.host.$id_host
09759 set dico_applis($clef.name) $hosts(host.$id_host.name)
09760 set dico_applis($clef.nb_procs) $hosts(host.$id_host.nb_procs)
09761 }
09762 }
09763 }
09764 destroy $win
09765 } else {
09766 notice_show "Please, enter some host on which the application will run !" error
09767 return error
09768 }
09769 }
09770
09771 ret {chemin} (type x1 , type y1 , type x2 , type y2) {
09772 #=========de dessus a dessous
09773 if { $y1 < $y2 } {
09774 set y10 [expr $y1 +12 ]
09775 set y11 [expr $y2 -12]
09776 set y3 [expr $y1+($y2-$y1)/10 +12]
09777 set y4 [expr $y2-($y2-$y1)/10 -12]
09778 set x3 [expr $x1+($x2-$x1)/10 ]
09779 set x4 [expr $x2-($x2-$x1)/10 ]
09780 return "$x1 $y1 $x1 $y10 $x3 $y3 $x4 $y4 $x2 $y11 $x2 $y2"
09781 #=========de dessous a dessus
09782 } else {
09783 set y3 [expr $y1 +12]
09784 set y4 [expr $y2 -12]
09785 set x3 [expr ($x1+$x2)/2]
09786 return "$x1 $y1 $x1 $y3 $x3 $y3 $x3 $y4 $x2 $y4 $x2 $y2"
09787 }
09788 }
09789
09790 ret {chemin_force} (type x1 , type y1 , type x2 , type y2 , optional milieu_x ={) {milieu_y {}}} {
09791
09792
09793 if { $y1 < $y2 } {
09794 y10 = [expr $y1 +12 ]
09795 y11 = [expr $y2 -12]
09796 y3 = [expr $y1+($y2-$y1)/10 +12]
09797 y4 = [expr $y2-($y2-$y1)/10 -12]
09798 x3 = [expr $x1+($x2-$x1)/10 ]
09799 x4 = [expr $x2-($x2-$x1)/10 ]
09800 if { $milieu_x != ""} {
09801 return "$x1 $y1 $x1 $y10 $x3 $y3 $milieu_x $milieu_y $x4 $y4 $x2 $y11 $x2 $y2"
09802 } else {
09803 return "$x1 $y1 $x1 $y10 $x3 $y3 $x4 $y4 $x2 $y11 $x2 $y2"
09804 }
09805
09806 } else {
09807 y3 = [expr $y1 +12]
09808 y4 = [expr $y2 -12]
09809 x3 = [expr ($x1+$x2)/2]
09810 if { $milieu_x != ""} {
09811 if { $milieu_y > $y3 } {
09812 y3 = [expr $milieu_y +12]
09813 }
09814 if { $milieu_y < $y4 } {
09815 y4 = [expr $milieu_y -12]
09816 }
09817 return "$x1 $y1 $x1 $y3 $milieu_x $y3 $milieu_x $milieu_y $milieu_x $y4 $x2 $y4 $x2 $y2"
09818 } else {
09819 return "$x1 $y1 $x1 $y3 $x3 $y3 $x3 $y4 $x2 $y4 $x2 $y2"
09820 }
09821 }
09822 }
09823
09824 ret {choose_font} (optional choose_init ={helvetica 12) texttoedit colortext just} {
09825 set w .choose_font
09826 global dxf
09827 set dxf(text) $texttoedit
09828 set dxf(choose_font_cb_color) $colortext
09829 set dxf(choose_font_cb_justify) $just
09830 set tmp [get_actual_font $choose_init]
09831
09832 window.font $choose_init $texttoedit
09833 update
09834
09835 catch {.choose_font.view delete 0.0 end}
09836 catch {.choose_font.view insert 0.0 $texttoedit}
09837 catch {.choose_font.view configure -foreground $colortext}
09838 catch {.choose_font.view configure -justify $just}
09839 update
09840 catch {grab $w}
09841 focus -force $w
09842 wm deiconify $w
09843 tkwait window $w
09844
09845 grab release $w
09846 return [list $dxf(tmp) $dxf(text) $dxf(choose_font_cb_color) $dxf(choose_font_cb_justify)]
09847 }
09848
09849 ret {color_fonce} (type color) {
09850 set r 0
09851 set g 0
09852 set b 0
09853 scan $color "\#%2x%2x%2x" r g b
09854 set r [expr $r*7/8]
09855 set g [expr $g*7/8]
09856 set b [expr $b*7/8]
09857
09858 return [color_rgb $r $g $b]
09859 }
09860
09861 ret {color_melange} (type color1 , type color2) {
09862 set r 0
09863 set g 0
09864 set b 0
09865 set r1 0
09866 set g1 0
09867 set b1 0
09868
09869
09870 scan $color1 "\#%2x%2x%2x" r g b
09871 scan $color2 "\#%2x%2x%2x" r1 g1 b1
09872 set r [expr ($r+$r1)/2]
09873 set g [expr ($g+$g1)/2]
09874 set b [expr ($b+$b1)/2]
09875 return [color_rgb $r $g $b]
09876 }
09877
09878 ret {color_pastelise} (type color) {
09879 set r 0
09880 set g 0
09881 set b 0
09882
09883
09884 scan $color "\#%2x%2x%2x" r g b
09885 set r [expr ($r+127)/3*2]
09886 set g [expr ($g+127)/3*2]
09887 set b [expr ($b+127)/3*2]
09888 return [color_rgb $r $g $b]
09889 }
09890
09891 ret {color_rgb} (type r , type g , type b) {
09892 set rgb \#[format "%.2X%.2X%.2X" $r $g $b]
09893 return $rgb
09894 }
09895
09896 ret {color_tresclair} (type color) {
09897 set r 0
09898 set g 0
09899 set b 0
09900 scan $color "\#%2x%2x%2x" r g b
09901
09902 while {[expr $r+$g+$b] < 712} {
09903 set r [expr ($r+127)/3*2]
09904 set g [expr ($g+127)/3*2]
09905 set b [expr ($b+127)/3*2]
09906 }
09907 return [color_rgb $r $g $b]
09908 }
09909
09910 ret {color_white_or_black} (type color) {
09911 set r 0
09912 set g 0
09913 set b 0
09914
09915 scan $color "\#%2x%2x%2x" r g b
09916 set colorreturn white
09917 if {[expr $r + $g + $b] > 300 } {set colorreturn black}
09918
09919 return $colorreturn
09920 }
09921
09922 ret {combobox_init} () {
09923 # Copyright (c) 1998-2002, Bryan Oakley
09924 # All Rights Reservered
09925 #
09926 # Bryan Oakley
09927 # oakley@bardo.clearlight.com
09928 #
09929 # combobox v2.2.1 September 22, 2002
09930 #
09931 # a combobox / dropdown listbox (pick your favorite name) widget
09932 # written in pure tcl
09933 #
09934 # this code is freely distributable without restriction, but is
09935 # provided as-is with no warranty expressed or implied.
09936 #
09937 # thanks to the following people who provided beta test support or
09938 # patches to the code (in no particular order):
09939 #
09940 # Scott Beasley Alexandre Ferrieux Todd Helfter
09941 # Matt Gushee Laurent Duperval John Jackson
09942 # Fred Rapp Christopher Nelson
09943 # Eric Galluzzo Jean-Francois Moine
09944 #
09945 # A special thanks to Martin M. Hunt who provided several good ideas,
09946 # and always with a patch to implement them. Jean-Francois Moine,
09947 # Todd Helfter and John Jackson were also kind enough to send in some
09948 # code patches.
09949 #
09950 # ... and many others over the years.
09951
09952 package require Tk 8.0
09953 package provide combobox 2.2.1
09954
09955 namespace eval ::combobox {
09956
09957 # this is the public interface
09958 namespace export combobox
09959
09960 # these contain references to available options
09961 variable widgetOptions
09962
09963 # these contain references to available commands and subcommands
09964 variable widgetCommands
09965 variable scanCommands
09966 variable listCommands
09967 }
09968
09969 # ::combobox::combobox --
09970 #
09971 # This is the command that gets exported. It creates a new
09972 # combobox widget.
09973 #
09974 # Arguments:
09975 #
09976 # w path of new widget to create
09977 # args additional option/value pairs (eg: -background white, etc.)
09978 #
09979 # Results:
09980 #
09981 # It creates the widget and sets up all of the default bindings
09982 #
09983 # Returns:
09984 #
09985 # The name of the newly create widget
09986
09987 proc ::combobox::combobox {w args} {
09988 variable widgetOptions
09989 variable widgetCommands
09990 variable scanCommands
09991 variable listCommands
09992
09993 # perform a one time initialization
09994 if {![info exists widgetOptions]} {
09995 Init
09996 }
09997
09998 # build it...
09999 eval Build $w $args
10000
10001 # set some bindings...
10002 SetBindings $w
10003
10004 # and we are done!
10005 return $w
10006 }
10007
10008
10009 # ::combobox::Init --
10010 #
10011 # Initialize the namespace variables. This should only be called
10012 # once, immediately prior to creating the first instance of the
10013 # widget
10014 #
10015 # Arguments:
10016 #
10017 # none
10018 #
10019 # Results:
10020 #
10021 # All state variables are set to their default values; all of
10022 # the option database entries will exist.
10023 #
10024 # Returns:
10025 #
10026 # empty string
10027
10028 proc ::combobox::Init {} {
10029 variable widgetOptions
10030 variable widgetCommands
10031 variable scanCommands
10032 variable listCommands
10033 variable defaultEntryCursor
10034
10035 array set widgetOptions [list -background {background Background} -bd -borderwidth -bg -background -borderwidth {borderWidth BorderWidth} -command {command Command} -commandstate {commandState State} -cursor {cursor Cursor} -disabledbackground {disabledBackground DisabledBackground} -disabledforeground {disabledForeground DisabledForeground} -dropdownwidth {dropdownWidth DropdownWidth} -editable {editable Editable} -fg -foreground -font {font Font} -foreground {foreground Foreground} -height {height Height} -highlightbackground {highlightBackground HighlightBackground} -highlightcolor {highlightColor HighlightColor} -highlightthickness {highlightThickness HighlightThickness} -image {image Image} -maxheight {maxHeight Height} -opencommand {opencommand Command} -relief {relief Relief} -selectbackground {selectBackground Foreground} -selectborderwidth {selectBorderWidth BorderWidth} -selectforeground {selectForeground Background} -state {state State} -takefocus {takeFocus TakeFocus} -textvariable {textVariable Variable} -value {value Value} -width {width Width} -xscrollcommand {xScrollCommand ScrollCommand} ]
10036
10037
10038 set widgetCommands [list bbox cget configure curselection delete get icursor index insert list scan selection xview select toggle open close ]
10039
10040 set listCommands [list delete get index insert size ]
10041
10042 set scanCommands [list mark dragto]
10043
10044 # why check for the Tk package? This lets us be sourced into
10045 # an interpreter that doesn't have Tk loaded, such as the slave
10046 # interpreter used by pkg_mkIndex. In theory it should have no
10047 # side effects when run
10048 if {[lsearch -exact [package names] "Tk"] != -1} {
10049
10050 ##################################################################
10051 #- this initializes the option database. Kinda gross, but it works
10052 #- (I think).
10053 ##################################################################
10054
10055 # the image used for the button...
10056 if {$::tcl_platform(platform) == "windows"} {
10057 image create bitmap ::combobox::bimage -data {
10058 #define down_arrow_width 12
10059 #define down_arrow_height 12
10060 static char down_arrow_bits[] = {
10061 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
10062 0xfc,0xf1,0xf8,0xf0,0x70,0xf0,0x20,0xf0,
10063 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00;
10064 }
10065 }
10066 } else {
10067 image create bitmap ::combobox::bimage -data {
10068 #define down_arrow_width 15
10069 #define down_arrow_height 15
10070 static char down_arrow_bits[] = {
10071 0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,
10072 0x00,0x80,0xf8,0x8f,0xf0,0x87,0xe0,0x83,
10073 0xc0,0x81,0x80,0x80,0x00,0x80,0x00,0x80,
10074 0x00,0x80,0x00,0x80,0x00,0x80
10075 }
10076 }
10077 }
10078
10079 # compute a widget name we can use to create a temporary widget
10080 set tmpWidget ".__tmp__"
10081 set count 0
10082 while {[winfo exists $tmpWidget] == 1} {
10083 set tmpWidget ".__tmp__$count"
10084 incr count
10085 }
10086
10087 # get the scrollbar width. Because we try to be clever and draw our
10088 # own button instead of using a tk widget, we need to know what size
10089 # button to create. This little hack tells us the width of a scroll
10090 # bar.
10091 #
10092 # NB: we need to be sure and pick a window that doesn't already
10093 # exist...
10094 scrollbar $tmpWidget
10095 set sb_width [winfo reqwidth $tmpWidget]
10096 destroy $tmpWidget
10097
10098 # steal options from the entry widget
10099 # we want darn near all options, so we'll go ahead and do
10100 # them all. No harm done in adding the one or two that we
10101 # don't use.
10102 entry $tmpWidget
10103 foreach foo [$tmpWidget configure] {
10104 # the cursor option is special, so we'll save it in
10105 # a special way
10106 if {[lindex $foo 0] == "-cursor"} {
10107 set defaultEntryCursor [lindex $foo 4]
10108 }
10109 if {[llength $foo] == 5} {
10110 set option [lindex $foo 1]
10111 set value [lindex $foo 4]
10112 option add *Combobox.$option $value widgetDefault
10113
10114 # these options also apply to the dropdown listbox
10115 if {[string compare $option "foreground"] == 0 || [string compare $option "background"] == 0 || [string compare $option "font"] == 0} {
10116 option add *Combobox*ComboboxListbox.$option $value widgetDefault
10117 }
10118 }
10119 }
10120 destroy $tmpWidget
10121
10122 # these are unique to us...
10123 option add *Combobox.dropdownWidth {} widgetDefault
10124 option add *Combobox.openCommand {} widgetDefault
10125 option add *Combobox.cursor {} widgetDefault
10126 option add *Combobox.commandState normal widgetDefault
10127 option add *Combobox.editable 1 widgetDefault
10128 option add *Combobox.maxHeight 10 widgetDefault
10129 option add *Combobox.height 0
10130 }
10131
10132 # set class bindings
10133 SetClassBindings
10134 }
10135
10136 # ::combobox::SetClassBindings --
10137 #
10138 # Sets up the default bindings for the widget class
10139 #
10140 # this proc exists since it's The Right Thing To Do, but
10141 # I haven't had the time to figure out how to do all the
10142 # binding stuff on a class level. The main problem is that
10143 # the entry widget must have focus for the insertion cursor
10144 # to be visible. So, I either have to have the entry widget
10145 # have the Combobox bindtag, or do some fancy juggling of
10146 # events or some such. What a pain.
10147 #
10148 # Arguments:
10149 #
10150 # none
10151 #
10152 # Returns:
10153 #
10154 # empty string
10155
10156 proc ::combobox::SetClassBindings {} {
10157
10158 # make sure we clean up after ourselves...
10159 bind Combobox <Destroy> [list ::combobox::DestroyHandler %W]
10160
10161 # this will (hopefully) close (and lose the grab on) the
10162 # listbox if the user clicks anywhere outside of it. Note
10163 # that on Windows, you can click on some other app and
10164 # the listbox will still be there, because tcl won't see
10165 # that button click
10166 set this {[::combobox::convert %W -W]}
10167 bind Combobox <Any-ButtonPress> "$this close"
10168 bind Combobox <Any-ButtonRelease> "$this close"
10169
10170 # this helps (but doesn't fully solve) focus issues. The general
10171 # idea is, whenever the frame gets focus it gets passed on to
10172 # the entry widget
10173 bind Combobox <FocusIn> {::combobox::tkTabToWindow [::combobox::convert %W -W].entry}
10174
10175 # this closes the listbox if we get hidden
10176 bind Combobox <Unmap> {[::combobox::convert %W -W] close}
10177
10178 return ""
10179 }
10180
10181 # ::combobox::SetBindings --
10182 #
10183 # here's where we do most of the binding foo. I think there's probably
10184 # a few bindings I ought to add that I just haven't thought
10185 # about...
10186 #
10187 # I'm not convinced these are the proper bindings. Ideally all
10188 # bindings should be on "Combobox", but because of my juggling of
10189 # bindtags I'm not convinced thats what I want to do. But, it all
10190 # seems to work, its just not as robust as it could be.
10191 #
10192 # Arguments:
10193 #
10194 # w widget pathname
10195 #
10196 # Returns:
10197 #
10198 # empty string
10199
10200 proc ::combobox::SetBindings {w} {
10201 upvar ::combobox::${w}::widgets widgets
10202 upvar ::combobox::${w}::options options
10203
10204 # juggle the bindtags. The basic idea here is to associate the
10205 # widget name with the entry widget, so if a user does a bind
10206 # on the combobox it will get handled properly since it is
10207 # the entry widget that has keyboard focus.
10208 bindtags $widgets(entry) [concat $widgets(this) [bindtags $widgets(entry)]]
10209
10210 bindtags $widgets(button) [concat $widgets(this) [bindtags $widgets(button)]]
10211
10212 # override the default bindings for tab and shift-tab. The
10213 # focus procs take a widget as their only parameter and we
10214 # want to make sure the right window gets used (for shift-
10215 # tab we want it to appear as if the event was generated
10216 # on the frame rather than the entry.
10217 bind $widgets(entry) <Tab> "::combobox::tkTabToWindow \[tk_focusNext $widgets(entry)\]; break"
10218 bind $widgets(entry) <Shift-Tab> "::combobox::tkTabToWindow \[tk_focusPrev $widgets(this)\]; break"
10219
10220 # this makes our "button" (which is actually a label)
10221 # do the right thing
10222 bind $widgets(button) <ButtonPress-1> [list $widgets(this) toggle]
10223
10224 # this lets the autoscan of the listbox work, even if they
10225 # move the cursor over the entry widget.
10226 bind $widgets(entry) <B1-Enter> "break"
10227
10228 bind $widgets(listbox) <ButtonRelease-1> "::combobox::Select [list $widgets(this)] \[$widgets(listbox) nearest %y\]; break"
10229
10230 bind $widgets(vsb) <ButtonPress-1> {continue}
10231 bind $widgets(vsb) <ButtonRelease-1> {continue}
10232
10233 bind $widgets(listbox) <Any-Motion> {
10234 %W selection clear 0 end
10235 %W activate @%x,%y
10236 %W selection anchor @%x,%y
10237 %W selection set @%x,%y @%x,%y
10238 # need to do a yview if the cursor goes off the top
10239 # or bottom of the window... (or do we?)
10240 }
10241
10242 # these events need to be passed from the entry widget
10243 # to the listbox, or otherwise need some sort of special
10244 # handling.
10245 foreach event [list <Up> <Down> <Tab> <Return> <Escape> <Next> <Prior> <Double-1> <1> <Any-KeyPress> <FocusIn> <FocusOut>] {
10246 bind $widgets(entry) $event [list ::combobox::HandleEvent $widgets(this) $event]
10247 }
10248
10249 # like the other events, <MouseWheel> needs to be passed from
10250 # the entry widget to the listbox. However, in this case we
10251 # need to add an additional parameter
10252 catch {
10253 bind $widgets(entry) <MouseWheel> [list ::combobox::HandleEvent $widgets(this) <MouseWheel> %D]
10254 }
10255 }
10256
10257 # ::combobox::Build --
10258 #
10259 # This does all of the work necessary to create the basic
10260 # combobox.
10261 #
10262 # Arguments:
10263 #
10264 # w widget name
10265 # args additional option/value pairs
10266 #
10267 # Results:
10268 #
10269 # Creates a new widget with the given name. Also creates a new
10270 # namespace patterened after the widget name, as a child namespace
10271 # to ::combobox
10272 #
10273 # Returns:
10274 #
10275 # the name of the widget
10276
10277 proc ::combobox::Build {w args } {
10278 variable widgetOptions
10279
10280 if {[winfo exists $w]} {
10281 error "window name \"$w\" already exists"
10282 }
10283
10284 # create the namespace for this instance, and define a few
10285 # variables
10286 namespace eval ::combobox::$w {
10287
10288 variable ignoreTrace 0
10289 variable oldFocus {}
10290 variable oldGrab {}
10291 variable oldValue {}
10292 variable options
10293 variable this
10294 variable widgets
10295
10296 set widgets(foo) foo ;# coerce into an array
10297 set options(foo) foo ;# coerce into an array
10298
10299 unset widgets(foo)
10300 unset options(foo)
10301 }
10302
10303 # import the widgets and options arrays into this proc so
10304 # we don't have to use fully qualified names, which is a
10305 # pain.
10306 upvar ::combobox::${w}::widgets widgets
10307 upvar ::combobox::${w}::options options
10308
10309 # this is our widget -- a frame of class Combobox. Naturally,
10310 # it will contain other widgets. We create it here because
10311 # we need it in order to set some default options.
10312 set widgets(this) [frame $w -class Combobox -takefocus 0]
10313 set widgets(entry) [entry $w.entry -takefocus 1]
10314 set widgets(button) [label $w.button -takefocus 0]
10315
10316 # this defines all of the default options. We get the
10317 # values from the option database. Note that if an array
10318 # value is a list of length one it is an alias to another
10319 # option, so we just ignore it
10320 foreach name [array names widgetOptions] {
10321 if {[llength $widgetOptions($name)] == 1} continue
10322
10323 set optName [lindex $widgetOptions($name) 0]
10324 set optClass [lindex $widgetOptions($name) 1]
10325
10326 set value [option get $w $optName $optClass]
10327 set options($name) $value
10328 }
10329
10330 # a couple options aren't available in earlier versions of
10331 # tcl, so we'll set them to sane values. For that matter, if
10332 # they exist but are empty, set them to sane values.
10333 if {[string length $options(-disabledforeground)] == 0} {
10334 set options(-disabledforeground) $options(-foreground)
10335 }
10336 if {[string length $options(-disabledbackground)] == 0} {
10337 set options(-disabledbackground) $options(-background)
10338 }
10339
10340 # if -value is set to null, we'll remove it from our
10341 # local array. The assumption is, if the user sets it from
10342 # the option database, they will set it to something other
10343 # than null (since it's impossible to determine the difference
10344 # between a null value and no value at all).
10345 if {[info exists options(-value)] && [string length $options(-value)] == 0} {
10346 unset options(-value)
10347 }
10348
10349 # we will later rename the frame's widget proc to be our
10350 # own custom widget proc. We need to keep track of this
10351 # new name, so we'll define and store it here...
10352 set widgets(frame) ::combobox::${w}::$w
10353
10354 # gotta do this sooner or later. Might as well do it now
10355 pack $widgets(entry) -side left -fill both -expand yes
10356 pack $widgets(button) -side right -fill y -expand no
10357
10358 # I should probably do this in a catch, but for now it's
10359 # good enough... What it does, obviously, is put all of
10360 # the option/values pairs into an array. Make them easier
10361 # to handle later on...
10362 array set options $args
10363
10364 # now, the dropdown list... the same renaming nonsense
10365 # must go on here as well...
10366 set widgets(dropdown) [toplevel $w.top]
10367 set widgets(listbox) [listbox $w.top.list]
10368 set widgets(vsb) [scrollbar $w.top.vsb]
10369
10370 pack $widgets(listbox) -side left -fill both -expand y
10371
10372 # fine tune the widgets based on the options (and a few
10373 # arbitrary values...)
10374
10375 # NB: we are going to use the frame to handle the relief
10376 # of the widget as a whole, so the entry widget will be
10377 # flat. This makes the button which drops down the list
10378 # to appear "inside" the entry widget.
10379
10380 $widgets(vsb) configure -command "$widgets(listbox) yview" -highlightthickness 0
10381
10382 $widgets(button) configure -highlightthickness 0 -borderwidth 1 -relief raised -width [expr {[winfo reqwidth $widgets(vsb)] - 2}]
10383
10384 $widgets(entry) configure -borderwidth 0 -relief flat -highlightthickness 0
10385
10386 $widgets(dropdown) configure -borderwidth 1 -relief sunken
10387
10388 $widgets(listbox) configure -selectmode browse -background [$widgets(entry) cget -bg] -yscrollcommand "$widgets(vsb) set" -exportselection false -borderwidth 0
10389
10390
10391 # trace variable ::combobox::${w}::entryTextVariable w # [list ::combobox::EntryTrace $w]
10392
10393 # do some window management foo on the dropdown window
10394 wm overrideredirect $widgets(dropdown) 1
10395 wm transient $widgets(dropdown) [winfo toplevel $w]
10396 wm group $widgets(dropdown) [winfo parent $w]
10397 wm resizable $widgets(dropdown) 0 0
10398 wm withdraw $widgets(dropdown)
10399
10400 # this moves the original frame widget proc into our
10401 # namespace and gives it a handy name
10402 rename ::$w $widgets(frame)
10403
10404 # now, create our widget proc. Obviously (?) it goes in
10405 # the global namespace. All combobox widgets will actually
10406 # share the same widget proc to cut down on the amount of
10407 # bloat.
10408 proc ::$w {command args} "eval ::combobox::WidgetProc $w \$command \$args"
10409
10410
10411 # ok, the thing exists... let's do a bit more configuration.
10412 if {[catch "::combobox::Configure [list $widgets(this)] [array get options]" error]} {
10413 catch {destroy $w}
10414 error "internal error: $error"
10415 }
10416
10417 return ""
10418
10419 }
10420
10421 # ::combobox::HandleEvent --
10422 #
10423 # this proc handles events from the entry widget that we want
10424 # handled specially (typically, to allow navigation of the list
10425 # even though the focus is in the entry widget)
10426 #
10427 # Arguments:
10428 #
10429 # w widget pathname
10430 # event a string representing the event (not necessarily an
10431 # actual event)
10432 # args additional arguments required by particular events
10433
10434 proc ::combobox::HandleEvent {w event args} {
10435 upvar ::combobox::${w}::widgets widgets
10436 upvar ::combobox::${w}::options options
10437 upvar ::combobox::${w}::oldValue oldValue
10438
10439 # for all of these events, if we have a special action we'll
10440 # do that and do a "return -code break" to keep additional
10441 # bindings from firing. Otherwise we'll let the event fall
10442 # on through.
10443 switch $event {
10444
10445 "<MouseWheel>" {
10446 if {[winfo ismapped $widgets(dropdown)]} {
10447 set D [lindex $args 0]
10448 # the '120' number in the following expression has
10449 # it's genesis in the tk bind manpage, which suggests
10450 # that the smallest value of %D for mousewheel events
10451 # will be 120. The intent is to scroll one line at a time.
10452 $widgets(listbox) yview scroll [expr {-($D/120)}] units
10453 }
10454 }
10455
10456 "<Any-KeyPress>" {
10457 # if the widget is editable, clear the selection.
10458 # this makes it more obvious what will happen if the
10459 # user presses <Return> (and helps our code know what
10460 # to do if the user presses return)
10461 if {$options(-editable)} {
10462 $widgets(listbox) see 0
10463 $widgets(listbox) selection clear 0 end
10464 $widgets(listbox) selection anchor 0
10465 $widgets(listbox) activate 0
10466 }
10467 }
10468
10469 "<FocusIn>" {
10470 set oldValue [$widgets(entry) get]
10471 }
10472
10473 "<FocusOut>" {
10474 if {![winfo ismapped $widgets(dropdown)]} {
10475 # did the value change?
10476 set newValue [$widgets(entry) get]
10477 if {$oldValue != $newValue} {
10478 CallCommand $widgets(this) $newValue
10479 }
10480 }
10481 }
10482
10483 "<1>" {
10484 set editable [::combobox::GetBoolean $options(-editable)]
10485 if {!$editable} {
10486 if {[winfo ismapped $widgets(dropdown)]} {
10487 $widgets(this) close
10488 return -code break;
10489
10490 } else {
10491 if {$options(-state) != "disabled"} {
10492 $widgets(this) open
10493 return -code break;
10494 }
10495 }
10496 }
10497 }
10498
10499 "<Double-1>" {
10500 if {$options(-state) != "disabled"} {
10501 $widgets(this) toggle
10502 return -code break;
10503 }
10504 }
10505
10506 "<Tab>" {
10507 if {[winfo ismapped $widgets(dropdown)]} {
10508 ::combobox::Find $widgets(this) 0
10509 return -code break;
10510 } else {
10511 ::combobox::SetValue $widgets(this) [$widgets(this) get]
10512 }
10513 }
10514
10515 "<Escape>" {
10516 # $widgets(entry) delete 0 end
10517 # $widgets(entry) insert 0 $oldValue
10518 if {[winfo ismapped $widgets(dropdown)]} {
10519 $widgets(this) close
10520 return -code break;
10521 }
10522 }
10523
10524 "<Return>" {
10525 # did the value change?
10526 set newValue [$widgets(entry) get]
10527 if {$oldValue != $newValue} {
10528 CallCommand $widgets(this) $newValue
10529 }
10530
10531 if {[winfo ismapped $widgets(dropdown)]} {
10532 ::combobox::Select $widgets(this) [$widgets(listbox) curselection]
10533 return -code break;
10534 }
10535
10536 }
10537
10538 "<Next>" {
10539 $widgets(listbox) yview scroll 1 pages
10540 set index [$widgets(listbox) index @0,0]
10541 $widgets(listbox) see $index
10542 $widgets(listbox) activate $index
10543 $widgets(listbox) selection clear 0 end
10544 $widgets(listbox) selection anchor $index
10545 $widgets(listbox) selection set $index
10546
10547 }
10548
10549 "<Prior>" {
10550 $widgets(listbox) yview scroll -1 pages
10551 set index [$widgets(listbox) index @0,0]
10552 $widgets(listbox) activate $index
10553 $widgets(listbox) see $index
10554 $widgets(listbox) selection clear 0 end
10555 $widgets(listbox) selection anchor $index
10556 $widgets(listbox) selection set $index
10557 }
10558
10559 "<Down>" {
10560 if {[winfo ismapped $widgets(dropdown)]} {
10561 ::combobox::tkListboxUpDown $widgets(listbox) 1
10562 return -code break;
10563
10564 } else {
10565 if {$options(-state) != "disabled"} {
10566 $widgets(this) open
10567 return -code break;
10568 }
10569 }
10570 }
10571 "<Up>" {
10572 if {[winfo ismapped $widgets(dropdown)]} {
10573 ::combobox::tkListboxUpDown $widgets(listbox) -1
10574 return -code break;
10575
10576 } else {
10577 if {$options(-state) != "disabled"} {
10578 $widgets(this) open
10579 return -code break;
10580 }
10581 }
10582 }
10583 }
10584
10585 return ""
10586 }
10587
10588 # ::combobox::DestroyHandler {w} --
10589 #
10590 # Cleans up after a combobox widget is destroyed
10591 #
10592 # Arguments:
10593 #
10594 # w widget pathname
10595 #
10596 # Results:
10597 #
10598 # The namespace that was created for the widget is deleted,
10599 # and the widget proc is removed.
10600
10601 proc ::combobox::DestroyHandler {w} {
10602
10603 # if the widget actually being destroyed is of class Combobox,
10604 # crush the namespace and kill the proc. Get it? Crush. Kill.
10605 # Destroy. Heh. Danger Will Robinson! Oh, man! I'm so funny it
10606 # brings tears to my eyes.
10607 if {[string compare [winfo class $w] "Combobox"] == 0} {
10608 upvar ::combobox::${w}::widgets widgets
10609 upvar ::combobox::${w}::options options
10610
10611 # delete the namespace and the proc which represents
10612 # our widget
10613 namespace delete ::combobox::$w
10614 rename $w {}
10615 }
10616
10617 return ""
10618 }
10619
10620 # ::combobox::Find
10621 #
10622 # finds something in the listbox that matches the pattern in the
10623 # entry widget and selects it
10624 #
10625 # N.B. I'm not convinced this is working the way it ought to. It
10626 # works, but is the behavior what is expected? I've also got a gut
10627 # feeling that there's a better way to do this, but I'm too lazy to
10628 # figure it out...
10629 #
10630 # Arguments:
10631 #
10632 # w widget pathname
10633 # exact boolean; if true an exact match is desired
10634 #
10635 # Returns:
10636 #
10637 # Empty string
10638
10639 proc ::combobox::Find {w {exact 0}} {
10640 upvar ::combobox::${w}::widgets widgets
10641 upvar ::combobox::${w}::options options
10642
10643 ## *sigh* this logic is rather gross and convoluted. Surely
10644 ## there is a more simple, straight-forward way to implement
10645 ## all this. As the saying goes, I lack the time to make it
10646 ## shorter...
10647
10648 # use what is already in the entry widget as a pattern
10649 set pattern [$widgets(entry) get]
10650
10651 if {[string length $pattern] == 0} {
10652 # clear the current selection
10653 $widgets(listbox) see 0
10654 $widgets(listbox) selection clear 0 end
10655 $widgets(listbox) selection anchor 0
10656 $widgets(listbox) activate 0
10657 return
10658 }
10659
10660 # we're going to be searching this list...
10661 set list [$widgets(listbox) get 0 end]
10662
10663 # if we are doing an exact match, try to find,
10664 # well, an exact match
10665 set exactMatch -1
10666 if {$exact} {
10667 set exactMatch [lsearch -exact $list $pattern]
10668 }
10669
10670 # search for it. We'll try to be clever and not only
10671 # search for a match for what they typed, but a match for
10672 # something close to what they typed. We'll keep removing one
10673 # character at a time from the pattern until we find a match
10674 # of some sort.
10675 set index -1
10676 while {$index == -1 && [string length $pattern]} {
10677 set index [lsearch -glob $list "$pattern*"]
10678 if {$index == -1} {
10679 regsub {.$} $pattern {} pattern
10680 }
10681 }
10682
10683 # this is the item that most closely matches...
10684 set thisItem [lindex $list $index]
10685
10686 # did we find a match? If so, do some additional munging...
10687 if {$index != -1} {
10688
10689 # we need to find the part of the first item that is
10690 # unique WRT the second... I know there's probably a
10691 # simpler way to do this...
10692
10693 set nextIndex [expr {$index + 1}]
10694 set nextItem [lindex $list $nextIndex]
10695
10696 # we don't really need to do much if the next
10697 # item doesn't match our pattern...
10698 if {[string match $pattern* $nextItem]} {
10699 # ok, the next item matches our pattern, too
10700 # now the trick is to find the first character
10701 # where they *don't* match...
10702 set marker [string length $pattern]
10703 while {$marker <= [string length $pattern]} {
10704 set a [string index $thisItem $marker]
10705 set b [string index $nextItem $marker]
10706 if {[string compare $a $b] == 0} {
10707 append pattern $a
10708 incr marker
10709 } else {
10710 break
10711 }
10712 }
10713 } else {
10714 set marker [string length $pattern]
10715 }
10716
10717 } else {
10718 set marker end
10719 set index 0
10720 }
10721
10722 # ok, we know the pattern and what part is unique;
10723 # update the entry widget and listbox appropriately
10724 if {$exact && $exactMatch == -1} {
10725 # this means we didn't find an exact match
10726 $widgets(listbox) selection clear 0 end
10727 $widgets(listbox) see $index
10728
10729 } elseif {!$exact} {
10730 # this means we found something, but it isn't an exact
10731 # match. If we find something that *is* an exact match we
10732 # don't need to do the following, since it would merely
10733 # be replacing the data in the entry widget with itself
10734 set oldstate [$widgets(entry) cget -state]
10735 $widgets(entry) configure -state normal
10736 $widgets(entry) delete 0 end
10737 $widgets(entry) insert end $thisItem
10738 $widgets(entry) selection clear
10739 $widgets(entry) selection range $marker end
10740 $widgets(listbox) activate $index
10741 $widgets(listbox) selection clear 0 end
10742 $widgets(listbox) selection anchor $index
10743 $widgets(listbox) selection set $index
10744 $widgets(listbox) see $index
10745 $widgets(entry) configure -state $oldstate
10746 }
10747 }
10748
10749 # ::combobox::Select --
10750 #
10751 # selects an item from the list and sets the value of the combobox
10752 # to that value
10753 #
10754 # Arguments:
10755 #
10756 # w widget pathname
10757 # index listbox index of item to be selected
10758 #
10759 # Returns:
10760 #
10761 # empty string
10762
10763 proc ::combobox::Select {w index} {
10764 upvar ::combobox::${w}::widgets widgets
10765 upvar ::combobox::${w}::options options
10766
10767 # the catch is because I'm sloppy -- presumably, the only time
10768 # an error will be caught is if there is no selection.
10769 if {![catch {set data [$widgets(listbox) get [lindex $index 0]]}]} {
10770 ::combobox::SetValue $widgets(this) $data
10771
10772 $widgets(listbox) selection clear 0 end
10773 $widgets(listbox) selection anchor $index
10774 $widgets(listbox) selection set $index
10775
10776 }
10777 $widgets(entry) selection range 0 end
10778
10779 $widgets(this) close
10780
10781 return ""
10782 }
10783
10784 # ::combobox::HandleScrollbar --
10785 #
10786 # causes the scrollbar of the dropdown list to appear or disappear
10787 # based on the contents of the dropdown listbox
10788 #
10789 # Arguments:
10790 #
10791 # w widget pathname
10792 # action the action to perform on the scrollbar
10793 #
10794 # Returns:
10795 #
10796 # an empty string
10797
10798 proc ::combobox::HandleScrollbar {w {action "unknown"}} {
10799 upvar ::combobox::${w}::widgets widgets
10800 upvar ::combobox::${w}::options options
10801
10802 if {$options(-height) == 0} {
10803 set hlimit $options(-maxheight)
10804 } else {
10805 set hlimit $options(-height)
10806 }
10807
10808 switch $action {
10809 "grow" {
10810 if {$hlimit > 0 && [$widgets(listbox) size] > $hlimit} {
10811 pack $widgets(vsb) -side right -fill y -expand n
10812 }
10813 }
10814
10815 "shrink" {
10816 if {$hlimit > 0 && [$widgets(listbox) size] <= $hlimit} {
10817 pack forget $widgets(vsb)
10818 }
10819 }
10820
10821 "crop" {
10822 # this means the window was cropped and we definitely
10823 # need a scrollbar no matter what the user wants
10824 pack $widgets(vsb) -side right -fill y -expand n
10825 }
10826
10827 default {
10828 if {$hlimit > 0 && [$widgets(listbox) size] > $hlimit} {
10829 pack $widgets(vsb) -side right -fill y -expand n
10830 } else {
10831 pack forget $widgets(vsb)
10832 }
10833 }
10834 }
10835
10836 return ""
10837 }
10838
10839 # ::combobox::ComputeGeometry --
10840 #
10841 # computes the geometry of the dropdown list based on the size of the
10842 # combobox...
10843 #
10844 # Arguments:
10845 #
10846 # w widget pathname
10847 #
10848 # Returns:
10849 #
10850 # the desired geometry of the listbox
10851
10852 proc ::combobox::ComputeGeometry {w} {
10853 upvar ::combobox::${w}::widgets widgets
10854 upvar ::combobox::${w}::options options
10855
10856 if {$options(-height) == 0 && $options(-maxheight) != "0"} {
10857 # if this is the case, count the items and see if
10858 # it exceeds our maxheight. If so, set the listbox
10859 # size to maxheight...
10860 set nitems [$widgets(listbox) size]
10861 if {$nitems > $options(-maxheight)} {
10862 # tweak the height of the listbox
10863 $widgets(listbox) configure -height $options(-maxheight)
10864 } else {
10865 # un-tweak the height of the listbox
10866 $widgets(listbox) configure -height 0
10867 }
10868 update idletasks
10869 }
10870
10871 # compute height and width of the dropdown list
10872 set bd [$widgets(dropdown) cget -borderwidth]
10873 set height [expr {[winfo reqheight $widgets(dropdown)] + $bd + $bd}]
10874 if {[string length $options(-dropdownwidth)] == 0 ||
10875 $options(-dropdownwidth) == 0} {
10876 set width [winfo width $widgets(this)]
10877 } else {
10878 set m [font measure [$widgets(listbox) cget -font] "m"]
10879 set width [expr {$options(-dropdownwidth) * $m}]
10880 }
10881
10882 # figure out where to place it on the screen, trying to take into
10883 # account we may be running under some virtual window manager
10884 set screenWidth [winfo screenwidth $widgets(this)]
10885 set screenHeight [winfo screenheight $widgets(this)]
10886 set rootx [winfo rootx $widgets(this)]
10887 set rooty [winfo rooty $widgets(this)]
10888 set vrootx [winfo vrootx $widgets(this)]
10889 set vrooty [winfo vrooty $widgets(this)]
10890
10891 # the x coordinate is simply the rootx of our widget, adjusted for
10892 # the virtual window. We won't worry about whether the window will
10893 # be offscreen to the left or right -- we want the illusion that it
10894 # is part of the entry widget, so if part of the entry widget is off-
10895 # screen, so will the list. If you want to change the behavior,
10896 # simply change the if statement... (and be sure to update this
10897 # comment!)
10898 set x [expr {$rootx + $vrootx}]
10899 if {0} {
10900 set rightEdge [expr {$x + $width}]
10901 if {$rightEdge > $screenWidth} {
10902 set x [expr {$screenWidth - $width}]
10903 }
10904 if {$x < 0} {set x 0}
10905 }
10906
10907 # the y coordinate is the rooty plus vrooty offset plus
10908 # the height of the static part of the widget plus 1 for a
10909 # tiny bit of visual separation...
10910 set y [expr {$rooty + $vrooty + [winfo reqheight $widgets(this)] + 1}]
10911 set bottomEdge [expr {$y + $height}]
10912
10913 if {$bottomEdge >= $screenHeight} {
10914 # ok. Fine. Pop it up above the entry widget isntead of
10915 # below.
10916 set y [expr {($rooty - $height - 1) + $vrooty}]
10917
10918 if {$y < 0} {
10919 # this means it extends beyond our screen. How annoying.
10920 # Now we'll try to be real clever and either pop it up or
10921 # down, depending on which way gives us the biggest list.
10922 # then, we'll trim the list to fit and force the use of
10923 # a scrollbar
10924
10925 # (sadly, for windows users this measurement doesn't
10926 # take into consideration the height of the taskbar,
10927 # but don't blame me -- there isn't any way to detect
10928 # it or figure out its dimensions. The same probably
10929 # applies to any window manager with some magic windows
10930 # glued to the top or bottom of the screen)
10931
10932 if {$rooty > [expr {$screenHeight / 2}]} {
10933 # we are in the lower half of the screen --
10934 # pop it up. Y is zero; that parts easy. The height
10935 # is simply the y coordinate of our widget, minus
10936 # a pixel for some visual separation. The y coordinate
10937 # will be the topof the screen.
10938 set y 1
10939 set height [expr {$rooty - 1 - $y}]
10940
10941 } else {
10942 # we are in the upper half of the screen --
10943 # pop it down
10944 set y [expr {$rooty + $vrooty + [winfo reqheight $widgets(this)] + 1}]
10945 set height [expr {$screenHeight - $y}]
10946
10947 }
10948
10949 # force a scrollbar
10950 HandleScrollbar $widgets(this) crop
10951 }
10952 }
10953
10954 if {$y < 0} {
10955 # hmmm. Bummer.
10956 set y 0
10957 set height $screenheight
10958 }
10959
10960 set geometry [format "=%dx%d+%d+%d" $width $height $x $y]
10961
10962 return $geometry
10963 }
10964
10965 # ::combobox::DoInternalWidgetCommand --
10966 #
10967 # perform an internal widget command, then mung any error results
10968 # to look like it came from our megawidget. A lot of work just to
10969 # give the illusion that our megawidget is an atomic widget
10970 #
10971 # Arguments:
10972 #
10973 # w widget pathname
10974 # subwidget pathname of the subwidget
10975 # command subwidget command to be executed
10976 # args arguments to the command
10977 #
10978 # Returns:
10979 #
10980 # The result of the subwidget command, or an error
10981
10982 proc ::combobox::DoInternalWidgetCommand {w subwidget command args} {
10983 upvar ::combobox::${w}::widgets widgets
10984 upvar ::combobox::${w}::options options
10985
10986 set subcommand $command
10987 set command [concat $widgets($subwidget) $command $args]
10988 if {[catch $command result]} {
10989 # replace the subwidget name with the megawidget name
10990 regsub $widgets($subwidget) $result $widgets(this) result
10991
10992 # replace specific instances of the subwidget command
10993 # with out megawidget command
10994 switch $subwidget,$subcommand {
10995 listbox,index {regsub "index" $result "list index" result}
10996 listbox,insert {regsub "insert" $result "list insert" result}
10997 listbox,delete {regsub "delete" $result "list delete" result}
10998 listbox,get {regsub "get" $result "list get" result}
10999 listbox,size {regsub "size" $result "list size" result}
11000 }
11001 error $result
11002
11003 } else {
11004 return $result
11005 }
11006 }
11007
11008
11009 # ::combobox::WidgetProc --
11010 #
11011 # This gets uses as the widgetproc for an combobox widget.
11012 # Notice where the widget is created and you'll see that the
11013 # actual widget proc merely evals this proc with all of the
11014 # arguments intact.
11015 #
11016 # Note that some widget commands are defined "inline" (ie:
11017 # within this proc), and some do most of their work in
11018 # separate procs. This is merely because sometimes it was
11019 # easier to do it one way or the other.
11020 #
11021 # Arguments:
11022 #
11023 # w widget pathname
11024 # command widget subcommand
11025 # args additional arguments; varies with the subcommand
11026 #
11027 # Results:
11028 #
11029 # Performs the requested widget command
11030
11031 proc ::combobox::WidgetProc {w command args} {
11032 upvar ::combobox::${w}::widgets widgets
11033 upvar ::combobox::${w}::options options
11034 upvar ::combobox::${w}::oldFocus oldFocus
11035 upvar ::combobox::${w}::oldFocus oldGrab
11036
11037 set command [::combobox::Canonize $w command $command]
11038
11039 # this is just shorthand notation...
11040 set doWidgetCommand [list ::combobox::DoInternalWidgetCommand $widgets(this)]
11041
11042 if {$command == "list"} {
11043 # ok, the next argument is a list command; we'll
11044 # rip it from args and append it to command to
11045 # create a unique internal command
11046 #
11047 # NB: because of the sloppy way we are doing this,
11048 # we'll also let the user enter our secret command
11049 # directly (eg: listinsert, listdelete), but we
11050 # won't document that fact
11051 set command "list-[lindex $args 0]"
11052 set args [lrange $args 1 end]
11053 }
11054
11055 set result ""
11056
11057 # many of these commands are just synonyms for specific
11058 # commands in one of the subwidgets. We'll get them out
11059 # of the way first, then do the custom commands.
11060 switch $command {
11061 bbox -
11062 delete -
11063 get -
11064 icursor -
11065 index -
11066 insert -
11067 scan -
11068 selection -
11069 xview {
11070 set result [eval $doWidgetCommand entry $command $args]
11071 }
11072 list-get {set result [eval $doWidgetCommand listbox get $args]}
11073 list-index {set result [eval $doWidgetCommand listbox index $args]}
11074 list-size {set result [eval $doWidgetCommand listbox size $args]}
11075
11076 select {
11077 if {[llength $args] == 1} {
11078 set index [lindex $args 0]
11079 set result [Select $widgets(this) $index]
11080 } else {
11081 error "usage: $w select index"
11082 }
11083 }
11084
11085 subwidget {
11086 set knownWidgets [list button entry listbox dropdown vsb]
11087 if {[llength $args] == 0} {
11088 return $knownWidgets
11089 }
11090
11091 set name [lindex $args 0]
11092 if {[lsearch $knownWidgets $name] != -1} {
11093 set result $widgets($name)
11094 } else {
11095 error "unknown subwidget $name"
11096 }
11097 }
11098
11099 curselection {
11100 set result [eval $doWidgetCommand listbox curselection]
11101 }
11102
11103 list-insert {
11104 eval $doWidgetCommand listbox insert $args
11105 set result [HandleScrollbar $w "grow"]
11106 }
11107
11108 list-delete {
11109 eval $doWidgetCommand listbox delete $args
11110 set result [HandleScrollbar $w "shrink"]
11111 }
11112
11113 toggle {
11114 # ignore this command if the widget is disabled...
11115 if {$options(-state) == "disabled"} return
11116
11117 # pops down the list if it is not, hides it
11118 # if it is...
11119 if {[winfo ismapped $widgets(dropdown)]} {
11120 set result [$widgets(this) close]
11121 } else {
11122 set result [$widgets(this) open]
11123 }
11124 }
11125
11126 open {
11127
11128 # if this is an editable combobox, the focus should
11129 # be set to the entry widget
11130 if {$options(-editable)} {
11131 focus $widgets(entry)
11132 $widgets(entry) select range 0 end
11133 $widgets(entry) icur end
11134 }
11135
11136 # if we are disabled, we won't allow this to happen
11137 if {$options(-state) == "disabled"} {
11138 return 0
11139 }
11140
11141 # if there is a -opencommand, execute it now
11142 if {[string length $options(-opencommand)] > 0} {
11143 # hmmm... should I do a catch, or just let the normal
11144 # error handling handle any errors? For now, the latter...
11145 uplevel \#0 $options(-opencommand)
11146 }
11147
11148 # compute the geometry of the window to pop up, and set
11149 # it, and force the window manager to take notice
11150 # (even if it is not presently visible).
11151 #
11152 # this isn't strictly necessary if the window is already
11153 # mapped, but we'll go ahead and set the geometry here
11154 # since its harmless and *may* actually reset the geometry
11155 # to something better in some weird case.
11156 set geometry [::combobox::ComputeGeometry $widgets(this)]
11157 wm geometry $widgets(dropdown) $geometry
11158 update idletasks
11159
11160 # if we are already open, there's nothing else to do
11161 if {[winfo ismapped $widgets(dropdown)]} {
11162 return 0
11163 }
11164
11165 # save the widget that currently has the focus; we'll restore
11166 # the focus there when we're done
11167 set oldFocus [focus]
11168
11169 # ok, tweak the visual appearance of things and
11170 # make the list pop up
11171 $widgets(button) configure -relief sunken
11172 raise $widgets(dropdown) [winfo parent $widgets(this)]
11173 wm deiconify $widgets(dropdown)
11174 raise $widgets(dropdown)
11175
11176 # force focus to the entry widget so we can handle keypress
11177 # events for traversal
11178 focus -force $widgets(entry)
11179
11180 # select something by default, but only if its an
11181 # exact match...
11182 ::combobox::Find $widgets(this) 1
11183
11184 # save the current grab state for the display containing
11185 # this widget. We'll restore it when we close the dropdown
11186 # list
11187 set status "none"
11188 set grab [grab current $widgets(this)]
11189 if {$grab != ""} {set status [grab status $grab]}
11190 set oldGrab [list $grab $status]
11191 unset grab status
11192
11193 # *gasp* do a global grab!!! Mom always told me not to
11194 # do things like this, but sometimes a man's gotta do
11195 # what a man's gotta do.
11196 grab -global $widgets(this)
11197
11198 # fake the listbox into thinking it has focus. This is
11199 # necessary to get scanning initialized properly in the
11200 # listbox.
11201 event generate $widgets(listbox) <B1-Enter>
11202
11203 return 1
11204 }
11205
11206 close {
11207 # if we are already closed, don't do anything...
11208 if {![winfo ismapped $widgets(dropdown)]} {
11209 return 0
11210 }
11211
11212 # restore the focus and grab, but ignore any errors...
11213 # we're going to be paranoid and release the grab before
11214 # trying to set any other grab because we really really
11215 # really want to make sure the grab is released.
11216 catch {focus $oldFocus} result
11217 catch {grab release $widgets(this)}
11218 catch {
11219 set status [lindex $oldGrab 1]
11220 if {$status == "global"} {
11221 grab -global [lindex $oldGrab 0]
11222 } elseif {$status == "local"} {
11223 grab [lindex $oldGrab 0]
11224 }
11225 unset status
11226 }
11227
11228 # hides the listbox
11229 $widgets(button) configure -relief raised
11230 wm withdraw $widgets(dropdown)
11231
11232 # select the data in the entry widget. Not sure
11233 # why, other than observation seems to suggest that's
11234 # what windows widgets do.
11235 set editable [::combobox::GetBoolean $options(-editable)]
11236 if {$editable} {
11237 $widgets(entry) selection range 0 end
11238 $widgets(button) configure -relief raised
11239 }
11240
11241
11242 # magic tcl stuff (see tk.tcl in the distribution
11243 # lib directory)
11244 ::combobox::tkCancelRepeat
11245
11246 return 1
11247 }
11248
11249 cget {
11250 if {[llength $args] != 1} {
11251 error "wrong # args: should be $w cget option"
11252 }
11253 set opt [::combobox::Canonize $w option [lindex $args 0]]
11254
11255 if {$opt == "-value"} {
11256 set result [$widgets(entry) get]
11257 } else {
11258 set result $options($opt)
11259 }
11260 }
11261
11262 configure {
11263 set result [eval ::combobox::Configure {$w} $args]
11264 }
11265
11266 default {
11267 error "bad option \"$command\""
11268 }
11269 }
11270
11271 return $result
11272 }
11273
11274 # ::combobox::Configure --
11275 #
11276 # Implements the "configure" widget subcommand
11277 #
11278 # Arguments:
11279 #
11280 # w widget pathname
11281 # args zero or more option/value pairs (or a single option)
11282 #
11283 # Results:
11284 #
11285 # Performs typcial "configure" type requests on the widget
11286
11287 proc ::combobox::Configure {w args} {
11288 variable widgetOptions
11289 variable defaultEntryCursor
11290
11291 upvar ::combobox::${w}::widgets widgets
11292 upvar ::combobox::${w}::options options
11293
11294 if {[llength $args] == 0} {
11295 # hmmm. User must be wanting all configuration information
11296 # note that if the value of an array element is of length
11297 # one it is an alias, which needs to be handled slightly
11298 # differently
11299 set results {}
11300 foreach opt [lsort [array names widgetOptions]] {
11301 if {[llength $widgetOptions($opt)] == 1} {
11302 set alias $widgetOptions($opt)
11303 set optName $widgetOptions($alias)
11304 lappend results [list $opt $optName]
11305 } else {
11306 set optName [lindex $widgetOptions($opt) 0]
11307 set optClass [lindex $widgetOptions($opt) 1]
11308 set default [option get $w $optName $optClass]
11309 if {[info exists options($opt)]} {
11310 lappend results [list $opt $optName $optClass $default $options($opt)]
11311 } else {
11312 lappend results [list $opt $optName $optClass $default ""]
11313 }
11314 }
11315 }
11316
11317 return $results
11318 }
11319
11320 # one argument means we are looking for configuration
11321 # information on a single option
11322 if {[llength $args] == 1} {
11323 set opt [::combobox::Canonize $w option [lindex $args 0]]
11324
11325 set optName [lindex $widgetOptions($opt) 0]
11326 set optClass [lindex $widgetOptions($opt) 1]
11327 set default [option get $w $optName $optClass]
11328 set results [list $opt $optName $optClass $default $options($opt)]
11329 return $results
11330 }
11331
11332 # if we have an odd number of values, bail.
11333 if {[expr {[llength $args]%2}] == 1} {
11334 # hmmm. An odd number of elements in args
11335 error "value for \"[lindex $args end]\" missing"
11336 }
11337
11338 # Great. An even number of options. Let's make sure they
11339 # are all valid before we do anything. Note that Canonize
11340 # will generate an error if it finds a bogus option; otherwise
11341 # it returns the canonical option name
11342 foreach {name value} $args {
11343 set name [::combobox::Canonize $w option $name]
11344 set opts($name) $value
11345 }
11346
11347 # process all of the configuration options
11348 # some (actually, most) options require us to
11349 # do something, like change the attributes of
11350 # a widget or two. Here's where we do that...
11351 #
11352 # note that the handling of disabledforeground and
11353 # disabledbackground is a little wonky. First, we have
11354 # to deal with backwards compatibility (ie: tk 8.3 and below
11355 # didn't have such options for the entry widget), and
11356 # we have to deal with the fact we might want to disable
11357 # the entry widget but use the normal foreground/background
11358 # for when the combobox is not disabled, but not editable either.
11359
11360 set updateVisual 0
11361 foreach option [array names opts] {
11362 set newValue $opts($option)
11363 if {[info exists options($option)]} {
11364 set oldValue $options($option)
11365 }
11366
11367 switch -- $option {
11368 -background {
11369 set updateVisual 1
11370 set options($option) $newValue
11371 }
11372
11373 -borderwidth {
11374 $widgets(frame) configure -borderwidth $newValue
11375 set options($option) $newValue
11376 }
11377
11378 -command {
11379 # nothing else to do...
11380 set options($option) $newValue
11381 }
11382
11383 -commandstate {
11384 # do some value checking...
11385 if {$newValue != "normal" && $newValue != "disabled"} {
11386 set options($option) $oldValue
11387 set message "bad state value \"$newValue\";"
11388 append message " must be normal or disabled"
11389 error $message
11390 }
11391 set options($option) $newValue
11392 }
11393
11394 -cursor {
11395 $widgets(frame) configure -cursor $newValue
11396 $widgets(entry) configure -cursor $newValue
11397 $widgets(listbox) configure -cursor $newValue
11398 set options($option) $newValue
11399 }
11400
11401 -disabledforeground {
11402 set updateVisual 1
11403 set options($option) $newValue
11404 }
11405
11406 -disabledbackground {
11407 set updateVisual 1
11408 set options($option) $newValue
11409 }
11410
11411 -dropdownwidth {
11412 set options($option) $newValue
11413 }
11414
11415 -editable {
11416 set updateVisual 1
11417 if {$newValue} {
11418 # it's editable...
11419 $widgets(entry) configure -state normal -cursor $defaultEntryCursor
11420 } else {
11421 $widgets(entry) configure -state disabled -cursor $options(-cursor)
11422 }
11423 set options($option) $newValue
11424 }
11425
11426 -font {
11427 $widgets(entry) configure -font $newValue
11428 $widgets(listbox) configure -font $newValue
11429 set options($option) $newValue
11430 }
11431
11432 -foreground {
11433 set updateVisual 1
11434 set options($option) $newValue
11435 }
11436
11437 -height {
11438 $widgets(listbox) configure -height $newValue
11439 HandleScrollbar $w
11440 set options($option) $newValue
11441 }
11442
11443 -highlightbackground {
11444 $widgets(frame) configure -highlightbackground $newValue
11445 set options($option) $newValue
11446 }
11447
11448 -highlightcolor {
11449 $widgets(frame) configure -highlightcolor $newValue
11450 set options($option) $newValue
11451 }
11452
11453 -highlightthickness {
11454 $widgets(frame) configure -highlightthickness $newValue
11455 set options($option) $newValue
11456 }
11457
11458 -image {
11459 if {[string length $newValue] > 0} {
11460 $widgets(button) configure -image $newValue
11461 } else {
11462 $widgets(button) configure -image ::combobox::bimage
11463 }
11464 set options($option) $newValue
11465 }
11466
11467 -maxheight {
11468 # ComputeGeometry may dork with the actual height
11469 # of the listbox, so let's undork it
11470 $widgets(listbox) configure -height $options(-height)
11471 HandleScrollbar $w
11472 set options($option) $newValue
11473 }
11474
11475 -opencommand {
11476 # nothing else to do...
11477 set options($option) $newValue
11478 }
11479
11480 -relief {
11481 $widgets(frame) configure -relief $newValue
11482 set options($option) $newValue
11483 }
11484
11485 -selectbackground {
11486 $widgets(entry) configure -selectbackground $newValue
11487 $widgets(listbox) configure -selectbackground $newValue
11488 set options($option) $newValue
11489 }
11490
11491 -selectborderwidth {
11492 $widgets(entry) configure -selectborderwidth $newValue
11493 $widgets(listbox) configure -selectborderwidth $newValue
11494 set options($option) $newValue
11495 }
11496
11497 -selectforeground {
11498 $widgets(entry) configure -selectforeground $newValue
11499 $widgets(listbox) configure -selectforeground $newValue
11500 set options($option) $newValue
11501 }
11502
11503 -state {
11504 if {$newValue == "normal"} {
11505 set updateVisual 1
11506 # it's enabled
11507
11508 set editable [::combobox::GetBoolean $options(-editable)]
11509 if {$editable} {
11510 $widgets(entry) configure -state normal
11511 $widgets(entry) configure -takefocus 1
11512 }
11513
11514 # note that $widgets(button) is actually a label,
11515 # not a button. And being able to disable labels
11516 # wasn't possible until tk 8.3. (makes me wonder
11517 # why I chose to use a label, but that answer is
11518 # lost to antiquity)
11519 if {[info patchlevel] >= 8.3} {
11520 $widgets(button) configure -state normal
11521 }
11522
11523 } elseif {$newValue == "disabled"} {
11524 set updateVisual 1
11525 # it's disabled
11526 $widgets(entry) configure -state disabled
11527 $widgets(entry) configure -takefocus 0
11528 # note that $widgets(button) is actually a label,
11529 # not a button. And being able to disable labels
11530 # wasn't possible until tk 8.3. (makes me wonder
11531 # why I chose to use a label, but that answer is
11532 # lost to antiquity)
11533 if {$::tcl_version >= 8.3} {
11534 $widgets(button) configure -state disabled
11535 }
11536
11537 } else {
11538 set options($option) $oldValue
11539 set message "bad state value \"$newValue\";"
11540 append message " must be normal or disabled"
11541 error $message
11542 }
11543
11544 set options($option) $newValue
11545 }
11546
11547 -takefocus {
11548 $widgets(entry) configure -takefocus $newValue
11549 set options($option) $newValue
11550 }
11551
11552 -textvariable {
11553 $widgets(entry) configure -textvariable $newValue
11554 set options($option) $newValue
11555 }
11556
11557 -value {
11558 ::combobox::SetValue $widgets(this) $newValue
11559 set options($option) $newValue
11560 }
11561
11562 -width {
11563 $widgets(entry) configure -width $newValue
11564 $widgets(listbox) configure -width $newValue
11565 set options($option) $newValue
11566 }
11567
11568 -xscrollcommand {
11569 $widgets(entry) configure -xscrollcommand $newValue
11570 set options($option) $newValue
11571 }
11572 }
11573
11574 if {$updateVisual} {UpdateVisualAttributes $w}
11575 }
11576 }
11577
11578 # ::combobox::UpdateVisualAttributes --
11579 #
11580 # sets the visual attributes (foreground, background mostly)
11581 # based on the current state of the widget (normal/disabled,
11582 # editable/non-editable)
11583 #
11584 # why a proc for such a simple thing? Well, in addition to the
11585 # various states of the widget, we also have to consider the
11586 # version of tk being used -- versions from 8.4 and beyond have
11587 # the notion of disabled foreground/background options for various
11588 # widgets. All of the permutations can get nasty, so we encapsulate
11589 # it all in one spot.
11590 #
11591 # note also that we don't handle all visual attributes here; just
11592 # the ones that depend on the state of the widget. The rest are
11593 # handled on a case by case basis
11594 #
11595 # Arguments:
11596 # w widget pathname
11597 #
11598 # Returns:
11599 # empty string
11600
11601 proc ::combobox::UpdateVisualAttributes {w} {
11602
11603 upvar ::combobox::${w}::widgets widgets
11604 upvar ::combobox::${w}::options options
11605
11606 if {$options(-state) == "normal"} {
11607
11608 set foreground $options(-foreground)
11609 set background $options(-background)
11610
11611 } elseif {$options(-state) == "disabled"} {
11612
11613 set foreground $options(-disabledforeground)
11614 set background $options(-disabledbackground)
11615 }
11616
11617 $widgets(entry) configure -foreground $foreground -background $background
11618 $widgets(listbox) configure -foreground $foreground -background $background
11619 $widgets(button) configure -foreground $foreground
11620 $widgets(vsb) configure -background $background -troughcolor $background
11621 $widgets(frame) configure -background $background
11622
11623 # we need to set the disabled colors in case our widget is disabled.
11624 # We could actually check for disabled-ness, but we also need to
11625 # check whether we're enabled but not editable, in which case the
11626 # entry widget is disabled but we still want the enabled colors. It's
11627 # easier just to set everything and be done with it.
11628
11629 if {$::tcl_version >= 8.4} {
11630 $widgets(entry) configure -disabledforeground $foreground -disabledbackground $background
11631 $widgets(button) configure -disabledforeground $foreground
11632 $widgets(listbox) configure -disabledforeground $foreground
11633 }
11634 }
11635
11636 # ::combobox::SetValue --
11637 #
11638 # sets the value of the combobox and calls the -command,
11639 # if defined
11640 #
11641 # Arguments:
11642 #
11643 # w widget pathname
11644 # newValue the new value of the combobox
11645 #
11646 # Returns
11647 #
11648 # Empty string
11649
11650 proc ::combobox::SetValue {w newValue} {
11651
11652 upvar ::combobox::${w}::widgets widgets
11653 upvar ::combobox::${w}::options options
11654 upvar ::combobox::${w}::ignoreTrace ignoreTrace
11655 upvar ::combobox::${w}::oldValue oldValue
11656
11657 if {[info exists options(-textvariable)] && [string length $options(-textvariable)] > 0} {
11658 set variable ::$options(-textvariable)
11659 set $variable $newValue
11660 } else {
11661 set oldstate [$widgets(entry) cget -state]
11662 $widgets(entry) configure -state normal
11663 $widgets(entry) delete 0 end
11664 $widgets(entry) insert 0 $newValue
11665 $widgets(entry) configure -state $oldstate
11666 }
11667
11668 # set our internal textvariable; this will cause any public
11669 # textvariable (ie: defined by the user) to be updated as
11670 # well
11671 # set ::combobox::${w}::entryTextVariable $newValue
11672
11673 # redefine our concept of the "old value". Do it before running
11674 # any associated command so we can be sure it happens even
11675 # if the command somehow fails.
11676 set oldValue $newValue
11677
11678
11679 # call the associated command. The proc will handle whether or
11680 # not to actually call it, and with what args
11681 CallCommand $w $newValue
11682
11683 return ""
11684 }
11685
11686 # ::combobox::CallCommand --
11687 #
11688 # calls the associated command, if any, appending the new
11689 # value to the command to be called.
11690 #
11691 # Arguments:
11692 #
11693 # w widget pathname
11694 # newValue the new value of the combobox
11695 #
11696 # Returns
11697 #
11698 # empty string
11699
11700 proc ::combobox::CallCommand {w newValue} {
11701 upvar ::combobox::${w}::widgets widgets
11702 upvar ::combobox::${w}::options options
11703
11704 # call the associated command, if defined and -commandstate is
11705 # set to "normal"
11706 if {$options(-commandstate) == "normal" && [string length $options(-command)] > 0} {
11707 set args [list $widgets(this) $newValue]
11708 uplevel \#0 $options(-command) $args
11709 }
11710 }
11711
11712
11713 # ::combobox::GetBoolean --
11714 #
11715 # returns the value of a (presumably) boolean string (ie: it should
11716 # do the right thing if the string is "yes", "no", "true", 1, etc
11717 #
11718 # Arguments:
11719 #
11720 # value value to be converted
11721 # errorValue a default value to be returned in case of an error
11722 #
11723 # Returns:
11724 #
11725 # a 1 or zero, or the value of errorValue if the string isn't
11726 # a proper boolean value
11727
11728 proc ::combobox::GetBoolean {value {errorValue 1}} {
11729 if {[catch {expr {([string trim $value])?1:0}} res]} {
11730 return $errorValue
11731 } else {
11732 return $res
11733 }
11734 }
11735
11736 # ::combobox::convert --
11737 #
11738 # public routine to convert %x, %y and %W binding substitutions.
11739 # Given an x, y and or %W value relative to a given widget, this
11740 # routine will convert the values to be relative to the combobox
11741 # widget. For example, it could be used in a binding like this:
11742 #
11743 # bind .combobox <blah> {doSomething [::combobox::convert %W -x %x]}
11744 #
11745 # Note that this procedure is *not* exported, but is intended for
11746 # public use. It is not exported because the name could easily
11747 # clash with existing commands.
11748 #
11749 # Arguments:
11750 #
11751 # w a widget path; typically the actual result of a %W
11752 # substitution in a binding. It should be either a
11753 # combobox widget or one of its subwidgets
11754 #
11755 # args should one or more of the following arguments or
11756 # pairs of arguments:
11757 #
11758 # -x <x> will convert the value <x>; typically <x> will
11759 # be the result of a %x substitution
11760 # -y <y> will convert the value <y>; typically <y> will
11761 # be the result of a %y substitution
11762 # -W (or -w) will return the name of the combobox widget
11763 # which is the parent of $w
11764 #
11765 # Returns:
11766 #
11767 # a list of the requested values. For example, a single -w will
11768 # result in a list of one items, the name of the combobox widget.
11769 # Supplying "-x 10 -y 20 -W" (in any order) will return a list of
11770 # three values: the converted x and y values, and the name of
11771 # the combobox widget.
11772
11773 proc ::combobox::convert {w args} {
11774 set result {}
11775 if {![winfo exists $w]} {
11776 error "window \"$w\" doesn't exist"
11777 }
11778
11779 while {[llength $args] > 0} {
11780 set option [lindex $args 0]
11781 set args [lrange $args 1 end]
11782
11783 switch -exact -- $option {
11784 -x {
11785 set value [lindex $args 0]
11786 set args [lrange $args 1 end]
11787 set win $w
11788 while {[winfo class $win] != "Combobox"} {
11789 incr value [winfo x $win]
11790 set win [winfo parent $win]
11791 if {$win == "."} break
11792 }
11793 lappend result $value
11794 }
11795
11796 -y {
11797 set value [lindex $args 0]
11798 set args [lrange $args 1 end]
11799 set win $w
11800 while {[winfo class $win] != "Combobox"} {
11801 incr value [winfo y $win]
11802 set win [winfo parent $win]
11803 if {$win == "."} break
11804 }
11805 lappend result $value
11806 }
11807
11808 -w -
11809 -W {
11810 set win $w
11811 while {[winfo class $win] != "Combobox"} {
11812 set win [winfo parent $win]
11813 if {$win == "."} break;
11814 }
11815 lappend result $win
11816 }
11817 }
11818 }
11819 return $result
11820 }
11821
11822 # ::combobox::Canonize --
11823 #
11824 # takes a (possibly abbreviated) option or command name and either
11825 # returns the canonical name or an error
11826 #
11827 # Arguments:
11828 #
11829 # w widget pathname
11830 # object type of object to canonize; must be one of "command",
11831 # "option", "scan command" or "list command"
11832 # opt the option (or command) to be canonized
11833 #
11834 # Returns:
11835 #
11836 # Returns either the canonical form of an option or command,
11837 # or raises an error if the option or command is unknown or
11838 # ambiguous.
11839
11840 proc ::combobox::Canonize {w object opt} {
11841 variable widgetOptions
11842 variable columnOptions
11843 variable widgetCommands
11844 variable listCommands
11845 variable scanCommands
11846
11847 switch $object {
11848 command {
11849 if {[lsearch -exact $widgetCommands $opt] >= 0} {
11850 return $opt
11851 }
11852
11853 # command names aren't stored in an array, and there
11854 # isn't a way to get all the matches in a list, so
11855 # we'll stuff the commands in a temporary array so
11856 # we can use [array names]
11857 set list $widgetCommands
11858 foreach element $list {
11859 set tmp($element) ""
11860 }
11861 set matches [array names tmp ${opt}*]
11862 }
11863
11864 {list command} {
11865 if {[lsearch -exact $listCommands $opt] >= 0} {
11866 return $opt
11867 }
11868
11869 # command names aren't stored in an array, and there
11870 # isn't a way to get all the matches in a list, so
11871 # we'll stuff the commands in a temporary array so
11872 # we can use [array names]
11873 set list $listCommands
11874 foreach element $list {
11875 set tmp($element) ""
11876 }
11877 set matches [array names tmp ${opt}*]
11878 }
11879
11880 {scan command} {
11881 if {[lsearch -exact $scanCommands $opt] >= 0} {
11882 return $opt
11883 }
11884
11885 # command names aren't stored in an array, and there
11886 # isn't a way to get all the matches in a list, so
11887 # we'll stuff the commands in a temporary array so
11888 # we can use [array names]
11889 set list $scanCommands
11890 foreach element $list {
11891 set tmp($element) ""
11892 }
11893 set matches [array names tmp ${opt}*]
11894 }
11895
11896 option {
11897 if {[info exists widgetOptions($opt)] && [llength $widgetOptions($opt)] == 2} {
11898 return $opt
11899 }
11900 set list [array names widgetOptions]
11901 set matches [array names widgetOptions ${opt}*]
11902 }
11903
11904 }
11905
11906 if {[llength $matches] == 0} {
11907 set choices [HumanizeList $list]
11908 error "unknown $object \"$opt\"; must be one of $choices"
11909
11910 } elseif {[llength $matches] == 1} {
11911 set opt [lindex $matches 0]
11912
11913 # deal with option aliases
11914 switch $object {
11915 option {
11916 set opt [lindex $matches 0]
11917 if {[llength $widgetOptions($opt)] == 1} {
11918 set opt $widgetOptions($opt)
11919 }
11920 }
11921 }
11922
11923 return $opt
11924
11925 } else {
11926 set choices [HumanizeList $list]
11927 error "ambiguous $object \"$opt\"; must be one of $choices"
11928 }
11929 }
11930
11931 # ::combobox::HumanizeList --
11932 #
11933 # Returns a human-readable form of a list by separating items
11934 # by columns, but separating the last two elements with "or"
11935 # (eg: foo, bar or baz)
11936 #
11937 # Arguments:
11938 #
11939 # list a valid tcl list
11940 #
11941 # Results:
11942 #
11943 # A string which as all of the elements joined with ", " or
11944 # the word " or "
11945
11946 proc ::combobox::HumanizeList {list} {
11947
11948 if {[llength $list] == 1} {
11949 return [lindex $list 0]
11950 } else {
11951 set list [lsort $list]
11952 set secondToLast [expr {[llength $list] -2}]
11953 set most [lrange $list 0 $secondToLast]
11954 set last [lindex $list end]
11955
11956 return "[join $most {, }] or $last"
11957 }
11958 }
11959
11960 # This is some backwards-compatibility code to handle TIP 44
11961 # (http://purl.org/tcl/tip/44.html). For all private tk commands
11962 # used by this widget, we'll make duplicates of the procs in the
11963 # combobox namespace.
11964 #
11965 # I'm not entirely convinced this is the right thing to do. I probably
11966 # shouldn't even be using the private commands. Then again, maybe the
11967 # private commands really should be public. Oh well; it works so it
11968 # must be OK...
11969 foreach command {TabToWindow CancelRepeat ListboxUpDown} {
11970 if {[llength [info commands ::combobox::tk$command]] == 1} break;
11971
11972 set tmp [info commands tk$command]
11973 set proc ::combobox::tk$command
11974 if {[llength [info commands tk$command]] == 1} {
11975 set command [namespace which [lindex $tmp 0]]
11976 proc $proc {args} "uplevel $command \$args"
11977 } else {
11978 if {[llength [info commands ::tk::$command]] == 1} {
11979 proc $proc {args} "uplevel ::tk::$command \$args"
11980 }
11981 }
11982 }
11983
11984 # end of combobox.tcl
11985 }
11986
11987 ret {combobox_lim} (type window , optional loclist ={) {cmdproc {}} {cb_textvar c_var} {cb_width 15} {cb_opt 0} {lim 1} args} {
11988
11989
11990
11991
11992
11993
11994
11995
11996
11997
11998
11999
12000
12001
12002 catch {namespace import combobox::*}
12003 edita = 1
12004 if {$lim == 1} { edita = 0}
12005 global $cb_textvar
12006 $cb = _textvar $cb_opt
12007 combobox $window -command $cmdret -editable $edita -textvariable $cb_textvar -width $cb_width -background white
12008 # eval $window list insert end $loclist
12009 foreach elem $loclist (
12010 $type window , type list , type insert , type end $, type elem
12011 )
12012 # Sélectionne la valeur initiale dans la liste
12013 set indice [lsearch $loclist $cb_opt]
12014 if {$indice != -1} { $window select $indice }
12015 }
12016
12017 ret {comm_add} (type win , type i_, type source , type i_, type target , type exch_, type per_, type unit , type exch_, type per_, type val , type lag , type src_, type time_, type op , type src_, type add_, type val , type src_, type mult_, type val , type dbg_, type source , type stat_, type source_, type mask , type stat_, type source_, type nmsk , type stat_, type source_, type all , type remail , type tgt_, type time_, type op , type tgt_, type add_, type val , type tgt_, type mult_, type val , type dbg_, type cible , type stat_, type cible_, type mask , type stat_, type cible_, type nmsk , type stat_, type cible_, type all , type file_, type packing , type file_, type scaling , type file_, type adding , type file_, type fill_, type value) {
12018 #**** comm_add - add a new connexion
12019
12020 # Variables globales
12021 global dico_applis dico_caract_fichiers
12022 global dico_caract_cnx
12023 global dico_caract_points
12024 global liste_cnx_in dico_cnx_out
12025
12026 # Var. de saisie des options de remaillage
12027 global nbr_neighbours_m bi3_method_m if_masked_m norm_method_m norm_near_nei_m
12028 # Var globale indiquant que l'utilisateur a validé sa saisie des options de remaillage
12029 global valid_remail
12030
12031 # Vérifie les informations entrées
12032 if { [comm_validation $exch_per_unit $exch_per_val $remail] } {
12033 return error
12034 }
12035
12036 # Extrait les infos pertinentes
12037 # -----------------------------
12038
12039 # Nom de l'application du composant source
12040 set appli_source $dico_caract_points($i_source.appli)
12041 # Nom du composant source
12042 set comp_source $dico_caract_points($i_source.comp)
12043 # Nom du champ source
12044 set champ_source $dico_caract_points($i_source.champ)
12045
12046 # Nom de l'application du composant cible
12047 set appli_cible $dico_caract_points($i_target.appli)
12048 # Nom du composant cible
12049 set comp_cible $dico_caract_points($i_target.comp)
12050 # Nom du champ cible
12051 set champ_cible $dico_caract_points($i_target.champ)
12052
12053 # Mémorise la nouvelle connexion
12054 # ------------------------------
12055
12056 # 1) Au niveau des points de couplage
12057 # -----------------------------------
12058
12059 # 1.a) Point de couplage cible
12060 # Mémorise que le point cible est connecté
12061 set dico_caract_points($i_target.lcnx) "i"
12062
12063 # 1.b) Point de couplage source
12064 # Le point source peut avoir plusieurs connexions
12065 # Liste des connexions sortantes déjà existantes
12066 set l_cnx_out ""
12067 if { [info exists dico_caract_points($i_source.lcnx)] } {
12068 set l_cnx_out $dico_caract_points($i_source.lcnx)
12069 }
12070
12071 # Crée un nouvel id pour cette nouvelle connexion sortante
12072 # Il est formé de la lettre "o" suivie d'un numéro
12073 # On prend le dernier numéro utilisé plus 1
12074 set dernier_id [lindex $l_cnx_out end]
12075 if { $dernier_id != "" } {
12076 set num_dernier_id [string range $dernier_id 1 end]
12077 } else {
12078 set num_dernier_id 0
12079 }
12080 incr num_dernier_id
12081 set id_new_cnx_out "o$num_dernier_id"
12082
12083 # Met à jour la liste des identifiants de connexion pour le point source
12084 lappend dico_caract_points($i_source.lcnx) $id_new_cnx_out
12085
12086 # 2) Dans les listes des connexions
12087 # ---------------------------------
12088
12089 # Clef (index) de la connexion sortante
12090 set clef_new_cnx_out $i_source$num_dernier_id
12091
12092 # 2.a) la liste des connexions entrantes
12093 lappend liste_cnx_in $i_target
12094
12095 # 2.b) le dico des connexions sortantes
12096 set dico_cnx_out($clef_new_cnx_out) $i_target
12097
12098 # 2.c) la liste des connexions avec leurs caractéristiques
12099 set dico_caract_cnx($i_target.app_source) $appli_source
12100 set dico_caract_cnx($i_target.app_cible) $appli_cible
12101 set dico_caract_cnx($i_target.comp_source) $comp_source
12102 set dico_caract_cnx($i_target.comp_cible) $comp_cible
12103 set dico_caract_cnx($i_target.champ_source) $champ_source
12104 set dico_caract_cnx($i_target.champ_cible) $champ_cible
12105 set dico_caract_cnx($i_target.pt_source) $id_new_cnx_out
12106
12107 # Enlever le 's' de pluriel aux unités de temps de la période des échanges
12108 set exch_per_unit [string range $exch_per_unit 0 end-1]
12109
12110 # Réinterprète le champ "type de remaillage"
12111 # ------------------------------------------
12112
12113 # Liste de descriptions lisibles et de mots-clefs correspondants
12114 array set remaillages { None {} {3D Nearest neighbour} nneighbour3D {3D Trilinear} trilinear {2D Nearest neighbour} nneighbour2D
12115 {2D Bilinear} bilinear {2D Bicubic} bicubic {2D Conservativ} conservativ2D }
12116
12117 # Transforme le mot-clef en description lisible
12118 if { $remail != "" } { set remail $remaillages($remail) }
12119
12120 # Réinterprète le champ "source time operation"
12121 array set mots_clefs { None {} {Time average} taverage {Time accumulation} accumul }
12122 if { $src_time_op != "" } { set src_time_op $mots_clefs($src_time_op) }
12123
12124 # Réinterprète le champ "target time operation"
12125 array unset mots_clefs
12126 array set mots_clefs { {None (Closest time)} {} {Time interpolation} time_linear }
12127 if { $tgt_time_op != "" } { set tgt_time_op $mots_clefs($tgt_time_op) }
12128
12129 # Réinterprète les booléens
12130 # Pour tous les champs booléens
12131 foreach nom_champ { dbg_source dbg_cible } {
12132 set valeur [set $nom_champ]
12133 if { $valeur != "" } {
12134 if {$valeur == "yes"} {set $nom_champ true} else {set $nom_champ false}
12135 }
12136 }
12137
12138 # Enregistre les attributs de la connexion
12139 # ----------------------------------------
12140
12141 # Initialise avec valeurs par defaut
12142 set dico_caract_cnx($i_target.src_time_op) ""
12143 set dico_caract_cnx($i_target.src_add_val) 0
12144 set dico_caract_cnx($i_target.src_mult_val) 1
12145 set dico_caract_cnx($i_target.tgt_time_op) ""
12146 set dico_caract_cnx($i_target.tgt_add_val) 0
12147 set dico_caract_cnx($i_target.tgt_mult_val) 1
12148 set dico_caract_cnx($i_target.remail) ""
12149
12150 foreach attrib {exch_per_unit exch_per_val lag dbg_source dbg_cible src_time_op src_add_val src_mult_val
12151 remail tgt_time_op tgt_add_val tgt_mult_val
12152 stat_source_mask stat_source_nmsk stat_source_all stat_cible_mask stat_cible_nmsk stat_cible_all} {
12153 set value [set $attrib]
12154 if { $value != "" } { set dico_caract_cnx($i_target.$attrib) $value }
12155 }
12156
12157 # Enregistre les options de remaillage
12158 global options_remail
12159 if { $remail != "" } {
12160 # Réinterprète l'option booléenne norm_near_nei
12161 if {$options_remail(norm_near_nei) == "yes"} {set options_remail(norm_near_nei) true} else {set options_remail(norm_near_nei) false}
12162 # Traduit l'option de remaillage conservatif
12163 switch $options_remail(norm_method) {
12164 "Fractional area" { set options_remail(norm_method) fracarea }
12165 "Destination area" { set options_remail(norm_method) destarea }
12166 }
12167 foreach option {nbr_neighbours bi3_method if_masked norm_method norm_near_nei} {
12168 set dico_caract_cnx($i_target.$option) $options_remail($option)
12169 }
12170 }
12171 array unset options_remail
12172
12173 # Si la cible est un fichier NetCDF
12174 if { [string equal $appli_cible "///file///"] } {
12175 # Enregistre les attributs du champ du fichier NetCDF
12176 set dico_caract_fichiers($comp_cible.field.packing) $file_packing
12177 set dico_caract_fichiers($comp_cible.field.scaling) $file_scaling
12178 set dico_caract_fichiers($comp_cible.field.adding) $file_adding
12179 set dico_caract_fichiers($comp_cible.field.fill_value) $file_fill_value
12180
12181 # Maintenant qu'il est connecté, le champ du fichier a un type numérique connu
12182 set dico_caract_fichiers($comp_cible.field.type) $dico_applis(app.$appli_source.comp.$comp_source.champ.$champ_source.datatype)
12183 }
12184
12185 catch {destroy $win}
12186 }
12187
12188 ret {comm_delete} (type clef_, type cnx) {
12189 #** suppression d'une communication
12190 #
12191 global dico_caract_cnx
12192
12193 set appli_source $dico_caract_cnx($clef_cnx.app_source)
12194 set appli_cible $dico_caract_cnx($clef_cnx.app_cible)
12195 set comp_source $dico_caract_cnx($clef_cnx.comp_source)
12196 set comp_cible $dico_caract_cnx($clef_cnx.comp_cible)
12197
12198 # Remove from memory
12199 comm_remove $clef_cnx
12200
12201 # Redessine les composants source et cible
12202 catch {Draw_one_unit $appli_source.$comp_source}
12203 catch {Draw_one_unit $appli_cible.$comp_cible}
12204
12205 # Redessine les connexions des composants source et cible
12206 Draw_comm $appli_source.$comp_source
12207 Draw_comm $appli_cible.$comp_cible
12208
12209 # Affiche la liste des communications
12210 control_entity CONNECTION
12211 }
12212
12213 ret {comm_edit} (type clef_, type cnx) {
12214 #** edition d'une communications
12215 #
12216 global dico_caract_cnx dico_applis
12217 global viewcommcheck
12218
12219 # Extrait les infos pertinentes
12220 # -----------------------------
12221
12222 # Crée une variable pour chaque champ
12223 foreach nom_champ { lag src_time_op src_add_val src_mult_val dbg_source stat_source_mask stat_source_nmsk stat_source_all remail tgt_time_op tgt_add_val tgt_mult_val dbg_cible stat_cible_mask stat_cible_nmsk stat_cible_all } {
12224 set $nom_champ ""
12225 }
12226
12227 # Extrait tous les champs attributs de la connexion
12228 foreach {name value} [array get dico_caract_cnx $clef_cnx.*] {
12229 set nom_attribut [string range $name [string length $clef_cnx.] end]
12230 # Crée une variable pour chaque attribut
12231 set $nom_attribut $value
12232 }
12233
12234 # Clef d'accès au champ de couplage source
12235 set clef_champ_source app.$app_source.comp.$comp_source.champ.$champ_source.o
12236 # Minimal period
12237 set period_source [array get dico_applis $clef_champ_source.nbr_*]
12238 set unite_period_source [string range [lindex $period_source 0] [string length $clef_champ_source.nbr_] end]
12239 set qte_period_source [lindex $period_source 1]
12240 set scatter ""
12241 catch {set scatter $dico_applis($clef_champ_source.scatter)}
12242 # CF name (transient standard name) du champ de couplage source
12243 set std_name_source ""
12244 catch {set std_name_source $dico_applis(app.$app_source.comp.$comp_source.champ.$champ_source.std_name)}
12245
12246 # Clef d'accès au champ de couplage cible
12247 set clef_champ_cible app.$app_cible.comp.$comp_cible.champ.$champ_cible.i
12248 # Minimal period
12249 set period_cible [array get dico_applis $clef_champ_cible.nbr_*]
12250 set unite_period_cible [string range [lindex $period_cible 0] [string length $clef_champ_cible.nbr_] end]
12251 set qte_period_cible [lindex $period_cible 1]
12252 set gather ""
12253 catch {set gather $dico_applis($clef_champ_cible.gather)}
12254 # CF name (transient standard name) du champ de couplage cible
12255 set std_name_cible ""
12256 catch {set std_name_cible $dico_applis(app.$app_cible.comp.$comp_cible.champ.$champ_cible.std_name)}
12257
12258 # Convertir les unites de temps
12259 # de : secs, mins, hours, days, months, years
12260 # a : seconds, minutes, hours, days, months, years
12261 array set conversion { {} {} secs seconds mins minutes hours hours days days months months years years }
12262 set unite_period_source $conversion($unite_period_source)
12263 set unite_period_cible $conversion($unite_period_cible)
12264
12265 # Ajouter un 's' de pluriel aux unités de temps de la période des échanges
12266 set exch_per_unit ${exch_per_unit}s
12267
12268 # Réinterprèter le champ "type de remaillage"
12269 # ------------------------------------------
12270
12271 # Liste de mots-clefs et de descriptions lisibles correspondantes
12272 array set remaillages { {} None nneighbour3D {3D Nearest neighbour} trilinear {3D Trilinear} nneighbour2D {2D Nearest neighbour}
12273 bilinear {2D Bilinear} bicubic {2D Bicubic} conservativ2D {2D Conservativ} }
12274
12275 # Transforme le mot-clef en description lisible
12276 set remail $remaillages($remail)
12277
12278 # Réinterprète le champ "source time operation"
12279 array set mots_clefs { {} None taverage {Time average} accumul {Time accumulation} }
12280 set src_time_op $mots_clefs($src_time_op)
12281
12282 # Réinterprète le champ "target time operation"
12283 array unset mots_clefs
12284 array set mots_clefs { {} {None (closest time)} time_nneighbour {None (closest time)} time_linear {Time interpolation} }
12285 set tgt_time_op $mots_clefs($tgt_time_op)
12286
12287 # Réinterprète les booléens
12288 # Pour tous les champs booléens
12289 foreach nom_champ { dbg_source dbg_cible } {
12290 set valeur [set $nom_champ]
12291 if {$valeur == "true"} {set $nom_champ yes} else {set $nom_champ no}
12292 }
12293
12294 if { $remail != "None" } {
12295 if {$norm_near_nei == "true"} {set norm_near_nei yes} else {set norm_near_nei no}
12296 # Traduit l'option de remaillage conservatif
12297 switch $norm_method {
12298 fracarea { set norm_method "Fractional area" }
12299 destarea { set norm_method "Destination area" }
12300 }
12301 }
12302
12303 # Crée la boite de dialogue de saisie de tous les paramètres d'une connexion
12304 if { $remail != "None" } {
12305 # Passe tous les parametres, avec les options de remaillage
12306 comm_saisie 0 $clef_cnx $comp_source $champ_source $std_name_source $qte_period_source $unite_period_source $comp_cible $champ_cible $std_name_cible $qte_period_cible $unite_period_cible $scatter $gather $exch_per_unit $exch_per_val $lag $src_time_op $src_add_val $src_mult_val $dbg_source $stat_source_mask $stat_source_nmsk $stat_source_all $remail $tgt_time_op $tgt_add_val $tgt_mult_val $dbg_cible $stat_cible_mask $stat_cible_nmsk $stat_cible_all $nbr_neighbours $bi3_method $if_masked $norm_method $norm_near_nei
12307 } else {
12308 # Passe tous les parametres sans les options de remaillage
12309 comm_saisie 0 $clef_cnx $comp_source $champ_source $std_name_source $qte_period_source $unite_period_source $comp_cible $champ_cible $std_name_cible $qte_period_cible $unite_period_cible $scatter $gather $exch_per_unit $exch_per_val $lag $src_time_op $src_add_val $src_mult_val $dbg_source $stat_source_mask $stat_source_nmsk $stat_source_all $remail $tgt_time_op $tgt_add_val $tgt_mult_val $dbg_cible $stat_cible_mask $stat_cible_nmsk $stat_cible_all
12310 }
12311 # Remarque : si la connexion a pour source ou cible un fichier, beaucoup des paramètres passés
12312 # à la procedure com_saisie() sont inutilisés
12313 # De plus, si la connexion a un fichier pour cible, certains paramètres du fichier
12314 # ne sont pas passés explicitement mais par l'intermédiaire du param. "clef_cnx"
12315
12316 catch {tkwait window .edit_comm}
12317 # Si les connexions sont dessinées
12318 if {$viewcommcheck != 0} {
12319 # Redessine toutes les cnx allant au composant cible (dont celle qu'on vient de modifier)
12320 Draw_comm $app_cible.$comp_cible
12321 }
12322 # Si la cible est un fichier NetCDF
12323 if { $app_cible == "///file///" } {
12324 # Redessine le fichier car des attributs qui sont affichés dans une info-bulle ont pu changer
12325 Draw_one_unit $app_cible.$comp_cible
12326 }
12327
12328 # Affiche la liste des connexions et sélectionne celle-ci
12329 control_entity CONNECTION $clef_cnx
12330 }
12331
12332 ret {comm_insert} (type i_, type source , type i_, type target) {
12333 # Crée une nouvelle connexion entre deux composants
12334
12335 # Variables globales
12336 global dico_caract_points dico_applis
12337
12338 # Extrait les infos pertinentes
12339 # -----------------------------
12340
12341 # Appli du composant source
12342 set appli_source $dico_caract_points($i_source.appli)
12343 # Nom du composant source
12344 set comp_source $dico_caract_points($i_source.comp)
12345 # Nom du champ source
12346 set champ_source $dico_caract_points($i_source.champ)
12347
12348 # Si la source est un fichier NetCDF
12349 if { $appli_source == "///file///"} {
12350 set unite_period_source ""
12351 set qte_period_source ""
12352 set scatter ""
12353 set std_name_source ""
12354 } else {
12355 # Clef d'accès au champ de couplage source
12356 set clef_champ_source app.$appli_source.comp.$comp_source.champ.$champ_source.o
12357 # Minimal period
12358 set period_source [array get dico_applis $clef_champ_source.nbr_*]
12359 set unite_period_source [string range [lindex $period_source 0] [string length $clef_champ_source.nbr_] end]
12360 set qte_period_source [lindex $period_source 1]
12361 set scatter $dico_applis($clef_champ_source.scatter)
12362 # CF name (transient standard name) du champ de couplage source
12363 catch {set std_name_source $dico_applis(app.$appli_source.comp.$comp_source.champ.$champ_source.std_name)}
12364 }
12365
12366 # Appli du composant cible
12367 set appli_cible $dico_caract_points($i_target.appli)
12368 # Nom du composant cible
12369 set comp_cible $dico_caract_points($i_target.comp)
12370 # Nom du champ cible
12371 set champ_cible $dico_caract_points($i_target.champ)
12372
12373 # Si la cible est un fichier NetCDF
12374 if { $appli_cible == "///file///"} {
12375 set unite_period_cible ""
12376 set qte_period_cible ""
12377 set gather ""
12378 set std_name_cible ""
12379 } else {
12380 # Clef d'accès au champ de couplage cible
12381 set clef_champ_cible app.$appli_cible.comp.$comp_cible.champ.$champ_cible.i
12382 # Minimal period
12383 set period_cible [array get dico_applis $clef_champ_cible.nbr_*]
12384 set unite_period_cible [string range [lindex $period_cible 0] [string length $clef_champ_cible.nbr_] end]
12385 set qte_period_cible [lindex $period_cible 1]
12386 set gather $dico_applis($clef_champ_cible.gather)
12387 # CF name (transient standard name) du champ de couplage cible
12388 catch {set std_name_cible $dico_applis(app.$appli_cible.comp.$comp_cible.champ.$champ_cible.std_name)}
12389 }
12390
12391 # Convertit les unites de temps
12392 # de : secs, mins, hours, days, months, years
12393 # a : seconds, minutes, hours, days, months, years
12394 array set conversion { secs seconds mins minutes hours hours days days months months years years }
12395 if { $unite_period_source != "" } {
12396 set unite_period_source $conversion($unite_period_source)
12397 }
12398 if { $unite_period_cible != "" } {
12399 set unite_period_cible $conversion($unite_period_cible)
12400 }
12401
12402 # Crée la boite de dialogue de saisie de tous les paramètres d'une connexion
12403 comm_saisie 1 "$i_source $i_target" $comp_source $champ_source $std_name_source $qte_period_source $unite_period_source $comp_cible $champ_cible $std_name_cible $qte_period_cible $unite_period_cible $scatter $gather
12404 }
12405
12406 ret {comm_new} (type flag , type point_, type index) {
12407 #
12408 global oldput oldget
12409 global oldcolorput oldcolorget
12410 global i_source i_target
12411 global dico_cnx_out
12412 global dico_caract_cnx
12413 global dico_caract_points
12414 global entityselected objectselected tagselected oldcolor
12415
12416 set w .gui.pr.cpd22.03
12417
12418 #** annulation
12419 #-------------
12420 if { $flag == "menage" } {
12421 # S'il y avait un point d'entrée sélectionné
12422 if { [info exists oldget ]} {
12423 $w itemconfigure $oldget -fill $oldcolorget
12424 # Désélectionne et oublie ce point
12425 unset oldget
12426 unset i_target
12427 }
12428 # S'il y avait un point de sortie sélectionné
12429 if { [info exists oldput ]} {
12430 $w itemconfigure $oldput -fill $oldcolorput
12431 # Désélectionne et oublie ce point
12432 unset oldput
12433 unset i_source
12434 }
12435 } else {
12436
12437 # Si il y avait un objet sélectionné
12438 if {$objectselected != ""} {
12439 # Déselectionne cet obet sur le graphe
12440 $w itemconfigure $tagselected -fill $oldcolor
12441 set tagselected ""
12442 set objectselected ""
12443 }
12444
12445 #** connexion sortante d'un composant
12446 #------------------------------------
12447 if { $flag == "out" } {
12448
12449 if { [info exists oldput ]} { $w itemconfigure $oldput -fill $oldcolorput}
12450
12451 # Si on a cliqué sur le point sélectionné
12452 set point [$w find withtag current]
12453 if { [info exists oldput ] && $oldput == $point } {
12454 # Désélectionne et oublie ce point
12455 unset oldput
12456 unset i_source
12457 } else {
12458 # Mémorise le point sélectionné et sa couleur d'origine
12459 set oldput $point
12460 set oldcolorput [$w itemcget $oldput -fill ]
12461 # Change la couleur du point sélectionné
12462 $w itemconfigure current -fill red
12463 # Mémorise le point de couplage source (de la future connexion)
12464 set i_source $point_index
12465 }
12466 }
12467
12468 #** connexion entrante dans un composant
12469 #---------------------------------------
12470 if { $flag == "in" } {
12471 # Si le point cible n'est pas déjà connecté
12472 set lcnx ""
12473 catch {set lcnx $dico_caract_points($point_index.lcnx)}
12474 if { $lcnx == "" } {
12475
12476 # S'il y avait déjà un point sélectionné
12477 if { [info exists oldget ]} {
12478 $w itemconfigure $oldget -fill $oldcolorget
12479 }
12480 # Si on a cliqué sur le point sélectionné
12481 set point [$w find withtag current]
12482 if { [info exists oldget ] && $oldget == $point } {
12483 # Désélectionne et oublie ce point
12484 unset oldget
12485 unset i_target
12486 } else {
12487 # Mémorise le point sélectionné et sa couleur d'origine
12488 set oldget $point
12489 set oldcolorget [$w itemcget $oldget -fill ]
12490 # Change la couleur du point sélectionné
12491 $w itemconfigure current -fill red
12492 # Mémorise le point de couplage source (de la future connexion)
12493 set i_target $point_index
12494 }
12495 }
12496 }
12497 }
12498
12499 # Si un point source et un point cible sont sélectionnés
12500 if { [info exists i_source ] && [info exists i_target ] } {
12501
12502 set si_annule 0
12503 # Nom de l'application du composant source
12504 set appli_source $dico_caract_points($i_source.appli)
12505 # Nom de l'application du composant cible
12506 set appli_cible $dico_caract_points($i_target.appli)
12507
12508 # Si la source et la cible sont tous deux des fichiers NetCDF
12509 if { $appli_source == "///file///" && $appli_cible == "///file///" } {
12510 # On ne peut pas créer une telle connexion
12511 set si_annule 1
12512 } else {
12513
12514 # On saisit les paramètres de la connexion
12515 comm_insert $i_source $i_target
12516 tkwait window .edit_comm
12517 # A ce stade, l'utilisateur peut avoir annulé la creation de la connexion
12518
12519 # Si le point cible est maintenant connecté
12520 if { [info exists dico_caract_points($i_target.lcnx)] } {
12521
12522 # Nom du composant source
12523 set comp_source $dico_caract_points($i_source.comp)
12524 # Nom du composant cible
12525 set comp_cible $dico_caract_points($i_target.comp)
12526
12527 # Redessine les composants source et cible
12528 catch {Draw_one_unit $appli_source.$comp_source}
12529 catch {Draw_one_unit $appli_cible.$comp_cible}
12530
12531 # Redessine les connexions du cible
12532 # Draw_comm $appli_source.$comp_source
12533 Draw_comm $appli_cible.$comp_cible
12534
12535 # Affiche la liste des communications en sélectionnant la dernière créée
12536 # et annule la selection des points de couplage
12537 minimenu_comm $i_target
12538 } else {
12539 # L'utilisateur a annulé la creation de la connexion
12540 set si_annule 1
12541 }
12542 }
12543
12544 if { $si_annule } {
12545 # On annule la selection du dernier point de couplage
12546 if { $flag == "in" } {
12547 # Désélectionne et oublie ce point
12548 $w itemconfigure $oldget -fill $oldcolorget
12549 unset oldget
12550 unset i_target
12551 } else {
12552 # Désélectionne et oublie ce point
12553 $w itemconfigure $oldput -fill $oldcolorput
12554 unset oldput
12555 unset i_source
12556 }
12557 }
12558 }
12559 }
12560
12561 ret {comm_remove} (type clef_, type cnx) {
12562 # Remove from memory one connexion between two component or between one component and one file
12563 global dico_caract_cnx
12564 global dico_caract_points
12565 global liste_cnx_in dico_cnx_out
12566
12567 # Extrait les infos pertinentes
12568 # -----------------------------
12569
12570 set appli_source $dico_caract_cnx($clef_cnx.app_source)
12571 set appli_cible $dico_caract_cnx($clef_cnx.app_cible)
12572 set comp_source $dico_caract_cnx($clef_cnx.comp_source)
12573 set comp_cible $dico_caract_cnx($clef_cnx.comp_cible)
12574 set champ_source $dico_caract_cnx($clef_cnx.champ_source)
12575 set champ_cible $dico_caract_cnx($clef_cnx.champ_cible)
12576 # L'id (la clef) de la connexion est celui du point de couplage cible
12577 set id_point_in $clef_cnx
12578 # Recherche le numéro du point de couplage source (o1 ou o2, o3,...)
12579 set num_point_out $dico_caract_cnx($clef_cnx.pt_source)
12580 # Id du point de couplage source
12581 set id_point_out $appli_source.$comp_source.$champ_source.o
12582
12583 # Supprime la memoire de la connexion
12584 # -----------------------------------
12585
12586 # 1) Au niveau des points de couplage
12587 # -----------------------------------
12588
12589 # 1.a) Point de couplage cible
12590 # Mémorise que le point cible n'est plus connecté
12591 unset dico_caract_points($id_point_in.lcnx)
12592
12593 # 1.b) Point de couplage source
12594 # Le point source peut avoir plusieurs connexions
12595 # Liste de toutes les connexions sortantes
12596 set l_cnx_out $dico_caract_points($id_point_out.lcnx)
12597 # Supprime de la liste la connexion en question
12598 set dico_caract_points($id_point_out.lcnx) [lsearch -not -all -inline $l_cnx_out $num_point_out]
12599
12600 # 2) Des listes des connexions
12601 # ----------------------------
12602
12603 # 2.a) la liste des connexions sortantes
12604 set clef_cnx_out $appli_source.$comp_source.$champ_source.$num_point_out
12605 unset dico_cnx_out($clef_cnx_out)
12606
12607 # 2.b) la liste des connexions entrantes
12608 set liste_cnx_in [lsearch -not -all -inline $liste_cnx_in $clef_cnx]
12609
12610 # 2.c) la liste des connexions avec leurs caractéristiques
12611 array unset dico_caract_cnx $clef_cnx.*
12612 }
12613
12614 ret {comm_saisie} (type si_, type nouveau , type clef_, type cnx , type comp_, type source , type champ_, type source , type std_, type name_, type source , type qte_, type period_, type source , type unite_, type period_, type source , type comp_, type cible , type champ_, type cible , type std_, type name_, type cible , type qte_, type period_, type cible , type unite_, type period_, type cible , type scatter , type gather , optional exch_per_unit ={) {exch_per_val {}} {lag {}} {src_time_op None} {src_add_val 0} {src_mult_val 1} {dbg_source no} {stat_source_mask off} {stat_source_nmsk off} {stat_source_all off} {remail None} {tgt_time_op {None (Closest time)}} {tgt_add_val 0} {tgt_mult_val 1} {dbg_cible no} {stat_cible_mask off} {stat_cible_nmsk off} {stat_cible_all off} {nbr_neighbours {}} {bi3_ret Choose...} (type if_, type masked , optional No =value) {norm_method None} {norm_near_nei no}} {
12615
12616
12617
12618
12619
12620 global dico_caract_points dico_caract_cnx
12621 global dico_caract_fichiers
12622
12623
12624 foreach var_name { exch_per_unit_m exch_per_val_m lag_m src_time_op_m src_add_val_m src_mult_val_m scatter_m dbg_source_m stat_cible_mask_m stat_cible_nmsk_m stat_cible_all_m remail_m tgt_time_op_m tgt_add_val_m tgt_mult_val_m gather_m dbg_cible_m stat_cible_mask_m stat_cible_nmsk_m stat_cible_all_m file_packing_m file_scaling_m file_adding_m file_fill_value_m } {
12625 global $var_name
12626 $var = _name ""
12627 }
12628
12629
12630
12631
12632 u = .edit_comm
12633 catch {destroy $u}
12634 toplevel $u
12635 if {$si_nouveau} {
12636 wm title $u "Insert a connection"
12637 wm iconname $u "Insert_Cnx"
12638
12639 i = _source [lindex $clef_cnx 0]
12640 i = _target [lindex $clef_cnx 1]
12641
12642 appli = _source $dico_caract_points($i_source.appli)
12643
12644 appli = _cible $dico_caract_points($i_target.appli)
12645
12646
12647 on = _OK "comm_add $u $i_source $i_target"
12648 } else {
12649 wm title $u "Change connection properties"
12650 wm iconname $u "change_cnx"
12651
12652 appli = _source $dico_caract_cnx($clef_cnx.app_source)
12653
12654 appli = _cible $dico_caract_cnx($clef_cnx.app_cible)
12655
12656
12657 on = _OK "comm_update $u $clef_cnx"
12658 }
12659
12660
12661 si = _source_fichier [string equal $appli_source "
12662 si = _cible_fichier [string equal $appli_cible "
12663
12664
12665 if {$exch_per_unit == ""} {
12666
12667
12668
12669
12670
12671 if {$si_source_fichier || $si_cible_fichier} {
12672 if {$si_source_fichier} {
12673
12674 exch = _per_unit $unite_period_cible
12675 exch = _per_val $qte_period_cible
12676 } else {
12677
12678 exch = _per_unit $unite_period_source
12679 exch = _per_val $qte_period_source
12680 }
12681
12682 } else {
12683
12684
12685
12686 liste = _unites {seconds minutes hours days months years}
12687 indx = _period_source [lsearch $liste_unites $unite_period_source]
12688 indx = _period_cible [lsearch $liste_unites $unite_period_cible]
12689
12690
12691 if { $indx_period_source != $indx_period_cible } {
12692
12693 if { $indx_period_source < $indx_period_cible } {
12694 min = _index $indx_period_source
12695 max = _index $indx_period_cible
12696 exch = _per_unit $unite_period_source
12697 } else {
12698 min = _index $indx_period_cible
12699 max = _index $indx_period_source
12700 exch = _per_unit $unite_period_cible
12701 }
12702
12703
12704
12705
12706
12707 liste = _facteurs {60 60 24 30 12}
12708 liste = _facteurs [lrange $liste_facteurs $min_index [expr $max_index-1]]
12709 facteur = 1
12710 foreach nombre $liste_facteurs {
12711 facteur = [expr $facteur * $nombre]
12712 }
12713
12714 if {$indx_period_source < $indx_period_cible} {
12715 valeur = _cible [expr $qte_period_cible * $facteur]
12716 valeur = _source $qte_period_source
12717 } else {
12718 valeur = _source [expr $qte_period_source * $facteur]
12719 valeur = _cible $qte_period_cible
12720 }
12721
12722
12723 } else {
12724
12725 exch = _per_unit $unite_period_source
12726 valeur = _source $qte_period_source
12727 valeur = _cible $qte_period_cible
12728 }
12729
12730
12731 exch = _per_val [expr $valeur_cible * $valeur_source / [pgcd $valeur_cible $valeur_source]]
12732 }
12733 }
12734
12735 x = [expr [winfo rootx .gui]+200]
12736 y = [expr [winfo rooty .gui]-20]
12737 wm geometry $u "+$x+$y"
12738
12739 w = $u.menu
12740 frame $w
12741 grid $w -row 2 -column 0
12742 grid configure $w -columnspan 2 -padx 4 -pady 4
12743
12744
12745
12746
12747
12748 frame $w.buttons
12749 pack $w.buttons -side bottom -fill x -pady 2m
12750 button $w.buttons.dismiss -text Cancel -command "catch {destroy .remaillage}; destroy $u"
12751 button $w.buttons.ok -text OK -command "$on_OK \$exch_per_unit_m \$exch_per_val_m \$lag_m \$src_time_op_m \$src_add_val_m \$src_mult_val_m \$dbg_source_m \$stat_source_mask_m \$stat_source_nmsk_m \$stat_source_all_m \$remail_m \$tgt_time_op_m \$tgt_add_val_m \$tgt_mult_val_m \$dbg_cible_m \$stat_cible_mask_m \$stat_cible_nmsk_m \$stat_cible_all_m \$file_packing_m \$file_scaling_m \$file_adding_m \$file_fill_value_m"
12752
12753 bind $w.buttons.ok <KeyPress-Return> "$on_OK \$exch_per_unit_m \$exch_per_val_m \$lag_m \$src_time_op_m \$src_add_val_m \$src_mult_val_m \$dbg_source_m \$stat_source_mask_m \$stat_source_nmsk_m \$stat_source_all_m \$remail_m \$tgt_time_op_m \$tgt_add_val_m \$tgt_mult_val_m \$dbg_cible_m \$stat_cible_mask_m \$stat_cible_nmsk_m \$stat_cible_all_m \$file_packing_m \$file_scaling_m \$file_adding_m \$file_fill_value_m"
12754
12755 pack $w.buttons.dismiss -side left -expand 1 -padx 10
12756 pack $w.buttons.ok -side right -expand 1 -padx 10
12757
12758
12759
12760
12761 w = $u.char
12762 frame $w
12763 grid $w -row 0 -column 1
12764 grid configure $w -padx 4 -pady 4
12765
12766
12767
12768
12769
12770
12771 r = 0
12772 if {$si_source_fichier} {
12773 label $w.label0 -text "Source file :"
12774 } else {
12775 label $w.label0 -text "Source component :"
12776 }
12777 grid $w.label0 -row $r -column 0 -sticky e -padx 10 -pady 4
12778 grid [label $w.label0b -relief sunken -width 60 -text $comp_source -anchor w] -row $r -column 1 -sticky w -padx 2
12779 incr r
12780
12781 grid [label $w.label1 -text "Source field :"] -row $r -column 0 -sticky e -padx 10 -pady 4
12782 grid [label $w.label1b -relief sunken -width 60 -text $champ_source -anchor w] -row $r -column 1 -sticky w -padx 2
12783 incr r
12784
12785 grid [label $w.label1c -text "CF standard name:"] -row $r -column 0 -sticky e -padx 10 -pady 4
12786 grid [label $w.label1d -relief sunken -width 60 -text $std_name_source -anchor w] -row $r -column 1 -sticky w -padx 2
12787 incr r
12788
12789 if {! $si_source_fichier} {
12790 grid [label $w.label2 -text "Minimal period :"] -row $r -column 0 -sticky e -padx 10 -pady 4
12791 grid [label $w.label22 -relief sunken -text "$qte_period_source $unite_period_source"] -row $r -column 1 -sticky w -padx 2
12792 incr r
12793 }
12794
12795
12796
12797
12798 grid [ frame $w.sep1 -width 430 -height 2 -borderwidth 1 -relief sunken] -row $r -column 0 -pady 5 -columnspan 2
12799 incr r
12800
12801
12802 if {$si_cible_fichier} {
12803
12804 nom = _fichier $dico_caract_fichiers($comp_cible.name)
12805 label $w.label3 -text "Target file :"
12806 label $w.label3b -relief sunken -width 60 -text $nom_fichier -anchor w
12807 } else {
12808 label $w.label3 -text "Target component :"
12809 label $w.label3b -relief sunken -width 60 -text $comp_cible -anchor w
12810 }
12811 grid $w.label3 -row $r -column 0 -sticky e -padx 10 -pady 4
12812 grid $w.label3b -row $r -column 1 -sticky w -padx 2
12813 incr r
12814
12815 grid [label $w.label4 -text "Target field :"] -row $r -column 0 -sticky e -padx 10 -pady 4
12816 grid [label $w.entry4 -relief sunken -width 60 -text $champ_cible -anchor w] -row $r -column 1 -sticky w -padx 2
12817 incr r
12818
12819 grid [label $w.label4a -text "CF standard name:"] -row $r -column 0 -sticky e -padx 10 -pady 4
12820 grid [label $w.label4b -relief sunken -width 60 -text $std_name_cible -anchor w] -row $r -column 1 -sticky w -padx 2
12821 incr r
12822
12823 if {! $si_cible_fichier} {
12824 grid [label $w.label5 -text "Minimal period :"] -row $r -column 0 -sticky e -padx 10 -pady 4
12825 grid [label $w.label55 -relief sunken -text "$qte_period_cible $unite_period_cible"] -row $r -column 1 -sticky w -padx 2
12826 incr r
12827 }
12828
12829
12830
12831
12832 grid [ frame $w.sep2 -width 430 -height 2 -borderwidth 1 -relief sunken] -row $r -column 0 -pady 5 -columnspan 2
12833 incr r
12834
12835
12836 grid [label $w.label6 -text "Exchange period :" ] -row $r -column 0 -sticky e -padx 10 -pady 4
12837
12838 grid [frame $w.frexch] -row $r -column 1 -sticky w -padx 2
12839 global exch_per_val_m exch_per_val_m_regexp
12840 trace variable exch_per_val_m w {entry_forceRegexp {^[0-9]*$} }
12841 exch = _per_val_m $exch_per_val
12842 pack [entry $w.frexch.e1 -takefocus 1 -textvariable exch_per_val_m -width 10 -background white] -side left
12843
12844 liste = _unites {seconds minutes hours days months years}
12845 combobox_lim $w.frexch.cmb $liste_unites {} exch_per_unit_m 28 $exch_per_unit
12846 pack $w.frexch.cmb -side left -padx 2
12847 incr r
12848
12849
12850 help = _text {Enter here the exchange period for the connection.}
12851 entry_help_balloon $w.frexch $help_text
12852
12853
12854
12855
12856
12857
12858 if {$si_source_fichier} {
12859
12860 global src_time_op_m src_add_val_m src_mult_val_m scatter_m dbg_source_m stat_source_mask_m stat_source_nmsk_m stat_source_all_m
12861 src = _time_op_m ""
12862 src = _add_val_m ""
12863 src = _mult_val_m ""
12864 scatter = _m ""
12865 dbg = _source_m ""
12866 stat = _source_mask_m ""
12867 stat = _source_nmsk_m ""
12868 stat = _source_all_m ""
12869 } else {
12870
12871 comm_saisie_param_source $w $r $lag $src_time_op $src_add_val $src_mult_val $scatter $dbg_source $stat_source_mask $stat_source_nmsk $stat_source_all
12872 }
12873 incr r
12874
12875
12876
12877
12878
12879
12880 if {! ($si_cible_fichier || $si_source_fichier) } {
12881
12882
12883
12884
12885 global options_remail
12886 foreach option {nbr_neighbours bi3_ret if_masked norm_method norm_near_nei} (
12887 type set , type value [, type set $, type option]
12888 , type set , type options_, type remail($, type option) $, type value
12889 )
12890
12891 # Champs de saisie
12892 grid [label $w.label13 -text "Regridding :" ] -row $r -column 0 -sticky e -padx 10 -pady 4
12893 grid [frame $w.fr_remail] -row $r -column 1 -sticky w -padx 2
12894 set liste_descript { None "3D Nearest neighbour" "3D Trilinear" "2D Nearest neighbour"
12895 "2D Bilinear" "2D Bicubic" "2D Conservativ" }
12896 global si_debut_remail; si = _debut_remail 1
12897 combobox_lim $w.fr_remail.cmb5 $liste_descript comm_saisie_remaillage remail_m 28 $remail
12898 pack $w.fr_remail.cmb5 -side left
12899 button $w.fr_remail.det -text Options -command [list comm_saisie_remaillage "$w.fr_remail.cmb5" -1 ]
12900 pack $w.fr_remail.det -side left -expand 1 -padx 10
12901 incr r
12902
12903
12904 help = _text {Choose the regridding to be performed on the output coupling field to express it on the target model grid.
12905 Note that the regridding will provide values interpolated from the source field for all target grid cells except for the following ones:
12906 • the target cell does not intersect any part of the source grid domain; for those cells, the target field keeps the same value as before the call to prism get ;
12907 • the target cell is masked; for those cells, the target field keeps the same value as before the call to prism get ;
12908 • the target cell is not masked, but the interpolation as requested in the SMIOC file cannot be performed; for those cells, the target field will take the 'psmile_undef' value (=-280177).
12909
12910 A '2D conservative' regridding means that the weight of a source cell is proportional to area intersected by target cell.}
12911 entry_help_balloon $w.fr_remail.cmb5 $help_text
12912
12913
12914 global no_help_balloon
12915 if { $no_help_balloon == 0 } {
12916 help = _text {Click here to select the interpolation options.}
12917 help = _action "help_object %W [list $help_text] message"
12918 bind $w.fr_remail.det <Any-Enter> $help_action
12919 bind $w.fr_remail.det <FocusIn> $help_action
12920 bind $w.fr_remail.det <Any-Leave> "help_object_hide"
12921 bind $w.fr_remail.det <FocusOut> "help_object_hide"
12922 bind $w.fr_remail.det <ButtonPress> "help_object_hide"
12923 }
12924 }
12925
12926
12927
12928
12929
12930
12931 if {$si_cible_fichier} {
12932
12933 if { $si_nouveau } {
12934 file = _packing ""
12935 file = _scaling ""
12936 file = _adding ""
12937 file = _fill_value ""
12938 } else {
12939 file = _packing $dico_caract_fichiers($comp_cible.field.packing)
12940 file = _scaling $dico_caract_fichiers($comp_cible.field.scaling)
12941 file = _adding $dico_caract_fichiers($comp_cible.field.adding)
12942 file = _fill_value $dico_caract_fichiers($comp_cible.field.fill_value)
12943 }
12944 comm_saisie_attrib_NetCDF $w $r $file_packing $file_scaling $file_adding $file_fill_value
12945
12946
12947 global tgt_time_op_m tgt_add_val_m tgt_mult_val_m gather_m dbg_cible_m stat_cible_mask_m stat_cible_nmsk_m stat_cible_all_m
12948 tgt = _time_op_m ""
12949 tgt = _add_val_m ""
12950 tgt = _mult_val_m ""
12951 gather = _m ""
12952 dbg = _cible_m ""
12953 stat = _cible_mask_m ""
12954 stat = _cible_nmsk_m ""
12955 stat = _cible_all_m ""
12956 } else {
12957
12958
12959 comm_saisie_param_cible $w $r $tgt_time_op $tgt_add_val $tgt_mult_val $gather $dbg_cible $stat_cible_mask $stat_cible_nmsk $stat_cible_all $si_source_fichier
12960 }
12961 incr r
12962
12963
12964 bind $u <Destroy> "help_object_hide; catch {destroy .remaillage}"
12965
12966 }
12967
12968 ret {pgcd} (type a , type b) {
12969 # Calcule de Plus Grand Diviseur Commun de deux nombres entiers
12970 # selon la méthode Euclidienne
12971 if {$a > $b} {
12972 set n1 $a; set n2 $b
12973 } else {
12974 set n1 $b; set n2 $a
12975 }
12976
12977 set r [expr $n1 % $n2]
12978 if { $r == 0} {
12979 return $n2
12980 } else {
12981 return [pgcd $n2 $r]
12982 }
12983 }
12984
12985 ret {comm_saisie_attrib_NetCDF} (type win , type row , type file_, type packing , type file_, type scaling , type file_, type adding , type file_, type fill_, type value) {
12986 # Prépare un cadre rempli de zones de saisie pour la saisie des attributs d'un champ de fichier NetCDF
12987 #
12988 # Crée le cadre de couleur et le place dans la grille de la fenêtre mère
12989 labelframe $win.netCDF -bg AntiqueWhite1 -borderwidth 1 -relief solid -text " NetCDF field attributes "
12990 grid $win.netCDF -row $row -column 0 -columnspan 2 -pady 4
12991 set fr $win.netCDF
12992 set r 0
12993
12994 #=== packing
12995 grid [label $fr.label2 -text "Packing :"] -row $r -column 0 -sticky e -padx 10 -pady 4
12996 global file_packing_m
12997 trace variable file_packing_m w {entry_forceRegexp {^[ 1248]?$} }
12998 set file_packing_m $file_packing
12999 grid [entry $fr.entry2 -textvariable file_packing_m -width 10 -background white] -row $r -column 1 -sticky w -padx 2
13000 incr r
13001
13002 # Ajoute une bulle d'aide pour 'packing'
13003 set help_text {If packing is chosen, data on file is compressed to 1, 2, 4 or 8 bit data fields. Choose either 1, 2, 4 or 8 or none.}
13004 entry_help_balloon $fr.entry2 $help_text
13005
13006 #=== scaling
13007 grid [label $fr.label3 -text "Scaling :"] -row $r -column 0 -sticky e -padx 10 -pady 4
13008 global file_scaling_m
13009 trace variable file_scaling_m w {entry_forceReal }
13010 set file_scaling_m $file_scaling
13011 grid [entry $fr.entry3 -textvariable file_scaling_m -width 10 -background white] -row $r -column 1 -sticky w -padx 2
13012 incr r
13013
13014 # Ajoute une bulle d'aide pour 'scaling'
13015 set help_text {if present, data are stored in file after dividing by the ‘scaling’ value (1.0 by default).
13016 The scaling factor is also stored in the file for the purpose of reading applications.}
13017 entry_help_balloon $fr.entry3 $help_text
13018
13019 #=== adding
13020 grid [label $fr.label4 -text "Adding :"] -row $r -column 0 -sticky e -padx 10 -pady 4
13021 global file_adding_m
13022 trace variable file_adding_m w {entry_forceReal }
13023 set file_adding_m $file_adding
13024 grid [entry $fr.entry4 -textvariable file_adding_m -width 10 -background white] -row $r -column 1 -sticky w -padx 2
13025 incr r
13026
13027 # Ajoute une bulle d'aide pour 'adding'
13028 set help_text {if present, data are stored in file after subtracting the adding’ value (0.0 by default).
13029 The adding value is also stored in the file for the purpose of reading applications.}
13030 entry_help_balloon $fr.entry4 $help_text
13031
13032 #=== fill_value
13033 grid [label $fr.label5 -text "Fill value :"] -row $r -column 0 -sticky e -padx 10 -pady 4
13034 global file_fill_value_m
13035 trace variable file_fill_value_m w {entry_forceReal }
13036 set file_fill_value_m $file_fill_value
13037 grid [entry $fr.entry5 -textvariable file_fill_value_m -width 10 -background white] -row $r -column 1 -sticky w -padx 2
13038 incr r
13039
13040 # Ajoute une bulle d'aide pour 'fill_value'
13041 set help_text {Specifies the value given in the file to undefined or missing data. For example, value given to grid points for which no meaningfull value was calculated.}
13042 entry_help_balloon $fr.entry5 $help_text
13043 }
13044
13045 ret {comm_saisie_param_cible} (type win , type row , type tgt_, type time_, type op , type tgt_, type add_, type val , type tgt_, type mult_, type val , type gather , type dbg_, type cible , type stat_, type cible_, type mask , type stat_, type cible_, type nmsk , type stat_, type cible_, type all , type si_, type source_, type fichier) {
13046 # Prépare un cadre rempli de zones de saisie pour la saisie d'une connexion
13047 # Ce cadre est spécialisé dans les paramètres du côté de la cible de la connexion
13048 #
13049 # Crée le cadre de couleur et le place dans la grille de la fenêtre mère
13050 labelframe $win.tgt_param -bg AntiqueWhite1 -borderwidth 1 -relief solid -text " Target parameters "
13051 grid $win.tgt_param -row $row -column 0 -columnspan 2 -pady 4
13052 set fr_tgt $win.tgt_param
13053 set r_tgt 0
13054
13055 # Si la source est un fichier
13056 if {$si_source_fichier} {
13057 #=== time operation
13058 grid [label $fr_tgt.label14 -text "Time operation :"] -row $r_tgt -column 0 -sticky e -padx 10 -pady 4
13059 combobox_lim $fr_tgt.cmb6 {{None (Closest time)} {Time interpolation}} {} tgt_time_op_m 28 $tgt_time_op
13060 grid $fr_tgt.cmb6 -row $r_tgt -column 1 -sticky w -padx 2
13061 incr r_tgt
13062
13063 # Ajoute une bulle d'aide pour 'Time operation'
13064 set help_text {Target time interpolation is supported only for IO data read from a file. It is a linear time interpolation between the two closest timestamps in the input file.}
13065 entry_help_balloon $fr_tgt.cmb6 $help_text
13066 }
13067
13068 #=== opération algébrique
13069 grid [label $fr_tgt.label15 -text "Algebraic operation :"] -row $r_tgt -column 0 -sticky e -padx 10 -pady 4
13070 grid [frame $fr_tgt.fr_tgt_algb] -row $r_tgt -column 1 -sticky w -padx 2
13071
13072 pack [label $fr_tgt.fr_tgt_algb.label1 -text "Mult by "] -side left -padx 2
13073 global tgt_mult_val_m
13074 trace variable tgt_mult_val_m w {entry_forceReal}
13075 set tgt_mult_val_m $tgt_mult_val
13076 pack [entry $fr_tgt.fr_tgt_algb.e1 -textvariable tgt_mult_val_m -width 10 -background white] -side left
13077
13078 pack [label $fr_tgt.fr_tgt_algb.label2 -text "Add "] -side left -padx 2
13079 global tgt_add_val_m
13080 trace variable tgt_add_val_m w {entry_forceReal}
13081 set tgt_add_val_m $tgt_add_val
13082 pack [entry $fr_tgt.fr_tgt_algb.e2 -textvariable tgt_add_val_m -width 10 -background white] -side left
13083 incr r_tgt
13084
13085 # Ajoute une bulle d'aide pour 'Algebraic operation'
13086 set help_text {Each grid point coupling/IO field value is multiplied then increased by scalars specified in this element after being received from source component.}
13087 entry_help_balloon $fr_tgt.fr_tgt_algb $help_text
13088
13089 #===non masked value gathering
13090 grid [label $fr_tgt.label16 -text "Non masked value gathering :"] -row $r_tgt -column 0 -sticky e -padx 10 -pady 4
13091 array set conversion { 1 yes 0 no "" no }
13092 label $fr_tgt.label17 -relief sunken -text $conversion($gather)
13093 grid $fr_tgt.label17 -row $r_tgt -column 1 -sticky w -padx 2
13094 incr r_tgt
13095
13096 #===mode debug at target
13097 grid [label $fr_tgt.label9 -text "Target debug mode :"] -row $r_tgt -column 0 -sticky e -padx 10 -pady 4
13098 combobox_lim $fr_tgt.cmb2 "yes no" {} dbg_cible_m 28 $dbg_cible
13099 grid $fr_tgt.cmb2 -row $r_tgt -column 1 -sticky w -padx 2
13100 incr r_tgt
13101
13102 # Ajoute une bulle d'aide pour 'debug mode'
13103 set help_text {If set to true, the input coupling/IO field is automatically written to a file each time it is received from the source component.}
13104 entry_help_balloon $fr_tgt.cmb2 $help_text
13105
13106 #=== statistics at target
13107 grid [label $fr_tgt.label9b -text "Target statistics :"] -row $r_tgt -column 0 -sticky e -padx 10 -pady 4
13108 grid [frame $fr_tgt.fr_tgt_stat] -row $r_tgt -column 1 -sticky w -padx 2
13109 pack [label $fr_tgt.fr_tgt_stat.label1 -text "Masked :"] -side left -padx 2
13110 combobox_lim $fr_tgt.fr_tgt_stat.cmb1 "on off" {} stat_cible_mask_m 9 $stat_cible_mask
13111 pack $fr_tgt.fr_tgt_stat.cmb1 -side left
13112
13113 pack [label $fr_tgt.fr_tgt_stat.label2 -text "Non Masked :"] -side left -padx 2
13114 combobox_lim $fr_tgt.fr_tgt_stat.cmb2 "on off" {} stat_cible_nmsk_m 9 $stat_cible_nmsk
13115 pack $fr_tgt.fr_tgt_stat.cmb2 -side left
13116
13117 pack [label $fr_tgt.fr_tgt_stat.label3 -text "All :"] -side left -padx 2
13118 combobox_lim $fr_tgt.fr_tgt_stat.cmb3 "on off" {} stat_cible_all_m 9 $stat_cible_all
13119 pack $fr_tgt.fr_tgt_stat.cmb3 -side left
13120 incr r_tgt
13121
13122 # Ajoute une bulle d'aide pour 'Statistics'
13123 set help_text {Different statistics (minimum, maximum, integral) are calculated for the field on the masked points, and/or on the non masked points, and/or on all points of the input coupling/IO field.
13124 This is done each time the input field is received (before the time operation if any).
13125 These statitistics are printed to the log file for information only; they do not transform the input coupling/IO field.}
13126 entry_help_balloon $fr_tgt.fr_tgt_stat $help_text
13127 }
13128
13129 ret {comm_saisie_param_source} (type win , type row , type lag , type src_, type time_, type op , type src_, type add_, type val , type src_, type mult_, type val , type scatter , type dbg_, type source , type stat_, type source_, type mask , type stat_, type source_, type nmsk , type stat_, type source_, type all) {
13130 # Prépare un cadre rempli de zones de saisie pour la saisie d'une connexion
13131 # Ce cadre est spécialisé dans les paramètres du côté de la source de la connexion
13132 #
13133 # Crée le cadre de couleur et le place dans la grille de la fenêtre mère
13134 labelframe $win.src_param -bg LavenderBlush -borderwidth 1 -text " Source parameters " -relief solid
13135 grid $win.src_param -row $row -column 0 -columnspan 2 -pady 4
13136 set fr_src $win.src_param
13137 set r_src 0
13138
13139 #===lag
13140 grid [label $fr_src.label7 -text "Lag :"] -row $r_src -column 0 -sticky e -padx 10 -pady 4
13141 global lag_m lag_m_regexp
13142 trace variable lag_m w {entry_forceRegexp {^[0-9]*$} }
13143 set lag_m $lag
13144 grid [entry $fr_src.e7 -textvariable lag_m -width 10 -background white] -row $r_src -column 1 -sticky w -padx 2
13145 incr r_src
13146
13147 # Ajoute une bulle d'aide pour 'lag'
13148 set help_text {The lag specifies the number of periods to be added to the output date (prism_put) to match the corresponding input date (prism_get) in the target component.
13149
13150 Note : if lag > 0 (see Oasis user guide, section 5.5.4), a coupling restart file is needed to start the run.}
13151 entry_help_balloon $fr_src.e7 $help_text
13152
13153 #=== time operation
13154 grid [label $fr_src.label10 -text "Time operation :"] -row $r_src -column 0 -sticky e -padx 10 -pady 4
13155 combobox_lim $fr_src.cmb3 {None {Time accumulation} {Time average}} {} src_time_op_m 28 $src_time_op
13156 grid $fr_src.cmb3 -row $r_src -column 1 -sticky w -padx 2
13157 incr r_src
13158
13159 # Ajoute une bulle d'aide pour 'Time operation'
13160 set help_text {For each grid point, the output coupling/IO field can be averaged or accumulated over the last coupling period before transfer to target component.}
13161 entry_help_balloon $fr_src.cmb3 $help_text
13162
13163 #=== opération algébrique
13164 grid [label $fr_src.label11 -text "Algebraic operation :"] -row $r_src -column 0 -sticky e -padx 10 -pady 4
13165 grid [frame $fr_src.fr_src_algb] -row $r_src -column 1 -sticky w -padx 2
13166
13167 pack [label $fr_src.fr_src_algb.label1 -text "Mult by "] -side left -padx 2
13168 global src_mult_val_m
13169 trace variable src_mult_val_m w {entry_forceReal}
13170 set src_mult_val_m $src_mult_val
13171 pack [entry $fr_src.fr_src_algb.e1 -textvariable src_mult_val_m -width 10 -background white] -side left
13172
13173 pack [label $fr_src.fr_src_algb.label2 -text "Add "] -side left -padx 2
13174 global src_add_val_m
13175 trace variable src_add_val_m w {entry_forceReal}
13176 set src_add_val_m $src_add_val
13177 pack [entry $fr_src.fr_src_algb.e2 -textvariable src_add_val_m -width 10 -background white] -side left
13178 incr r_src
13179
13180 # Ajoute une bulle d'aide pour 'Algebraic operation'
13181 set help_text {Each grid point coupling/IO field value is multiplied then increased by scalars specified in this element before transfer to target component.}
13182 entry_help_balloon $fr_src.fr_src_algb $help_text
13183
13184 #===non masked value scattering
13185 grid [label $fr_src.label12 -text "Non masked value scattering :"] -row $r_src -column 0 -sticky e -padx 10 -pady 4
13186 array set conversion { 1 yes 0 no "" no }
13187 label $fr_src.label13 -relief sunken -text $conversion($scatter)
13188 grid $fr_src.label13 -row $r_src -column 1 -sticky w -padx 2
13189 incr r_src
13190
13191 #===mode debug at source
13192 grid [label $fr_src.label8 -text "Debug mode :"] -row $r_src -column 0 -sticky e -padx 10 -pady 4
13193 combobox_lim $fr_src.cmb1 "yes no" {} dbg_source_m 28 $dbg_source
13194 grid $fr_src.cmb1 -row $r_src -column 1 -sticky w -padx 2
13195 incr r_src
13196
13197 # Ajoute une bulle d'aide pour 'Debug mode'
13198 set help_text {If set to true, the output coupling/IO field is automatically written to a file each time it is sent to the target component.}
13199 entry_help_balloon $fr_src.cmb1 $help_text
13200
13201 #=== statistics at source
13202 grid [label $fr_src.label8b -text "Statistics :"] -row $r_src -column 0 -sticky e -padx 10 -pady 4
13203 grid [frame $fr_src.fr_src_stat] -row $r_src -column 1 -sticky w -padx 2
13204 pack [label $fr_src.fr_src_stat.label1 -text "Masked :"] -side left -padx 2
13205 combobox_lim $fr_src.fr_src_stat.cmb1 "on off" {} stat_source_mask_m 9 $stat_source_mask
13206 pack $fr_src.fr_src_stat.cmb1 -side left
13207
13208 pack [label $fr_src.fr_src_stat.label2 -text "Non Masked :"] -side left -padx 2
13209 combobox_lim $fr_src.fr_src_stat.cmb2 "on off" {} stat_source_nmsk_m 9 $stat_source_nmsk
13210 pack $fr_src.fr_src_stat.cmb2 -side left
13211
13212 pack [label $fr_src.fr_src_stat.label3 -text "All :"] -side left -padx 2
13213 combobox_lim $fr_src.fr_src_stat.cmb3 "on off" {} stat_source_all_m 9 $stat_source_all
13214 pack $fr_src.fr_src_stat.cmb3 -side left
13215 incr r_src
13216
13217 # Ajoute une bulle d'aide pour 'Statistics'
13218 set help_text {Different statistics (minimum, maximum, integral) are calculated for the field on the masked points, and/or on the non masked points, and/or on all points of the output coupling/IO field.
13219 This is done each time the output field is sent, after any time operation (accumulation or average).
13220 These statitistics are printed to the log file for information only; they do not transform the output coupling/IO field.}
13221 entry_help_balloon $fr_src.fr_src_stat $help_text
13222 }
13223
13224 ret {comm_saisie_remaillage} (type nom_, type widget , type indice_, type select) {
13225 # Procedure appelee automatiquement sur selection d'un mode de remaillage
13226 # dans la listbox lors de la specification d'une connexion.
13227 # Cette meme proc. est appelee sur clic du bouton "Options" de la meme boite de dialogue.
13228 # Dans ce cas, le parametre "indice_select" n'est pas renseigné et vaut -1.
13229 #
13230 # Copie les options de remaillage dans des var globales
13231 global options_remail
13232 global nbr_neighbours_m nbr_neighbours_m_regexp bi3_method_m if_masked_m norm_method_m norm_near_nei_m
13233 foreach option {nbr_neighbours bi3_method if_masked norm_method norm_near_nei} {
13234 set value $options_remail($option)
13235 set $option\_m $value
13236 }
13237
13238 # Var globale indiquant que l'utilisateur a validé sa saisie
13239 global valid_remail
13240 # Var globale indiquant qu'on vient de créer la liste déroulante (listbox)
13241 global si_debut_remail
13242
13243 # Si sélection du type de remaillage dans la liste déroulante
13244 if { $indice_select != -1 } {
13245 # Ferme la liste déroulante
13246 $nom_widget close
13247 # Si c'est la première fois
13248 if { $si_debut_remail } {
13249 # Ce n'est pas une sélection manuelle : celle faite à l'init de la liste déroulante
13250 set si_debut_remail 0
13251 return
13252 }
13253 }
13254
13255 # Type de remaillage sélectionné
13256 set type_remail [$nom_widget get]
13257 if { $type_remail != "None" } {
13258 # Création de la fenêtre de saisie du mode de remaillage avec les champs appropriés
13259 set u .remaillage
13260 catch {destroy $u}
13261 toplevel $u
13262 wm title $u "Regridding options"
13263 wm iconname $u "regrid_option"
13264 set x [expr [winfo rootx $nom_widget]+60]
13265 set y [expr [winfo rooty $nom_widget]+20]
13266 wm geometry $u "+$x+$y"
13267 # Var globale indiquant que l'utilisateur a validé sa saisie
13268 set valid_remail 0
13269
13270 set w $u.menu
13271 frame $w
13272 grid $w -row 2 -column 0
13273 grid configure $w -columnspan 2 -padx 4 -pady 4
13274
13275 # Boutons OK et Cancel
13276 # ---------------------
13277 frame $w.buttons
13278 pack $w.buttons -side bottom -fill x -pady 2m
13279
13280 button $w.buttons.dismiss -text Cancel -command "destroy $u"
13281 button $w.buttons.ok -text Ok -command "global valid_remail; set valid_remail 1; destroy $u"
13282
13283 pack $w.buttons.dismiss -side left -expand 1 -padx 10
13284 pack $w.buttons.ok -side left -expand 1 -padx 10
13285
13286 frame $w.sep1 -width 200 -height 2 -borderwidth 1 -relief sunken
13287 pack $w.sep1 -side bottom -fill x -pady 2m -expand 1
13288
13289 # Champs de saisie
13290 # ----------------
13291
13292 set w $u.char
13293 frame $w
13294 grid $w -row 0 -column 1
13295 grid configure $w -padx 4 -pady 4
13296 set r 0
13297
13298 # Type de remaillage
13299 label $w.label_t1 -text "Regridding method :"
13300 label $w.label_t2 -relief sunken -text $type_remail
13301 grid $w.label_t1 $w.label_t2 -row $r -sticky w
13302 incr r
13303 # Séparateur
13304 grid [ frame $w.sep1 -width 200 -height 2 -borderwidth 1 -relief sunken] -row $r -column 0 -pady 5 -columnspan 2
13305 incr r
13306
13307 # Suivant le type de remaillage
13308 switch $type_remail {
13309 # Si remaillage par la methode des voisins
13310 "3D Nearest neighbour" -
13311 "2D Nearest neighbour" {
13312 label $w.label0 -text "Nbr of neighbours :"
13313 trace variable nbr_neighbours_m w {entry_forceRegexp {^[0-9]*$} }
13314 if {$nbr_neighbours_m == 0} {set nbr_neighbours_m 3}
13315 entry $w.entry0 -relief sunken -width 40 -textvariable nbr_neighbours_m -background white
13316 grid $w.label0 $w.entry0 -row $r -sticky w
13317 incr r
13318 }
13319 "2D Bicubic" {
13320 label $w.label0 -text "Bicubic method :"
13321 combobox_lim $w.comb0 "gradient sixteen" {} bi3_method_m 28 $bi3_method_m
13322 grid $w.label0 $w.comb0 -row $r -sticky w
13323 incr r
13324
13325 # Ajoute une bulle d'aide pour 'Bicubic method'
13326 set help_text {Either 'gradient' (the four enclosing source neighbour values and gradient values are used), or 'sixteen' (the sixteen enclosing source neighbour values are used).}
13327 entry_help_balloon $w.comb0 $help_text
13328 }
13329 "2D Conservativ" {
13330 label $w.label0 -text "Normalisation method :"
13331 combobox_lim $w.comb0 {None {Fractional area} {Destination area}} {} norm_method_m 28 $norm_method_m
13332 grid $w.label0 $w.comb0 -row $r -sticky w
13333 incr r
13334 label $w.label1 -text "Near neighbour :"
13335 combobox_lim $w.comb1 "yes no" {} norm_near_nei_m 28 $norm_near_nei_m
13336 grid $w.label1 $w.comb1 -row $r -sticky w
13337 incr r
13338
13339 # Ajoute une bulle d'aide pour 'Normalisation method'
13340 set help_text {It can be:
13341 · fracarea: The sum of the non-masked source cell intersected areas is used to normalise each target cell field value: the flux is not locally conserved, but the flux value itself is reasonable.
13342
13343 · destarea: The total target cell area is used to normalise each target cell field value even if it only partly intersects non-masked source grid cells: local flux conservation is ensured, but unreasonable flux values may result.
13344
13345 · none: No normalisation is applied.}
13346 entry_help_balloon $w.comb0 $help_text
13347 }
13348 }
13349 if { $type_remail != "2D Conservativ" } {
13350 label $w.label2 -text "If masked :"
13351 combobox_lim $w.comb2 {{no_value} tneighbour nneighbour} {} if_masked_m 28 $if_masked_m
13352 grid $w.label2 $w.comb2 -row $r -sticky w
13353 incr r
13354
13355 # Ajoute une bulle d'aide pour 'If masked '
13356 set help_text {Policy applied when some of N nearest neighbour points are masked (N being dependant on the interpolation method):
13357 * novalue: psmile_undef' value (=-280177) is given to the target point;
13358
13359 * tneighbour: the non-masked points among neighbours are used for calculating a weighted average; if all N neighbours are masked, 'psmile_undef' value is given to that target point;
13360
13361 * nneighbour: the non-masked points among neighbours are used for calculating a weighted average; if all N neighbours are masked, the non-masked nearest neighbour is used.}
13362 entry_help_balloon $w.comb2 $help_text
13363 }
13364 bind $u <Destroy> "help_object_hide"
13365 tkwait window .remaillage
13366
13367 # Si la fenêtre est fermée pour la dernière fois
13368 if {[info exists valid_remail]} {
13369 # Si on a validé la saisie
13370 if { $valid_remail } {
13371 # Sauve les options de remaillage saisies dans une var globale
13372 global options_remail
13373 foreach option {nbr_neighbours bi3_method if_masked norm_method norm_near_nei} {
13374 set value [set $option\_m]
13375 set options_remail($option) $value
13376 unset $option\_m
13377 }
13378 }
13379 unset valid_remail
13380 }
13381 }
13382 }
13383
13384 ret {comm_update} (type win , type clef_, type cnx , type exch_, type per_, type unit , type exch_, type per_, type val , type lag , type src_, type time_, type op , type src_, type add_, type val , type src_, type mult_, type val , type dbg_, type source , type stat_, type source_, type mask , type stat_, type source_, type nmsk , type stat_, type source_, type all , type remail , type tgt_, type time_, type op , type tgt_, type add_, type val , type tgt_, type mult_, type val , type dbg_, type cible , type stat_, type cible_, type mask , type stat_, type cible_, type nmsk , type stat_, type cible_, type all , type file_, type packing , type file_, type scaling , type file_, type adding , type file_, type fill_, type value) {
13385 # Variables globales
13386 global dico_caract_fichiers
13387 global dico_caract_cnx
13388 global dico_caract_points
13389 global dico_cnx_out
13390
13391 # Vérifie les informations entrées
13392 if { [comm_validation $exch_per_unit $exch_per_val $remail] } {
13393 return error
13394 }
13395
13396 # Enlever le 's' de pluriel aux unités de temps de la période des échanges
13397 set exch_per_unit [string range $exch_per_unit 0 end-1]
13398
13399 # Réinterprète le champ "type de remaillage"
13400 # ------------------------------------------
13401
13402 # Liste de descriptions lisibles et de mots-clefs correspondants
13403 array set remaillages { None {} {3D Nearest neighbour} nneighbour3D {3D Trilinear} trilinear {2D Nearest neighbour} nneighbour2D
13404 {2D Bilinear} bilinear {2D Bicubic} bicubic {2D Conservativ} conservativ2D }
13405
13406 # Transforme le mot-clef en description lisible
13407 if { $remail != "" } { set remail $remaillages($remail) }
13408
13409 # Réinterprète le champ "source time operation"
13410 array set mots_clefs { None {} {Time average} taverage {Time accumulation} accumul }
13411 if { $src_time_op != "" } { set src_time_op $mots_clefs($src_time_op) }
13412
13413 # Réinterprète le champ "target time operation"
13414 array unset mots_clefs
13415 array set mots_clefs { {None (Closest time)} {} {Time interpolation} time_linear }
13416 if { $tgt_time_op != "" } { set tgt_time_op $mots_clefs($tgt_time_op) }
13417
13418 # Réinterprète les booléens
13419 # Pour tous les champs booléens
13420 foreach nom_champ { dbg_source dbg_cible } {
13421 set valeur [set $nom_champ]
13422 if { $valeur != "" } {
13423 if {$valeur == "yes"} {set $nom_champ true} else {set $nom_champ false}
13424 }
13425 }
13426
13427 # Enregistre les attributs de la connexion
13428 # ----------------------------------------
13429
13430 set dico_caract_cnx($clef_cnx.src_time_op) ""
13431 set dico_caract_cnx($clef_cnx.src_add_val) 0
13432 set dico_caract_cnx($clef_cnx.src_mult_val) 1
13433 set dico_caract_cnx($clef_cnx.tgt_time_op) ""
13434 set dico_caract_cnx($clef_cnx.tgt_add_val) 0
13435 set dico_caract_cnx($clef_cnx.tgt_mult_val) 1
13436 set dico_caract_cnx($clef_cnx.remail) ""
13437
13438 foreach attrib {exch_per_unit exch_per_val lag dbg_source dbg_cible src_time_op src_add_val src_mult_val
13439 remail tgt_time_op tgt_add_val tgt_mult_val
13440 stat_source_mask stat_source_nmsk stat_source_all stat_cible_mask stat_cible_nmsk stat_cible_all } {
13441 set value [set $attrib]
13442 if { $value != "" } { set dico_caract_cnx($clef_cnx.$attrib) $value }
13443 }
13444
13445 # Enregistre les options de remaillage
13446 global options_remail
13447 if { $remail != "" } {
13448 # Réinterprète l'option booléenne norm_near_nei
13449 if {$options_remail(norm_near_nei) == "yes"} {set options_remail(norm_near_nei) true} else {set options_remail(norm_near_nei) false}
13450 # Traduit l'option de remaillage conservatif
13451 switch $options_remail(norm_method) {
13452 "Fractional area" { set options_remail(norm_method) fracarea }
13453 "Destination area" { set options_remail(norm_method) destarea }
13454 }
13455 foreach option {nbr_neighbours bi3_method if_masked norm_method norm_near_nei} {
13456 set dico_caract_cnx($clef_cnx.$option) $options_remail($option)
13457 }
13458 }
13459 array unset options_remail
13460
13461 # Appli du composant cible
13462 set appli_cible $dico_caract_cnx($clef_cnx.app_cible)
13463 # Si la cible est un fichier NetCDF
13464 if { [string equal $appli_cible "///file///"] } {
13465 # Identifiant du fichier cible
13466 set id_fichier $dico_caract_cnx($clef_cnx.comp_cible)
13467 # Enregistre les attributs du champ du fichier NetCDF
13468 set dico_caract_fichiers($id_fichier.field.packing) $file_packing
13469 set dico_caract_fichiers($id_fichier.field.scaling) $file_scaling
13470 set dico_caract_fichiers($id_fichier.field.adding) $file_adding
13471 set dico_caract_fichiers($id_fichier.field.fill_value) $file_fill_value
13472 }
13473
13474 catch {destroy .remaillage}; destroy $win
13475 }
13476
13477 ret {comm_validation} (type exch_, type per_, type unit , type exch_, type per_, type val , type remail) {
13478 # Vérifie les informations entrées dans la boite de dialogue de paramétrisation
13479 # d'une connexion.
13480 # Retourne 0 si pas d'erreur, 1 sinon.
13481
13482 # Les options de remaillage
13483 global options_remail
13484
13485 if {$exch_per_val == "" || $exch_per_unit == "Choose..."} {
13486 notice_show "Exchange period not filled !" error
13487 return 1
13488 }
13489
13490 # Suivant le type de remaillage
13491 switch $remail {
13492 # Si remaillage par la methode des voisins
13493 "3D Nearest neighbour" -
13494 "2D Nearest neighbour" {
13495 if { $options_remail(nbr_neighbours) == "" } {
13496 notice_show "Regridding option : nbr of neighbours not filled !" error
13497 return 1
13498 }
13499 }
13500 }
13501
13502 return 0
13503 }
13504
13505 ret {component_edit} (type clef_, type comp) {
13506 #
13507 global dico_applis dico_units
13508
13509 # Extrait les informations pertinentes
13510 # ------------------------------------
13511
13512 set nom_composant $dico_units($clef_comp)
13513 # Extrait de la clef le nom de l'appli
13514 set len_comp [string length $nom_composant]
13515 incr len_comp
13516 set nom_appli [string range $clef_comp 0 end-$len_comp]
13517 # Nom long du composant
13518 set clef_comp_2 app.$nom_appli.comp.$nom_composant
13519 set nom_long_comp ""
13520 if {[info exists dico_applis($clef_comp_2.long_name)]} {
13521 set nom_long_comp $dico_applis($clef_comp_2.long_name)
13522 }
13523 #== nb de processus
13524 set clef_proc $clef_comp_2.proc
13525 set min_procnumber 0
13526 catch {set min_procnumber $dico_applis($clef_proc.min_value)}
13527 set max_procnumber $min_procnumber
13528 catch {set max_procnumber $dico_applis($clef_proc.max_value)}
13529 set step_procnumber 1
13530 catch {set step_procnumber $dico_applis($clef_proc.increment)}
13531 # Plage du nombre de processus
13532 if { $max_procnumber != $min_procnumber } {
13533 if { $step_procnumber != 1 } {
13534 set procnumber "$min_procnumber to $max_procnumber by step of $step_procnumber"
13535 } else {
13536 set procnumber "$min_procnumber to $max_procnumber"
13537 }
13538 } else {
13539 set procnumber $min_procnumber
13540 }
13541
13542 # Rang des processus dans l'application
13543 global min_rank_m min_rank_m_regexp
13544 global max_rank_m max_rank_m_regexp
13545
13546 set min_rank_m 0
13547 catch { set min_rank_m $dico_applis($clef_comp_2.min_rank) }
13548 set max_rank_m $max_procnumber
13549 if {$max_procnumber != 0} {incr max_rank_m -1}
13550 catch { set max_rank_m $dico_applis($clef_comp_2.max_rank) }
13551
13552 # Cree une boite de dialogue
13553 # --------------------------
13554
13555 set u .mod_component
13556 catch {destroy $u}
13557 toplevel $u
13558 wm title $u "Edit component"
13559 wm iconname $u "Mod_Compt"
13560 window_position $u 20 20
13561
13562 set w $u.menu
13563 frame $w
13564 grid $w -row 2 -column 0
13565 grid configure $w -columnspan 2 -padx 4 -pady 4
13566
13567 frame $w.buttons
13568 pack $w.buttons -side bottom -fill x -pady 2m
13569
13570 button $w.buttons.dismiss -text Cancel -command "destroy $u"
13571 button $w.buttons.ok -text Ok -command "component_update $u $clef_comp_2 $nom_appli $nom_composant \$min_rank_m \$max_rank_m \$color_m"
13572
13573 pack $w.buttons.dismiss -side left -expand 1 -padx 10
13574 pack $w.buttons.ok -side left -expand 1 -padx 10
13575
13576 frame $w.sep1 -width 200 -height 2 -borderwidth 1 -relief sunken
13577 pack $w.sep1 -side bottom -fill x -pady 2m -expand 1
13578
13579 set w $u.char
13580 frame $w
13581 grid $w -row 0 -column 1
13582 grid configure $w -padx 4 -pady 4
13583 set r 1
13584
13585 #== nom
13586 label $w.label1 -text "Name:"
13587 label $w.label11 -relief sunken -text $nom_composant
13588 grid $w.label1 $w.label11 -row $r -sticky w
13589 incr r
13590
13591 #== nom long
13592 label $w.label2 -text "Long name:"
13593 label $w.label22 -relief sunken -text $nom_long_comp
13594 grid $w.label2 $w.label22 -row $r -sticky w
13595 incr r
13596
13597 #== nb process
13598 label $w.label3 -text "Number of Processes :"
13599 label $w.label33 -relief sunken -text $procnumber
13600 grid $w.label3 $w.label33 -row $r -sticky w
13601 incr r
13602
13603 grid [ frame $w.sep1 -width 430 -height 2 -borderwidth 1 -relief sunken] -row $r -column 0 -pady 5 -columnspan 2
13604 incr r
13605
13606 #== rang des processus dans l'application
13607 label $w.label4 -text "Ranks of Process :" -fg #ee3333
13608 frame $w.frrank
13609 trace variable min_rank_m w {entry_forceRegexp {^[0-9]*$} }
13610 trace variable max_rank_m w {entry_forceRegexp {^[0-9]*$} }
13611 pack [entry $w.frrank.e1 -textvariable min_rank_m -width 10 -background white] -side left
13612 pack [label $w.frrank.l1 -text " to "] -side left -padx 2
13613 pack [entry $w.frrank.e2 -textvariable max_rank_m -width 10 -background white] -side left -padx 2
13614 grid $w.label4 $w.frrank -row $r -sticky w
13615 incr r
13616
13617 #== couleur
13618 global color_m
13619 set color_m $dico_units($clef_comp.colour)
13620 label $w.label5 -text "Color :"
13621 button $w.entry5 -relief sunken -width 20 -text $color_m -background $color_m -command {
13622 global color_m
13623 set color_m [tk_chooseColor -initialcolor $color_m]
13624 catch {.mod_component.char.entry5 configure -background $color_m}
13625 }
13626 grid $w.label5 $w.entry5 -row $r -sticky w
13627
13628 # Ajoute une bulle d'aide pour 'min_rank' and 'max_rank'
13629 set help_text {Enter here the ranks of first and last process of this component as they appear in the application process group.
13630 Process ranks start from 0. Component processes are consecutive.}
13631 entry_help_balloon $w.frrank $help_text
13632
13633 # Ajoute une bulle d'aide pour 'color'
13634 global no_help_balloon
13635 if { $no_help_balloon == 0 } {
13636 set help_text {Click here to change the color of the component.}
13637 set help_action "help_object %W [list $help_text] message"
13638 bind $w.entry5 <Any-Enter> $help_action
13639 bind $w.entry5 <FocusIn> $help_action
13640 bind $w.entry5 <Any-Leave> "help_object_hide"
13641 bind $w.entry5 <FocusOut> "help_object_hide"
13642 bind $w.entry5 <ButtonPress> "help_object_hide"
13643
13644 bind $u <Destroy> "help_object_hide"
13645 }
13646 }
13647
13648 ret {entry_help_balloon} (type win , type help_, type text) {
13649 # Programme l'affichage d'un texte d'aide pour la zone de saisie 'win'
13650 global no_help_balloon
13651
13652 if { $no_help_balloon == 0 } {
13653 set help_action "help_object %W [list $help_text] message"
13654 # Le message d'aide s'affiche quand la souris survole la zone de saisie
13655 bind $win <Any-Enter> $help_action
13656 # et quand le curseur entre dans la zone de saisie
13657 bind $win <FocusIn> $help_action
13658 # Le message d'aide disparait quand la souris ne survole plus la zone de saisie
13659 bind $win <Any-Leave> "help_object_hide"
13660 bind $win <FocusOut> "help_object_hide"
13661 # ou quand l'utilisateur a frappe une touche
13662 bind $win <Any-KeyPress> "help_object_hide"
13663 }
13664 }
13665
13666 ret {component_update} (type win , type clef_, type comp , type nom_, type appli , type nom_, type composant , type min_, type rank , type max_, type rank , type couleur) {
13667 #
13668 global dico_applis dico_units
13669
13670 set min_rank_b $min_rank
13671 set max_rank_b $max_rank
13672 if {$min_rank_b > $max_rank_b} {
13673 set min_rank_b $max_rank
13674 set max_rank_b $min_rank
13675 }
13676
13677 # Nombre de processus de l'application
13678 catch { set proc_appli $dico_applis(app.$nom_appli.nbr_proc) }
13679 if { [info exists proc_appli] && $max_rank_b >= $proc_appli } {
13680 notice_show "invalid rank of process\n must be less than total number of application processes: $proc_appli" error
13681 return
13682 }
13683
13684 # Nombre max de processus du composant
13685 set clef_proc $clef_comp.proc
13686 set max_procnumber 0
13687 catch {set max_procnumber $dico_applis($clef_proc.max_value)}
13688 if { $max_procnumber && $max_rank_b >= $max_procnumber } {
13689 notice_show "invalid rank of process\n must be less than maximum number of component processes: $max_procnumber" error
13690 return
13691 }
13692
13693 # Met a jour le rang des processus dans l'application
13694 set dico_applis($clef_comp.min_rank) $min_rank_b
13695 set dico_applis($clef_comp.max_rank) $max_rank_b
13696 # Met a jour la couleur
13697 set clef_comp_1 $nom_appli.$nom_composant
13698 set dico_units($clef_comp_1.colour) $couleur
13699
13700 catch {destroy $win}
13701 # Redessine le composant
13702 Draw_one_unit $clef_comp_1
13703 }
13704
13705 ret {config_RAZ} () {
13706 # Efface toutes les données de configuration du couplage
13707 #
13708 global dico_experiment dico_applis
13709 global liste_points_i liste_points_o dico_caract_points
13710 global liste_cnx_in dico_cnx_out dico_caract_cnx
13711 global dico_units
13712 global liste_fichiers dico_caract_fichiers
13713
13714 array unset dico_experiment *
13715 array unset dico_applis *
13716 set liste_points_i {}
13717 set liste_points_o {}
13718 array unset dico_caract_points *
13719
13720 set liste_cnx_in {}
13721 array unset dico_cnx_out *
13722 array unset dico_caract_cnx *
13723
13724 array unset dico_units *
13725 set liste_fichiers {}
13726 array unset dico_caract_fichiers *
13727 }
13728
13729 ret {config_new} () {
13730 #
13731 # Starts a new coupling configuration
13732
13733 global env
13734 global dico_applis
13735 global file_lue
13736
13737 # S'il y a un couplage a l'ecran (au moins une appli chargee)
13738 set continuer 1
13739 set liste_applis {}
13740 catch { set liste_applis $dico_applis(lapplis) }
13741 if {[llength $liste_applis]} {
13742 set rep [tk_messageBox -message "Save current coupling configuration ?" -type yesno -icon question]
13743 if {$rep == "yes"} {
13744 set continuer [sauve_tout]
13745 }
13746 }
13747
13748 if { $continuer } {
13749 # Efface la config du couplage
13750 config_RAZ
13751 set file_lue ""
13752 wm title .gui "OASIS - New configuration"
13753
13754 global entityselected
13755 control_entity $entityselected
13756 drawall
13757 }
13758 }
13759
13760 ret {config_read} () {
13761 #
13762 # Load a coupling configuration
13763 #
13764 #** Verify that file SCC exists and read its content
13765 #
13766 global env
13767 global dico_applis
13768 global file_lue
13769
13770 # S'il y a un couplage a l'ecran (au moins une appli chargee)
13771 set continuer 1
13772 set liste_applis {}
13773 catch { set liste_applis $dico_applis(lapplis) }
13774 if {[llength $liste_applis]} {
13775 set rep [tk_messageBox -message "Save current coupling configuration ?" -type yesno -icon question]
13776 if {$rep == "yes"} {
13777 set continuer [sauve_tout]
13778 }
13779 }
13780
13781 set file ""
13782 if { $continuer } {
13783 set tk_strictMotif 1
13784 set types {
13785 {{Coupling configuration} {scc.xml}}
13786 }
13787 set file [tk_getOpenFile -initialfile scc.xml -title "Load coupling configuration scc.xml" -filetypes $types ]
13788 }
13789 if {$file == ""} {return}
13790
13791 #
13792 #** Lecture du fichier .XML
13793 #
13794 if {[file exists $file]} {
13795 .gui configure -cursor watch
13796 update
13797 # Efface la config du couplage
13798 config_RAZ
13799 set erreur [lit_fichier_SCC $file]
13800 .gui configure -cursor ""
13801
13802 if {! $erreur } {
13803 set file_lue $file
13804 wm title .gui "OASIS - $file"
13805
13806 global entityselected
13807 control_entity $entityselected
13808 drawall
13809 } else {
13810 # Efface les traces d'une config qui serait lue de façon incomplète
13811 config_RAZ
13812 }
13813 }
13814 }
13815
13816 ret {sauve_tout} () {
13817
13818 # Sauve le SCC.xml
13819 set res_list [sauve_scc]
13820 set result [lindex $res_list 0]
13821
13822 # Si la sauvegarde du SCC s'est bien passée
13823 if {$result != 0} {
13824 # Répertoire où on a sauvé le SCC
13825 set dir_name [lindex $res_list 1]
13826 # Sauve les SMIOC
13827 set result [sauve_smioc $dir_name]
13828 }
13829 return $result
13830 }
13831
13832 ret {sauve_scc} () {
13833 # Génère les fichiers XML de configuration d'un couplage :
13834 # - le fichier SCC.XML
13835 #
13836 global dico_applis
13837 global dico_units
13838
13839 set result 1
13840 set dir_name ""
13841
13842 # Vérifie qu'il y a au moins un composant ou un fichier NetCDF chargé en mémoire
13843 set liste_comp [array names dico_units]
13844 if { [llength $liste_comp] > 0 } {
13845 # Génere le texte XML pour le fichier SCC.xml
13846 set texte_xml [genere_SCC]
13847
13848 # Si génération possible
13849 if {$texte_xml != ""} {
13850
13851 # Sauve le texte dans un fichier scc.xml
13852 # Demande le choix du répertoire
13853
13854 set dir_name [tk_chooseDirectory -title "directory where to save file scc.xml" -mustexist yes]
13855 if {$dir_name != ""} {
13856
13857 set nom_fichier_SCC [file join $dir_name scc.xml]
13858 set continuer yes
13859 # Si le fichier existe déjà
13860 if { [file exists $nom_fichier_SCC] } {
13861 # Affiche un message d'avertissement
13862 set continuer [tk_messageBox -message "Overwrite existing file \"$nom_fichier_SCC\" ?" -type yesno -icon question]
13863 }
13864 if {$continuer == "yes"} {
13865
13866 set fichier_XML [open $nom_fichier_SCC w]
13867 puts $fichier_XML $texte_xml
13868 close $fichier_XML
13869 # if {$si_erreur} { file delete $nom_fichier_SCC }
13870
13871 # Si la sauvegarde s'est bien passée
13872 if {$result != 0} {
13873 # Sauve les parametres graphiques des composants du couplage dans un fichier XML
13874 # ------------------------------------------------------------------------------
13875
13876 # Cree un fichier appelé Graphics.xml dans le même répertoire que le fichier SCC.XML
13877 set nom_fichier_graphics [file join $dir_name Graphics.xml]
13878 set fichier_XML [open $nom_fichier_graphics w]
13879 # Remplit le fichier du texte XML
13880 puts $fichier_XML [genere_graphics_XML]
13881 close $fichier_XML
13882 }
13883 } else {
13884 set result 0
13885 }
13886 } else {
13887 set result 0
13888 }
13889 } else {
13890 set result 0
13891 }
13892 }
13893
13894 return [list $result $dir_name]
13895 }
13896
13897 ret {sauve_smioc} (optional dir_name ="") {
13898
13899 # Variables globales
13900 global dico_applis
13901 global dico_units
13902
13903 set result 1
13904
13905 # Vérifie qu'il y a au moins un composant ou un fichier NetCDF chargé en mémoire
13906 set liste_comp [array names dico_units]
13907 if { [llength $liste_comp] > 0 } {
13908
13909 # Génère les SMIOC de tous les composants chargés en mémoire
13910 # ----------------------------------------------------------
13911 if {$dir_name == ""} {
13912 set dir_name [tk_chooseDirectory -title "directory where to save file SMIOC.xml" -mustexist yes]
13913 }
13914 if {$dir_name != ""} {
13915 # Pour toutes les applications chargées en mémoire
13916 foreach nom_appli $dico_applis(lapplis) {
13917 # Pour tous les composants de cette application
13918 foreach nom_composant $dico_applis(app.$nom_appli.lcomp) {
13919 # Détermine le nom du fichier SMIOC (dans le même répertoire que le fichier SCC)
13920 set nom_fichier [file join $dir_name $nom_appli\_$nom_composant\_smioc.xml]
13921 set continuer yes
13922 # Si le fichier existe déjà
13923 if { [file exists $nom_fichier] } {
13924 # Affiche un message d'avertissement
13925 set continuer [tk_messageBox -message "Overwrite existing file \"$nom_fichier\" ?" -type yesno -icon question]
13926 }
13927 if {$continuer == "yes"} {
13928 # Ecrit dans le fichier XML
13929 set fichier_XML [open $nom_fichier w]
13930 puts $fichier_XML [genere_SMIOC $nom_appli $nom_composant]
13931 close $fichier_XML
13932 } else {
13933 set result 0
13934 break
13935 }
13936 }
13937 # Si un composant n'a pas été sauvegardé
13938 if {$result == 0} {
13939 # Annule tout
13940 break
13941 }
13942 }
13943 return $result
13944 } else {
13945 return 0
13946 }
13947 } else {
13948 return 0
13949 }
13950 }
13951
13952 ret {control_delete_entity} () {
13953 #
13954 global entityselected
13955 global objectselected
13956
13957 switch $entityselected {
13958 CONNECTION {
13959 # Si une connexion est sélectionnée
13960 if {$objectselected != ""} {
13961 comm_delete $objectselected
13962 set objectselected ""
13963 }
13964 }
13965 COUPLING_FIELD {
13966 # Les champs ne peuvent pas être supprimés
13967 }
13968 FILE {
13969 # Si un fichier est sélectionné
13970 if {$objectselected != ""} {
13971 NetCDF_file_delete $objectselected
13972 set objectselected ""
13973 }
13974 }
13975 COMPONENT {
13976 # a completer
13977 }
13978 }
13979 }
13980
13981 ret {control_edit_entity} () {
13982 # action sur le bouton edit
13983 global entityselected
13984 global objectselected tagselected oldcolor
13985 global dico_units
13986
13987 switch $entityselected {
13988 CONNECTION {
13989 # Si une connexion est sélectionnée
13990 if {$objectselected != ""} {
13991 comm_edit $objectselected
13992 }
13993 }
13994 FILE {
13995 # Si un fichier est sélectionné
13996 if {$objectselected != ""} {
13997 set id_fichier $dico_units($objectselected)
13998 # Permet la modif des param. de ce fichier
13999 NetCDF_file_edit $id_fichier
14000 tkwait window .mod_file
14001
14002 # Le nom ou la couleur ont pu changer : raffiche le fichier sur le graphe
14003 set clef
14004 Draw_one_unit $clef
14005
14006 # Remet la couleur de l'objet sélectionné
14007 set w .gui.pr.cpd22.03
14008 set oldcolor [$w itemcget $tagselected -fill ]
14009 $w itemconfigure $tagselected -fill red
14010 }
14011 }
14012 COUPLING_FIELD {
14013 # a completer
14014 }
14015 COMPONENT {
14016 # Si un composant est sélectionné
14017 if {$objectselected != ""} {
14018 # Si c'est un composant d'application
14019 if { [info exists dico_units($objectselected)] } {
14020 component_edit $objectselected
14021 catch {tkwait window .mod_component}
14022
14023 # La couleur a pu changer : raffiche le composant sur le graphe
14024 Draw_one_unit $objectselected
14025 # Remet la couleur de l'objet sélectionné
14026 set w .gui.pr.cpd22.03
14027 set oldcolor [$w itemcget $tagselected -fill ]
14028 $w itemconfigure $tagselected -fill red
14029 } else {
14030 application_edit $objectselected
14031 catch {tkwait window .mod_appli}
14032 }
14033 }
14034 }
14035 }
14036 }
14037
14038 ret {control_entity} (type entity , optional element ={)} {
14039 # reinitialise la multi-lisbox en fonction de l'entity
14040
14041 global dico_units
14042 global objectselected tagselected oldcolor
14043 global entityselected
14044 global orderentity
14045 global ordertri
14046 global entity_id
14047
14048 # Si changement de type d'entités affichées
14049 if { $entity != $entityselected } {
14050
14051
14052 if {$tagselected != ""} {
14053
14054 w = .gui.pr.cpd22.03
14055 $w itemconfigure $tagselected -fill $oldcolor
14056 }
14057 }
14058 entityselected = $entity
14059
14060
14061 switch $entity {
14062 COMPONENT {
14063
14064 entity = _id 0
14065
14066 listopt = {application component "long name" "start mode" "coupling mode" "nb ret esses"}
14067 # Contenu de la multiliste
14068 set loclist [liste_tous_composants]
14069 }
14070 FILE (
14071 # type Numero , type du , type bouton , type radio
14072 , type set , type entity_, type id 3
14073 # , type Titre , type des , type colonnes
14074 , type set , type listopt , optional name ="io direction" ="io mode" ="suffix"
14075 # , type Contenu , type de , type la , type multiliste
14076 , type set , type loclist [, type liste_, type tous_, type fichiers]
14077 )
14078 COUPLING_FIELD {
14079 # Numero du bouton radio
14080 set entity_id 1
14081 # Titre des colonnes
14082 set listopt {name "long name" application component type datatype "I/O"}
14083 # Contenu de la multiliste
14084 set loclist [liste_points_de_couplage]
14085 }
14086 CONNECTION {
14087
14088 entity = _id 2
14089
14090 listopt = {from "from component" to "to component" type datatype}
14091
14092 loclist = [liste_toutes_connexions]
14093 }
14094 default {
14095 entity = _id 0
14096 listopt = {}
14097 loclist = {}
14098 }
14099 }
14100
14101
14102 w = .gui.pr.toolframe.cpd18.01
14103
14104 foreach col [$w column names] {
14105 $w column delete $col
14106 }
14107 $w delete 0 end
14108
14109
14110 nbcol = [llength $listopt]
14111 for { i = 0} {$i < $nbcol} {incr i} { lenmax = ($i) [string length [lindex $listopt $i]]}
14112
14113
14114 foreach elm $loclist {
14115 i = 0
14116 foreach col $elm {
14117 if { $i < $nbcol } {
14118 longueur = [string length $col]
14119 if { [string is upper $col] } {
14120 longueur = [expr $longueur * 10 / 8]
14121 }
14122 if {$longueur > $lenmax($i)} { lenmax = ($i) $longueur}
14123 }
14124 incr i
14125 }
14126 }
14127
14128
14129 if { $entity != "COMPONENT" } {
14130 loclist = [lsort -dictionary -index $orderentity($entity) $loclist]
14131 }
14132
14133
14134 for { j = 0} {$j < $nbcol} {incr j} {
14135 col = [lindex $listopt $j]
14136 nom = _col [string map { " " "-" } $col]
14137 $w column add $nom_col -label $col -width [expr $lenmax($j)+1]
14138 if {[MOD $j 2] == 0} {$w column configure $nom_col -background grey95}
14139
14140 $w label bind $nom_col <ButtonPress-1> " orderentity = ($entityselected) $j ; control_entity $entityselected "
14141 }
14142
14143
14144 foreach elm $loclist {
14145 $w insert end [lrange $elm 0 end-1]
14146 }
14147
14148
14149 array un ordertri =
14150 i = 0
14151 foreach elm $loclist {
14152 clef = [lrange $elm end end]
14153 ordertri = ($clef) $i
14154 incr i
14155 }
14156
14157 .gui.pr.toolframe.buttonfrc.deleteb configure -state disabled
14158 .gui.pr.toolframe.buttonfrc.editb configure -state disabled
14159
14160
14161 if {$element != ""} {
14162
14163 $w selection $ordertri = ($element)
14164 $w yview $ordertri($element)
14165
14166 switch $entity {
14167 COMPONENT {
14168
14169 .gui.pr.toolframe.buttonfrc.deleteb configure -state disabled
14170 .gui.pr.toolframe.buttonfrc.editb configure -state normal
14171 }
14172 COUPLING_FIELD {
14173
14174 .gui.pr.toolframe.buttonfrc.deleteb configure -state disabled
14175 .gui.pr.toolframe.buttonfrc.editb configure -state disabled
14176 }
14177 FILE -
14178 CONNECTION {
14179 .gui.pr.toolframe.buttonfrc.deleteb configure -state normal
14180 .gui.pr.toolframe.buttonfrc.editb configure -state normal
14181 }
14182 }
14183 }
14184 }
14185
14186 ret {control_entity_selected} () {
14187 # Met a jour la liste des éléments dans la fenetre de gauche
14188
14189 global entityselected objectselected tagselected
14190 if {![info exists entityselected]} {return}
14191
14192 # Teste si l'element selectionne sur le graphe existe toujours
14193 set w .gui.pr.cpd22.03
14194 set selection [$w find withtag $tagselected]
14195
14196 # Si l'élément selectionne sur le graphe existe toujours
14197 if { $selection != "" } {
14198 # Met a jour la liste en gardant l'élément sélectionné
14199 control_entity $entityselected $objectselected
14200 } else {
14201 # Met a jour la liste
14202 control_entity $entityselected
14203 }
14204 }
14205
14206 ret {control_entity_selectionChanged} (type w , type args) {
14207 #
14208 global dico_units
14209 global entityselected objectselected tagselected oldcolor
14210 global ordertri
14211
14212 if { [$w curselection] == "" } {
14213 # pass
14214 } else {
14215 switch $entityselected {
14216 COMPONENT {
14217 # Dans le futur, on pourra supprimer des composants : s'ils sont optionnels
14218 .gui.pr.toolframe.buttonfrc.deleteb configure -state disabled
14219 .gui.pr.toolframe.buttonfrc.editb configure -state normal
14220 }
14221 COUPLING_FIELD {
14222 # Ni edition ni suppression des champs
14223 .gui.pr.toolframe.buttonfrc.deleteb configure -state disabled
14224 .gui.pr.toolframe.buttonfrc.editb configure -state disabled
14225 }
14226 FILE -
14227 CONNECTION {
14228 .gui.pr.toolframe.buttonfrc.deleteb configure -state normal
14229 .gui.pr.toolframe.buttonfrc.editb configure -state normal
14230 }
14231 }
14232
14233 # Recherche la connexion selectionnée
14234 set rang_selection [$w curselection]
14235
14236 foreach {clef rang} [array get ordertri] {
14237 if { $rang == $rang_selection } { break }
14238 }
14239
14240 # Met a jour la sélection sur le graphe
14241 set w .gui.pr.cpd22.03
14242 # Si il y avait un autre objet selectionne
14243 if {$tagselected != ""} {
14244 # Deselectionne ce composant sur le graphe
14245 $w itemconfigure $tagselected -fill $oldcolor
14246 }
14247 set tagselected ""
14248
14249 # Selon le type d'objets listes
14250 switch $entityselected {
14251 # Applis et composants
14252 COMPONENT {
14253 # Si c'est un composant d'application
14254 if { [info exists dico_units($clef)] } {
14255 set tagselected unitpoint_color($clef)
14256 } else {
14257 # C'est une application : rien à sélectionner sur le graphe
14258 set tagselected ""
14259 }
14260 set objectselected $clef
14261 }
14262 FILE {
14263 set tagselected unitpoint_color($clef)
14264 set objectselected $clef
14265 }
14266 COUPLING_FIELD {
14267 }
14268 CONNECTION {
14269 set tagselected tag_fils_connexions($clef)
14270 set objectselected $clef
14271 }
14272 }
14273
14274 # Si un objet est selectionne sur le graphe
14275 if { $tagselected != "" } {
14276 # Change la couleur de l'objet sélectionné sur le graphe
14277 set oldcolor [$w itemcget $tagselected -fill ]
14278 $w itemconfigure $tagselected -fill red
14279 }
14280 }
14281 }
14282
14283 ret {date_is_valid_date} (type nom_, type date) {
14284 # Teste si une date est valide
14285 # "nom_date" est le nom d'une var globale de type array
14286 upvar \#0 $nom_date date
14287
14288 set msg ok
14289 # Recopie les infos de la date (a cause de l'instruction "trace" sur la var globale de nom "$nom_date")
14290 foreach {name value} [array get date] {
14291 set new_date($name) $value
14292 }
14293
14294 if {$new_date(year) == ""} {set new_date(year) 0}
14295 if {$new_date(month) == ""} {set new_date(month) 1}
14296 if {$new_date(day) == ""} {set new_date(day) 1}
14297 if {$new_date(hour) == ""} {set new_date(hour) 0}
14298 if {$new_date(minute) == ""} {set new_date(minute) 0}
14299 if {$new_date(second) == ""} {set new_date(second) 0}
14300
14301 switch [date_nb_days_in_year $new_date(year)] {
14302 366 {
14303 set daylist [list 31 29 31 30 31 30 31 31 30 31 30 31]
14304 }
14305 365 {
14306 set daylist [list 31 28 31 30 31 30 31 31 30 31 30 31]
14307 }
14308 360 {
14309 set daylist [list 30 30 30 30 30 30 30 30 30 30 30 30]
14310 }
14311 }
14312 if {$new_date(second) < 0 } {set msg "negative second"}
14313 if {$new_date(second) > 60} {set msg "second > 60"}
14314 if {$new_date(minute) < 0 } {set msg "negative minute"}
14315 if {$new_date(minute) > 60} {set msg "minute > 60"}
14316 if {$new_date(hour) < 0} {set msg "negative hour"}
14317 if {$new_date(hour) > 24} {set msg "hour > 24"}
14318 if {$new_date(month) > 12} {set msg "month > 12"}
14319 if {$new_date(month) < 1 } {set msg "negative month "}
14320 if {$new_date(year) < 0 } {set msg "negative year "}
14321
14322 set maxday [lindex $daylist [expr $new_date(month) -1 ]]
14323 if {$new_date(day) > $maxday} {set msg "invalid day "}
14324
14325 return $msg
14326 }
14327
14328 ret {date_nb_days_in_year} (type year) {
14329 # Détermine le nombre de jours dans une année donnée
14330 set calendar STANDARD
14331
14332 switch $calendar {
14333 STANDARD {
14334 if {[expr $year/4.] == [expr int($year/4.)]} {
14335 set nb_days 366
14336 if {[expr $year/100.] == [expr int($year/100.)]} {set nb_days 365}
14337 if {[expr $year/400.] == [expr int($year/400.)]} {set nb_days 366}
14338 } else {
14339 set nb_days 365
14340 }
14341 }
14342 NOLEAP {
14343 set nb_days 365
14344 }
14345 360 {
14346 set nb_days 360
14347 }
14348 JULIAN {
14349 if {[expr $year/4.] == [expr int($year/4.)]} {
14350 set nb_days 366
14351 } else {
14352 set nb_days 365
14353 }
14354 }
14355 }
14356 return $nb_days
14357 }
14358
14359 ret {demi_chemin_1} (type x1 , type y1 , type xm , type ym , type cote , type clef_, type source) {
14360 # Calcule le chemin du composant source au point milieu (xm, ym)
14361 # - cote : vaut bas, droit ou gauche : il indique le côté par lequel on approche le point milieu
14362 # - clef_source : clef d'acces au composant source
14363 global dico_units
14364 global DRAW
14365
14366 #=========de dessous a dessus
14367 if { $cote == "bas" } {
14368
14369 # Quitte le point source par le dessous
14370 set y10 [expr $y1 +17 ]
14371 # Fait le tour du coin inferieur du composant source
14372 set coin_y [expr $dico_units($clef_source.coor_y) + $DRAW(heigthunit) + 17]
14373 if { $coin_y < $ym + 17 } {
14374 set coin_y [expr $ym + 17]
14375 }
14376
14377 set milieu_x [expr ($x1 + $xm) / 2]
14378 # Si on va de gauche a droite
14379 if { $x1 < $xm } {
14380 # Fait le tour du coin inferieur droit du composant source
14381 set coin_x [expr $dico_units($clef_source.coor_x) + $dico_units($clef_source.largeur) + 17]
14382 # if { $coin_x < $milieu_x } { set coin_x $milieu_x }
14383 if { $coin_x < $xm } { set coin_x $xm }
14384 } else {
14385 # Fait le tour du coin inferieur gauche du composant source
14386 set coin_x [expr $dico_units($clef_source.coor_x) - 17]
14387 # if { $coin_x > $milieu_x } { set coin_x $milieu_x }
14388 if { $coin_x > $xm } { set coin_x $xm }
14389 }
14390
14391 if { $coin_x == $xm } {
14392 return "$x1 $y1 $x1 $y10 $coin_x $coin_y $xm $ym"
14393 } else {
14394 # Approche le point milieu par le dessous
14395 set xm1 $xm
14396 set ym1 [expr $ym +20]
14397
14398 return "$x1 $y1 $x1 $y10 $coin_x $coin_y $xm1 $ym1 $xm $ym"
14399 }
14400
14401 #=========de dessus a dessous
14402 } else {
14403 # Approche le point milieu par le coté gauche ou droit
14404 if { $cote == "gauche" } {
14405 # Approche le point milieu par la gauche
14406 set xm1 [expr $xm -20]
14407 } else {
14408 set xm1 [expr $xm +20]
14409 }
14410 set ym1 $ym
14411 # Quitte le point source par le dessous
14412 set y10 [expr $y1 +17 ]
14413 return "$x1 $y1 $x1 $y10 $xm1 $ym1 $xm $ym"
14414 }
14415 }
14416
14417 ret {demi_chemin_2} (type xm , type ym , type x2 , type y2 , type cote , type clef_, type cible) {
14418 # Calcule le chemin du point milieu (xm, ym) au composant cible
14419 # - cote : vaut bas, droit ou gauche : il indique le côté par lequel on approche le point milieu
14420 # == le côté opposé de celui par lequel on quitte
14421 # - clef_cible : clef d'acces au composant cible
14422 global dico_units
14423 global DRAW
14424 #=========de dessous a dessus
14425 if { $cote == "bas" } {
14426
14427 # Fait le tour du coin superieur du composant cible
14428 set coin_y [expr $dico_units($clef_cible.coor_y) - 17]
14429 if { $coin_y > $ym - 17 } {
14430 set coin_y [expr $ym - 17]
14431 }
14432
14433 set milieu_x [expr ($xm + $x2) / 2]
14434 # Si on va de gauche a droite
14435 if { $xm < $x2 } {
14436 # Fait le tour du coin superieur gauche du composant cible
14437 set coin_x [expr $dico_units($clef_cible.coor_x) - 17]
14438 # if { $coin_x > $milieu_x } { set coin_x $milieu_x }
14439 if { $coin_x > $xm } { set coin_x $xm }
14440 } else {
14441 # Fait le tour du coin superieur droit du composant cible
14442 set coin_x [expr $dico_units($clef_cible.coor_x) + $dico_units($clef_cible.largeur) + 17]
14443 # if { $coin_x < $milieu_x } { set coin_x $milieu_x }
14444 if { $coin_x < $xm } { set coin_x $xm }
14445 }
14446 # Arrive à dest. par le dessus
14447 set y20 [expr $y2 - 17]
14448
14449 if { $coin_x == $xm } {
14450 return "$xm $ym $coin_x $coin_y $x2 $y20 $x2 $y2"
14451 } else {
14452 # Quitte le point milieu par le dessus
14453 set xm1 $xm
14454 set ym1 [expr $ym -20]
14455 return "$xm $ym $xm1 $ym1 $coin_x $coin_y $x2 $y20 $x2 $y2"
14456 }
14457
14458 #=========de dessus a dessous
14459 } else {
14460 # Quitte le point milieu par le coté gauche ou droit
14461 if { $cote == "gauche" } {
14462 # Quitte le point milieu par la droite
14463 set xm1 [expr $xm +20]
14464 } else {
14465 set xm1 [expr $xm -20]
14466 }
14467 set ym1 $ym
14468 # Arrive à dest. par le dessus
14469 set y20 [expr $y2 - 17]
14470 return "$xm $ym $xm1 $ym1 $x2 $y20 $x2 $y2"
14471 }
14472 }
14473
14474 ret {dialog_controls} (type win) {
14475 return "$win.controls"
14476 }
14477
14478 ret {dialog_create} (type class , optional win =auto) {
14479 #
14480 if {$win == "auto"} {
14481 set count 0
14482 set win ".dialog[incr count]"
14483 while {[winfo exists $win]} {
14484 set win ".dialog[incr count]"
14485 }
14486 }
14487 catch {destroy $win}
14488 toplevel $win -class $class
14489
14490 frame $win.info
14491 pack $win.info -expand yes -fill both -padx 4 -pady 4
14492
14493 frame $win.sep -height 2 -borderwidth 1 -relief sunken
14494 pack $win.sep -fill x -pady 4
14495
14496 frame $win.controls
14497 pack $win.controls -fill x -padx 4 -pady 4
14498
14499 wm title $win $class
14500 wm group $win .
14501
14502 after idle [format {
14503 update idletasks
14504 wm minsize %s [winfo reqwidth %s] [winfo reqheight %s]
14505 } $win $win $win]
14506
14507 return $win
14508 }
14509
14510 ret {dialog_info} (type win) {
14511 return "$win.info"
14512 }
14513
14514 ret {dialog_safeguard} (type win) {
14515 if {[lsearch [bindtags $win] modalDialog] < 0} {
14516 bindtags $win [linsert [bindtags $win] 0 modalDialog]
14517 }
14518 }
14519
14520 ret {dialog_wait} (type win , type varName) {
14521 #
14522 dialog_safeguard $win
14523
14524 set x [expr [winfo rootx .]+50]
14525 set y [expr [winfo rooty .]+50]
14526 wm geometry $win "+$x+$y"
14527
14528 wm deiconify $win
14529 grab set $win
14530
14531 vwait $varName
14532
14533 grab release $win
14534 wm withdraw $win
14535 }
14536
14537 ret {distmin} (type x1 , type y1 , type x2 , type y2) {
14538 global DRAW
14539 set dist [expr sqrt(($x2-$x1)*($x2-$x1)+($y2-$y1)*($y2-$y1))]
14540 if {$dist < $DRAW(maxi_line_size)} {return 1} else {return 0}
14541 }
14542
14543 ret {distming} (type x1 , type y1 , type x2 , type y2) {
14544 global DRAW
14545 set dist [expr sqrt(($x2-$x1)*($x2-$x1)+($y2-$y1)*($y2-$y1))]
14546 if {$dist < $DRAW(grouped_maxi_line_size)} {return 1} else {return 0}
14547 }
14548
14549 ret {draw_print} () {
14550 #
14551 #
14552 #**** draw_print - print the canvas
14553 #
14554 # Purpose:
14555 # --------
14556 # This tcl/tk script print the canvas directly to a pinter
14557 # or to a postcripts file
14558 #
14559 # Interface:
14560 # ----------
14561 # draw_print
14562 #
14563 #*** Externals:
14564 # ----------
14565 # This code uses Tcl/Tk
14566 #
14567 # References:
14568 # -----------
14569 # Effective Tcl/Tk Programming, M. Harrison and M. McLennan,
14570 # Addison-Wesley professional computing series, 1998
14571 #
14572 # History:
14573 # -------
14574 # Version Programmer Date Description
14575 # ------- ---------- ---- -----------
14576 # 0.0 Julien 1999/08/05 created
14577 #*----------------------------------------------------------------
14578 #
14579 #** Print the canvas in a postcript file
14580 #
14581 #
14582 set win .gui.pr.cpd22.03
14583
14584 set x0 0
14585 set y0 0
14586
14587 set x1 [winfo width $win]
14588 set y1 [winfo height $win]
14589
14590 foreach {x0 y0 x1 y1} [$win bbox all] {}
14591 set w [expr $x1-$x0]
14592 set h [expr $y1-$y0]
14593
14594 return [$win postscript -x $x0 -y $y0 -width $w -height $h]
14595 }
14596
14597 ret {drawall} () {
14598 #
14599 global DRAW
14600 global zoomfactor
14601
14602 .gui configure -cursor watch
14603
14604 #-------------------------------------
14605 #** variables a calculer avant de tracer
14606 #-------------------------------------
14607 Draw_set_init_variables
14608
14609 #-------------------------------------
14610 #** fenetre d'affichage ,clean
14611 #-------------------------------------
14612 set w $DRAW(window)
14613 $w delete all
14614 $w dtag all
14615
14616 #-------------------------------------
14617 #** affichage des unites
14618 #-------------------------------------
14619 Draw_drawunit
14620
14621 #-------------------------------------
14622 #** affichage des communications
14623 #-------------------------------------
14624 Draw_comm
14625
14626 #-------------------------------------
14627 #** bulle aide objet
14628 #-------------------------------------
14629 set u .ballon_object
14630 catch {destroy $u}
14631 toplevel $u -borderwidth 1 -relief flat
14632 wm iconify $u
14633 label $u.text -text "" -background #fefed4 -foreground black -font {helvetica 10} -justify left
14634 pack $u.text -side left -anchor w
14635 wm overrideredirect $u 1
14636 wm withdraw $u
14637
14638 .gui configure -cursor {}
14639 }
14640
14641 ret {dump_array} (type nom_, type dico , optional match_expression =*) {
14642 # Pour debug : dump le contenu d'un tableau
14643 upvar 1 $nom_dico dico
14644 puts "${nom_dico}($match_expression) :"
14645 foreach {n v} [array get dico $match_expression] {
14646 puts "$n : $v"
14647 }
14648 }
14649
14650 ret {entryLimit} (type entry , type traceProc , optional init ={)} {
14651 ## entryLimit - a convenience proc for managing traces on entry widgets
14652 ## Perhaps to make this even nicer, it could create a textvar for the
14653 ## user with the name the same as the entry?
14654 # ARGS: entry - the entry widget to trace
14655 # traceProc - trace procedure
14656 # init - initial value to use, defaults to {}
14657
14658
14659
14660
14661
14662
14663 if [string match {} [ var = [$entry cget -textvariable]]] {
14664 return -code error "-textvariable not for = entry \"$entry\""
14665 }
14666
14667 if {[string compare $traceProc {}]} {
14668
14669 uplevel \
14670 uplevel \
14671 if {[catch {uplevel \
14672
14673
14674 return -code error "an error was received ting = the initial value of \"$var\" to \"$init\". Make sure the value is valid and the traceProc is functional:\n$err"
14675 } else {
14676
14677
14678
14679 return
14680 }
14681 }
14682 foreach p [uplevel \
14683 if {[string match w [lindex $p 0]]} {
14684 uplevel \
14685 }
14686 }
14687 }
14688
14689 ret {entry_forceAlpha} (type name , type el , type op) {
14690 global $name ${name}_alpha
14691 if [string comp {} $el] {
14692 set old ${name}_alpha\($el)
14693 set name $name\($el)
14694 } else { set old ${name}_alpha }
14695 if ![regexp {^[a-zA-Z]*$} [set $name]] {
14696 set $name [set $old]
14697 bell; return
14698 }
14699 set $old [set $name]
14700 }
14701
14702 ret {entry_forceInt} (type name , type el , type op) {
14703 global $name ${name}_int
14704 if [string comp {} $el] {
14705 set old ${name}_int\($el)
14706 set name $name\($el)
14707 } else { set old ${name}_int }
14708 if ![regexp {^[-+]?[0-9]*$} [set $name]] {
14709 set $name [set $old]
14710 bell; return
14711 }
14712 set $old [set $name]
14713 }
14714
14715 ret {entry_forceInt_min_max} (type min , type max , type name , type el , type op) {
14716 global $name ${name}_int
14717 if [string comp {} $el] {
14718 set old ${name}_int\($el)
14719 set name $name\($el)
14720 } else { set old ${name}_int }
14721 if ![regexp {^[-+]?[0-9]*$} [set $name]] {
14722 set $name [set $old]
14723 bell; return
14724 }
14725 if {[set $name] != ""} {
14726 if {[set $name] > $max} {set $name $max}
14727 if {[set $name] < $min} {set $name $min}
14728 }
14729 set $old [set $name]
14730 }
14731
14732 ret {entry_forceLen} (type len , type name , type el , type op) {
14733 global $name ${name}_len
14734 if [string comp $el {}] {
14735 set old ${name}_len\($el)
14736 set name $name\($el)
14737 } else { set old ${name}_len }
14738 if {[string length [set $name]] > $len} {
14739 set $name [set $old]
14740 bell; return
14741 }
14742 set $old [set $name]
14743 }
14744
14745 ret {entry_forceReal} (type name , type el , type op) {
14746 global $name ${name}_real
14747 if [string comp {} $el] {
14748 set old ${name}_real\($el)
14749 set name $name\($el)
14750 } else { set old ${name}_real }
14751 if ![regexp {^[-+]?[0-9]*\.?[0-9]*([0-9]\.?e[-+]?[0-9]*)?$} [set $name]] {
14752 set $name [set $old]
14753 bell; return
14754 }
14755 set $old [set $name]
14756 }
14757
14758 ret {entry_forceReal_min_max} (type min , type max , type name , type el , type op) {
14759 global $name ${name}_int
14760 global $name ${name}_real
14761 if [string comp {} $el] {
14762 set old ${name}_real\($el)
14763 set name $name\($el)
14764 } else { set old ${name}_real }
14765 if ![regexp {^[-+]?[0-9]*\.?[0-9]*([0-9]\.?e[-+]?[0-9]*)?$} [set $name]] {
14766 set $name [set $old]
14767 bell; return
14768 }
14769 if {[set $name] != ""} {
14770 if {[set $name] > $max} {set $name $max}
14771 if {[set $name] < $min} {set $name $min}
14772 }
14773 set $old [set $name]
14774 }
14775
14776 ret {entry_forceRegexp} (type regexp , type name , type el , type op) {
14777 global $name ${name}_regexp
14778 if [string comp {} $el] {
14779 set old ${name}_regexp\($el)
14780 set name $name\($el)
14781 } else { set old ${name}_regexp }
14782 if ![regexp $regexp [set $name]] {
14783 set $name [set $old]
14784 bell; return
14785 }
14786 set $old [set $name]
14787 }
14788
14789 ret {entry_forceValue} (type default , type name , type el , type op) {
14790 global $name
14791 if [string comp {} $el] { set name $name\($el) }
14792 if ![info exists $name] { set $name $default }
14793 }
14794
14795 ret {experiment_settings} () {
14796 # boite de dialogue pour saisir les parametres de l'expérience et du run Oasis
14797
14798 global dico_experiment dico_applis
14799
14800 # Prépare les variables à saisir
14801 global local_name_m long_name_m start_mode_m drv_procs_m
14802 global expe_start_date expe_end_date
14803 global run_start_date run_end_date
14804
14805 # Prépare les variables à saisir
14806 set local_name_m ""
14807 catch {set local_name_m $dico_experiment(name)}
14808 set long_name_m ""
14809 catch {set long_name_m $dico_experiment(long_name)}
14810 set start_mode_m ""
14811 catch {set start_mode_m $dico_experiment(start_mode)}
14812 set drv_procs_m ""
14813 catch {set drv_procs_m $dico_experiment(drv_procs)}
14814
14815 # Initialisation des quatres dates
14816 foreach element { year month day hour minute second } {
14817 set expe_start_date($element) 1
14818 catch {set expe_start_date($element) $dico_experiment(start.$element)}
14819 set expe_end_date($element) 1
14820 catch {set expe_end_date($element) $dico_experiment(end.$element)}
14821 set run_start_date($element) 1
14822 catch {set run_start_date($element) $dico_experiment(run_start.$element)}
14823 set run_end_date($element) 1
14824 catch {set run_end_date($element) $dico_experiment(run_end.$element)}
14825 }
14826
14827
14828 # Liste des modes de démarrage autorisés
14829 # --------------------------------------
14830
14831 set si_autorise_mode_spawn 1
14832 set si_autorise_mode_notspawn 1
14833
14834 set liste_applis {}
14835 catch { set liste_applis $dico_applis(lapplis) }
14836 foreach nom_appli $liste_applis {
14837 set start_mode $dico_applis(app.$nom_appli.start_mode)
14838 switch $start_mode {
14839 # Si une appli ne marche que dans un mode donné, l'autre mode est interdit pour toutes les autres applis
14840 spawn { set si_autorise_mode_notspawn 0 }
14841 notspawn { set si_autorise_mode_spawn 0 }
14842 }
14843 }
14844 # Si il y a des restrictions incompatibles .... On n'y peut rien
14845 set options_start_mode {}
14846 if { $si_autorise_mode_notspawn } {
14847 lappend options_start_mode not_spawn
14848 }
14849 if { $si_autorise_mode_spawn } {
14850 lappend options_start_mode spawn
14851 }
14852
14853 # Crée une boite de dialogue
14854 set u .set_experiment
14855 catch {destroy $u}
14856 toplevel $u
14857 wm title $u "Experiment settings"
14858 wm iconname $u "settings"
14859 window_position $u 200 80
14860
14861 set w [frame $u.boutons]
14862 pack $w -side bottom -fill x -pady 2m -padx 2m
14863 button $w.dismiss -text Cancel -command "destroy $u"
14864 pack $w.dismiss -side left -expand 1
14865 button $w.ok -text Ok -command "experiment_update $u \$local_name_m \$long_name_m \$start_mode_m \$drv_procs_m"
14866 pack $w.ok -side left -expand 1
14867
14868 frame $u.sep -width 100 -height 2 -borderwidth 1 -relief sunken
14869 pack $u.sep -side bottom
14870
14871 set w [frame $u.char -borderwidth 1 -relief sunken]
14872 pack $w -side top -expand 1 -pady 10 -padx 10 -ipadx 3 -ipady 5
14873 set r 1
14874
14875 #== nom
14876 label $w.label1 -text "Experiment name: " -fg #ee3333
14877 entry $w.entry1 -textvariable local_name_m -width 15 -background white
14878 grid $w.label1 $w.entry1 -row $r -sticky w
14879 incr r
14880
14881 # Ajoute une bulle d'aide pour 'Experiment name'
14882 set help_text {This entry is mandatory.}
14883 entry_help_balloon $w.entry1 $help_text
14884
14885 #== Long name
14886 label $w.label2 -text "Long name : "
14887 entry $w.entry2 -textvariable long_name_m -width 25 -background white
14888 grid $w.label2 $w.entry2 -row $r -sticky w
14889 incr r
14890
14891 # Ajoute une bulle d'aide pour 'Long name'
14892 set help_text {Enter here a description of the experiment.}
14893 entry_help_balloon $w.entry2 $help_text
14894
14895 #== Start mode
14896 label $w.label3 -text "Start mode : " -fg #ee3333
14897 combobox_lim $w.cmb3 $options_start_mode {} start_mode_m 10 $start_mode_m
14898 grid $w.label3 $w.cmb3 -row $r -sticky w
14899 incr r
14900
14901 # Ajoute une bulle d'aide pour 'Start mode'
14902 set help_text {Choose the mode into which all applications of the coupled model will be started: either spawn or not spawn, (see User Guide section 3.1); this user’s choice, restricted by the possibilities given in the Application Descriptions, determines the way the applications should be started in the run script.}
14903 entry_help_balloon $w.cmb3 $help_text
14904
14905 #== nombre de processus du driver
14906 trace variable drv_procs_m w {entry_forceRegexp {^[0-9]*$} }
14907 label $w.label4 -text "Number of processes for OASIS driver : " -fg #ee3333
14908 entry $w.entry4 -textvariable drv_procs_m -width 10 -background white
14909 grid $w.label4 $w.entry4 -row $r -sticky w
14910 incr r
14911
14912 # Ajoute une bulle d'aide pour 'process number'
14913 set help_text {Enter the number of processes used for the OASIS4 Driver/Transformer.}
14914 entry_help_balloon $w.entry4 $help_text
14915
14916
14917 # Start/End Experiment/Run dates dans un autre cadre en-dessous
14918 # -------------------------------------------------------------
14919
14920 frame $u.sep2 -width 100 -height 2 -borderwidth 1 -relief sunken
14921 pack $u.sep2 -side top
14922
14923 set w [frame $u.char2 -borderwidth 1 -relief sunken]
14924 pack $w -side top -expand 1 -pady 10 -padx 10 -ipadx 3 -ipady 5
14925 set r 0
14926
14927 # Limitation des valeurs possibles
14928 foreach date {expe_start_date expe_end_date run_start_date run_end_date} {
14929 trace variable ${date}(year) w {entry_forceInt_min_max -500000 500000}
14930 trace variable ${date}(month) w {entry_forceInt_min_max 1 12}
14931 trace variable ${date}(day) w {entry_forceInt_min_max 1 31}
14932 trace variable ${date}(hour) w {entry_forceInt_min_max 0 24}
14933 trace variable ${date}(minute) w {entry_forceInt_min_max 0 60}
14934 trace variable ${date}(second) w {entry_forceReal_min_max 0 60}
14935 }
14936
14937 # Organise la saisie des quatre dates sur quatre lignes
14938 # avec les années, mois, jours, etc... disposés en colonnes
14939
14940 # Titre des colonnes
14941 label $w.l11 -text "Year:"
14942 label $w.l12 -text "Month:"
14943 label $w.l13 -text "Day:"
14944 label $w.l14 -text "Hour:"
14945 label $w.l15 -text "Minute:"
14946 label $w.l16 -text "Second:"
14947 # Disposition des titres sur la première ligne
14948 for {set i 1} {$i <= 6} {incr i} {
14949 grid $w.l1$i -row $r -column $i -pady 2 -padx 4 -sticky w
14950 }
14951 incr r
14952
14953 # Crée les zones de saisie
14954 foreach date {expe_start_date expe_end_date run_start_date run_end_date} {
14955 foreach {rank time_unit} {1 year 2 month 3 day 4 hour 5 minute 6 second} {
14956 entry $w.${date}a$rank -textvariable ${date}($time_unit) -width 7 -background white -justify right
14957
14958 frame $w.${date}fram$rank
14959 button $w.${date}fram$rank.plus -text "+" -padx 2m -pady 0 -font "helvetica -10 bold" -command "increment_date ${date} $time_unit 1"
14960 button $w.${date}fram$rank.moins -text "-" -padx 2m -pady 0 -font "helvetica -10 bold" -command "increment_date ${date} $time_unit -1"
14961 }
14962
14963 # Disposition des champs en colonnes
14964 for {set i 1} {$i <= 6} {incr i} {
14965 grid $w.${date}a$i -row $r -column $i -pady 0 -padx 4 -sticky w
14966 }
14967 incr r
14968 # Disposition des boutons "+" "-" en colonnes
14969 for {set i 1} {$i <= 6} {incr i} {
14970 grid $w.${date}fram$i -row $r -column $i
14971 pack $w.${date}fram$i.moins -side left -pady 0 -padx 0
14972 pack $w.${date}fram$i.plus -side right -pady 0 -padx 0
14973 }
14974 incr r
14975
14976 # Saute une ligne entre les dates de "Experiment" et les dates du "Run"
14977 if {$r == 5} {set r 6}
14978 }
14979
14980 # La ligne 5 est vide : on lui donne une hauteur minimum
14981 grid rowconfigure $w 5 -minsize 40
14982
14983 # Titre des lignes
14984 set r 1
14985 foreach {abbrev titre} { e_start "Experiment start date" e_end "Experiment end date" } {
14986 label $w.$abbrev -text $titre -anchor w -width 20
14987 # Disposé en colonne 0
14988 grid $w.$abbrev -row $r -column 0
14989 incr r 2
14990 }
14991 incr r
14992 foreach {abbrev titre} { r_start "Run start date" r_end "Run end date" } {
14993 label $w.$abbrev -text $titre -anchor w -width 20
14994 # Disposé en colonne 0
14995 grid $w.$abbrev -row $r -column 0
14996 incr r 2
14997 }
14998
14999 # Ajoute une bulle d'aide pour 'Run start and end date'
15000 array set help_text_array {
15001 run_start_date
15002 {Enter the start date of the run; the start date has to correspond to the lower bound of the time interval which is represented by the first time step of the run.}
15003 run_end_date
15004 {Enter the end date of the run; the end date has to correspond to the upper bound of the time interval which is represented by the last time step of the run. Note that the end date of the current run has to be used as start date for the subsequent run.}
15005 }
15006
15007 foreach date {run_start_date run_end_date} {
15008 for {set i 1} {$i <= 6} {incr i} {
15009 entry_help_balloon $w.${date}a$i $help_text_array($date)
15010 }
15011 }
15012 }
15013
15014 ret {experiment_update} (type win , type local_, type name , type long_, type name , type start_, type mode , type drv_, type procs) {
15015 # Valide la saisie des paramètres de l'expérience et du run
15016 global dico_experiment dico_applis
15017
15018 global expe_start_date expe_end_date
15019 global run_start_date run_end_date
15020
15021 # Experiment name is required
15022 if {$local_name == ""} {
15023 notice_show "Experiment name is required !" error
15024 focus .set_experiment.entry1
15025 return error
15026 }
15027
15028 # Teste les quatres dates saisies
15029 foreach {date_var_name date_long_name} {expe_start_date "Experiment start date"
15030 expe_end_date "Experiment end date" run_start_date "Run start date" run_end_date "Run end date" } {
15031 set msg [date_is_valid_date $date_var_name]
15032 if { $msg != "ok" } {
15033 notice_show "$date_long_name is invalid !" error
15034 focus .set_experiment.char2.${date_var_name}a1
15035 return error
15036 }
15037 }
15038
15039 # Sauve en mémoire toutes les valeurs saisies
15040 set dico_experiment(name) $local_name
15041 set dico_experiment(long_name) $long_name
15042 set dico_experiment(start_mode) $start_mode
15043 set dico_experiment(drv_procs) $drv_procs
15044
15045 # Sauve en mémoire les quatres dates
15046 foreach element { year month day hour minute second } {
15047 set dico_experiment(start.$element) $expe_start_date($element)
15048 set dico_experiment(end.$element) $expe_end_date($element)
15049 set dico_experiment(run_start.$element) $run_start_date($element)
15050 set dico_experiment(run_end.$element) $run_end_date($element)
15051 }
15052
15053 destroy $win
15054 }
15055
15056 ret {font_view_update} (optional font ={) {dummy {}}} {
15057 global dxf
15058 cur = _font [get_cur_font]
15059 .choose_font.view configure -font "$cur_font"
15060 .choose_font.view configure -foreground $dxf(choose_font_cb_color)
15061 }
15062
15063 ret {genere_SCC} () {
15064 # Génère le texte du fichier SCC.XML au format XML, bien entendu
15065 #
15066 global dico_experiment
15067 global dico_applis
15068 global dico_units
15069 global oasis4_version
15070
15071 # Texte retourné par la procédure
15072 set texte_xml ""
15073
15074 # Vérifie qu'il y a au moins un composant ou un fichier NetCDF chargé en mémoire
15075 set liste_comp [array names dico_units]
15076 if { [llength $liste_comp] > 0 } {
15077 # Si toutes les infos générales nécessaires sont renseignées
15078 if { [info exists dico_experiment(name)]
15079 && [info exists dico_experiment(start_mode)]
15080 && [info exists dico_experiment(drv_procs)]
15081 && [info exists dico_experiment(start.year)]
15082 && $dico_experiment(name) != ""
15083 && $dico_experiment(drv_procs) != "" } {
15084
15085 # Vérifie la compatibilité des applis avec le mode de lancement choisi
15086 # --------------------------------------------------------------------
15087
15088 # Analyse le mode de démarrage requis par les applications
15089 set si_autorise_mode_notspawn 1
15090 set si_autorise_mode_spawn 1
15091 set liste_applis $dico_applis(lapplis)
15092 foreach nom_appli $liste_applis {
15093 set start_mode $dico_applis(app.$nom_appli.start_mode)
15094 switch $start_mode {
15095 # Si une appli ne marche que dans un mode donné, l'autre mode est interdit pour toutes les autres applis
15096 spawn { set si_autorise_mode_notspawn 0 }
15097 notspawn { set si_autorise_mode_spawn 0 }
15098 }
15099 }
15100
15101 # Recherche une incompatibilité éventuelle
15102 set si_erreur 0
15103 switch $dico_experiment(start_mode) {
15104 spawn {
15105 if {$si_autorise_mode_spawn == 0} {set si_erreur 1}
15106 }
15107 not_spawn {
15108 if {$si_autorise_mode_notspawn == 0} {set si_erreur 1}
15109 }
15110 }
15111
15112 # Si erreur, message d'erreur
15113 if {$si_erreur} {
15114 notice_show "Experiment start mode ($dico_experiment(start_mode)) is incompatible with one or more application.
15115 Please, change experiment stat mode in menu 'Experiment settings' !"
15116 return ""
15117 }
15118
15119 # Recherche le N° de version d'OASIS4
15120 set nom_appli [lindex $liste_applis 0]
15121 set oasis4_version OASIS4_0_2
15122 if {[info exists dico_applis(app.$nom_appli.oasis4_version)] } {
15123 set oasis4_version $dico_applis(app.$nom_appli.oasis4_version)
15124 }
15125
15126 # Crée le document XML
15127 set doc [dom::DOMImplementation create]
15128
15129 # Crée l'élément SCC racine
15130 set scc_element [::dom::document createElement $doc scc]
15131 # Ses attributs
15132 dom::element setAttribute $scc_element xmlns "http://www.cerfacs.fr/PRISM/XML/1.1"
15133 dom::element setAttribute $scc_element "xmlns:xsi" "http://www.w3.org/2001/XMLSchema-instance"
15134 dom::element setAttribute $scc_element "xsi:schemaLocation" "http://www.cerfacs.fr/PRISM/XML/1.1"
15135 dom::element setAttribute $scc_element oasis4_version $oasis4_version
15136
15137 # Crée l'élément "experiment"
15138 set experiment_elt [::dom::document createElement $scc_element experiment]
15139 # Ses attributs
15140 dom::element setAttribute $experiment_elt local_name $dico_experiment(name)
15141 if { [info exists dico_experiment(long_name)] } {
15142 dom::element setAttribute $experiment_elt long_name $dico_experiment(long_name)
15143 }
15144 dom::element setAttribute $experiment_elt start_mode $dico_experiment(start_mode)
15145
15146 # Crée le sous-élément "driver"
15147 set driver_elt [::dom::document createElement $experiment_elt driver]
15148 set node [::dom::document createElement $driver_elt nbr_procs]
15149 set nbr_procs $dico_experiment(drv_procs)
15150 ::dom::document createTextNode $node $nbr_procs
15151
15152 # Crée le sous-élément "Experiment start date"
15153 set start_date_elt [::dom::document createElement $experiment_elt start_date]
15154 genere_element_date $start_date_elt "start"
15155
15156 # Crée le sous-élément "Experiment end date"
15157 set end_date_elt [::dom::document createElement $experiment_elt end_date]
15158 genere_element_date $end_date_elt "end"
15159
15160 set run_elt [::dom::document createElement $scc_element run]
15161 # Crée le sous-élément "Run start date"
15162 set start_date_elt [::dom::document createElement $run_elt start_date]
15163 genere_element_date $start_date_elt "start"
15164 # Crée le sous-élément "Run end date"
15165 set end_date_elt [::dom::document createElement $run_elt end_date]
15166 genere_element_date $end_date_elt "end"
15167
15168 # Pour toutes les applications chargées en mémoire
15169 foreach nom_appli $liste_applis {
15170 set appli_elt [::dom::document createElement $scc_element application]
15171
15172 # Test si toutes les données sont renseignées
15173 if { [info exists dico_applis(app.$nom_appli.executable_name)]
15174 && [info exists dico_applis(app.$nom_appli.redirect)] } {
15175
15176 # Ses attributs
15177 dom::element setAttribute $appli_elt local_name $nom_appli
15178 set executable_name $dico_applis(app.$nom_appli.executable_name)
15179 set redirect $dico_applis(app.$nom_appli.redirect)
15180 dom::element setAttribute $appli_elt executable_name $executable_name
15181 dom::element setAttribute $appli_elt redirect $redirect
15182
15183 # Sous-élément hosts
15184 foreach id_host $dico_applis(app.$nom_appli.lhosts) {
15185 set host_elt [::dom::document createElement $appli_elt host]
15186 # Son attribut local_name
15187 dom::element setAttribute $host_elt local_name $dico_applis(app.$nom_appli.host.$id_host.name)
15188 set node [::dom::document createElement $host_elt nbr_procs]
15189 # Le sous-element nbr_procs
15190 set nbr_procs $dico_applis(app.$nom_appli.host.$id_host.nb_procs)
15191 ::dom::document createTextNode $node $nbr_procs
15192 }
15193 # Pour tous les composants de cette application
15194 foreach nom_composant $dico_applis(app.$nom_appli.lcomp) {
15195
15196 # Test si toutes les données de ce composant sont renseignées
15197 if { [info exists dico_applis(app.$nom_appli.comp.$nom_composant.min_rank)] } {
15198 # élément component
15199 set component_elt [::dom::document createElement $appli_elt component]
15200 # Son attribut local_name
15201 dom::element setAttribute $component_elt local_name $nom_composant
15202
15203 # Sous-élément rank
15204 set rank_elt [::dom::document createElement $component_elt rank]
15205 # Sous-élément min_value
15206 set node [::dom::document createElement $rank_elt min_value]
15207 set min_value $dico_applis(app.$nom_appli.comp.$nom_composant.min_rank)
15208 ::dom::document createTextNode $node $min_value
15209 # Sous-élément max_value
15210 if { [info exists dico_applis(app.$nom_appli.comp.$nom_composant.max_rank)] } {
15211 set node [::dom::document createElement $rank_elt max_value]
15212 set max_value $dico_applis(app.$nom_appli.comp.$nom_composant.max_rank)
15213 ::dom::document createTextNode $node $max_value
15214 }
15215 } else {
15216 # Il manque des infos pour poursuivre
15217 notice_show "Please, edit attributes of component \"$nom_appli/$nom_composant\" prior to generate SCC !"
15218 set si_erreur 1
15219 break
15220 }
15221 }
15222 } else {
15223 # Il manque des infos pour poursuivre
15224 notice_show "Please, edit attributes of application \"$nom_appli\" prior to generate SCC !"
15225 set si_erreur 1
15226 break
15227 }
15228 }
15229
15230 if {!$si_erreur} {
15231 # Traduit en texte à syntaxe XML
15232 set texte_xml [::dom::DOMImplementation serialize $doc -indent 1]
15233 }
15234 # Libère la mémoire
15235 ::dom::DOMImplementation destroy $doc
15236 } else {
15237 # Il manque des infos pour poursuivre
15238 notice_show "Please, edit experiment settings prior to generate SCC !"
15239 return ""
15240 }
15241 }
15242 return $texte_xml
15243 }
15244
15245 ret {genere_SMIOC} (type nom_, type appli , type nom_, type composant) {
15246 #
15247 global dico_applis
15248 global dico_caract_fichiers
15249 global dico_caract_points
15250 global dico_cnx_out
15251 global dico_caract_cnx
15252
15253 global oasis4_version
15254
15255 # Cle d'acces du composant dans dico_applis
15256 set clef_composant app.$nom_appli.comp.$nom_composant
15257
15258 # Crée le document XML
15259 set doc [dom::DOMImplementation create]
15260
15261
15262 # Crée l'élément "prismcomponent" racine
15263 set prismcomponent_elt [::dom::document createElement $doc prismcomponent]
15264 # Ses attributs
15265 dom::element setAttribute $prismcomponent_elt xmlns "http://www.cerfacs.fr/PRISM/XML/1.1"
15266 dom::element setAttribute $prismcomponent_elt "xmlns:xsi" "http://www.w3.org/2001/XMLSchema-instance"
15267 dom::element setAttribute $prismcomponent_elt "xsi:schemaLocation" "http://www.cerfacs.fr/PRISM/XML/1.1"
15268 dom::element setAttribute $prismcomponent_elt oasis4_version $oasis4_version
15269 dom::element setAttribute $prismcomponent_elt local_name $nom_composant
15270
15271 # recopie la/les grille(s) depuis le PMIOD
15272 #
15273 foreach grid_name $dico_applis($clef_composant.lgrids) {
15274 set grid_elt [::dom::document createElement $prismcomponent_elt grid]
15275 dom::element setAttribute $grid_elt local_name $grid_name
15276 # Indexing dimensions
15277 if { [info exists dico_applis($clef_composant.grid.$grid_name.periodi)] } {
15278 set periodi_elt [::dom::document createElement $grid_elt indexing_dimension]
15279 dom::element setAttribute $periodi_elt index 1
15280 dom::element setAttribute $periodi_elt periodic $dico_applis($clef_composant.grid.$grid_name.periodi)
15281 }
15282 if { [info exists dico_applis($clef_composant.grid.$grid_name.periodj)] } {
15283 set periodj_elt [::dom::document createElement $grid_elt indexing_dimension]
15284 dom::element setAttribute $periodj_elt index 2
15285 dom::element setAttribute $periodj_elt periodic $dico_applis($clef_composant.grid.$grid_name.periodj)
15286 }
15287 if { [info exists dico_applis($clef_composant.grid.$grid_name.periodk)] } {
15288 set periodk_elt [::dom::document createElement $grid_elt indexing_dimension]
15289 dom::element setAttribute $periodk_elt index 3
15290 dom::element setAttribute $periodk_elt periodic $dico_applis($clef_composant.grid.$grid_name.periodk)
15291 }
15292 }
15293
15294 # Pour tous les noms des champs de couplage du composant
15295 # Rappel : un champ peut avoir deux points de couplage, un en entrée et un en sortie.
15296 foreach nom_champ $dico_applis($clef_composant.lchamps) {
15297 set lcnx_out ""
15298 catch { set lcnx_out $dico_caract_points($nom_appli.$nom_composant.$nom_champ.o.lcnx) }
15299 set lcnx_in ""
15300 catch { set lcnx_in $dico_caract_points($nom_appli.$nom_composant.$nom_champ.i.lcnx) }
15301
15302 # Si le champ a des connexions (en entrée ou en sortie)
15303 if { $lcnx_out != "" || $lcnx_in != "" } {
15304
15305 # Elément "transient"
15306 set transient_elt [::dom::document createElement $prismcomponent_elt transient]
15307 # Son attribut "local_name"
15308 dom::element setAttribute $transient_elt local_name $nom_champ
15309
15310 # Elément transient_standard_name
15311 set std_name_elt [::dom::document createElement $transient_elt transient_standard_name]
15312 ::dom::document createTextNode $std_name_elt $dico_applis($clef_composant.champ.$nom_champ.std_name)
15313
15314 # Elément XML "physics"
15315 set physics_elt [::dom::document createElement $transient_elt physics]
15316 dom::element setAttribute $physics_elt transient_type $dico_applis($clef_composant.champ.$nom_champ.type)
15317
15318 # Sous-élément physical_units
15319 set units_elt [::dom::document createElement $physics_elt physical_units]
15320 ::dom::document createTextNode $units_elt $dico_applis($clef_composant.champ.$nom_champ.units)
15321 # Sous-élément valid_min
15322 if { [info exists dico_applis($clef_composant.champ.$nom_champ.min)] } {
15323 set min_elt [::dom::document createElement $physics_elt valid_min]
15324 ::dom::document createTextNode $min_elt $dico_applis($clef_composant.champ.$nom_champ.min)
15325 }
15326 # Sous-élément valid_max
15327 if { [info exists dico_applis($clef_composant.champ.$nom_champ.max)] } {
15328 set max_elt [::dom::document createElement $physics_elt valid_max]
15329 ::dom::document createTextNode $max_elt $dico_applis($clef_composant.champ.$nom_champ.max)
15330 }
15331
15332 # Elément numerics
15333 set numerics_elt [::dom::document createElement $transient_elt numerics]
15334 set datatype $dico_applis($clef_composant.champ.$nom_champ.datatype)
15335 dom::element setAttribute $numerics_elt datatype "xs:$datatype"
15336
15337 # Elément "intent"
15338 set intent_elt [::dom::document createElement $transient_elt intent]
15339
15340 # Si le champ est en sortie
15341 if { $lcnx_out != "" } {
15342
15343 # Pour toutes les connexions sortantes
15344 foreach num_output $lcnx_out {
15345 # Elément "output"
15346 set output_elt [::dom::document createElement $intent_elt output]
15347 # Nom du point de connexion sortante ou "transi_out_name"
15348 set numero [string range $num_output 1 end]
15349 set nom_point_cnx $nom_champ\_out$numero
15350 dom::element setAttribute $output_elt transi_out_name $nom_point_cnx
15351
15352 # Elément "minimal_period" du champ en sortie
15353 genere_element_min_period $output_elt $clef_composant.champ.$nom_champ.o
15354
15355 # Retrouve le point cible
15356 set clef_point_source $nom_appli.$nom_composant.$nom_champ.$num_output
15357 set clef_point_cible $dico_cnx_out($clef_point_source)
15358 # Exchange period unit and value
15359 set exch_period_unit $dico_caract_cnx($clef_point_cible.exch_per_unit)
15360 set exch_period_value $dico_caract_cnx($clef_point_cible.exch_per_val)
15361
15362 # Element "exchange_date"
15363 set exchange_elt [::dom::document createElement $output_elt exchange_date]
15364 set period_elt [::dom::document createElement $exchange_elt period]
15365 set elt [::dom::document createElement $period_elt $exch_period_unit]
15366 ::dom::document createTextNode $elt $exch_period_value
15367
15368 # Element "corresp_transi_in_name" : le nom du point cible
15369 # Si la cible est un fichier
15370 if { $dico_caract_cnx($clef_point_cible.app_cible) == "///file///" } {
15371 # Identifiant du fichier
15372 set id_fichier $dico_caract_cnx($clef_point_cible.comp_cible)
15373 # Le nom du point cible est simplement le nom du champ du fichier
15374 set nom_pt_cible $dico_caract_fichiers($id_fichier.field.name)
15375 } else {
15376 # Le nom du point cible est le nom du champ suivi du suffixe _in
15377 set nom_pt_cible $dico_caract_cnx($clef_point_cible.champ_cible)\_in
15378 }
15379 set elt [::dom::document createElement $output_elt corresp_transi_in_name]
15380 ::dom::document createTextNode $elt $nom_pt_cible
15381
15382 # Si la cible est un fichier
15383 if { $dico_caract_cnx($clef_point_cible.app_cible) == "///file///" } {
15384 # Element "file"
15385 set file_elt [::dom::document createElement $output_elt file]
15386 # Sous-élément "name" : le nom du fichier
15387 set nom_fichier $dico_caract_fichiers($id_fichier.name)
15388 # Si l'option "suffix" est "true"
15389 if { $dico_caract_fichiers($id_fichier.suffix) == "true" } {
15390 # Enleve le suffixe .nc du nom du fichier
15391 if { [string match *.nc $nom_fichier] } {
15392 set nom_fichier [string range $nom_fichier 0 end-3]
15393 }
15394 }
15395 set elt [::dom::document createElement $file_elt name]
15396 ::dom::document createTextNode $elt $nom_fichier
15397
15398 # Sous-élément "suffix"
15399 set elt [::dom::document createElement $file_elt suffix]
15400 ::dom::document createTextNode $elt $dico_caract_fichiers($id_fichier.suffix)
15401 # Sous-élément "format"
15402 set elt [::dom::document createElement $file_elt format]
15403 ::dom::document createTextNode $elt mpp_netcdf
15404 # Sous-élément "io_mode"
15405 set elt [::dom::document createElement $file_elt io_mode]
15406 ::dom::document createTextNode $elt $dico_caract_fichiers($id_fichier.io_mode)
15407
15408 # Sous-élément "packing" (attribut NetCDF)
15409 set packing $dico_caract_fichiers($id_fichier.field.packing)
15410 if { [string match "\[1248\]" $packing] } {
15411 set elt [::dom::document createElement $file_elt packing]
15412 ::dom::document createTextNode $elt $packing
15413 }
15414 # Sous-élément "scaling" (attribut NetCDF)
15415 set scaling $dico_caract_fichiers($id_fichier.field.scaling)
15416 if { $scaling != "" } {
15417 set elt [::dom::document createElement $file_elt scaling]
15418 ::dom::document createTextNode $elt $scaling
15419 }
15420 # Sous-élément "adding" (attribut NetCDF)
15421 set adding $dico_caract_fichiers($id_fichier.field.adding)
15422 if { $adding != "" } {
15423 set elt [::dom::document createElement $file_elt adding]
15424 ::dom::document createTextNode $elt $adding
15425 }
15426 # Sous-élément "fill_value" (attribut NetCDF)
15427 set fill_value $dico_caract_fichiers($id_fichier.field.fill_value)
15428 if { $fill_value != "" } {
15429 set elt [::dom::document createElement $file_elt fill_value]
15430 ::dom::document createTextNode $elt $fill_value
15431 }
15432 } else {
15433 # Le nom du composant cible
15434 set nom_comp_cible $dico_caract_cnx($clef_point_cible.comp_cible)
15435 # Element "component_name"
15436 set corresp_comp_elt [::dom::document createElement $output_elt component_name]
15437 ::dom::document createTextNode $corresp_comp_elt $nom_comp_cible
15438 }
15439
15440 # Element lag
15441 set lag ""
15442 catch {set lag $dico_caract_cnx($clef_point_cible.lag)}
15443 if { $lag != ""} {
15444 set elt [::dom::document createElement $output_elt lag]
15445 ::dom::document createTextNode $elt $lag
15446 }
15447
15448 # Element "source_transformation"
15449 set transfo_elt [::dom::document createElement $output_elt source_transformation]
15450 # Element "source_time_operation"
15451 set src_time_op $dico_caract_cnx($clef_point_cible.src_time_op)
15452 if { $src_time_op != "" } {
15453 set elt [::dom::document createElement $transfo_elt source_time_operation]
15454 ::dom::document createTextNode $elt $src_time_op
15455 }
15456 # Element "statistics"
15457 set stat_source_mask $dico_caract_cnx($clef_point_cible.stat_source_mask)
15458 set stat_source_nmsk $dico_caract_cnx($clef_point_cible.stat_source_nmsk)
15459 set stat_source_all $dico_caract_cnx($clef_point_cible.stat_source_all)
15460 if {$stat_source_mask == "on" || $stat_source_nmsk == "on" || $stat_source_all == "on"} {
15461 set stat_elt [::dom::document createElement $transfo_elt statistics]
15462 set elt [::dom::document createElement $stat_elt masked_points]
15463 ::dom::document createTextNode $elt $stat_source_mask
15464 set elt [::dom::document createElement $stat_elt notmasked_points]
15465 ::dom::document createTextNode $elt $stat_source_nmsk
15466 set elt [::dom::document createElement $stat_elt all_points]
15467 ::dom::document createTextNode $elt $stat_source_all
15468 }
15469
15470 # Element "source_local_transformation"
15471
15472 # La transformation "scattering" est un attribut du point de couplage
15473 set scatter 0
15474 catch {set scatter $dico_applis($clef_composant.champ.$nom_champ.o.scatter)}
15475 # Les autres transformations sont des attributs de la connexion
15476 set src_add_val $dico_caract_cnx($clef_point_cible.src_add_val)
15477 set src_mult_val $dico_caract_cnx($clef_point_cible.src_mult_val)
15478 # Si il y a au moins une transformation a la source
15479 if { $scatter == 1 || [expr $src_add_val != 0] || [expr $src_mult_val != 1] } {
15480 # Creer l'element
15481 set local_transfo_elt [::dom::document createElement $transfo_elt source_local_transformation]
15482 # Element "scattering"
15483 if { $scatter } {
15484 set elt [::dom::document createElement $local_transfo_elt scattering]
15485 }
15486 # Element "add_scalar"
15487 if { $src_add_val != 0 } {
15488 set elt [::dom::document createElement $local_transfo_elt add_scalar]
15489 ::dom::document createTextNode $elt $src_add_val
15490 }
15491 # Element "mult_scalar"
15492 if { $src_mult_val != 1 } {
15493 set elt [::dom::document createElement $local_transfo_elt mult_scalar]
15494 ::dom::document createTextNode $elt $src_mult_val
15495 }
15496 }
15497
15498 # Element "debug_mode" a la source
15499 set debug_mode $dico_caract_cnx($clef_point_cible.dbg_source)
15500 set elt [::dom::document createElement $output_elt debug_mode]
15501 ::dom::document createTextNode $elt $debug_mode
15502 }
15503 }
15504
15505 # Si le champ est en entrée
15506 if { $lcnx_in != "" } {
15507
15508 # Elément "input"
15509 set input_elt [::dom::document createElement $intent_elt input]
15510
15511 # Attribut "required_but_changeable" du champ
15512 if { [info exists dico_applis($clef_composant.champ.$nom_champ.i.rbc)] } {
15513 set rbc $dico_applis($clef_composant.champ.$nom_champ.i.rbc)
15514 dom::element setAttribute $input_elt required_but_changeable $rbc
15515 }
15516
15517 # Elément "minimal_period" du champ en entrée
15518 genere_element_min_period $input_elt $clef_composant.champ.$nom_champ.i
15519
15520 # Exchange period unit and value
15521 set clef_point_cible $nom_appli.$nom_composant.$nom_champ.i
15522 set exch_period_unit $dico_caract_cnx($clef_point_cible.exch_per_unit)
15523 set exch_period_value $dico_caract_cnx($clef_point_cible.exch_per_val)
15524
15525 # Element "exchange_date"
15526 set exchange_elt [::dom::document createElement $input_elt exchange_date]
15527 set period_elt [::dom::document createElement $exchange_elt period]
15528 set elt [::dom::document createElement $period_elt $exch_period_unit]
15529 ::dom::document createTextNode $elt $exch_period_value
15530
15531 # Elément "origin"
15532 # Nom du point de connexion entrant ou "transi_in_name"
15533 set nom_point_cnx $nom_champ\_in
15534 set origin_elt [::dom::document createElement $input_elt origin]
15535 dom::element setAttribute $origin_elt transi_in_name $nom_point_cnx
15536
15537 # Retrouve le point source
15538 # L'appli du champ source ou
15539 set appli_source $dico_caract_cnx($clef_point_cible.app_source)
15540 # Le nom du composant source ou l'id du fichier source
15541 set nom_comp_source $dico_caract_cnx($clef_point_cible.comp_source)
15542 # Le nom du champ source
15543 set nom_champ_source $dico_caract_cnx($clef_point_cible.champ_source)
15544 # Le numéro du point source
15545 set num_pt_source [string range $dico_caract_cnx($clef_point_cible.pt_source) 1 end]
15546
15547 # Element "corresp_transi_out_name"
15548 # Si la source est un fichier
15549 if { $appli_source == "///file///" } {
15550 # c'est simplement le nom du champ
15551 set corresp_transi_out_name $nom_champ_source
15552 } else {
15553 # c'est le nom du champ suivi du suffixe _out<numéro>
15554 set corresp_transi_out_name $nom_champ_source\_out$num_pt_source
15555 }
15556 set elt [::dom::document createElement $origin_elt corresp_transi_out_name]
15557 ::dom::document createTextNode $elt $corresp_transi_out_name
15558
15559 # Si la source est un fichier
15560 if { $appli_source == "///file///" } {
15561 # Element "file"
15562 set file_elt [::dom::document createElement $origin_elt file]
15563 # Sous-élément "name" : le nom du fichier
15564 set nom_fichier $nom_comp_source
15565 # Si l'option "suffix" est "true"
15566 if { $dico_caract_fichiers($nom_comp_source.suffix) == "true" } {
15567 # Enleve le suffixe .nc du nom du fichier
15568 if { [string match *.nc $nom_fichier] } {
15569 set nom_fichier [string range $nom_fichier 0 end-3]
15570 }
15571 }
15572 set elt [::dom::document createElement $file_elt name]
15573 ::dom::document createTextNode $elt $nom_fichier
15574
15575 # Sous-élément "suffix"
15576 set elt [::dom::document createElement $file_elt suffix]
15577 ::dom::document createTextNode $elt $dico_caract_fichiers($nom_comp_source.suffix)
15578 # Sous-élément "format"
15579 set elt [::dom::document createElement $file_elt format]
15580 ::dom::document createTextNode $elt mpp_netcdf
15581 # Sous-élément "io_mode"
15582 set elt [::dom::document createElement $file_elt io_mode]
15583 ::dom::document createTextNode $elt $dico_caract_fichiers($nom_comp_source.io_mode)
15584 } else {
15585 # Element "component_name"
15586 set corresp_comp_elt [::dom::document createElement $origin_elt component_name]
15587 ::dom::document createTextNode $corresp_comp_elt $nom_comp_source
15588 }
15589
15590 # Element "middle_transformation"
15591 set remaillage $dico_caract_cnx($clef_point_cible.remail)
15592 if { $remaillage != "" } {
15593 set transfo_elt [::dom::document createElement $origin_elt middle_transformation]
15594 set interpol_elt [::dom::document createElement $transfo_elt interpolation]
15595
15596 # Test : interpolation 2D ou 3D ?
15597 switch $remaillage {
15598 nneighbour3D -
15599 trilinear {
15600 # Interpolation 3D
15601 set interp_xD_elt [::dom::document createElement $interpol_elt interp3D]
15602 }
15603 default {
15604 # Interpolation 2D
15605 set interp_xD_elt [::dom::document createElement $interpol_elt interp2D]
15606 # Element <Interpolation 1D> et sous-element <none> obligatoires bien qu'inutiles
15607 set interp_1D_elt [::dom::document createElement $interpol_elt interp1D]
15608 ::dom::document createElement $interp_1D_elt none
15609 }
15610 }
15611
15612 # Sous-element specifiant le type d'interpolation :
15613 # nneighbour3D, trilinear (3D), nneighbour2D, bilinear, bicubic ou conservativ2D
15614 set interp_type_elt [::dom::document createElement $interp_xD_elt $remaillage]
15615
15616 # Element "parallel search"
15617 set elt [::dom::document createElement $interp_type_elt para_search]
15618 ::dom::document createTextNode $elt global
15619
15620 # Test : interpolation par plus proche voisin ?
15621 if { $remaillage == "nneighbour3D" || $remaillage == "nneighbour2D" } {
15622 # Element "nbr_neighbours"
15623 set elt [::dom::document createElement $interp_type_elt nbr_neighbours]
15624 ::dom::document createTextNode $elt $dico_caract_cnx($clef_point_cible.nbr_neighbours)
15625 }
15626
15627 # Element "if masked"
15628 if { $remaillage != "conservativ2D" } {
15629 set elt [::dom::document createElement $interp_type_elt if_masked]
15630 ::dom::document createTextNode $elt $dico_caract_cnx($clef_point_cible.if_masked)
15631 }
15632
15633 # Si remaillage bicubique, Element "bicubic_method"
15634 if { $remaillage == "bicubic" } {
15635 set elt [::dom::document createElement $interp_type_elt bicubic_method]
15636 ::dom::document createTextNode $elt $dico_caract_cnx($clef_point_cible.bi3_method)
15637 }
15638
15639 # Si remaillage conservatif
15640 if { $remaillage == "conservativ2D" } {
15641 # Element "order"
15642 set elt [::dom::document createElement $interp_type_elt order]
15643 ::dom::document createTextNode $elt first
15644 # Element "normalisation method"
15645 set norm_elt [::dom::document createElement $interp_type_elt normalisation2D]
15646 # Element "methodnorm2D"
15647 set elt [::dom::document createElement $norm_elt methodnorm2D]
15648 ::dom::document createTextNode $elt $dico_caract_cnx($clef_point_cible.norm_method)
15649 # Element "nearnei"
15650 set elt [::dom::document createElement $norm_elt nearnei]
15651 ::dom::document createTextNode $elt $dico_caract_cnx($clef_point_cible.norm_near_nei)
15652 }
15653 }
15654
15655 # Element "target_transformation"
15656 set transfo_elt [::dom::document createElement $input_elt target_transformation]
15657 # Sous-element "target_local_transformation"
15658
15659 # La transformation "gathering" est un attribut du point de couplage
15660 set gather 0
15661 catch {set gather $dico_applis($clef_composant.champ.$nom_champ.i.gather)}
15662 # Les autres transformations sont des attributs de la connexion
15663 set tgt_add_val $dico_caract_cnx($clef_point_cible.tgt_add_val)
15664 set tgt_mult_val $dico_caract_cnx($clef_point_cible.tgt_mult_val)
15665 # Si il y a au moins une transformation à la source
15666 if { $gather == 1 || [expr $tgt_add_val != 0] || [expr $tgt_mult_val != 1] } {
15667 # Creer l'element
15668 set local_transfo_elt [::dom::document createElement $transfo_elt target_local_transformation]
15669 # Element "gathering"
15670 if { $gather } {
15671 set elt [::dom::document createElement $local_transfo_elt gathering]
15672 }
15673 # Element "add_scalar"
15674 if { $tgt_add_val != 0 } {
15675 set elt [::dom::document createElement $local_transfo_elt add_scalar]
15676 ::dom::document createTextNode $elt $tgt_add_val
15677 }
15678 # Element "mult_scalar"
15679 if { $tgt_mult_val != 1 } {
15680 set elt [::dom::document createElement $local_transfo_elt mult_scalar]
15681 ::dom::document createTextNode $elt $tgt_mult_val
15682 }
15683 }
15684 # Sous-element "target_time_operation"
15685 set tgt_time_op $dico_caract_cnx($clef_point_cible.tgt_time_op)
15686 if { $tgt_time_op != "" } {
15687 set elt [::dom::document createElement $transfo_elt target_time_operation]
15688 ::dom::document createTextNode $elt $tgt_time_op
15689 }
15690 # Element "statistics"
15691 set stat_cible_mask $dico_caract_cnx($clef_point_cible.stat_cible_mask)
15692 set stat_cible_nmsk $dico_caract_cnx($clef_point_cible.stat_cible_nmsk)
15693 set stat_cible_all $dico_caract_cnx($clef_point_cible.stat_cible_all)
15694 if {$stat_cible_mask == "on" || $stat_cible_nmsk == "on" || $stat_cible_all == "on"} {
15695 set stat_elt [::dom::document createElement $transfo_elt statistics]
15696 set elt [::dom::document createElement $stat_elt masked_points]
15697 ::dom::document createTextNode $elt $stat_cible_mask
15698 set elt [::dom::document createElement $stat_elt notmasked_points]
15699 ::dom::document createTextNode $elt $stat_cible_nmsk
15700 set elt [::dom::document createElement $stat_elt all_points]
15701 ::dom::document createTextNode $elt $stat_cible_all
15702 }
15703
15704 # Element "debug_mode"
15705 set dbg_cible $dico_caract_cnx($clef_point_cible.dbg_cible)
15706 set elt [::dom::document createElement $input_elt debug_mode]
15707 ::dom::document createTextNode $elt $dbg_cible
15708 }
15709 }
15710 }
15711
15712 # Traduit en texte à syntaxe XML
15713 set texte_xml [::dom::DOMImplementation serialize $doc -indent 1]
15714 # Libère la mémoire
15715 ::dom::DOMImplementation destroy $doc
15716
15717 return $texte_xml
15718 }
15719
15720 ret {genere_element_date} (type element_, type pere , type prefixe) {
15721 # Génère un sous-élément de type "date" dans l'élément element_pere passé en paramètre
15722 # Le sous-élément "date" comprend les sous-éléments suivants :
15723 # year month day hou minute second
15724 #
15725 # Paramètres d'entrée :
15726 # - element_pere
15727 # - prefixe : prefixe de la clef permettant d'acceder au valeurs dans le dictionnaire global "dico_experiment"
15728 #
15729 global dico_experiment
15730
15731 # Crée un sous-élément "date"
15732 set date_elt [::dom::document createElement $element_pere date]
15733 # Crée un sous-élément pour chaque unité de durée : year, month, etc...
15734 foreach time_unit {year month day hour minute second} {
15735 set value $dico_experiment($prefixe.$time_unit)
15736 if {$value != ""} {
15737 set node [::dom::document createElement $date_elt $time_unit]
15738 ::dom::document createTextNode $node $value
15739 }
15740 }
15741 }
15742
15743 ret {genere_element_min_period} (type element_, type XML , type prefixe) {
15744 global dico_applis
15745
15746 set period_elt [::dom::document createElement $element_XML minimal_period]
15747 # Pour toutes les unités possibles de temps
15748 foreach unit_temps {secs mins hours days months years} {
15749
15750 set name nbr_$unit_temps
15751 # Si une valeur est définie pour cette unité
15752 if { [info exists dico_applis($prefixe.$name)] } {
15753 # Crée un sous-élément correspondant
15754 set sous_element [::dom::document createElement $period_elt $name]
15755 ::dom::document createTextNode $sous_element $dico_applis($prefixe.$name)
15756 }
15757 }
15758 }
15759
15760 ret {genere_graphics_XML} () {
15761 # Génere le texte du fichier XML devant contenir
15762 # les parametres graphiques des composants du couplage
15763 #
15764 global dico_applis
15765 global dico_units
15766 global liste_fichiers dico_caract_fichiers
15767
15768 # Crée le document XML
15769 set doc [dom::DOMImplementation create]
15770
15771 # Crée l'élément SCC racine
15772 set graphics_elt [::dom::document createElement $doc graphics]
15773
15774 # Pour toutes les applications
15775 foreach nom_appli $dico_applis(lapplis) {
15776 # Pour tous les composants de cette application
15777 foreach nom_composant $dico_applis(app.$nom_appli.lcomp) {
15778 set clef_comp $nom_appli.$nom_composant
15779
15780 # Si l'élément apparait sur le graphe
15781 if { [info exists dico_units($clef_comp)] } {
15782 # Crée un élément "component"
15783 set component_elt [::dom::document createElement $graphics_elt component]
15784 # Ses attributs :
15785 # name
15786 dom::element setAttribute $component_elt name $nom_composant
15787 # appli
15788 dom::element setAttribute $component_elt application $nom_appli
15789 # Position en x et y, couleur et mode d'affichage
15790 foreach attrib {coor_x coor_y colour expand} {
15791 dom::element setAttribute $component_elt $attrib $dico_units($clef_comp.$attrib)
15792 }
15793 }
15794 }
15795 }
15796
15797 # Pour tous les fichiers NetCDF
15798 foreach id_fichier $liste_fichiers {
15799 set clef_fichier
15800
15801 # Si l'élément apparait sur le graphe
15802 if { [info exists dico_units($clef_fichier)] } {
15803 # Crée un élément "file"
15804 set file_elt [::dom::document createElement $graphics_elt file]
15805 # Ses attributs :
15806 # name
15807 dom::element setAttribute $file_elt name $dico_caract_fichiers($id_fichier.name)
15808 # Position en x et y, couleur et mode d'affichage
15809 foreach attrib {coor_x coor_y colour expand} {
15810 dom::element setAttribute $file_elt $attrib $dico_units($clef_fichier.$attrib)
15811 }
15812 }
15813 }
15814
15815 # Traduit en texte à syntaxe XML
15816 set texte_xml [::dom::DOMImplementation serialize $doc -indent 1]
15817 # Libère la mémoire
15818 ::dom::DOMImplementation destroy $doc
15819
15820 return $texte_xml
15821 }
15822
15823 ret {get_actual_font} (type font) {
15824 global dxf
15825 set dxf(choose_font_cb_name) ""
15826 set dxf(choose_font_cb_size) ""
15827 set dxf(choose_font_c_bold) ""
15828 set dxf(choose_font_c_italic) ""
15829 set dxf(choose_font_c_underline) ""
15830
15831 set new_font ""
15832 set lfont_opt [font actual $font]
15833 for { set i 1 } { $i < 10 } { incr i 2 } {
15834 set opt_val [string trim [lindex $lfont_opt $i]]
15835 if {$i == 1 } { set dxf(choose_font_cb_name) $opt_val }
15836 if {$i == 3 } { set dxf(choose_font_cb_size) $opt_val }
15837 if { $i == 5 } {
15838 if { $opt_val == "normal" } {
15839 set opt_val ""
15840 } else {
15841 set dxf(choose_font_c_bold) $opt_val
15842 }
15843 }
15844
15845 if { $i == 7 } {
15846 if { $opt_val == "roman" } {
15847 set opt_val ""
15848 } else {
15849 set dxf(choose_font_c_italic) $opt_val
15850 }
15851 }
15852 if { $i == 9 } {
15853 if { $opt_val == "0" } {
15854 set opt_val ""
15855 } else {
15856 set opt_val "underline"
15857 set dxf(choose_font_c_underline) $opt_val
15858 }
15859 }
15860
15861 if { [llength [split $opt_val " "]] <= 1 } {
15862 append new_font " $opt_val"
15863 } else {
15864 append new_font " \{$opt_val\}"
15865 }
15866
15867 }
15868 return [string trim $new_font]
15869 }
15870
15871 ret {get_cur_font} () {
15872 global dxf
15873 set cur_font ""
15874 foreach el [list $dxf(choose_font_cb_name) $dxf(choose_font_cb_size) $dxf(choose_font_c_bold) $dxf(choose_font_c_italic) $dxf(choose_font_c_underline)] {
15875 if { $el != "" } {
15876 set trim_el [string trim $el]
15877 if { [llength [split $trim_el " "]] <= 1 } {
15878 append cur_font " $trim_el"
15879 } else {
15880 append cur_font " \{$trim_el\}"
15881 }
15882 }
15883 }
15884
15885 return [string trim $cur_font]
15886 }
15887
15888 ret {help_communication} (type x , type y , type i) {
15889 #
15890 global dico_caract_cnx dico_caract_fichiers
15891
15892 set champ_source $dico_caract_cnx($i.champ_source)
15893
15894 # Si la cible est un fichier NetCDF
15895 if { $dico_caract_cnx($i.app_cible) == "///file///" } {
15896 # Le nom est mémorisé comme un attribut du champ "field"
15897 set id_fichier $dico_caract_cnx($i.comp_cible)
15898 set champ_cible $dico_caract_fichiers($id_fichier.field.name)
15899 } else {
15900 set champ_cible $dico_caract_cnx($i.champ_cible)
15901 }
15902
15903 set exch_per_val $dico_caract_cnx($i.exch_per_val)
15904 set exch_per_unit $dico_caract_cnx($i.exch_per_unit)
15905 if {$exch_per_val != 1} {
15906 # Met les unités au pluriel
15907 set exch_per_unit ${exch_per_unit}s
15908 }
15909 set text "From: $champ_source\nTo: $champ_cible\nPeriod: $exch_per_val $exch_per_unit"
15910 help_object .null $text label $x $y #e0fee6
15911 }
15912
15913 ret {help_object} (type w , type text , type type , optional x ={) {y {}} {color
15914
15915
15916
15917
15918
15919
15920
15921
15922 if {$x == ""} {
15923
15924 x = [expr [winfo rootx $w] + [winfo width $w]]
15925 y = [expr [winfo rooty $w] + [winfo height $w] - 5]
15926 } else {
15927 incr y 15
15928 incr x 5
15929 }
15930
15931
15932 u = .ballon_object
15933 wm geometry $u +$x+$y
15934 destroy $u.text
15935 switch $type {
15936 message {message $u.text -text $text -padx 15 -pady 10 -justify left}
15937 label {label $u.text -text $text -padx 15 -pady 10 -wraplength 140 -justify left}
15938 }
15939 $u.text configure -foreground black -font {helvetica 10} -background $color
15940 pack $u.text -side left
15941 wm deiconify $u
15942 raise $u
15943 }
15944
15945 ret {help_object_hide} () {
15946 catch {wm withdraw .ballon_object}
15947 }
15948
15949 ret {host_boutons_delete} (type form , type host) {
15950 # Supprime une ligne du tableau des ordinateurs "hosts" pour l'appli
15951 # avant que la ligne ait été supprimée en mémoire de la variable hosts_m
15952 #
15953 global hosts_m
15954
15955 array set info_host [grid info $form.n$host]
15956 set num_ligne $info_host(-row)
15957
15958 destroy $form.n$host; destroy $form.p$host; destroy $form.delete$host
15959
15960 set hosts_suivants [lrange $hosts_m(lhosts) [expr $num_ligne + 1] end]
15961 # Pour toutes les lignes suivantes
15962 set i $num_ligne
15963 foreach host_suivant $hosts_suivants {
15964 # Change le no de lignes des trois widgets
15965 grid configure $form.n$host_suivant $form.p$host_suivant $form.delete$host_suivant -row $i
15966 incr i
15967 }
15968 }
15969
15970 ret {host_boutons_insert} (type form , type host , type nb_, type hosts) {
15971 # Ajoute une ligne au formulaire de saisie des ordinateurs hosts
15972 global hosts_m
15973 global OASIS_GUI_DIR
15974
15975 # Ajoute une ligne
15976 set no_ligne $nb_hosts
15977
15978 grid [entry $form.n$host -textvariable hosts_m(host.$host.name) -width 20 -relief groove -background white -borderwidth 1] -row $no_ligne -column 0
15979 grid [entry $form.p$host -textvariable hosts_m(host.$host.nb_procs) -width 15 -relief groove -background white -borderwidth 1] -row $no_ligne -column 1
15980
15981 set file delete1.xbm
15982 grid [button $form.delete$host -bitmap @[file join $OASIS_GUI_DIR IMAGES $file] -command "host_boutons_delete $form $host; host_delete $host" -background white -foreground red -relief groove -borderwidth 1] -row $no_ligne -column 2
15983 focus $form.n$host
15984 bind $form.p$host <KeyPress-Return> "host_boutons_next $form $host"
15985 bind $form.p$host <KeyPress-Tab> "host_boutons_next $form $host"
15986 }
15987
15988 ret {host_boutons_next} (type form , type host) {
15989 global hosts_m
15990
15991 # Determine le no de ligne du bouton
15992 array set info_host [grid info $form.n$host]
15993 set num_ligne $info_host(-row)
15994
15995 # Si le bouton est en derniere ligne de la table
15996 if { [lindex [grid size $form] 1] == [expr $num_ligne + 1] } {
15997 host_insert $form
15998 } else {
15999 set host_suivant [lindex $hosts_m(lhosts) [expr $num_ligne + 1]]
16000 focus $form.n$host_suivant
16001 }
16002 }
16003
16004 ret {host_delete} (type host) {
16005 # Supprime un ordinateur host de la liste pour une application
16006 global hosts_m
16007
16008 # Supprime de la liste
16009 set hosts_m(lhosts) [lsearch -not -all -inline $hosts_m(lhosts) $host]
16010 # Oublie ses parametres
16011 array unset hosts_m host.$host.*
16012 }
16013
16014 ret {host_insert} (type form) {
16015 # Ajoute une nouvel ordinateur a la liste des ordinateurs hosts
16016 global hosts_m
16017
16018 set nb_hosts [llength $hosts_m(lhosts)]
16019 # Si déja des ordinateurs hosts sont listés
16020 if { $nb_hosts != 0 } {
16021 # Détermine le no du dernier identifiant de host (id = numéro)
16022 set dernier_host [lindex $hosts_m(lhosts) end]
16023 # Crée un nouvel identifiant de host
16024 set nouvel_host [expr $dernier_host + 1]
16025 } else {
16026 set nouvel_host 1
16027 }
16028 # Ajoute a la liste
16029 lappend hosts_m(lhosts) $nouvel_host
16030 set hosts_m(host.$nouvel_host.name) ""
16031 set hosts_m(host.$nouvel_host.nb_procs) ""
16032
16033 # Ajoute une ligne au formulaire
16034 host_boutons_insert $form $nouvel_host $nb_hosts
16035 }
16036
16037 ret {incr_font} (type object , type incr_, type val) {
16038 #
16039 set font [lindex [$object configure -font] 4]
16040 set size [lindex $font 1]
16041 if { $size != "" && [regexp {^[0-9]+$} $size] && [regexp {^[+-]?[0-9]+$} $incr_val]} {
16042 set font [lreplace $font 1 1 [incr size $incr_val]]
16043 }
16044 return $font
16045 }
16046
16047 ret {increment_date} (type nom_, type date , type champ_, type date , type offset) {
16048 # Incrémente un champ de la variable globale nom_date de la quantité "offset"
16049 # Le nom du champ est donné par "champ_date"
16050 #
16051 global $nom_date
16052
16053 set xval [set ${nom_date}($champ_date)]
16054 if { $xval == ""} {set xval 0}
16055 set xval [expr $xval + $offset]
16056 set ${nom_date}($champ_date) $xval
16057 # Pour forcer la verification des limites
16058 set ${nom_date}($champ_date) [set ${nom_date}($champ_date)]
16059 }
16060
16061 ret {liste_points_de_couplage} () {
16062 global liste_points_i liste_points_o
16063 global dico_applis dico_caract_points
16064 global dico_caract_fichiers
16065
16066 set liste {}
16067
16068 # Pour tous les points de couplage en entrée ou en sortie
16069 foreach clef_point [concat $liste_points_i $liste_points_o] {
16070 set nom_appli $dico_caract_points($clef_point.appli)
16071 set nom_comp $dico_caract_points($clef_point.comp)
16072 set nom_champ $dico_caract_points($clef_point.champ)
16073
16074 # Sens I/O
16075 set I_O [string range $clef_point end end]
16076 if { $I_O == "i" } {
16077 set I_O input
16078 } else {
16079 set I_O output
16080 }
16081
16082 # Si le point de couplage appartient à un fichier NetCDF
16083 if { $nom_appli == "///file///" } {
16084 set id_fichier $nom_comp
16085 set id_champ $nom_champ
16086
16087 if { $I_O == "input" } {
16088 # Le nom du fichier
16089 set nom_comp $dico_caract_fichiers($id_fichier.name)
16090 # C'est un fichier de sortie : normalement $id_champ vaut "field"
16091 # Le vrai nom du champ
16092 set nom_champ $dico_caract_fichiers($id_fichier.field.name)
16093 }
16094
16095 set nom_appli "file"
16096 set type single
16097 set datatype $dico_caract_fichiers($id_fichier.$id_champ.type)
16098 if { [catch {set long_name $dico_caract_fichiers($id_fichier.$id_champ.long_name)} ] } {
16099 set long_name ""
16100 }
16101
16102 } else {
16103 set clef_champ app.$nom_appli.comp.$nom_comp.champ.$nom_champ
16104 if { [catch {set long_name $dico_applis($clef_champ.long_name)} ] } {
16105 set long_name ""
16106 }
16107 set type $dico_applis($clef_champ.type)
16108 set datatype $dico_applis($clef_champ.datatype)
16109 }
16110
16111 # Ajoute dans la liste une ligne par point de couplage
16112 # name "long name" application component type datatype I/O
16113 # Une ligne se termine par une clef d'acces a cette connexion
16114 set line [list $nom_champ $long_name $nom_appli $nom_comp $type $datatype $I_O $clef_point]
16115 lappend liste $line
16116 }
16117 return $liste
16118 }
16119
16120 ret {liste_tous_composants} () {
16121 #
16122 global dico_applis
16123
16124 set liste {}
16125
16126 set liste_applis {}
16127 catch { set liste_applis $dico_applis(lapplis) }
16128
16129 # Pour toutes les applications chargees en memoire
16130 foreach nom_appli $liste_applis {
16131 set long_name ""
16132 if {[info exists dico_applis(app.$nom_appli.long_name)]} {
16133 set long_name $dico_applis(app.$nom_appli.long_name)
16134 }
16135 set start_mode $dico_applis(app.$nom_appli.start_mode)
16136 set coupling_mode $dico_applis(app.$nom_appli.coupling_mode)
16137 set erreur [catch {
16138 set min_value $dico_applis(app.$nom_appli.proc.min_value)
16139 set max_value $dico_applis(app.$nom_appli.proc.max_value)
16140 set increment $dico_applis(app.$nom_appli.proc.increment)
16141 set nb_proc "\[$min_value:$max_value:$increment\]"
16142 }]
16143 if {$erreur} { set nb_proc "" }
16144
16145 # Ajoute dans la liste une ligne par appli
16146 # Une ligne se termine par une clef d'acces a cette ligne
16147 set line [list $nom_appli "" $long_name $start_mode $coupling_mode $nb_proc $nom_appli]
16148 lappend liste $line
16149
16150 # Pour tous les composants de cette application
16151 foreach nom_composant $dico_applis(app.$nom_appli.lcomp) {
16152 set clef_comp app.$nom_appli.comp.$nom_composant
16153 if {[catch {set long_name $dico_applis($clef_comp.long_name)}] } {
16154 set long_name ""
16155 }
16156 set erreur [catch {
16157 set min_value $dico_applis($clef_comp.proc.min_value)
16158 set max_value $dico_applis($clef_comp.proc.max_value)
16159 set increment $dico_applis($clef_comp.proc.increment)
16160 set nb_proc "\[$min_value):$max_value:$increment\]"
16161 }]
16162 if {$erreur} { set nb_proc "" }
16163
16164 # Ajoute dans la liste une ligne par composant
16165 # Une ligne se termine par une clef d'acces a cd composant
16166 set line [list $nom_appli $nom_composant $long_name $start_mode $coupling_mode $nb_proc $nom_appli.$nom_composant]
16167 lappend liste $line
16168 }
16169 }
16170 return $liste
16171 }
16172
16173 ret {liste_tous_fichiers} () {
16174 #
16175 global liste_fichiers dico_caract_fichiers
16176
16177 set liste {}
16178
16179 foreach file_id $liste_fichiers {
16180 set io_direction $dico_caract_fichiers($file_id.dir)
16181 set io_mode $dico_caract_fichiers($file_id.io_mode)
16182 set suffix $dico_caract_fichiers($file_id.suffix)
16183 set filename $dico_caract_fichiers($file_id.name)
16184
16185 # Ajoute dans la liste une ligne par fichier énumérant ceci :
16186 # nom, sens (sortie ou entrée), mode d'acces (single ou parallele), avec ou sans suffixe
16187 # Une ligne se termine par une clef d'acces a ce fichier :
16188 set line [list $filename $io_direction $io_mode $suffix "
16189 lappend liste $line
16190 }
16191 return $liste
16192 }
16193
16194 ret {liste_toutes_connexions} () {
16195 #
16196 global liste_cnx_in
16197 global dico_applis dico_caract_cnx dico_caract_fichiers
16198
16199 set liste {}
16200
16201 # Pour tous les points de couplage en entrée ou en sortie
16202 foreach clef_cnx $liste_cnx_in {
16203 set appli_source $dico_caract_cnx($clef_cnx.app_source)
16204 set appli_cible $dico_caract_cnx($clef_cnx.app_cible)
16205 set champ_source $dico_caract_cnx($clef_cnx.champ_source)
16206 set champ_cible $dico_caract_cnx($clef_cnx.champ_cible)
16207 set comp_source $dico_caract_cnx($clef_cnx.comp_source)
16208 set comp_cible $dico_caract_cnx($clef_cnx.comp_cible)
16209
16210 # Si la cible est un fichier NetCDF
16211 if { $appli_cible == "///file///" } {
16212 # "comp_cible" contient l'identifiant du fichier
16213 # Son nom
16214 set nom_comp_cible $dico_caract_fichiers($comp_cible.name)
16215 # "champ_cible" contient "field"
16216 # le nom du champ
16217 set nom_champ_cible $dico_caract_fichiers($comp_cible.field.name)
16218 # Détermine les attributs du champ d'après le champ source
16219 set clef_champ app.$appli_source.comp.$comp_source.champ.$champ_source
16220 } else {
16221 set nom_comp_cible $comp_cible
16222 set nom_champ_cible $champ_cible
16223 # Détermine les attributs du champ d'après le champ cible
16224 set clef_champ app.$appli_cible.comp.$comp_cible.champ.$champ_cible
16225 }
16226
16227 # Détermine le type du champ
16228 set type $dico_applis($clef_champ.type)
16229 set datatype $dico_applis($clef_champ.datatype)
16230
16231 # Ajoute dans la liste une ligne par connexion
16232 # from "from component" to "to component" type datatype
16233 # Une ligne se termine par une clef d'acces a cette connexion
16234 set line [list $champ_source $comp_source $nom_champ_cible $nom_comp_cible $type $datatype $clef_cnx]
16235 lappend liste $line
16236 }
16237 return $liste
16238 }
16239
16240 ret {lit_1er_sous_element} (type element) {
16241 # Retourne la ref. du premier sous-élément XML d'un élément XML donné
16242 # Balaie les noeuds enfants jusqu'au premier noeud de type "élément"
16243 # En effet, il peut y avoir des noeuds de type "texte" ou "commentaires"
16244 # avant le premier sous-élément.
16245 #
16246 set sous_elt [dom::node configure $element -firstChild]
16247 set sous_elt_type [dom::node configure $sous_elt -nodeType]
16248 while {$sous_elt_type != "element"} {
16249 set sous_elt [dom::node configure $sous_elt -nextSibling]
16250 set sous_elt_type [dom::node configure $sous_elt -nodeType]
16251 }
16252 return $sous_elt
16253 }
16254
16255 ret {lit_XML_texte} (type element_, type XML) {
16256 set texte ""
16257 # Lit les sous-éléments de l'élément XML
16258 set ss_elem_list [dom::node children $element_XML]
16259 foreach element $ss_elem_list {
16260 set name [dom::node configure $element -nodeName]
16261 if {$name == "#text"} {
16262 set value [dom::node configure $element -nodeValue]
16263 if { $value != "" } {
16264 set texte "$texte $value"
16265 }
16266 }
16267 }
16268 return [string trim $texte]
16269 }
16270
16271 ret {lit_element_application} (type appli_, type elt , type dir_, type name) {
16272 # Lit dans un fichier SCC l'élément <application> donné en parametre
16273 # Ouvre aussi le fichier PMIOD de tous les composants de l'application listés dans
16274 # l'élément <application> ou à défaut le fichier SMIOC.
16275 #
16276 # Paramètres d'entrée :
16277 # - element : element XML de type "application"
16278 # - dir_name : nom du repertoire contenant le fichier SCC.xml
16279 #
16280 # Valeur de retour :
16281 # 0 si pas d'erreur
16282 # 1 s'il manque un fichier PMIOD ou SMIOC
16283 #
16284 global dico_applis dico_units
16285 global liste_points_i liste_points_o dico_caract_points
16286
16287 # Lit les attributs local_name, executable_name, redirect
16288 set att [dom::node configure $appli_elt -attributes]
16289 set nom_appli [load_XML_attributes $att dico_applis "app"]
16290
16291 # Lit le fichier AD.xml de l'application, si présent dans le même répertoire
16292 # et lit aussi les fichiers PMIOD des composants de l'appli si ceux ci sont aussi présents
16293 # ----------------------------------------------------------------------------
16294 set liste_comp_ajoutes {}
16295 set nom_fichier_AD [file join $dir_name "$nom_appli\_ad.xml"]
16296 if {! [file exists $nom_fichier_AD]} {
16297 # Essaie avec des lettres majuscules
16298 set nom_fichier_AD [file join $dir_name "$nom_appli\_AD.xml"]
16299 }
16300 # Si le fichierAD existe
16301 if {[file exists $nom_fichier_AD]} {
16302 lit_fichier_AD $nom_fichier_AD dico_applis liste_comp_ajoutes
16303 } else {
16304 # erreur
16305 notice_show "Cannot find Application Description file for \n$nom_appli\nYou have to locate and load it manually" error
16306 # Ajoute le nom de l'appli à la liste
16307 lappend dico_applis(lapplis) $nom_appli
16308 # Initialise arbitrairement des champs pas renseignés qui sont en fait obligatoires
16309 set dico_applis(app.$nom_appli.start_mode) notspawn_or_spawn
16310 set dico_applis(app.$nom_appli.coupling_mode) coupled_or_standalone
16311 set dico_applis(app.$nom_appli.proc.min_value) 0
16312 set dico_applis(app.$nom_appli.proc.max_value) 0
16313 set dico_applis(app.$nom_appli.proc.increment) 0
16314 }
16315
16316 # Lit les sous-éléments de l'élément <application>
16317 set current_host_id 0
16318 set ss_elem_list [dom::node children $appli_elt]
16319 foreach element $ss_elem_list {
16320 set name [dom::node configure $element -nodeName]
16321 if {$name != "#text" && $name != "#comment"} {
16322 switch $name {
16323 host {
16324 # Lit l'attribut "local_name" qui est le nom du host
16325 set att [dom::node configure $element -attributes]
16326 set host_name [load_XML_attributes $att dico_applis "app.$nom_appli.host"]
16327 # L'identifiant du host est une numéro
16328 set dico_applis(app.$nom_appli.host.$current_host_id.name) $host_name
16329 # Ajoute a la liste
16330 lappend dico_applis(app.$nom_appli.lhosts) $current_host_id
16331 # Lit le sous-element "nbr_procs" qui est unique
16332 set nbr_procs_elt [lit_1er_sous_element $element]
16333 # Lit la valeur du sous-élément "nbr_procs"
16334 set txt_elem [dom::node configure $nbr_procs_elt -firstChild]
16335 set value [dom::node configure $txt_elem -nodeValue]
16336 set dico_applis(app.$nom_appli.host.$current_host_id.nb_procs) $value
16337 incr current_host_id
16338 }
16339 component {
16340 # Lit l'attribut "local_name" qui est le nom du composant
16341 set att [dom::node configure $element -attributes]
16342 set nom_comp [load_XML_attributes $att dico_applis "app.$nom_appli.comp"]
16343
16344 # Lit les sous-éléments de l'élément <component> (qui sont tous de type "rank")
16345 set ss_elem_list [dom::node children $element]
16346 foreach element $ss_elem_list {
16347 set name [dom::node configure $element -nodeName]
16348 if {$name == "rank"} {
16349 lit_element_rank $element app.$nom_appli.comp.$nom_comp
16350 # Pour l'instant, on ne lit que le premier
16351 break
16352 }
16353 }
16354
16355 # Si le fichier PMIOD du composant n'a pas été lu en même temps que le fichier AD de l'appli
16356 if {[lsearch $liste_comp_ajoutes $nom_appli.$nom_comp] == -1} {
16357 # Si le fichier PMIOD du composant est présent dans le répertoire
16358 set erreur 1
16359 set nom_fichier_PMIOD [file join $dir_name "$nom_appli\_$nom_comp\_pmiod.xml"]
16360 if { [file isfile $nom_fichier_PMIOD] } {
16361 # Lit le fichier PMIOD du composant
16362 set erreur [lit_fichier_component $nom_fichier_PMIOD dico_applis $nom_appli $nom_comp PMIOD]
16363 }
16364 # Si pas possible de lire le fichier PMIOD
16365 if { $erreur } {
16366 # En remplacement, ouvre et lit une première fois le fichier SMIOC.xml du composant
16367 set nom_fichier_SMIOC [file join $dir_name "$nom_appli\_$nom_comp\_smioc.xml"]
16368 set erreur [lit_fichier_component $nom_fichier_SMIOC dico_applis $nom_appli $nom_comp PMIOD]
16369 # Initialise arbitrairement des champs pas renseignés qui sont en fait obligatoires
16370 set dico_applis(app.$nom_appli.comp.$nom_comp.proc.min_value) 0
16371 set dico_applis(app.$nom_appli.comp.$nom_comp.proc.max_value) 0
16372 set dico_applis(app.$nom_appli.comp.$nom_comp.proc.increment) 0
16373 }
16374
16375 # Si erreur aussi a la lecture du fichier SMIOC
16376 if { $erreur } {
16377 notice_show "Both files $nom_fichier_PMIOD and $nom_fichier_SMIOC are absent or invalid !" error
16378 return 1
16379 } else {
16380 # Ajoute le composant à la liste
16381 lappend dico_applis(app.$nom_appli.lcomp) $nom_comp
16382 }
16383 }
16384
16385 # Ajoute le composant à la liste des unités graphiques
16386 set dico_units($nom_appli.$nom_comp) $nom_comp
16387
16388 # Ajoute tous les points d'échange (de couplage) de ce composant
16389 # à la liste générale des points de couplage
16390 if { ![info exists dico_applis(app.$nom_appli.comp.$nom_comp.lchamps)] } {
16391 set dico_applis(app.$nom_appli.comp.$nom_comp.lchamps) {}
16392 }
16393 set liste_champs $dico_applis(app.$nom_appli.comp.$nom_comp.lchamps)
16394 foreach nom_champ $liste_champs {
16395 set clef_base "$nom_appli.$nom_comp.$nom_champ"
16396
16397 # Si le champ de couplage est en entrée
16398 if { [info exists dico_applis(app.$nom_appli.comp.$nom_comp.champ.$nom_champ.input)] } {
16399 set clef "$clef_base.i"
16400 lappend liste_points_i $clef
16401 set dico_caract_points($clef.appli) $nom_appli
16402 set dico_caract_points($clef.comp) $nom_comp
16403 set dico_caract_points($clef.champ) $nom_champ
16404 }
16405
16406 # Si le champ de couplage est en sortie
16407 if { [info exists dico_applis(app.$nom_appli.comp.$nom_comp.champ.$nom_champ.output)] } {
16408 set clef "$clef_base.o"
16409 lappend liste_points_o $clef
16410 set dico_caract_points($clef.appli) $nom_appli
16411 set dico_caract_points($clef.comp) $nom_comp
16412 set dico_caract_points($clef.champ) $nom_champ
16413 }
16414 }
16415 }
16416 }
16417 }
16418 }
16419 return 0
16420 }
16421
16422 ret {lit_element_date} (type elt_, type parent , type prefixe) {
16423 # Lit dans le fichier SCC.XML la date de "start" ou "end" de "experiment" ou "run"
16424 #
16425 # Paramètres d'entrée :
16426 # - elt_parent : element XML qui contient le sous-element "date"
16427 # - prefixe : préfixe de la clef permettant d'accéder au valeurs dans le dictionnaire global "dico_experiment"
16428 #
16429 global dico_experiment
16430
16431 # Initialisation des champs de la date
16432 foreach champ { year month day hour minute second } {
16433 set dico_experiment($prefixe.$champ) ""
16434 }
16435
16436 # Accède au sous-element XML "date"
16437 set date_elt [lit_1er_sous_element $elt_parent]
16438 # Lit les sous-éléments de l'élément <date>
16439 set ss_elem_list [dom::node children $date_elt]
16440 foreach element $ss_elem_list {
16441 set name [dom::node configure $element -nodeName]
16442 if {$name != "#text" && $name != "#comment"} {
16443 # La var. $name contient une des valeurs suivantes : year month day hour minute second
16444 # Extrait la valeur du sous-element year month day hour minute ou second
16445 set ss_elem [dom::node configure $element -firstChild]
16446 set value [dom::node configure $ss_elem -nodeValue]
16447 set dico_experiment($prefixe.$name) $value
16448 }
16449 }
16450 }
16451
16452 ret {lit_element_exchange_date} (type element_, type XML) {
16453 # Lit un élément XML de type <exchange_date> (période des échanges)
16454 #
16455 # Retourne une liste contenant l'unité de temps de la période des échanges (year, month, day,...)
16456 # et le nombre d'unités.
16457 #
16458 # On suppose qu'il n'y a qu'une seule unité de temps. En fait, la période peut etre définie
16459 # par plusieurs unités de temps, par exemple : 2 heures 30 minutes
16460 # Mais ce cas n'est pas pris en charge.
16461
16462 # Accède au sous-élément <period> : le premier sous-element de <exchange_date>
16463 set period_elt [lit_1er_sous_element $element_XML]
16464
16465 # Accède au premier sous-element de <period> : year, month, day ou autre
16466 set ss_elt_unite [lit_1er_sous_element $period_elt]
16467 set unite [dom::node configure $ss_elt_unite -nodeName]
16468
16469 # Lit la valeur du sous-élément
16470 set txt_elem [dom::node configure $ss_elt_unite -firstChild]
16471 set valeur [dom::node configure $txt_elem -nodeValue]
16472
16473 return [list $unite $valeur]
16474 }
16475
16476 ret {lit_element_file} (type element_, type XML , type nom_, type dico) {
16477 # Lit un élément XML de type <file>
16478 #
16479 # Remplit un dictionnaire contenant tous les parametres du fichier
16480 # Retourne le nom du fichier.
16481 #
16482 upvar 1 $nom_dico dico_fichier
16483
16484 # Initialise la structure de donnees
16485 set dico_fichier(suffix) false
16486 set dico_fichier(io_mode) iosingle
16487
16488 # Lit les sous-éléments de l'élément <file>
16489 set ss_elem_list [dom::node children $element_XML]
16490 foreach element $ss_elem_list {
16491 set name [dom::node configure $element -nodeName]
16492 if {$name != "#text" && $name != "#comment"} {
16493 set value [lit_XML_texte $element]
16494 set dico_fichier($name) $value
16495 }
16496 }
16497 return $dico_fichier(name)
16498 }
16499
16500 ret {lit_element_input} (type element_, type XML , type nom_, type appli , type nom_, type comp , type nom_, type champ , type PMIOD_, type ou_, type SMIOC) {
16501 # Lit l'élément input d'un fichier SMIOC.xml
16502 # en particulier les éléments XML concernant la connexion arrivant a ce point couplage
16503 #
16504 # Parametres d'entrée :
16505 # - element_XML : élément XML de type <output>
16506 # - nom_appli : nom de l'application
16507 # - nom_comp : nom du composant
16508 # - nom_champ : nom du champ de couplage
16509 # - PMIOD_ou_SMIOC : vaut PMIOD ou SMIOC
16510 #
16511
16512 global dico_applis
16513
16514 global liste_points_i liste_points_o dico_caract_points
16515 global liste_cnx_in dico_cnx_out dico_caract_cnx
16516
16517 global liste_fichiers dico_caract_fichiers
16518 global dico_units
16519
16520 # Lit les sous-éléments de l'élément <input>
16521 # ------------------------------------------
16522
16523 set ss_elem_list [dom::node children $element_XML]
16524 foreach element $ss_elem_list {
16525 set name [dom::node configure $element -nodeName]
16526 switch $name {
16527 exchange_date {
16528 # Si on lit un fichier SMIOC
16529 if {$PMIOD_ou_SMIOC == "SMIOC"} {
16530 set exch_date [lit_element_exchange_date $element]
16531 }
16532 }
16533
16534 origin {
16535 # Si on lit un fichier SMIOC
16536 if {$PMIOD_ou_SMIOC == "SMIOC"} {
16537 array set cnx_attribute {}
16538 array set dico_fichier {}
16539 set origin [lit_element_origin $element cnx_attribute dico_fichier]
16540 set nom_comp_source [lindex $origin 0]
16541 set nom_corresp [lindex $origin 1]
16542 }
16543 }
16544
16545 target_transformation {
16546 array set cnx_attribute {}
16547 lit_element_src_tgt_transfo $element cnx_attribute target $PMIOD_ou_SMIOC
16548 }
16549
16550 debug_mode {
16551 # Si on lit un fichier SMIOC
16552 if {$PMIOD_ou_SMIOC == "SMIOC"} {
16553 # Lit la valeur du sous-élément <debug_mode> : a priori = "true"
16554 set txt_elem [dom::node configure $element -firstChild]
16555 set cnx_attribute(dbg_cible) [dom::node configure $txt_elem -nodeValue]
16556 }
16557 }
16558 }
16559 }
16560
16561 # Si on lit un fichier SMIOC
16562 if {$PMIOD_ou_SMIOC == "SMIOC"} {
16563
16564 # Crée une nouvelle connexion
16565 # ---------------------------
16566
16567 # Préfixe de la clef des éléments à mettre dans les dictionnaires dico_caract_points et dico_caract_cnx
16568 set prefixe "$nom_appli.$nom_comp.$nom_champ"
16569 # Mémorise que le point de couplage entrant est connecté
16570 lappend dico_caract_points($prefixe.i.lcnx) i
16571
16572 # Si la cible est un composant d'une application
16573 if {$nom_comp_source != ""} {
16574 # Recherche le nom de l'application à partir du nom du composant
16575 foreach nom_appli_source $dico_applis(lapplis) {
16576 if {[lsearch $dico_applis(app.$nom_appli_source.lcomp) $nom_comp_source] != -1} {
16577 break
16578 }
16579 }
16580 # La source de la connexion, extraite du SMIOC et mémorisée dans la variable "nom_corresp"
16581 # est décrite ainsi : <nom-champ>_out<numero>
16582 # Il faut extraire de cette chaine de caractères le nom du champ et le numéro de la connexion sortante
16583 regexp {^(.*)_out([0-9]*)$} $nom_corresp match_str nom_champ_source numero
16584 } else {
16585 # La cible de la connexion est un fichier NetCDF
16586 set nom_appli_source
16587 set nom_comp_source $dico_fichier(name)
16588 # Champ source
16589 set nom_champ_source $nom_corresp
16590 # Numéro de connexion sortant du point
16591 set numero 1
16592 }
16593
16594 # Clef (index) de la connexion : celle de la connexion entrante, construite sur celle du point cible
16595 set clef_cnx_in $prefixe.i
16596 # Ajoute à la liste des connexions entrantes
16597 if {[lsearch $liste_cnx_in $clef_cnx_in] == -1} {
16598 lappend liste_cnx_in $clef_cnx_in
16599 }
16600 # Clef de la connexion sortante : construite d'apres celle du point source
16601 set clef_cnx_out $nom_appli_source.$nom_comp_source.$nom_champ_source.o$numero
16602 # Ajoute au dico des connexions sortantes
16603 set dico_cnx_out($clef_cnx_out) $clef_cnx_in
16604
16605 # Renseigne les caractéristiques de la nouvelle connexion
16606 # -------------------------------------------------------
16607
16608 # Source et cible
16609 set dico_caract_cnx($clef_cnx_in.app_source) $nom_appli_source
16610 set dico_caract_cnx($clef_cnx_in.app_cible) $nom_appli
16611 set dico_caract_cnx($clef_cnx_in.comp_source) $nom_comp_source
16612 set dico_caract_cnx($clef_cnx_in.comp_cible) $nom_comp
16613 set dico_caract_cnx($clef_cnx_in.champ_source) $nom_champ_source
16614 set dico_caract_cnx($clef_cnx_in.champ_cible) $nom_champ
16615 set dico_caract_cnx($clef_cnx_in.pt_source) o$numero
16616
16617 # Période des échanges
16618 set dico_caract_cnx($clef_cnx_in.exch_per_unit) [lindex $exch_date 0]
16619 set dico_caract_cnx($clef_cnx_in.exch_per_val) [lindex $exch_date 1]
16620
16621 # Initialise les autres caractéristiques
16622 foreach {caract default_value} {
16623 dbg_cible false
16624 stat_cible_mask false
16625 stat_cible_nmsk false
16626 stat_cible_all false
16627 tgt_time_op {}
16628 tgt_add_val 0
16629 tgt_mult_val 1
16630 remail {} } {
16631 set dico_caract_cnx($clef_cnx_in.$caract) $default_value
16632 }
16633
16634 # Renseigne les vraies valeurs pour ces autres caractéristiques
16635 foreach {name value} [array get cnx_attribute] {
16636 set dico_caract_cnx($clef_cnx_in.$name) $value
16637 }
16638
16639 # Si la source est un fichier NetCDF
16640 if {$nom_appli_source == "///file///"} {
16641 # Met a zéro des caractéristiques qui ne sont pas significatives
16642 # pour une connexion depuis un fichier
16643 foreach {caract default_value} {
16644 lag {}
16645 dbg_source false
16646 stat_source_mask false
16647 stat_source_nmsk false
16648 stat_source_all false
16649 src_time_op {}
16650 src_add_val 0
16651 src_mult_val 1 } {
16652 set dico_caract_cnx($clef_cnx_in.$caract) $default_value
16653 }
16654 }
16655
16656 # Mémorise la source si c'est un fichier
16657 # --------------------------------------
16658
16659 # Si la source est un fichier NetCDF
16660 if {$nom_appli_source == "///file///"} {
16661 # Ajoute le fichier a la liste
16662 set id_fichier $nom_comp_source
16663 lappend liste_fichiers $id_fichier
16664
16665 # Renseigne les caractéristiques du fichier
16666 set dico_caract_fichiers($id_fichier.dir) input
16667 set dico_caract_fichiers($id_fichier.name) $nom_comp_source
16668 set dico_caract_fichiers($id_fichier.io_mode) $dico_fichier(io_mode)
16669 set dico_caract_fichiers($id_fichier.suffix) $dico_fichier(suffix)
16670 set dico_caract_fichiers($id_fichier.lchamps) $nom_champ_source
16671
16672 # Renseigne les caractéristiques du champ du fichier
16673 if {[info exists dico_fichier(fill_value)]} {
16674 set dico_caract_fichiers($id_fichier.$nom_champ_source.fill_value) $dico_fichier(fill_value)
16675 } else {
16676 set dico_caract_fichiers($id_fichier.$nom_champ_source.fill_value) ""
16677 }
16678 # type numérique est celui du champ cible
16679 set dico_caract_fichiers($id_fichier.$nom_champ_source.type) $dico_applis(app.$nom_appli.comp.$nom_comp.champ.$nom_champ.datatype)
16680
16681 # Crée le point de couplage du fichier
16682 set clef_pt_source $nom_appli_source.$nom_comp_source.$nom_champ_source.o
16683 lappend liste_points_o $clef_pt_source
16684 # Renseigne les caractéristiques du point de couplage
16685 set dico_caract_points($clef_pt_source.appli) $nom_appli_source
16686 set dico_caract_points($clef_pt_source.comp) $id_fichier
16687 set dico_caract_points($clef_pt_source.champ) $nom_champ_source
16688 set dico_caract_points($clef_pt_source.lcnx) o1
16689
16690 # Crée une nouvelle unité sur le graphe de couplage
16691 set dico_units(
16692 }
16693 }
16694 }
16695
16696 ret {lit_element_intent} (type element_, type XML , type nom_, type dico , type nom_, type appli , type nom_, type comp , type nom_, type champ , type PMIOD_, type ou_, type SMIOC) {
16697 # Lit dans un fichier XML (PMIOD ou SMIOC) d'un composant un élément <intent>
16698 #
16699 # Parametres d'entrée :
16700 # - element_XML : élément XML de type <transient>
16701 # - nom_dico : nom du dictionnaire à remplir (habituellement dico_applis)
16702 # - nom_appli : nom de l'application
16703 # - nom_comp : nom du composant
16704 # - nom_champ : nom du champ de couplage
16705 # - PMIOD_ou_SMIOC : vaut PMIOD ou SMIOC
16706 #
16707 upvar 1 $nom_dico dict_vars
16708
16709 # Préfixe de la clef des éléments à mettre dans le dictionnaire
16710 set prefixe "app.$nom_appli.comp.$nom_comp.champ.$nom_champ"
16711
16712 # Lit les sous-éléments de l'élément <transient>
16713 set ss_elem_list [dom::node children $element_XML]
16714 set nb_output 0
16715 foreach element $ss_elem_list {
16716 set name [dom::node configure $element -nodeName]
16717 switch $name {
16718 output {
16719 # Compte le nombre de sorties (output) du même champ
16720 incr nb_output
16721 # Si ce point de couplage n'est pas encore mémorisé
16722 if {! [info exists dict_vars($prefixe.output)]} {
16723 # Cree un nouveau point de couplage
16724 # Mémorise que le point de couplage est "output"
16725 set dict_vars($prefixe.output) 1
16726 # Lit le sous-élément <minimal_period> de l'élément <output>
16727 set ss_elem_list [dom::node children $element]
16728 foreach sous_element $ss_elem_list {
16729 set name [dom::node configure $sous_element -nodeName]
16730 if { $name == "minimal_period" } {
16731 lit_element_min_period $sous_element dict_vars "$prefixe.o"
16732 break
16733 }
16734 }
16735 }
16736 # Si on s'interesse au point de couplage (PMIOD)
16737 if {$PMIOD_ou_SMIOC == "PMIOD"} {
16738 # Si c'est la premiere sortie du champ
16739 if {$nb_output == 1} {
16740 # Lit les infos concernant l'element scatter du point de couplage
16741 set scatter [lit_element_output $element $nom_appli $nom_comp $nom_champ $PMIOD_ou_SMIOC]
16742 set dict_vars($prefixe.o.scatter) $scatter
16743 }
16744 } else {
16745 # Lit les infos concernant la connexion partant de ce point de couplage
16746 lit_element_output $element $nom_appli $nom_comp $nom_champ $PMIOD_ou_SMIOC
16747 }
16748 }
16749 input {
16750 # Si ce point de couplage n'est pas encore mémorisé
16751 if {! [info exists dict_vars($prefixe.input)]} {
16752 # Mémorise que le point de couplage est "input"
16753 set dict_vars($prefixe.input) 1
16754 # Lit l'attribut "required_but_changeable" si présent
16755 set value [dom::element getAttribute $element "required_but_changeable"]
16756 set dict_vars($prefixe.i.rbc) $value
16757 # Lit le sous-élément <minimal_period> de l'élément <output>
16758 set ss_elem_list [dom::node children $element]
16759 foreach sous_element $ss_elem_list {
16760 set name [dom::node configure $sous_element -nodeName]
16761 if { $name == "minimal_period" } {
16762 lit_element_min_period $sous_element dict_vars "$prefixe.i"
16763 }
16764 }
16765 }
16766 # Si on s'interesse au point de couplage (PMIOD)
16767 if {$PMIOD_ou_SMIOC == "PMIOD"} {
16768 # Lit les infos concernant l'element gather du point de couplage
16769 set gather [lit_element_input $element $nom_appli $nom_comp $nom_champ $PMIOD_ou_SMIOC]
16770 set dict_vars($prefixe.i.gather) $gather
16771 } else {
16772 # Lit les infos concernant la connexion arrivant à ce point de couplage
16773 lit_element_input $element $nom_appli $nom_comp $nom_champ $PMIOD_ou_SMIOC
16774 }
16775 }
16776 }
16777 }
16778 }
16779
16780 ret {lit_element_liste_ss_elts} (type element_, type XML , type nom_, type dico , type nom_, type traduction) {
16781 # Lit un élément XML donné composé d'une liste de sous-éléments simples
16782 #
16783 # Sauve en mémoire dans un dictionnaire les valeurs des sous-éléments.
16784 #
16785 # Paramètres d'entrée :
16786 # - element_XML : élément à lire
16787 # - nom_dico : nom du dictionnaire à remplir
16788 # - nom_traduction : nom du dictionnaire de traduction
16789 # Ce dictionnaire donne la traduction des nom des sous-éléments en clefs du dictionnaire a remplir
16790 #
16791 upvar 1 $nom_dico dico
16792 upvar 1 $nom_traduction traduction
16793
16794 # Lit les sous-éléments de l'élément
16795 set ss_elem_list [dom::node children $element_XML]
16796 foreach element $ss_elem_list {
16797 set name [dom::node configure $element -nodeName]
16798 if {$name != "#text" && $name != "#comment"} {
16799 # Convertit le nom du sous-élément en clef
16800 set clef $traduction($name)
16801 # Lit le contenu du sous-élément
16802 set txt_elem [dom::node configure $element -firstChild]
16803 # S'il a un contenu
16804 if {$txt_elem != ""} {
16805 # Lit la valeur du contenu
16806 set value [dom::node configure $txt_elem -nodeValue]
16807 } else {
16808 # Prend une valeur arbitraire de 1
16809 set value 1
16810 }
16811 # Mémorise le contenu du sous-élément
16812 set dico($clef) $value
16813 }
16814 }
16815 }
16816
16817 ret {lit_element_mid_transfo} (type element_, type XML , type nom_, type dico) {
16818 # Lit un élément XML de type <middle_transformation>
16819 #
16820 # Remplit un dictionnaire contenant tous les parametres lus dans l'élément XML.
16821 #
16822 # Parametres d'entrée :
16823 # - element_XML : élément XML
16824 # - nom_dico : nom du dictionnaire a remplir
16825 #
16826 upvar 1 $nom_dico cnx_attribute
16827
16828 # Accède au sous-élément <interpolation> : le premier sous-élément
16829 set interpolation_elt [lit_1er_sous_element $element_XML]
16830
16831 # Cherche le sous-élément <interp3D> ou <interp2D> de l'élément <interpolation>
16832 set ss_elem_list [dom::node children $interpolation_elt]
16833 foreach interp_elt $ss_elem_list {
16834 set name [dom::node configure $interp_elt -nodeName]
16835 if {$name == "interp3D" || $name == "interp2D"} { break }
16836 }
16837
16838 # Initialise les attributs de la méthode de remaillage
16839 set cnx_attribute(nbr_neighbours) 0
16840 set cnx_attribute(if_masked) no_value
16841 set cnx_attribute(bi3_method) gradient
16842 set cnx_attribute(norm_method) None
16843 set cnx_attribute(norm_near_nei) false
16844
16845
16846 # Accède au premier et seul sous-élément de <interpxD>
16847 # qui est de type <nneighbour3D>, <trilinear>, <nneighbour2D>, <bilinear>, <bicubic> ou <conservativ2D>
16848 set method_elt [lit_1er_sous_element $interp_elt]
16849 # Mémorise la methode de remaillage
16850 set cnx_attribute(remail) [dom::node configure $method_elt -nodeName]
16851
16852 # Lit les sous-éléments de l'élément "method_elt"
16853 set ss_elem_list [dom::node children $method_elt]
16854 foreach element $ss_elem_list {
16855 set name [dom::node configure $element -nodeName]
16856 switch $name {
16857 if_masked {
16858 # Lit la valeur du sous-élément
16859 set txt_elem [dom::node configure $element -firstChild]
16860 set cnx_attribute(if_masked) [dom::node configure $txt_elem -nodeValue]
16861 }
16862 bicubic_method {
16863 # Lit la valeur du sous-élément
16864 set txt_elem [dom::node configure $element -firstChild]
16865 set cnx_attribute(bi3_method) [dom::node configure $txt_elem -nodeValue]
16866 }
16867 nbr_neighbours {
16868 # Lit la valeur du sous-élément
16869 set txt_elem [dom::node configure $element -firstChild]
16870 set cnx_attribute(nbr_neighbours) [dom::node configure $txt_elem -nodeValue]
16871 }
16872 normalisation2D {
16873 # Lit les sous-éléments de l'élément <normalisation2D>
16874 set ss_elem_list [dom::node children $element]
16875 foreach element $ss_elem_list {
16876 set name [dom::node configure $element -nodeName]
16877 switch $name {
16878 methodnorm2D {
16879 # Lit la valeur du sous-élément
16880 set txt_elem [dom::node configure $element -firstChild]
16881 set cnx_attribute(norm_method) [dom::node configure $txt_elem -nodeValue]
16882 }
16883 nearnei {
16884 # Lit la valeur du sous-élément
16885 set txt_elem [dom::node configure $element -firstChild]
16886 set cnx_attribute(norm_near_nei) [dom::node configure $txt_elem -nodeValue]
16887 }
16888 }
16889 }
16890 }
16891 }
16892 }
16893 }
16894
16895 ret {lit_element_min_period} (type element_, type XML , type nom_, type dico , type prefixe) {
16896 upvar 1 $nom_dico dict_vars
16897
16898 # Lit les sous-éléments de l'élément <minimal_period>
16899 set ss_elem_list [dom::node children $element_XML]
16900 foreach element $ss_elem_list {
16901 set name [dom::node configure $element -nodeName]
16902 set value [lit_XML_texte $element]
16903 set dict_vars($prefixe.$name) $value
16904 }
16905 }
16906
16907 ret {lit_element_nbr_proc} (type element_, type XML , type nom_, type dico , type prefixe) {
16908 # Lit un element XML de type <nbr_proc>
16909
16910 upvar 1 $nom_dico dict_vars
16911 # Lit les sous-éléments de l'élément <nbr_proc>
16912 set ss_elem_list [dom::node children $element_XML]
16913 foreach element $ss_elem_list {
16914 set name [dom::node configure $element -nodeName]
16915 if {$name != "#text" && $name != "#comment"} {
16916 set value [lit_XML_texte $element]
16917 set dict_vars($prefixe.$name) $value
16918 }
16919 }
16920 # Complete les informations si necessaire
16921 if { ![info exists dict_vars($prefixe.max_value)] } {
16922 catch {set dict_vars($prefixe.max_value) $dict_vars($prefixe.min_value)}
16923 }
16924 if { [info exists dict_vars($prefixe.min_value)] && ![info exists dict_vars($prefixe.increment)] } {
16925 set dict_vars($prefixe.increment) 1
16926 }
16927 }
16928
16929 ret {lit_element_origin} (type element_, type XML , type nom_, type dico_, type cnx , type nom_, type dico_, type fichier) {
16930 # Lit un élément XML de type <origin>, qui est sous-élément de <input>
16931 # et qui décrit l'origine d'une connexion avec un champ de couplage.
16932 #
16933 # Retourne une liste contenant le nom du composant source et le nom du champ source.
16934 # Renseigne un dictionnaire avec les caractéristiques de la connexion
16935 # Si la source de la connexion est un fichier, renseigne un dictionnaire
16936 # avec les caractéristiques du fichier.
16937 #
16938 upvar 1 $nom_dico_cnx dico_cnx
16939 upvar 1 $nom_dico_fichier dico_fichier
16940 set nom_comp_source ""
16941 set nom_corresp ""
16942
16943 # Lit les sous-éléments de l'élément <origin>
16944 # -------------------------------------------
16945
16946 set ss_elem_list [dom::node children $element_XML]
16947 foreach element $ss_elem_list {
16948 set name [dom::node configure $element -nodeName]
16949 switch $name {
16950 corresp_transi_out_name {
16951 # Lit la valeur du sous-élément <corresp_transi_out_name>
16952 set txt_elem [dom::node configure $element -firstChild]
16953 set nom_corresp [dom::node configure $txt_elem -nodeValue]
16954 }
16955
16956 component_name {
16957 # Lit la valeur du sous-élément <component_name>
16958 set txt_elem [dom::node configure $element -firstChild]
16959 set nom_comp_source [dom::node configure $txt_elem -nodeValue]
16960 }
16961
16962 middle_transformation {
16963 lit_element_mid_transfo $element dico_cnx
16964 }
16965
16966 file {
16967 lit_element_file $element dico_fichier
16968 }
16969 }
16970 }
16971 return [list $nom_comp_source $nom_corresp]
16972 }
16973
16974 ret {lit_element_output} (type element_, type XML , type nom_, type appli , type nom_, type comp , type nom_, type champ , type PMIOD_, type ou_, type SMIOC) {
16975 # Lit l'élément output d'un fichier PMIOD.xml ou SMIOC.xml
16976 # Pour un fichier PMIOD :
16977 # cherche l'info <scatter> du point de couplage en question
16978 #
16979 # Pour un fichier SMIOC :
16980 # lit les éléments XML concernant la connexion partant de ce point couplage
16981 #
16982 # Parametres d'entrée :
16983 # - element_XML : élément XML de type <output>
16984 # - nom_appli : nom de l'application
16985 # - nom_comp : nom du composant
16986 # - nom_champ : nom du champ de couplage
16987 # - PMIOD_ou_SMIOC : vaut PMIOD ou SMIOC
16988 #
16989 # Valeur de retour
16990 # - Pour un fichier PMIOD, 1 si l'info <scatter> est presente, 0 sinon
16991 # - Pour un fichier SMIOC, rien
16992 #
16993 global dico_applis
16994
16995 global liste_points_i liste_points_o dico_caract_points
16996 global liste_cnx_in dico_cnx_out dico_caract_cnx
16997
16998 global liste_fichiers dico_caract_fichiers
16999 global dico_units
17000
17001 # Lit les sous-éléments de l'élément <output>
17002 # -------------------------------------------
17003
17004 set ss_elem_list [dom::node children $element_XML]
17005 foreach element $ss_elem_list {
17006 set name [dom::node configure $element -nodeName]
17007 switch $name {
17008 exchange_date {
17009 # Si on lit un fichier SMIOC
17010 if {$PMIOD_ou_SMIOC == "SMIOC"} {
17011 set exch_date [lit_element_exchange_date $element]
17012 }
17013 }
17014
17015 corresp_transi_in_name {
17016 # Si on lit un fichier SMIOC
17017 if {$PMIOD_ou_SMIOC == "SMIOC"} {
17018 # Lit la valeur du sous-élément <corresp_transi_in_name>
17019 set txt_elem [dom::node configure $element -firstChild]
17020 set corresp_name [dom::node configure $txt_elem -nodeValue]
17021 }
17022 }
17023
17024 file {
17025 # Si on lit un fichier SMIOC
17026 if {$PMIOD_ou_SMIOC == "SMIOC"} {
17027 array set dico_fichier {}
17028 set output_file [lit_element_file $element dico_fichier]
17029 }
17030 }
17031
17032 component_name {
17033 # Si on lit un fichier SMIOC
17034 if {$PMIOD_ou_SMIOC == "SMIOC"} {
17035 # Lit la valeur du sous-élément <component_name>
17036 set txt_elem [dom::node configure $element -firstChild]
17037 set nom_comp_cible [dom::node configure $txt_elem -nodeValue]
17038 }
17039 }
17040
17041 lag {
17042 # Si on lit un fichier SMIOC
17043 if {$PMIOD_ou_SMIOC == "SMIOC"} {
17044 # Lit la valeur du sous-élément <lag>
17045 set txt_elem [dom::node configure $element -firstChild]
17046 set cnx_attribute(lag) [dom::node configure $txt_elem -nodeValue]
17047 }
17048 }
17049
17050 source_transformation {
17051 array set cnx_attribute {}
17052 lit_element_src_tgt_transfo $element cnx_attribute source $PMIOD_ou_SMIOC
17053 }
17054
17055 debug_mode {
17056 # Si on lit un fichier SMIOC
17057 if {$PMIOD_ou_SMIOC == "SMIOC"} {
17058 # Lit la valeur du sous-élément <debug_mode> : a priori = "true"
17059 set txt_elem [dom::node configure $element -firstChild]
17060 set cnx_attribute(dbg_source) [dom::node configure $txt_elem -nodeValue]
17061 }
17062 }
17063 }
17064 }
17065
17066 # Si on lit un fichier PMIOD
17067 if {$PMIOD_ou_SMIOC == "PMIOD"} {
17068 # Retourne l'attribut <scattering> du point de couplage
17069 return [info exists cnx_attribute(scatter)]
17070
17071 # Si on lit un fichier SMIOC
17072 } else {
17073
17074 # Crée une nouvelle connexion
17075 # ---------------------------
17076
17077 # Préfixe de la clef des éléments à mettre dans les dictionnaires dico_caract_points et dico_caract_cnx
17078 set prefixe "$nom_appli.$nom_comp.$nom_champ"
17079
17080 # Lit l'attribut "transi_out_name"
17081 set value [dom::element getAttribute $element_XML "transi_out_name"]
17082
17083 # L'élément <output> que l'on lit décrit une connexion sortante
17084 # Le numéro de la cnx est celui de l'attribut "transi_out_name"
17085 # "transi_out_name" a la forme <nom_champ>_out*** ou *** est un nombre
17086 set num_output [string range $value [string length "${nom_champ}_out"] end]
17087
17088 # Ajoute la connexion a la liste
17089 lappend dico_caract_points($prefixe.o.lcnx) o$num_output
17090
17091 # Clef de la connexion sortante : construite d'apres celle du point source
17092 set clef_cnx_out $prefixe.o$num_output
17093
17094 # Si la cible est un composant d'une application
17095 if {[info exists nom_comp_cible]} {
17096 # Recherche le nom de l'application a partir du nom du composant
17097 foreach nom_appli_cible $dico_applis(lapplis) {
17098 if {[lsearch $dico_applis(app.$nom_appli_cible.lcomp) $nom_comp_cible] != -1} {
17099 break
17100 }
17101 }
17102 # Nom du champ cible : <nom-champ>_in<numero> ou <numero> est normalement absent
17103 # Il faut extraire de cette chaine de caractères le nom du champ
17104 regexp {^(.*)_in[0-9]*$} $corresp_name match_str nom_champ_cible
17105 } else {
17106 # La cible de la connexion est un fichier NetCDF
17107 set nom_appli_cible
17108 set nom_comp_cible [NetCDF_file_cree_nouvel_id]
17109 # Champ cible = "field"; le nom reel du champ sera indiqué ailleurs
17110 set nom_champ_cible field
17111 }
17112
17113 # Clef (index) de la connexion : celle de la connexion entrante, construite sur celle du point cible
17114 set clef_cnx_in $nom_appli_cible.$nom_comp_cible.$nom_champ_cible.i
17115 # Ajoute à la liste des connexions entrantes
17116 if {[lsearch $liste_cnx_in $clef_cnx_in] == -1} {
17117 lappend liste_cnx_in $clef_cnx_in
17118 }
17119 # Ajoute au dico des connexions sortantes
17120 set dico_cnx_out($clef_cnx_out) $clef_cnx_in
17121
17122 # Renseigne les caractéristiques de la nouvelle connexion
17123 # -------------------------------------------------------
17124
17125 # Source et cible
17126 set dico_caract_cnx($clef_cnx_in.app_source) $nom_appli
17127 set dico_caract_cnx($clef_cnx_in.app_cible) $nom_appli_cible
17128 set dico_caract_cnx($clef_cnx_in.comp_source) $nom_comp
17129 set dico_caract_cnx($clef_cnx_in.comp_cible) $nom_comp_cible
17130 set dico_caract_cnx($clef_cnx_in.champ_source) $nom_champ
17131 set dico_caract_cnx($clef_cnx_in.champ_cible) $nom_champ_cible
17132 set dico_caract_cnx($clef_cnx_in.pt_source) o$num_output
17133
17134 # Période des échanges
17135 set dico_caract_cnx($clef_cnx_in.exch_per_unit) [lindex $exch_date 0]
17136 set dico_caract_cnx($clef_cnx_in.exch_per_val) [lindex $exch_date 1]
17137
17138 # Initialise les autres caractéristiques
17139 foreach {caract default_value} {
17140 lag {}
17141 dbg_source false
17142 stat_source_mask false
17143 stat_source_nmsk false
17144 stat_source_all false
17145 src_time_op {}
17146 src_add_val 0
17147 src_mult_val 1 } {
17148 set dico_caract_cnx($clef_cnx_in.$caract) $default_value
17149 }
17150
17151 # Renseigne les vraies valeurs pour ces autres caractéristiques
17152 foreach {name value} [array get cnx_attribute] {
17153 set dico_caract_cnx($clef_cnx_in.$name) $value
17154 }
17155
17156 # Si la cible est un fichier NetCDF
17157 if {[info exists output_file]} {
17158 # Met a zéro des caractéristiques qui ne sont pas significatives
17159 # pour une connexion vers un fichier
17160 foreach {caract default_value} {
17161 dbg_cible false
17162 stat_cible_mask false
17163 stat_cible_nmsk false
17164 stat_cible_all false
17165 tgt_time_op {}
17166 tgt_add_val 0
17167 tgt_mult_val 1
17168 gather false
17169 remail {} } {
17170 set dico_caract_cnx($clef_cnx_in.$caract) $default_value
17171 }
17172 }
17173
17174 # Mémorise la cible si c'est un fichier
17175 # -------------------------------------
17176
17177 # Si la cible est un fichier NetCDF
17178 if {[info exists output_file]} {
17179 # Ajoute le fichier à la liste
17180 set id_fichier $nom_comp_cible
17181 lappend liste_fichiers $id_fichier
17182
17183 # Renseigne les caractéristiques du fichier
17184 set dico_caract_fichiers($id_fichier.dir) output
17185 set dico_caract_fichiers($id_fichier.name) $output_file
17186 set dico_caract_fichiers($id_fichier.io_mode) $dico_fichier(io_mode)
17187 set dico_caract_fichiers($id_fichier.suffix) $dico_fichier(suffix)
17188 set dico_caract_fichiers($id_fichier.lchamps) field
17189
17190 # Renseigne les caractéristiques du champ du fichier
17191 # Nom exact du champ
17192 set dico_caract_fichiers($id_fichier.field.name) $corresp_name
17193 # Autres caractéristiques
17194 foreach caractere {packing scaling adding fill_value} {
17195 if {[info exists dico_fichier($caractere)]} {
17196 set dico_caract_fichiers($id_fichier.field.$caractere) $dico_fichier($caractere)
17197 } else {
17198 set dico_caract_fichiers($id_fichier.field.$caractere) ""
17199 }
17200 }
17201 # type numérique est celui du champ source
17202 set dico_caract_fichiers($id_fichier.field.type) $dico_applis(app.$nom_appli.comp.$nom_comp.champ.$nom_champ.datatype)
17203
17204 # Crée le point de couplage du fichier
17205 lappend liste_points_i $clef_cnx_in
17206 # Renseigne les caractéristiques du point de couplage
17207 set dico_caract_points($clef_cnx_in.appli) $nom_appli_cible
17208 set dico_caract_points($clef_cnx_in.comp) $id_fichier
17209 set dico_caract_points($clef_cnx_in.champ) field
17210 set dico_caract_points($clef_cnx_in.lcnx) i
17211
17212 # Crée une nouvelle unité sur le graphe de couplage
17213 set dico_units(
17214 }
17215 }
17216 }
17217
17218 ret {lit_element_rank} (type element , type prefixe) {
17219 # Lit dans un fichier SCC.xml le contenu d'un élément de type <rank>
17220 # qui peut contenir trois sous-éléments : min_value, max_value et increment
17221 # min_value est toujours présent.
17222 #
17223 # Paramètres d'entrée :
17224 # - element : element XML de type "rank"
17225 # - prefixe : préfixe de la clef permettant d'accéder au valeurs dans le dictionnaire global "dico_applis"
17226 #
17227 global dico_applis
17228
17229 # Lit les sous-éléments de l'élément <rank>
17230 set ss_elem_list [dom::node children $element]
17231 foreach element $ss_elem_list {
17232 set name [dom::node configure $element -nodeName]
17233 if {$name != "#text" && $name != "#comment"} {
17234 switch $name {
17235 min_value {
17236 # Lit la valeur du sous-élément "min_value"
17237 set txt_elem [dom::node configure $element -firstChild]
17238 set value [dom::node configure $txt_elem -nodeValue]
17239 set dico_applis($prefixe.min_rank) $value
17240 }
17241 max_value {
17242 # Lit la valeur du sous-élément "max_value"
17243 set txt_elem [dom::node configure $element -firstChild]
17244 set value [dom::node configure $txt_elem -nodeValue]
17245 set dico_applis($prefixe.max_rank) $value
17246 }
17247 increment {
17248 # Pour l'instant, valeur ignorée
17249 }
17250 }
17251 }
17252 }
17253 }
17254
17255 ret {lit_element_src_tgt_transfo} (type element_, type XML , type nom_, type dico , type source_, type ou_, type target , type PMIOD_, type ou_, type SMIOC) {
17256 # Lit un élément XML de type <source_transformation> ou <target_transformation>
17257 #
17258 # Remplit un dictionnaire contenant tous les parametres lus dans l'élément XML.
17259 #
17260 # Parametres d'entrée :
17261 # - element_XML : élément XML
17262 # - nom_dico : nom du dictionnaire a remplir
17263 # - source_ou_target : source ou target selon le type d'élément XML
17264 # - PMIOD_ou_SMIOC : vaut PMIOD ou SMIOC
17265 #
17266 upvar 1 $nom_dico cnx_attribute
17267
17268 # Lit les sous-éléments de l'élément <source_transformation>
17269 set ss_elem_list [dom::node children $element_XML]
17270 foreach element $ss_elem_list {
17271 set name [dom::node configure $element -nodeName]
17272 switch $name {
17273 source_time_operation -
17274 target_time_operation {
17275 # Si on lit un fichier SMIOC
17276 if {$PMIOD_ou_SMIOC == "SMIOC"} {
17277 # Opération sur le temps à la source ou à la cible
17278 # Lit la valeur du sous-élément
17279 set txt_elem [dom::node configure $element -firstChild]
17280 if { $source_ou_target == "source" } {set clef src} else {set clef tgt}
17281 set cnx_attribute(${clef}_time_op) [dom::node configure $txt_elem -nodeValue]
17282 }
17283 }
17284 statistics {
17285 # Si on lit un fichier SMIOC
17286 if {$PMIOD_ou_SMIOC == "SMIOC"} {
17287 # Lit les sous-éléments de l'élément <statistics>
17288 # Traduit les sous-éléments XML (masked_points, notmasked_points, all_points) en autres mots-clefs
17289 if { $source_ou_target == "source" } {set clef source} else {set clef cible}
17290 array unset traduction
17291 array set traduction "
17292 masked_points stat_${clef}_mask
17293 notmasked_points stat_${clef}_nmsk
17294 all_points stat_${clef}_all
17295 "
17296 lit_element_liste_ss_elts $element cnx_attribute traduction
17297 }
17298 }
17299 source_local_transformation -
17300 target_local_transformation {
17301 # Lit les sous-éléments de l'élément <...._local_transformation>
17302 # Traduit les sous-éléments XML (scattering, add_scalar, mult_scalar) en autres mots-clefs
17303 if { $source_ou_target == "source" } {set clef src} else {set clef tgt}
17304 array unset traductionert
17305 array set traduction "
17306 gathering gather
17307 scattering scatter
17308 add_scalar ${clef}_add_val
17309 mult_scalar ${clef}_mult_val
17310 "
17311 lit_element_liste_ss_elts $element cnx_attribute traduction
17312 }
17313 }
17314 }
17315 }
17316
17317 ret {lit_fichier_AD} (type nom_, type fichier , type nom_, type dico , type nom_, type lcomp_, type ajout) {
17318 # Lit et décode un fichier XML contenant une AD (Application Description)
17319 # Lit aussi tous les fichiers PMIOD des composants listés dans ce fichier AD.
17320 # Suppose que les fichiers PMIOD sont dans le même répertoire que le fichier AD.
17321 #
17322
17323 # Accède à la variable dont le nom est $nom_dico
17324 upvar 1 $nom_dico dict_vars
17325 # Accède à la liste des composants ajoutés
17326 upvar 1 $nom_lcomp_ajout liste_comp_ajoutes
17327
17328 # Déclare toutes les variables globales
17329 global dico_caract_points
17330 global dico_units
17331
17332 # Lit le document à manipuler
17333 set text [read [open $nom_fichier]]
17334 if { [string trim $text] != "" } {
17335 set code_erreur [catch {set doc [dom::parse $text]} msg_erreur]
17336 if {$code_erreur} {
17337 notice_show "Error parsing file \"$nom_fichier\" :\n $msg_erreur" error
17338 return 1
17339 }
17340 } else {
17341 # Fichier vide
17342 notice_show "Error parsing file \"$nom_fichier\" :\n file is empty" error
17343 return 1
17344 }
17345
17346 # Extrait le nom de l'appli du nom du fichier : exemple "ocea4" extrait de "/chemin/de/oceoa4_ad.xml"
17347 if {[string match "*_ad.xml" $nom_fichier]} {
17348 set file_name [file tail $nom_fichier]
17349 set dir_name [file dirname $nom_fichier]
17350 set nom_appli [string range $file_name 0 end-7]
17351 } else {
17352 return 1
17353 }
17354 # Fait quelques vérifications
17355 if {! [dom::node hasChildNodes $doc] } {
17356 return 1
17357 }
17358
17359 # Récupère le premier élément du document
17360 # C'est l'élément principal (qui est de type <Application>)
17361 set element1 [dom::document configure $doc -documentElement]
17362 if { [dom::node configure $element1 -nodeType] != "element" } {
17363 return 1
17364 }
17365 if { [dom::node configure $element1 -nodeName] != "application" } {
17366 return 1
17367 }
17368
17369 # Lit les attributs de l'élément <Application>
17370 set att [dom::node configure $element1 -attributes]
17371 foreach {name value} [array get $att] {
17372 set dict_vars(app.$nom_appli.$name) $value
17373 }
17374
17375 # Vérifie que l'attribut "local_name" correspond au nom de l'appli
17376 set local_name $dict_vars(app.$nom_appli.local_name)
17377 if {$local_name != $nom_appli} {
17378 notice_show "Local name of application \"$local_name\" is not consistent with file name \"$nom_fichier\" !" error
17379 }
17380
17381 # A ce stade, l'appli est OK : on l'enregistre dans la liste
17382 lappend dict_vars(lapplis) $nom_appli
17383
17384 # Lit les sous-éléments de l'élément <application>
17385 set ss_elem_list [dom::node children $element1]
17386 foreach element $ss_elem_list {
17387 set name [dom::node configure $element -nodeName]
17388 if {$name != "#text" && $name != "#comment"} {
17389 switch $name {
17390 nbr_procs {
17391 lit_element_nbr_proc $element dict_vars "app.$nom_appli.proc"
17392 }
17393
17394 platform {
17395 set ss_elem [dom::node configure $element -firstChild]
17396 set value [dom::node configure $ss_elem -nodeValue]
17397 # Ajoute la plate-forme à la liste des plate-formes
17398 if { [info exists dict_vars(app.$nom_appli.lplatforms)] } {
17399 lappend dict_vars(app.$nom_appli.lplatforms) $value
17400 } else {
17401 set dict_vars(app.$nom_appli.lplatforms) $value
17402 }
17403 }
17404
17405 component {
17406 # Lit les attributs local_name, long_name, simulated, etc..
17407 set att [dom::node configure $element -attributes]
17408 set component_name [load_XML_attributes $att dict_vars "app.$nom_appli.comp"]
17409 # Ajoute le composants à la liste des composants
17410 if { [info exists dict_vars(app.$nom_appli.lcomp)] } {
17411 lappend dict_vars(app.$nom_appli.lcomp) $component_name
17412 } else {
17413 set dict_vars(app.$nom_appli.lcomp) $component_name
17414 }
17415
17416 # Lit le sous-élément nbr_procs
17417 set ss_elem_list [dom::node children $element]
17418 foreach element $ss_elem_list {
17419 set name [dom::node configure $element -nodeName]
17420 if {$name == "nbr_procs"} {
17421 lit_element_nbr_proc $element dict_vars "app.$nom_appli.comp.$component_name.proc"
17422 break
17423 }
17424 }
17425 # Lit le fichier PMIOD du composant
17426 set nom_fichier_PMIOD [file join $dir_name "$nom_appli\_$component_name\_pmiod.xml"]
17427 set result [lit_fichier_component $nom_fichier_PMIOD dict_vars $nom_appli $component_name PMIOD]
17428
17429 # Si erreur
17430 if { $result != 0 } {
17431 notice_show "Pb à la lecture du fichier $nom_fichier_PMIOD" error
17432 } else {
17433 # Ajoute le composant à la liste
17434 lappend liste_comp_ajoutes $nom_appli.$component_name
17435 set dico_units($nom_appli.$component_name) $component_name
17436 }
17437 }
17438 }
17439 }
17440 }
17441
17442 # Ajoute le nom de l'appli à la liste
17443 if { [info exists dict_vars(liste-applis)] } {
17444 lappend dict_vars(liste-applis) $nom_appli
17445 } else {
17446 set dict_vars(liste-applis) $nom_appli
17447 }
17448 # Libère la mémoire
17449 ::dom::DOMImplementation destroy $doc
17450 return 0
17451 }
17452
17453 ret {lit_fichier_Graphics} (type nom_, type fichier) {
17454 # Lit le fichier Graphics.xml contenant les attributs graphiques des unités du graphe de couplage
17455
17456 global dico_applis liste_fichiers dico_units
17457 global dico_caract_fichiers
17458
17459 if {! [file isfile $nom_fichier]} {
17460 return 1
17461 }
17462
17463 # Lit le document à manipuler
17464 set text [read [open $nom_fichier]]
17465 set doc [dom::parse $text]
17466
17467 # Récupère le premier élément du document
17468 # C'est l'élément principal (qui est de type <scc>)
17469 set element1 [dom::document configure $doc -documentElement]
17470 if { [dom::node configure $element1 -nodeType] != "element" } {
17471 return 1
17472 }
17473 if { [dom::node configure $element1 -nodeName] != "graphics" } {
17474 return 1
17475 }
17476
17477 # Lit les sous-éléments de l'élément <graphics>
17478 set ss_elem_list [dom::node children $element1]
17479 foreach element $ss_elem_list {
17480 set name [dom::node configure $element -nodeName]
17481 if {$name == "component" || $name == "file"} {
17482 # Lit les attributs : name, application, coor_x, coor_y, colour, expand
17483 set att [dom::node configure $element -attributes]
17484
17485 # Nom de l'application
17486 switch $name {
17487 component {
17488 # Nom de l'application
17489 set nom_appli [set ${att}(application)]
17490 # Nom du composant
17491 set nom_comp [set ${att}(name)]
17492 # Clef de l'unité dans le dictionnaire dico_units
17493 set clef_unit $nom_appli.$nom_comp
17494 set si_trouve 1
17495 }
17496 file {
17497 # Nom du fichier
17498 set nom_fichier [set ${att}(name)]
17499 # Recherche l'id du fichier qui a ce nom
17500 set si_trouve 0
17501 foreach {attrib value} [array get dico_caract_fichiers "*.name"] {
17502 if {$value == $nom_fichier} {
17503 set si_trouve 1
17504 # Identifiant du fichier dans le dictionnaire dico_caract_fichiers :
17505 # c'est la même que $attrib moins l'extension .name
17506 set id_fichier [string range $attrib 0 end-5]
17507 # Clef de l'unité dans le dictionnaire dico_units
17508 set clef_unit
17509 break
17510 }
17511 }
17512 }
17513 }
17514 if { $si_trouve } {
17515 # Mémorise les attributs graphiques de l'unité
17516 foreach attribut {coor_x coor_y colour expand} {
17517 set dico_units($clef_unit.$attribut) [set ${att}($attribut)]
17518 }
17519 }
17520 }
17521 }
17522
17523 # Libère la mémoire
17524 ::dom::DOMImplementation destroy $doc
17525
17526 return 0
17527 }
17528
17529 ret {lit_fichier_SCC} (type nom_, type fichier) {
17530 # Lit et décode un fichier XML contenant un SCC (Coupling Configuration) auparavant généré par ce programme
17531 # Lit aussi tous les fichiers AD des application listés dans ce fichier SCC, si ils existent.
17532 # Lit aussi tous les fichiers PMIOD des composants listés dans les fichiers AD, si ils existent.
17533 #
17534 # Lit aussi tous les fichiers SMIOC des composants listés dans ce fichier SCC
17535 # et recrée toutes les connexions qui sont décrites dans ces fichiers.
17536 # Suppose que les fichiers SMIOC sont dans le même répertoire que le fichier SCC.
17537 #
17538 # Si un fichier SMIOC est manquant, ça peut être une erreur grave
17539 # car il peut alors manquer une extrémité cible ou source d'une connexion sur le graphe de couplage.
17540 #
17541 # Si un fichier AD ou PMIOD est manquant, on compense avec les fichiers respectifs SCC et SMIOC.
17542 # Au pire, il manquera des points de couplage de composants mais qui ne seront pas connectés de toute façon.
17543 #
17544 global dico_applis
17545 global liste_fichiers dico_caract_fichiers
17546 global dico_experiment
17547
17548 # Repertoire du fichier a lire
17549 set dir_name [file dirname $nom_fichier]
17550
17551 # Lit le document à interprêter
17552 set text [read [open $nom_fichier]]
17553 if { [string trim $text] != "" } {
17554 set code_erreur [catch {set doc [dom::parse $text]} msg_erreur]
17555 if {$code_erreur} {
17556 notice_show "Error parsing file \"$nom_fichier\" :\n $msg_erreur" error
17557 return 1
17558 }
17559 } else {
17560 # Fichier vide
17561 notice_show "Error parsing file \"$nom_fichier\" :\n file is empty" error
17562 return 1
17563 }
17564
17565 # Récupère le premier élément du document
17566 # C'est l'élément principal (qui est de type <scc>)
17567 set element1 [dom::document configure $doc -documentElement]
17568 if { [dom::node configure $element1 -nodeType] != "element" } {
17569 return 1
17570 }
17571 if { [dom::node configure $element1 -nodeName] != "scc" } {
17572 return 1
17573 }
17574
17575 # Lit les sous-éléments de l'élément <scc>
17576 set ss_elem_list [dom::node children $element1]
17577 foreach element $ss_elem_list {
17578 set name [dom::node configure $element -nodeName]
17579 if {$name != "#text" && $name != "#comment"} {
17580 switch $name {
17581 experiment {
17582 # Lit les attributs local_name, long_name, start_mode
17583 set att [dom::node configure $element -attributes]
17584 set dico_experiment(name) [set ${att}(local_name)]
17585 set dico_experiment(long_name) [set ${att}(long_name)]
17586 set dico_experiment(start_mode) [set ${att}(start_mode)]
17587
17588 # Accède aux sous-elements
17589 set ss_elem_list [dom::node children $element]
17590 foreach element $ss_elem_list {
17591 set name [dom::node configure $element -nodeName]
17592 if {$name != "#text" && $name != "#comment"} {
17593 switch $name {
17594 driver {
17595 # Accède au sous-élément "nbr_procs" : le premier sous-element de "driver"
17596 set nbr_procs_elt [lit_1er_sous_element $element]
17597 # Lit la valeur du sous-élément "nbr_procs"
17598 set txt_elem [dom::node configure $nbr_procs_elt -firstChild]
17599 set value [dom::node configure $txt_elem -nodeValue]
17600 set dico_experiment(drv_procs) $value
17601 }
17602 start_date {
17603 lit_element_date $element start
17604 }
17605 end_date {
17606 lit_element_date $element end
17607 }
17608 }
17609 }
17610 }
17611 }
17612 run {
17613 # Accède aux sous-elements
17614 set ss_elem_list [dom::node children $element]
17615 foreach element $ss_elem_list {
17616 set name [dom::node configure $element -nodeName]
17617 if {$name != "#text" && $name != "#comment"} {
17618 switch $name {
17619 start_date {
17620 lit_element_date $element run_start
17621 }
17622 end_date {
17623 lit_element_date $element run_end
17624 }
17625 }
17626 }
17627 }
17628 }
17629 application {
17630 set erreur [lit_element_application $element $dir_name]
17631 if {$erreur} {return 1}
17632 }
17633 }
17634 }
17635 }
17636
17637 # Libère la mémoire
17638 ::dom::DOMImplementation destroy $doc
17639
17640 # Lit les connexions décrites dans les fichiers SMIOC
17641 # ---------------------------------------------------
17642
17643 # Liste des applications
17644 set lapplis {}
17645 catch {set lapplis $dico_applis(lapplis)}
17646
17647 # Pour toutes les applications
17648 foreach nom_appli $lapplis {
17649 # Pour tous les composants de cette application
17650 foreach nom_comp $dico_applis(app.$nom_appli.lcomp) {
17651 # Détermine le nom du fichier SMIOC (dans le même répertoire que le fichier SCC)
17652 set nom_fichier_SMIOC [file join $dir_name $nom_appli\_$nom_comp\_smioc.xml]
17653 # Lit les connexions du couplage dans le fichier SMIOC, s'il existe
17654 lit_fichier_component $nom_fichier_SMIOC dico_applis $nom_appli $nom_comp SMIOC
17655 }
17656 }
17657
17658 # Vérifie la coherénce des connexions lues
17659 # ----------------------------------------
17660 global liste_cnx_in dico_cnx_out dico_caract_cnx
17661 global dico_caract_points
17662
17663 # Pour toutes les connexions lues
17664 foreach clef_cnx_in $liste_cnx_in {
17665 # Si la source et la cible sont des composant d'application
17666 if { $dico_caract_cnx($clef_cnx_in.app_source) != "///file///"
17667 && $dico_caract_cnx($clef_cnx_in.app_cible) != "///file///" } {
17668
17669 # Source
17670 set app_source $dico_caract_cnx($clef_cnx_in.app_source)
17671 set comp_source $dico_caract_cnx($clef_cnx_in.comp_source)
17672 set champ_source $dico_caract_cnx($clef_cnx_in.champ_source)
17673 set pt_source $dico_caract_cnx($clef_cnx_in.pt_source)
17674 # Clef du point de couplage source
17675 set clef_pt_out $app_source.$comp_source.$champ_source.o
17676 # Liste des connexions au point de couplage source
17677 set lcnx_out ""
17678 catch {set lcnx_out $dico_caract_points($clef_pt_out.lcnx)}
17679
17680 # Vérifie que la connexion est bien listée au niveau du point de couplage source
17681 set erreur 0
17682 if { [lsearch $lcnx_out $pt_source] == -1 } {
17683 set erreur 1
17684 }
17685
17686 # Liste des connexions au point de couplage cible
17687 set lcnx_in ""
17688 catch {set lcnx_in $dico_caract_points($clef_cnx_in.lcnx)}
17689 # Vérifie que la connexion est bien listée au niveau du point de couplage cible
17690 if { $lcnx_in == "" } {
17691 set erreur 1
17692 }
17693
17694 if {$erreur} {
17695 set app_cible $dico_caract_cnx($clef_cnx_in.app_cible)
17696 set comp_cible $dico_caract_cnx($clef_cnx_in.comp_cible)
17697 set champ_cible $dico_caract_cnx($clef_cnx_in.champ_cible)
17698 notice_show "Connection not consistently declared between field $app_source-$comp_source-$champ_source and field $app_cible-$comp_cible-$champ_cible !" error
17699 return 1
17700 }
17701 }
17702 }
17703
17704 # Lit les fichiers NetCDF qui sont en entrée
17705 # ------------------------------------------
17706
17707 # Dictionnaire des fichiers lus
17708 array set dico_ajout {}
17709 # Init de la liste des fichiers lus
17710 set liste_fic_ajoutes {}
17711
17712 # Pour tous les fichiers du graphe
17713 foreach id_fichier $liste_fichiers {
17714 # Si le fichier est en entrée
17715 if { $dico_caract_fichiers($id_fichier.dir) == "input" } {
17716 # Détermine le nom du fichier (dans le même répertoire que le fichier SCC)
17717 set nom_fichier [file join $dir_name $dico_caract_fichiers($id_fichier.name)]
17718
17719 # Si le fichier est présent dans le répertoire du SCC
17720 if { [file isfile $nom_fichier]} {
17721
17722 set fic_ajoute [NetCDF_file_read dico_ajout $nom_fichier]
17723 if {$fic_ajoute != ""} {
17724 lappend liste_fic_ajoutes $fic_ajoute
17725 }
17726 }
17727 }
17728 }
17729 if { $liste_fic_ajoutes != ""} {
17730 # Met à jour les données avec les fichiers lus
17731 NetCDF_file_maj $liste_fic_ajoutes dico_ajout 0
17732 }
17733
17734 # Lit les données graphiques du couplage dans le fichier Graphics.xml
17735 # -------------------------------------------------------------------
17736
17737 # Initialise les données graphiques arbitrairement
17738 unit_init
17739
17740 # Nom et chemin du fichier : dans le même répertoire que le SCC
17741 set nom_fichier_Graphics [file join $dir_name "Graphics.xml"]
17742 set erreur [lit_fichier_Graphics $nom_fichier_Graphics]
17743
17744 return 0
17745 }
17746
17747 ret {lit_fichier_component} (type nom_, type fichier , type nom_, type dico , type nom_, type appli , type nom_, type comp , type PMIOD_, type ou_, type SMIOC) {
17748 # Lit un fichier PMIOD ou SMIOC d'un composant
17749 #
17750 # Parametres d'entrée :
17751 # - nom_fichier : nom du fichier
17752 # - nom_dico : nom du dictionnaire à remplir (habituellement dico_applis)
17753 # - nom_appli : nom de l'application
17754 # - nom_comp : nom du composant
17755 # - PMIOD_ou_SMIOC : vaut PMIOD ou SMIOC
17756 #
17757 upvar 1 $nom_dico dict_vars
17758 # Préfixe de la clef des éléments à mettre dans le dictionnaire
17759 set prefixe "app.$nom_appli.comp.$nom_comp"
17760
17761 if { ![file isfile $nom_fichier] } {
17762 return 1
17763 }
17764 # Lit le document à manipuler
17765 set text [read [open $nom_fichier]]
17766 if { [string trim $text] == "" } {
17767 # Fichier vide
17768 notice_show "Error parsing file \"$nom_fichier\" :\n file is empty" error
17769 return 1
17770 }
17771
17772 set doc [dom::parse $text]
17773
17774 # Récupère le premier élément du document
17775 # C'est l'élément principal (qui est de type <prismcomponent>)
17776 set element1 [dom::document configure $doc -documentElement]
17777
17778 # Lit les attributs de l'élément <prismcomponent>
17779 set att [dom::node configure $element1 -attributes]
17780 foreach {name value} [array get $att] {
17781 if { $name != "local_name" } {
17782 set dict_vars($prefixe.$name) $value
17783 }
17784 }
17785
17786 # Lit les sous-éléments de l'élément <prismcomponent>
17787 set ss_elem_list [dom::node children $element1]
17788 foreach element $ss_elem_list {
17789 set name [dom::node configure $element -nodeName]
17790 if {$name != "#text" && $name != "#comment"} {
17791 switch $name {
17792 code {
17793 # Pour l'instant, on ignore cet élément
17794 }
17795
17796 grid {
17797 # Lit les attributs local_name
17798 set att [dom::node configure $element -attributes]
17799 set grid_name [load_XML_attributes $att dict_vars "$prefixe.grid"]
17800 # Ajoute la grille a la liste des grilles
17801 if { [info exists dict_vars($prefixe.lgrids)] } {
17802 # Si la grille n'existe pas
17803 if {[lsearch $dict_vars($prefixe.lgrids) $grid_name] == -1 } {
17804 lappend dict_vars($prefixe.lgrids) $grid_name
17805 }
17806 } else {
17807 set dict_vars($prefixe.lgrids) $grid_name
17808 }
17809 # Lit les sous-éléments
17810 lit_element_grid $element dict_vars $nom_appli $nom_comp $grid_name
17811 }
17812
17813 transient {
17814 # Lit les attributs local_name, long_name, simulated, etc..
17815 set att [dom::node configure $element -attributes]
17816 set transient_name [load_XML_attributes $att dict_vars "$prefixe.champ"]
17817 # Ajoute le point de couplage à la liste des points de couplage
17818 if { [info exists dict_vars($prefixe.lchamps)] } {
17819 # Si le point de couplage n'est pas déjà listé
17820 if {[lsearch $dict_vars($prefixe.lchamps) $transient_name] == -1 } {
17821 lappend dict_vars($prefixe.lchamps) $transient_name
17822 }
17823 } else {
17824 set dict_vars($prefixe.lchamps) $transient_name
17825 }
17826 # Lit les sous-éléments
17827 lit_point_echange $element dict_vars $nom_appli $nom_comp $transient_name $PMIOD_ou_SMIOC
17828 }
17829 }
17830 }
17831 }
17832 # Libère la mémoire
17833 ::dom::DOMImplementation destroy $doc
17834 return 0
17835 }
17836
17837 ret {lit_element_grid} (type element_, type XML , type nom_, type dico , type nom_, type appli , type nom_, type comp , type nom_, type grid) {
17838 # Lit dans un fichier XML (PMIOD ou SMIOC) d'un composant un élément <grid>
17839 #
17840 # Parametres d'entrée :
17841 # - element_XML : élément XML de type <grid>
17842 # - nom_dico : nom du dictionnaire à remplir (habituellement dico_applis)
17843 # - nom_appli : nom de l'application
17844 # - nom_comp : nom du composant
17845 # - nom_grid : nom de la grille
17846 #
17847 upvar 1 $nom_dico dict_vars
17848
17849 # Préfixe de la clef des éléments à mettre dans le dictionnaire
17850 set prefixe "app.$nom_appli.comp.$nom_comp.grid.$nom_grid"
17851
17852 # Lit les sous-éléments de l'élément <grid>
17853 set ss_elem_list [dom::node children $element_XML]
17854 foreach element $ss_elem_list {
17855 set name [dom::node configure $element -nodeName]
17856 if {$name == "indexing_dimension"} {
17857 # Lit l'attribut "index" (1 ou 2 ou 3)
17858 set index [dom::element getAttribute $element "index"]
17859 switch $index {
17860 1 { set key $prefixe.periodi }
17861 2 { set key $prefixe.periodj }
17862 3 { set key $prefixe.periodk }
17863 }
17864 # Lit l'attribut "periodic" (true ou false)
17865 set value [dom::element getAttribute $element "periodic"]
17866 set dict_vars($key) $value
17867 }
17868 }
17869 }
17870
17871 ret {lit_point_echange} (type element_, type XML , type nom_, type dico , type nom_, type appli , type nom_, type comp , type nom_, type champ , type PMIOD_, type ou_, type SMIOC) {
17872 # Lit dans un fichier XML (PMIOD ou SMIOC) d'un composant un élément <transient>
17873 #
17874 # Parametres d'entrée :
17875 # - element_XML : élément XML de type <transient>
17876 # - nom_dico : nom du dictionnaire à remplir (habituellement dico_applis)
17877 # - nom_appli : nom de l'application
17878 # - nom_comp : nom du composant
17879 # - nom_champ : nom du champ de couplage
17880 # - PMIOD_ou_SMIOC : vaut PMIOD ou SMIOC
17881 #
17882 upvar 1 $nom_dico dict_vars
17883
17884 # Préfixe de la clef des éléments à mettre dans le dictionnaire
17885 set prefixe "app.$nom_appli.comp.$nom_comp.champ.$nom_champ"
17886
17887 # Lit les sous-éléments de l'élément <transient>
17888 set ss_elem_list [dom::node children $element_XML]
17889 foreach element $ss_elem_list {
17890 set name [dom::node configure $element -nodeName]
17891 switch $name {
17892 transient_standard_name {
17893 set value [lit_XML_texte $element]
17894 set dict_vars($prefixe.std_name) $value
17895 }
17896 physics {
17897 # Lit l'attribut "transient_type" (single ou vector)
17898 set value [dom::element getAttribute $element "transient_type"]
17899 set dict_vars($prefixe.type) $value
17900 # Lit les sous-éléments physical_units, valid_min et valid_max
17901 set ss_elem_list [dom::node children $element]
17902 foreach element $ss_elem_list {
17903 set name [dom::node configure $element -nodeName]
17904 switch $name {
17905 physical_units {
17906 set value [lit_XML_texte $element]
17907 set dict_vars($prefixe.units) $value
17908 }
17909 valid_min {
17910 set value [lit_XML_texte $element]
17911 set dict_vars($prefixe.min) $value
17912 }
17913 valid_max {
17914 set value [lit_XML_texte $element]
17915 set dict_vars($prefixe.max) $value
17916 }
17917 }
17918 }
17919 }
17920 numerics {
17921 # Lit l'attribut "datatype" (xs:real, xs:double ou xs:integer)
17922 set value [dom::element getAttribute $element "datatype"]
17923 # Extrait le type (enlève "xs:")
17924 set value [string range $value 3 end]
17925 set dict_vars($prefixe.datatype) $value
17926 }
17927 computation {
17928 }
17929 intent {
17930 # Peut contenir un seul <input> et/ou plusieurs <output>
17931 lit_element_intent $element dict_vars $nom_appli $nom_comp $nom_champ $PMIOD_ou_SMIOC
17932 }
17933 transient_dependency {
17934 }
17935 }
17936 }
17937 }
17938
17939 ret {load_NetCDF_files} () {
17940 load_dir_files "Load NetCDF files" "*.nc" NetCDF_file_read_files NetCDF_file_add_new
17941 }
17942
17943 ret {load_XML_ad_files} () {
17944 load_dir_files "Load Application Description files" "*_ad.xml" read_AD_files
17945 }
17946
17947 ret {load_XML_attributes} (type nom_, type attr , type nom_, type dico , type prefixe) {
17948 upvar 1 $nom_attr attributs
17949 upvar 1 $nom_dico dict_vars
17950
17951 set local_name $attributs(local_name)
17952 foreach {name value} [array get attributs] {
17953 if { $name != "local_name" } {
17954 set dict_vars($prefixe.$local_name.$name) $value
17955 }
17956 }
17957
17958 return $local_name
17959 }
17960
17961 ret {load_dir_files} (type title , type initial_, type mask , type on_, type OK , optional on_new ={)} {
17962 # Permet de selectionner des fichiers d'un type particulier dans un repertoire
17963 #
17964 # Permet de creer un nouveau fichier si le parametre on_new est specifie.
17965 #
17966 # Paramètres d'entrée :
17967 # - dirname (global) : repertoire initial
17968 # - title : titre de la boite de dialogue
17969 # - initial_mask : masque initial d'extension des fichiers
17970 # - on_OK : commande a executer si appui sur le bouton OK
17971 # - on_new : commande a executer si appui sur le bouton New
17972
17973 global dirname
17974 global masque
17975
17976 if {![info exists dirname]} { dirname = [pwd]}
17977
17978
17979
17980
17981
17982
17983 u = .
17984
17985
17986 catch {destroy $u}
17987 toplevel $u
17988 wm title $u $title
17989 wm iconname $u "Select files"
17990
17991 frame $u.fr1
17992 pack $u.fr1 -side top -fill x -padx 10 -pady 10
17993 label $u.fr1.lab1 -text "Directory :"
17994 pack $u.fr1.lab1 -side left
17995 label $u.fr1.lab2 -text $dirname -relief sunken -background grey97 -anchor w
17996 pack $u.fr1.lab2 -side left -expand yes -fill x -padx 10
17997 button $u.fr1.b1 -text "Browse" -command {
17998 global dirname
17999 dir = [tk_chooseDirectory -title "directory to
18000 if {$dir != ""} {
18001 dirname = $dir}
18002 .
18003
18004 }
18005 pack $u.fr1.b1 -side left
18006
18007 frame $u.fr2
18008 pack $u.fr2 -side top -expand yes -fill x
18009
18010 frame $u.fr2.f2
18011 pack $u.fr2.f2 -side left -fill both -padx 10 -pady 10 -expand yes
18012 pack [label $u.fr2.f2.lab1 -text "Select file list:"] -side top -anchor w
18013 listbox $u.fr2.f2.lb -background white -yscrollc "$u.fr2.f2.sb " -selectmode = extended
18014 scrollbar $u.fr2.f2.sb -bd 1 -command "$u.fr2.f2.lb yview"
18015 pack $u.fr2.f2.lb -side left -expand yes -fill both
18016 pack $u.fr2.f2.sb -side left -fill y
18017
18018 frame $u.fr2.f3
18019 masque = $initial_mask
18020 entry $u.fr2.f3.mask -textvariable masque -background white
18021 pack $u.fr2.f3 -side left -fill y -padx 10 -pady 10
18022 pack [label $u.fr2.f3.lab2 -text "File Mask:"] -side top -anchor w
18023 pack $u.fr2.f3.mask -expand yes -fill x -side top -anchor n
18024
18025 frame $u.fr2.f3.bu
18026 pack $u.fr2.f3.bu -side bottom -fill x
18027 button $u.fr2.f3.bu.ok -text "OK" -command "
18028 button $u.fr2.f3.bu.cancel -text "Cancel" -command "destroy $u"
18029 pack $u.fr2.f3.bu.cancel -side left
18030 pack $u.fr2.f3.bu.ok -side right
18031
18032 bind $u.fr2.f3.mask <Return> "
18033
18034
18035 if { $on_new != "" } {
18036 frame $u.fr3
18037 pack $u.fr3 -side bottom -expand yes -fill x -pady 10
18038
18039 label $u.fr3.lab1 -text "Or enter new file name :"
18040 pack $u.fr3.lab1 -side top -anchor w -padx 10
18041
18042 frame $u.fr3.f1
18043 pack $u.fr3.f1 -side top -expand yes -fill x
18044
18045 global new_filename_m; new = _filename_m ""
18046 entry $u.fr3.f1.e1 -textvariable new_filename_m -background white
18047 pack $u.fr3.f1.e1 -side left -fill x -padx 10 -expand yes
18048 button $u.fr3.f1.new -text "New" -command "global new_filename_m; $on_new \$new_filename_m; un new = _filename_m; destroy $u"
18049 pack $u.fr3.f1.new -side right -padx 10
18050 }
18051 }
18052
18053 ret {load_files} (type on_, type OK) {
18054 #
18055 global dirname
18056 set lst ""
18057 catch {set lst [selection get -displayof .load_dir.fr2.f2.lb]}
18058 set file_list ""
18059 foreach elm $lst {
18060 set file [file join $dirname $elm]
18061 lappend file_list $file
18062 }
18063 if {$file_list != ""} {$on_OK $file_list}
18064 }
18065
18066 ret {load_maj_listfile} () {
18067 #**** load_maj_listfile
18068 #
18069 # Purpose:
18070 # --------
18071 # update file list if the user enters a new mask file
18072 #
18073 # Interface:
18074 # ----------
18075 # load_maj_listfile
18076 #
18077 #
18078 #*** History:
18079 # -------
18080 # Version Programmer Date Description
18081 # ------- ---------- ---- -----------
18082 # 0.0 Thierry M. 2000/10/04 created
18083 #
18084 #*----------------------------------------------------------------
18085 global dirname
18086 global masque
18087 .load_dir.fr2.f2.lb delete 0 end
18088 foreach elm $masque {
18089 set loclist {}
18090 catch {set loclist [glob -directory $dirname $elm]}
18091 foreach filename $loclist {
18092 if {[file isfile $filename] } {.load_dir.fr2.f2.lb insert end [file tail $filename]}
18093 }
18094 }
18095 }
18096
18097 ret {maj_composants_ajoutes} (type nom_, type dico_, type ajout , type liste_, type comp_, type ajoutes) {
18098 #
18099 # Accède à la variable dont le nom est $nom_dico_ajout
18100 upvar 1 $nom_dico_ajout dico_ajout
18101
18102 global dico_applis
18103 global dico_units
18104 global liste_points_i liste_points_o
18105 global dico_caract_points
18106 global dico_cnx_out dico_caract_cnx
18107 global oasis4_version
18108
18109 # Position initiale du composant sur le graphe : en haut à gauche
18110 set position_x 80
18111 set position_y 25
18112
18113 # Si besoinm initialise la liste des applications déjà chargées en mémoire
18114 if { ! [info exists dico_applis(lapplis)] } {
18115 set dico_applis(lapplis) {}
18116 }
18117
18118 # Pour toutes les applis ajoutées
18119 foreach nom_appli $dico_ajout(lapplis) {
18120 # Si l'appli est chargée en mémoire pour la première fois
18121 if { [lsearch $dico_applis(lapplis) $nom_appli] == -1 } {
18122 # Ajoute l'appli a la liste
18123 lappend dico_applis(lapplis) $nom_appli
18124 # Initialise la liste des composants de l'appli
18125 set dico_applis(app.$nom_appli.lcomp) {}
18126 } else {
18127
18128 # Si le nombre de processus de l'appli a changé
18129 if { [array get dico_ajout "app.$nom_appli.proc.*"] != [array get dico_applis "app.$nom_appli.proc.*"] } {
18130
18131 # Vérifie la répartition des proc sur les ordinateurs hosts de l'application
18132 # --------------------------------------------------------------------------
18133
18134 # Si la liste des ordinateurs hosts existe déja
18135 if { [info exists dico_applis(app.$nom_appli.lhosts)]
18136 && [llength $dico_applis(app.$nom_appli.lhosts)] != 0 } {
18137
18138 set nb_proc_total 0
18139 foreach id_host $dico_applis(app.$nom_appli.lhosts) {
18140 # Additionne au total
18141 incr nb_proc_total $dico_applis(app.$nom_appli.host.$id_host.nb_procs)
18142 }
18143
18144 # Vérifie que le nombre de processus est dans la fourchette acceptable pour l'appli
18145 set si_OK 1
18146 set min_proc $dico_applis(app.$nom_appli.proc.min_value)
18147 set max_proc $dico_applis(app.$nom_appli.proc.max_value)
18148 set increment $dico_applis(app.$nom_appli.proc.increment)
18149 if { $nb_proc_total >= $min_proc && $nb_proc_total <= $max_proc } {
18150
18151 # Vérifie que le nombre est un multiple attendu
18152 if {[expr ($nb_proc_total - $min_proc) % $increment] == 0} {
18153 # OK
18154 } else {
18155 set si_OK 0
18156 }
18157 } else {
18158 set si_OK 0
18159 }
18160
18161 # Si pas OK
18162 if { ! $si_OK } {
18163 # Annule la répartition des proc. sur les ordinateurs hosts
18164 foreach id_host $dico_applis(app.$nom_appli.lhosts) {
18165 set dico_applis(app.$nom_appli.host.$id_host.nb_procs) ""
18166 }
18167 }
18168 }
18169 }
18170 }
18171
18172 # Recopie les attributs de l'appli
18173 foreach attrib {oasis4_version start_mode coupling_mode proc.min_value proc.max_value proc.increment} {
18174 set dico_applis(app.$nom_appli.$attrib) $dico_ajout(app.$nom_appli.$attrib)
18175 }
18176 catch { set dico_applis(app.$nom_appli.long_name) $dico_ajout(app.$nom_appli.long_name) }
18177
18178 # Met a jour la var globale 'oasis4_version'
18179 if {![info exists oasis4_version] && [info exists dico_applis(app.$nom_appli.oasis4_version)]} {
18180 set oasis4_version $dico_applis(app.$nom_appli.oasis4_version)
18181 }
18182 }
18183
18184 # Pour tous les composants ajoutés
18185 foreach clef_comp $liste_comp_ajoutes {
18186
18187 # Nom du composant
18188 set nom_composant $dico_units($clef_comp)
18189 # Extrait de la clef le nom de l'appli
18190 set len_comp [string length $nom_composant]
18191 incr len_comp
18192 set nom_appli [string range $clef_comp 0 end-$len_comp]
18193
18194 # Si le composant est chargé en mémoire pour la première fois
18195 if { [lsearch $dico_applis(app.$nom_appli.lcomp) $nom_composant] == -1 } {
18196
18197 # Ajoute le composant a la liste
18198 lappend dico_applis(app.$nom_appli.lcomp) $nom_composant
18199 # Ajoute toutes ses infos au dictionnaire global des applis et composants
18200 array set dico_applis [array get dico_ajout "app.$nom_appli.comp.$nom_composant.*"]
18201
18202 # Place le composant sur le graphe
18203 set dico_units($clef_comp.coor_x) $position_x
18204 set dico_units($clef_comp.coor_y) $position_y
18205 incr position_y 80
18206 # Met le composant dans l'état "connexions visibles"
18207 set dico_units($clef_comp.expand) 1
18208 # Choisit une couleur pour le composant
18209 set dico_units($clef_comp.colour) [color_rgb [expr int(rand()*254)] [expr int(rand()*254)] [expr int(rand()*254)]]
18210
18211 # Ajoute tous les points d'échange (de couplage) de ce composant
18212 # à la liste générale des points de couplage
18213 set liste_champs $dico_applis(app.$nom_appli.comp.$nom_composant.lchamps)
18214 foreach nom_champ $liste_champs {
18215 set clef_base "$clef_comp.$nom_champ"
18216
18217 # Si le champ de couplage est en entrée
18218 if { [info exists dico_applis(app.$nom_appli.comp.$nom_composant.champ.$nom_champ.input)] } {
18219 set clef "$clef_base.i"
18220 lappend liste_points_i $clef
18221 set dico_caract_points($clef.appli) $nom_appli
18222 set dico_caract_points($clef.comp) $nom_composant
18223 set dico_caract_points($clef.champ) $nom_champ
18224 }
18225
18226 # Si le champ de couplage est en sortie
18227 if { [info exists dico_applis(app.$nom_appli.comp.$nom_composant.champ.$nom_champ.output)] } {
18228 set clef "$clef_base.o"
18229 lappend liste_points_o $clef
18230 set dico_caract_points($clef.appli) $nom_appli
18231 set dico_caract_points($clef.comp) $nom_composant
18232 set dico_caract_points($clef.champ) $nom_champ
18233 }
18234 }
18235 Draw_one_unit $clef_comp
18236
18237 } else {
18238
18239 # Etablit la liste des points de couplage du nouveau composant
18240 set liste_pts_couplage {}
18241 # Pour tous les champs du composant chargé en mémoire
18242 foreach nom_champ $dico_ajout(app.$nom_appli.comp.$nom_composant.lchamps) {
18243 # Ajoute un ou deux points de couplage
18244 set clef_base "$clef_comp.$nom_champ"
18245
18246 # Si le champ de couplage est en entrée
18247 if { [info exists dico_ajout(app.$nom_appli.comp.$nom_composant.champ.$nom_champ.input)] } {
18248 set clef "$clef_base.i"
18249 lappend liste_pts_couplage $clef
18250 }
18251
18252 # Si le champ de couplage est en sortie
18253 if { [info exists dico_ajout(app.$nom_appli.comp.$nom_composant.champ.$nom_champ.output)] } {
18254 set clef "$clef_base.o"
18255 lappend liste_pts_couplage $clef
18256 }
18257 }
18258
18259 # Liste des points de couplage du composant existant auparavant
18260 set liste_clefs_points_i [lsearch -glob -all -inline $liste_points_i "$clef_comp.*"]
18261 set liste_clefs_points_o [lsearch -glob -all -inline $liste_points_o "$clef_comp.*"]
18262
18263 # Vérifie la liste des points de couplage et cherche des points supprimés ou ajoutés
18264 # ----------------------------------------------------------------------------------
18265
18266 # Pour tous les points de couplage du composant chargé en mémoire
18267 foreach clef_point $liste_pts_couplage {
18268 # Si c'est un point de couplage en sortie
18269 if { [string match *.o $clef_point] } {
18270 # Si le point de couplage n'existait pas auparavant
18271 if { [lsearch $liste_clefs_points_o $clef_point] == -1} {
18272 # Ajoute un point de couplage
18273 lappend liste_points_o $clef_point
18274 set dico_caract_points($clef_point.appli) $nom_appli
18275 set dico_caract_points($clef_point.comp) $nom_composant
18276 # Retrouve le nom du champ
18277 set pos [string length "$clef_comp." ]
18278 set nom_champ [string range $clef_point $pos end-2]
18279 set dico_caract_points($clef_point.champ) $nom_champ
18280 }
18281 # Si le point de couplage est en entrée
18282 } else {
18283
18284 # Si le point de couplage n'existait pas auparavant
18285 if { [lsearch $liste_clefs_points_i $clef_point] == -1} {
18286 # Ajoute un point de couplage
18287 lappend liste_points_i $clef_point
18288 set dico_caract_points($clef_point.appli) $nom_appli
18289 set dico_caract_points($clef_point.comp) $nom_composant
18290 # Retrouve le nom du champ
18291 set pos [string length "$clef_comp." ]
18292 set nom_champ [string range $clef_point $pos end-2]
18293 set dico_caract_points($clef_point.champ) $nom_champ
18294 }
18295 }
18296 }
18297
18298 # Init liste des composants ou fichiers touchés par les connexions supprimées
18299 set liste_comp_touches {}
18300 # Pour tous les points de couplage qui existaient auparavant
18301 foreach clef_point [concat $liste_clefs_points_i $liste_clefs_points_o] {
18302 # Si le point de couplage n'existe plus
18303 if { [lsearch $liste_pts_couplage $clef_point] == -1} {
18304 # Teste si le champ est connecté
18305 set lcnx ""
18306 catch {set lcnx $dico_caract_points($clef_point.lcnx)}
18307 # Pour toutes les connexions entrant ou sortant de ce point
18308 foreach num_cnx $lcnx {
18309 # Si c'est une connexion entrante
18310 if { $num_cnx == "i" } {
18311 set clef_cnx_in $clef_point
18312 # Memorise le composant source de la connexion
18313 set appli_source $dico_caract_cnx($clef_cnx_in.app_source)
18314 set comp_source $dico_caract_cnx($clef_cnx_in.comp_source)
18315 set comp_touche $appli_source.$comp_source
18316 } else {
18317 # C'est une connexion sortante : le numéro $num_cnx vaut "o1", "o2" ou "o#"....
18318 # Enlève la lettre "o" qui est en tête
18319 set num [string range $num_cnx 1 end]
18320 # Clef de la cnx sortante
18321 set clef_cnx_out "$clef_point$num"
18322 # Clef de la connexion : point de couplage cible de la connexion
18323 set clef_cnx_in $dico_cnx_out($clef_cnx_out)
18324 # Memorise le composant cible de la connexion
18325 set appli_cible $dico_caract_cnx($clef_cnx_in.app_cible)
18326 set comp_cible $dico_caract_cnx($clef_cnx_in.comp_cible)
18327 set comp_touche $appli_cible.$comp_cible
18328 }
18329 # Met a jour la liste des composants touchés
18330 lappend liste_comp_touches $comp_touche
18331 # Supprime la connexion
18332 comm_remove $clef_cnx_in
18333 }
18334 # Si c'est une point de couplage en entrée
18335 if { [string range $clef_point end end] == "i" } {
18336 # Met a jour la liste des points en entrée
18337 set liste_points_i [lsearch -not -all -inline -glob $liste_points_i "$clef_point"]
18338 } else {
18339 # Met a jour la liste des points en sortie
18340 set liste_points_o [lsearch -not -all -inline -glob $liste_points_o "$clef_point"]
18341 }
18342 # Supprime les caractéristiques du point
18343 array unset dico_caract_points "$clef_point.*"
18344 }
18345 }
18346
18347 # Met à jour en mémoire les champs du composant et leurs attributs
18348 array unset dico_applis "app.$nom_appli.comp.$nom_composant.champ.*"
18349 array set dico_applis [array get dico_ajout "app.$nom_appli.comp.$nom_composant.champ.*"]
18350
18351 # Met à jour en mémoire la liste des champs du composant
18352 set dico_applis(app.$nom_appli.comp.$nom_composant.lchamps) $dico_ajout(app.$nom_appli.comp.$nom_composant.lchamps)
18353
18354 # Met a jour les attributs du composant
18355 foreach attrib {long_name oasis4_version simulated proc.min_value proc.max_value proc.increment} {
18356 set dico_applis(app.$nom_appli.comp.$nom_composant.$attrib) $dico_ajout(app.$nom_appli.comp.$nom_composant.$attrib)
18357 }
18358
18359 # Pour tous les composants touchés
18360 foreach composant $liste_comp_touches {
18361 # Redessine le composant
18362 Draw_one_unit $composant
18363 }
18364
18365 # Affiche le nouveau composant sur le graphe
18366 Draw_one_unit $clef_comp
18367 # Redessine les connexions du composant
18368 Draw_comm $clef_comp
18369
18370 }
18371 }
18372 }
18373
18374 ret {minimenu_comm} (type i) {
18375 #
18376 global entityselected objectselected tagselected oldcolor
18377
18378 # Deselectionne les points de couplage
18379 comm_new menage -1
18380
18381 set w .gui.pr.cpd22.03
18382
18383 # Si il y avait un autre objet selectionne
18384 if {$objectselected != ""} {
18385 # Deselectionne ce composant sur le graphe
18386 $w itemconfigure $tagselected -fill $oldcolor
18387 }
18388
18389 # Change la couleur de l'element sélectionné sur le graphe
18390 set objectselected $i
18391 set tagselected tag_fils_connexions($i)
18392 set oldcolor [$w itemcget $tagselected -fill ]
18393 $w itemconfigure $tagselected -fill red
18394
18395 # Changer le type d'éléments listes et refaire la liste
18396 # et sélectionner le bon élément dans la liste
18397 set entityselected CONNECTION
18398 control_entity $entityselected $i
18399 }
18400
18401 ret {minimenu_unit} (type i) {
18402 #
18403 global entityselected objectselected tagselected oldcolor
18404
18405 # Désélectionne les points de couplage
18406 comm_new menage -1
18407
18408 set w .gui.pr.cpd22.03
18409
18410 # Si il y avait un autre composant sélectionné
18411 if {$tagselected != ""} {
18412 # Désélectionne ce composant sur le graphe
18413 $w itemconfigure $tagselected -fill $oldcolor
18414 }
18415
18416 # Change la couleur du composant sélectionné sur le graphe
18417 set tagselected unitpoint_color($i)
18418 set oldcolor [$w itemcget $tagselected -fill ]
18419 $w itemconfigure $tagselected -fill red
18420
18421 # Changer le type d'éléments listes et refaire la liste
18422 # et sélectionner le bon élément dans la liste
18423
18424 # Si il s'agit d'un fichier NetCDF
18425 if { [string match ///file///.* $i] } {
18426 set entityselected FILE
18427 } else {
18428 set entityselected COMPONENT
18429 }
18430 control_entity $entityselected $i
18431 set objectselected $i
18432 }
18433
18434 ret {notice_show} (type mesg , optional icon =info) {
18435 #
18436 #**** notice_show - notice show
18437 #
18438 # Purpose:
18439 # --------
18440 # Show a dialog box with a message and chosen icon
18441 #
18442 # Interface:
18443 # ----------
18444 # notice_show $mesg info
18445 #
18446 # Inputs :
18447 # --------
18448 # mesg : variable containing the message to be written
18449 # info : the chosen icon (info, error)
18450 #
18451 #*** Externals:
18452 # ----------
18453 # This code is using Tcl/Tk
18454 #
18455 # References:
18456 # -----------
18457 # Effective Tcl/Tk Programming, M. Harrison and M. McLennan,
18458 # Addison-Wesley professional computing series, 1998
18459 #
18460 # History:
18461 # -------
18462 # Version Programmer Date Description
18463 # ------- ---------- ---- -----------
18464 # 0.0 Anne 1999/01/11 created
18465 #*----------------------------------------------------------------
18466 #
18467 #** Declaration
18468 #
18469
18470 set top [dialog_create Notice]
18471 set x [expr [winfo rootx .gui]+200]
18472 set y [expr [winfo rooty .gui]+200]
18473 wm geometry $top "+$x+$y"
18474 set info [dialog_info $top]
18475 label $info.icon -bitmap $icon
18476 pack $info.icon -side left -padx 8 -pady 8
18477 label $info.mesg -text $mesg -wraplength 4i
18478 pack $info.mesg -side right -expand yes -fill both -padx 8 -pady 8
18479 set cntls [dialog_controls $top]
18480 button $cntls.dismiss -command "destroy $top" -text OK
18481 pack $cntls.dismiss -pady 4
18482 return $top
18483 }
18484
18485 ret {open_file} (type file , type mode) {
18486 set f [open $file $mode]
18487 if {$mode == "w" || $mode == "a"} {
18488 fconfigure $f -translation lf
18489 }
18490 return $f
18491 }
18492
18493 ret {printer_create} (type top , type filename) {
18494 global prInfo
18495 global global_font
18496
18497 set top [dialog_create Printer $top]
18498
18499 set info [dialog_info $top]
18500 radiobutton $info.printer -text "Send to printer with command: " -variable prInfo($top-where) -value "printer" -font $global_font
18501 entry $info.printerCmd -font $global_font -background white
18502 radiobutton $info.file -text "Save output in file: " -variable prInfo($top-where) -value "file" -font $global_font
18503
18504 entry $info.fileName -font $global_font -background white
18505
18506 grid $info.printer -row 0 -sticky w
18507 grid $info.printerCmd -row 1 -sticky ew
18508 grid rowconfigure $info 2 -minsize 6
18509 grid $info.file -row 3 -sticky w
18510 grid $info.fileName -row 4 -sticky ew
18511
18512 $info.printerCmd insert 0 "lpr"
18513 $info.fileName insert 0 "$filename.eps"
18514
18515 $info.printer invoke
18516
18517 bind $info.printerCmd <FocusIn> "$info.printer invoke"
18518 bind $info.fileName <FocusIn> "$info.file invoke"
18519
18520 set cntls [dialog_controls $top]
18521 button $cntls.ok -command "set prInfo($top-status) 1" -font $global_font
18522 pack $cntls.ok -side left -expand yes
18523 focus $cntls.ok
18524
18525 button $cntls.cancel -command "set prInfo($top-status) 0" -font $global_font
18526 pack $cntls.cancel -side left -expand yes
18527
18528 wm protocol $top WM_DELETE_WINDOW "$cntls.cancel invoke"
18529 wm withdraw $top
18530
18531
18532 return $top
18533 }
18534
18535 ret {printer_print} (type top , type cmd , optional ok =Print , optional cancel =Cancel) {
18536 global prInfo
18537 global file_lue
18538
18539 set cntls [dialog_controls $top]
18540 $cntls.ok configure -text $ok
18541 $cntls.cancel configure -text $cancel
18542
18543 dialog_wait $top prInfo($top-status)
18544
18545 if {$prInfo($top-status)} {
18546 switch $prInfo($top-where) {
18547 printer {
18548 set info [dialog_info $top]
18549
18550 set print [format {
18551 exec %s << [%s]
18552 } [$info.printerCmd get] $cmd]
18553
18554 if {[catch $print result] != 0} {
18555 notice_show $result error
18556 } elseif {[string trim $result] != ""} {
18557 notice_show $result info
18558 } else {
18559 notice_show "Document printed" info
18560 }
18561 }
18562 file {
18563 set info [dialog_info $top]
18564 set fname [$info.fileName get]
18565 if {[file pathtype $fname] == "relative"} {
18566 set fname [file dirname $file_lue]/$fname
18567 }
18568 set print [format {
18569 set fid [open_file %s w]
18570 puts -nonewline $fid [%s]
18571 close $fid
18572 } $fname $cmd]
18573
18574 if {[catch $print result] != 0} {
18575 notice_show $result error
18576 } else {
18577 notice_show "Output saved in file \"$fname\"" info
18578 }
18579 }
18580 }
18581 }
18582 }
18583
18584 ret {quit_gui_oasis} () {
18585 #
18586 if {![file isdirectory ~/.OASIS]} {catch {file mkdir ~/.OASIS}}
18587 catch {set f [open_file ~/.OASIS/gui_oasis_window w]
18588 puts $f "[winfo geometry .gui]"
18589 close $f
18590 }
18591
18592 global dico_applis
18593 set quitter 1
18594
18595 # S'il y a un couplage a l'ecran (au moins une appli chargee)
18596 set liste_applis {}
18597 catch { set liste_applis $dico_applis(lapplis) }
18598 if {[llength $liste_applis]} {
18599 set rep [tk_messageBox -message "Save current coupling configuration ?" -type yesno -icon question]
18600 if {$rep == "yes"} {
18601 set quitter [sauve_tout]
18602 }
18603 }
18604 if {$quitter == 1} {exit}
18605 }
18606
18607 ret {read_AD_files} (type file_, type list) {
18608 #
18609 global entityselected
18610 # Liste des composants ajoutés
18611 set liste_comp_ajoutes {}
18612 array set dico_ajout {}
18613
18614 # Lit les fichiers XML : AD et les PMIOD relatifs
18615 foreach file $file_list {
18616 if {$file != ""} {
18617 lit_fichier_AD $file dico_ajout liste_comp_ajoutes
18618 }
18619 }
18620 # Met à jour les données et le graphe avec les composants ajoutes
18621 maj_composants_ajoutes dico_ajout $liste_comp_ajoutes
18622
18623 if { $entityselected == "COMPONENT" } {
18624 control_entity $entityselected
18625 }
18626 }
18627
18628 ret {scrollform_create} (type win) {
18629 # ----------------------------------------------------------------------
18630 # USAGE: scrollform_resize <win>
18631 #
18632 # Used internally to handle size changes in the form area within
18633 # a scrollform assembly. Updates the canvas to recognize the new
18634 # scrolling area.
18635 # ----------------------------------------------------------------------
18636 proc scrollform_resize {win} {
18637 set bbox [$win.vport bbox all]
18638 set wid [winfo width $win.vport.form]
18639 $win.vport configure -width $wid -scrollregion $bbox -yscrollincrement 0.1i
18640 }
18641
18642 # ----------------------------------------------------------------------
18643 # USAGE: scrollform_interior <win>
18644 #
18645 # Returns the name of the interior frame that represents the
18646 # body of the scrollform. Widgets should be packed in this
18647 # frame to build the form.
18648 # ----------------------------------------------------------------------
18649 proc scrollform_interior {win} {
18650 return "$win.vport.form"
18651 }
18652
18653 # ----------------------------------------------------------------------
18654 # EXAMPLE: use the canvas to build a scrollable form
18655 # ----------------------------------------------------------------------
18656 # Effective Tcl/Tk Programming
18657 # Mark Harrison, DSC Communications Corp.
18658 # Michael McLennan, Bell Labs Innovations for Lucent Technologies
18659 # Addison-Wesley Professional Computing Series
18660 # ======================================================================
18661 # Copyright (c) 1996-1997 Lucent Technologies Inc. and Mark Harrison
18662 # ======================================================================
18663
18664 # ----------------------------------------------------------------------
18665 # USAGE: scrollform_create <win>
18666 #
18667 # Creates an empty scrollform assembly. The interior frame for this
18668 # form can be found by calling "scrollform_interior". Widgets packed
18669 # into the interior can be scrolled in the vertical direction.
18670 # ----------------------------------------------------------------------
18671 frame $win -class Scrollform
18672
18673 scrollbar $win.sbar -command "$win.vport yview"
18674 pack $win.sbar -side right -fill y
18675
18676 canvas $win.vport -yscrollcommand "$win.sbar set"
18677 pack $win.vport -side left -fill both -expand true
18678
18679 frame $win.vport.form
18680 $win.vport create window 0 0 -anchor nw -window $win.vport.form
18681
18682 bind $win.vport.form <Configure> "scrollform_resize $win"
18683
18684 return $win
18685 }
18686
18687 ret {unit_delete} (type clef_, type unit) {
18688 # Quand l'utilisateur appuie sur la touche <delete> sur une unité (composant ou fichier) dans le graphe
18689 # ceci provoque la suppression de cette unité (pour les fichiers seulement, pour l'instant)
18690 #
18691 global dico_applis dico_units dico_caract_fichiers
18692 global oldcolor tagselected
18693
18694 set nom_unit $dico_units($clef_unit)
18695 # Extrait de la clef le nom de l'appli
18696 set len_unit [string length $nom_unit]
18697 incr len_unit
18698 set nom_appli [string range $clef_unit 0 end-$len_unit]
18699
18700 # Si l'unité est un fichier
18701 if { $nom_appli == "///file///" } {
18702 # Supprime le fichier
18703 NetCDF_file_delete $clef_unit
18704 }
18705 }
18706
18707 ret {unit_edit} (type clef_, type unit) {
18708 # Quand l'utilisateur double-clique sur une unité (composant ou fichier) dans le graphe
18709 # ceci provoque la saisie des paramètres de cette unité
18710 #
18711 # Cette fonction appelle la procédure qu'il faut selon que l'unité en question
18712 # est un fichier ou un composant d'application
18713 #
18714 global dico_applis dico_units dico_caract_fichiers
18715 global oldcolor tagselected
18716
18717 set nom_unit $dico_units($clef_unit)
18718 # Extrait de la clef le nom de l'appli
18719 set len_unit [string length $nom_unit]
18720 incr len_unit
18721 set nom_appli [string range $clef_unit 0 end-$len_unit]
18722
18723 # Si l'unité est un fichier
18724 if { $nom_appli == "///file///" } {
18725 NetCDF_file_edit $nom_unit
18726 tkwait window .mod_file
18727
18728 # L'utilisateur a pu changer le nom du fichier
18729 # ==> raffiche le fichier sur le graphe
18730 Draw_one_unit $clef_unit
18731 Draw_comm $clef_unit
18732
18733 } else {
18734 component_edit $clef_unit
18735 tkwait window .mod_component
18736 # La couleur a pu changer : raffiche le composant sur le graphe
18737 Draw_one_unit $clef_unit
18738 }
18739
18740 # Si cette unité était sélectionnée
18741 if {$tagselected == "unitpoint_color($clef_unit)"} {
18742 # Change la couleur de l'objet sélectionné
18743 set w .gui.pr.cpd22.03
18744 set oldcolor [$w itemcget $tagselected -fill ]
18745 $w itemconfigure $tagselected -fill red
18746 }
18747 }
18748
18749 ret {unit_init} () {
18750 # Initialise arbitrairement les données graphiques des unités sur le graphe de couplage
18751 global dico_applis liste_fichiers dico_units
18752
18753 # Position de la 1ère unité sur le graphe : en haut à gauche
18754 # Les autres seront alignés sur une diagonale a travers l'écran
18755 set position_x 80
18756 set position_y 25
18757
18758 # Pour toutes les applications
18759 foreach nom_appli $dico_applis(lapplis) {
18760 # Pour tous les composants de cette application
18761 foreach nom_composant $dico_applis(app.$nom_appli.lcomp) {
18762 set clef_comp $nom_appli.$nom_composant
18763
18764 # Si l'élément apparait sur le graphe
18765 if { [info exists dico_units($clef_comp)] } {
18766 # Position en x et y, couleur et mode d'affichage
18767 set dico_units($clef_comp.coor_x) $position_x
18768 set dico_units($clef_comp.coor_y) $position_y
18769 set dico_units($clef_comp.colour) [color_rgb [expr int(rand()*254)] [expr int(rand()*254)] [expr int(rand()*254)]]
18770 set dico_units($clef_comp.expand) 1
18771 incr position_x 30
18772 incr position_y 80
18773 }
18774 }
18775 }
18776
18777 # Pour tous les fichiers NetCDF
18778 foreach id_fichier $liste_fichiers {
18779 set clef_fichier
18780
18781 # Si l'élément apparait sur le graphe
18782 if { [info exists dico_units($clef_fichier)] } {
18783 # Position en x et y, couleur et mode d'affichage
18784 set dico_units($clef_fichier.coor_x) $position_x
18785 set dico_units($clef_fichier.coor_y) $position_y
18786 set dico_units($clef_fichier.colour) [color_rgb [expr int(rand()*254)] [expr int(rand()*254)] [expr int(rand()*254)]]
18787 set dico_units($clef_fichier.expand) 1
18788 incr position_x 30
18789 incr position_y 80
18790 }
18791 }
18792 }
18793
18794 ret {unitplotdown} (type w , type x , type y , type i) {
18795 # plotDown --
18796 # This procedure is invoked when the mouse is pressed over one of the
18797 # data points. It sets up state to allow the point to be dragged.
18798 #
18799 # Arguments:
18800 # w - The canvas window.
18801 # x, y - The coordinates of the mouse press.
18802 global plot
18803 global unitindex
18804 global plotdown
18805
18806 set plotdown "active"
18807 $w dtag selected
18808 $w addtag selected withtag UNIT_tag($i)
18809 set plot(lastX) $x
18810 set plot(lastY) $y
18811 set plot(firstX) $x
18812 set plot(firstY) $y
18813 }
18814
18815 ret {unitplotmove} (type w , type x , type y) {
18816 # plotMove --
18817 # This procedure is invoked during mouse motion events. It drags the
18818 # current item.
18819 #
18820 # Arguments:
18821 # w - The canvas window.
18822 # x, y - The coordinates of the mouse.
18823 global plot
18824 $w move selected [expr $x-$plot(lastX)] [expr $y-$plot(lastY)]
18825 set plot(lastX) $x
18826 set plot(lastY) $y
18827 }
18828
18829 ret {unitplotrelease} (type w , type x , type y , type i) {
18830 #
18831 global zoomfactor
18832 global dico_units
18833 global plot
18834 global plotdown
18835 global tagselected
18836
18837 if {$plotdown == "active"} {
18838 $w dtag selected
18839 set plot(lastX) $x
18840 set plot(lastY) $y
18841 set dico_units($i.coor_x) [expr $dico_units($i.coor_x) + ($plot(lastX) - $plot(firstX))/$zoomfactor]
18842 set dico_units($i.coor_y) [expr $dico_units($i.coor_y) + ($plot(lastY) - $plot(firstY))/$zoomfactor]
18843
18844 Draw_one_unit $i
18845 # Si le composant est sélectionné
18846 if {$tagselected == "unitpoint_color($i)"} {
18847 # remet la couleur rouge de l'objet sélectionné
18848 $w itemconfigure $tagselected -fill red
18849 }
18850 update
18851 Draw_comm $i
18852 set plotdown "inactive"
18853 }
18854 }
18855
18856 ret {user_name} () {
18857 global env
18858 return $env(USER)
18859 }
18860
18861 ret {window.font} (optional init_font ={helvetica 12) texttoedit} {
18862 global dxf
18863 .gui configure -cursor watch
18864 update
18865 set dxf(tmp) ""
18866 catch {destroy .choose_font}
18867 w = .choose_font
18868 toplevel $w
18869 wm withdraw $w
18870 wm protocol $w WM_DELETE_WINDOW " dxf = (tmp) \"\"; destroy $w"
18871 catch {wm transient $w .appearance}
18872 wm title $w "Text edit"
18873
18874
18875 label $w.l11 -text "Font:"
18876 label $w.l12 -text "Size:"
18877 label $w.l13 -text "Color:"
18878 label $w.l14 -text "Justification:"
18879
18880
18881 combobox_lim $w.cb_name [lsort [font families]] font_view_update dxf(choose_font_cb_name) 30 $dxf(choose_font_cb_name)
18882
18883
18884 combobox_lim $w.cb_size [list 8 10 12 14 16 18 20 24 36] font_view_update dxf(choose_font_cb_size) 4 $dxf(choose_font_cb_size)
18885
18886
18887 combobox_lim $w.cb_color [list black red blue green cyan magenta yellow pink grey20 grey50 grey80] font_view_update dxf(choose_font_cb_color) 10 $dxf(choose_font_cb_color)
18888
18889
18890 combobox_lim $w.cb_justify [list left right center] font_view_update dxf(choose_font_cb_justify) 10 $dxf(choose_font_cb_justify)
18891
18892
18893 checkbutton $w.c_bold -highlightthickness 0 -indicatoron 0 -text "B" -font {Times 12 bold} -onvalue bold -offvalue "" -command "font_view_update" -variable dxf(choose_font_c_bold)
18894 checkbutton $w.c_italic -highlightthickness 0 -indicatoron 0 -text "I" -font {Times 12 italic} -onvalue italic -offvalue "" -command "font_view_update" -variable dxf(choose_font_c_italic)
18895 checkbutton $w.c_underline -highlightthickness 0 -indicatoron 0 -text "U" -font {Times 12 underline} -onvalue underline -offvalue "" -command "font_view_update" -variable dxf(choose_font_c_underline)
18896
18897 text $w.view -font "[get_cur_font]" -width 20 -height 5 -background white
18898
18899 frame $w.f
18900 button $w.f.ok -text "Ok" -command " dxf = (text) \"\[.choose_font.view get 0.0 end\]\" ; dxf = (tmp) \"\[get_cur_font\]\"; destroy $w"
18901 button $w.f.cancel -text "Close" -command " dxf = (tmp) \"\"; destroy $w"
18902
18903
18904 grid $w.l11 $w.l12 $w.l13 $w.l14 -row 0 -pady 2 -padx 4 -sticky w
18905 grid $w.cb_name $w.cb_size $w.cb_color $w.cb_justify $w.c_bold $w.c_italic $w.c_underline -row 1 -padx 4 -sticky w
18906 grid $w.view -row 2 -columnspan 7 -sticky we -pady 4
18907 grid $w.f -row 3 -columnspan 7 -sticky we -pady 5 -padx 5
18908 grid $w.f.ok $w.f.cancel -row 0 -padx 10
18909
18910 focus $w.view
18911
18912 wm geometry $w +150+150
18913 .gui configure -cursor ""
18914 }
18915
18916 ret {window_position} (type w , optional x =100 , optional y =100) {
18917 #
18918 set x [expr [winfo rootx .gui]+$x]
18919 set y [expr [winfo rooty .gui]+$y]
18920 wm geometry $w "+$x+$y"
18921 }
18922
18923 ret {write_file_as} () {
18924 set types { { { XML Files} {.xml} } }
18925 set file [tk_getSaveFile -initialfile "scc.xml" -title "Save configuration file" -filetypes $types -defaultextension .xml ]
18926
18927 if {$file != ""} {
18928 if {[file extension $file] != ".xml"} {
18929 set file $file.xml
18930 }
18931 }
18932
18933 return $file
18934 }
18935
18936 ret {main} (type argc , type argv) {
18937 #
18938 global largfen
18939 global entity_id
18940 global OASIS_GUI_DIR
18941 global entityselected
18942
18943 # Load "XML support" packages : they are in subdirectory 'packages'
18944 package require xml
18945 package require xml::libxml2
18946 package require dom
18947
18948 global env
18949 global file_lue
18950 set file_lue ""
18951 global DRAW
18952 set DRAW(unitXcur) 20
18953 set DRAW(unitYcur) 50
18954
18955 wm title .gui "OASIS"
18956 if {$argc > 0} {
18957 set file [lindex $argv 0]
18958
18959 #
18960 #** Lecture du fichier .XML
18961 #
18962 if {[file exists $file]} {
18963 .gui configure -cursor watch
18964 update
18965 set erreur [lit_fichier_SCC $file]
18966 .gui configure -cursor ""
18967
18968 if {! $erreur } {
18969 set file_lue $file
18970 wm title .gui "OASIS - $file"
18971
18972 global entityselected
18973 control_entity $entityselected
18974 drawall
18975 } else {
18976 # Efface les traces d'une config qui serait lue de façon incomplète
18977 config_RAZ
18978 }
18979 }
18980 }
18981
18982 #==recupere la derniere taille de la fenetre
18983 catch {
18984 set f [open_file ~/.OASIS/gui_oasis_window r]
18985 gets $f geom
18986 wm geometry .gui $geom
18987 close $f
18988 }
18989
18990 wm protocol .gui WM_DELETE_WINDOW "quit_gui_oasis"
18991 drawall
18992 catch {destroy .start_banner}
18993
18994 set largfen 37
18995 control_entity $entityselected
18996
18997 #===creation des images
18998
18999 # Symboles des tranformations
19000 foreach transform {add multiply remaillage accumulate average interpol} {
19001 image create photo img_$transform -file [file join $OASIS_GUI_DIR IMAGES $transform.gif]
19002 }
19003
19004 # Boutons
19005 set imag [image create photo -file [file join $OASIS_GUI_DIR IMAGES open.gif]]
19006 .gui.pr.toolframe.toolsbox.fobt configure -image $imag
19007 bind .gui.pr.toolframe.toolsbox.fobt <Any-Enter> ".gui.pr.tools.infolabel configure -text {Open SCC file}"
19008 bind .gui.pr.toolframe.toolsbox.fobt <Any-Leave> ".gui.pr.tools.infolabel configure -text {}"
19009
19010 set imag [image create photo -file [file join $OASIS_GUI_DIR IMAGES save.gif]]
19011 .gui.pr.toolframe.toolsbox.but32 configure -image $imag
19012 bind .gui.pr.toolframe.toolsbox.but32 <Any-Enter> ".gui.pr.tools.infolabel configure -text {Save all (SCC and SMIOC)}"
19013 bind .gui.pr.toolframe.toolsbox.but32 <Any-Leave> ".gui.pr.tools.infolabel configure -text {}"
19014
19015 set imag [image create photo -file [file join $OASIS_GUI_DIR IMAGES zoommoins.gif]]
19016 .gui.pr.zoomframe.zm configure -image $imag
19017 bind .gui.pr.zoomframe.zm <Any-Enter> ".gui.pr.tools.infolabel configure -text {Zoom -}"
19018 bind .gui.pr.zoomframe.zm <Any-Leave> ".gui.pr.tools.infolabel configure -text {}"
19019
19020 set imag [image create photo -file [file join $OASIS_GUI_DIR IMAGES zoomplus.gif]]
19021 .gui.pr.zoomframe.zp configure -image $imag
19022 bind .gui.pr.zoomframe.zp <Any-Enter> ".gui.pr.tools.infolabel configure -text {Zoom +}"
19023 bind .gui.pr.zoomframe.zp <Any-Leave> ".gui.pr.tools.infolabel configure -text {}"
19024
19025 set imag [image create photo -file [file join $OASIS_GUI_DIR IMAGES lunit.gif]]
19026 .gui.pr.toolframe.toolsbox.but34 configure -image $imag
19027 bind .gui.pr.toolframe.toolsbox.but34 <Any-Enter> ".gui.pr.tools.infolabel configure -text {Load XML application definition}"
19028 bind .gui.pr.toolframe.toolsbox.but34 <Any-Leave> ".gui.pr.tools.infolabel configure -text {}"
19029
19030 set imag [image create photo -file [file join $OASIS_GUI_DIR IMAGES binary.gif]]
19031 .gui.pr.toolframe.toolsbox.but35 configure -image $imag
19032 bind .gui.pr.toolframe.toolsbox.but35 <Any-Enter> ".gui.pr.tools.infolabel configure -text {Load NetCDF file}"
19033 bind .gui.pr.toolframe.toolsbox.but35 <Any-Leave> ".gui.pr.tools.infolabel configure -text {}"
19034 }
19035
19036 ret init (type argc , type argv) {
19037 #initialisations
19038 combobox_init
19039 #** chemins
19040 global OASIS_GUI_DIR
19041 global env
19042 global zoomfactor
19043 set zoomfactor 1
19044
19045 global plotdown
19046 set plotdown inactive
19047
19048 # Determine le chemin du script en cours d'execution
19049 global argv0
19050 set script_file [file normalize [file join [pwd] $argv0]]
19051 # Prend le repertoire
19052 set OASIS_GUI_DIR [file dirname $script_file]
19053
19054 #LAURE
19055 # packages : they are in subdirectory 'packages/lib'
19056 global auto_path
19057 lappend auto_path [file join $OASIS_GUI_DIR packages/lib]
19058 # Lit les paramètres de la ligne de commande
19059 package require cmdline
19060 set options {
19061 {silent "silent mode : no help balloon"}
19062 }
19063 set usage ": oasis-gui.tcl \[options] \noptions:"
19064 array set params [::cmdline::getoptions argv $options $usage]
19065 # Vérifie si l'option -silent a été mise sur la ligne de commande
19066 global no_help_balloon
19067 set no_help_balloon $params(silent)
19068
19069 global plot
19070 set plot(lastX) 0
19071 set plot(lastY) 0
19072
19073 global oasis_GUI_param
19074
19075 global global_font
19076 set global_font "-adobe-helvetica-bold-r-normal--12-180-90-90-m-90-iso8859-1"
19077
19078 global viewcommcheck
19079 set viewcommcheck 1
19080 global oasis4_version; set oasis4_version OASIS4_0_2
19081
19082 global dico_applis
19083 array set dico_applis {}
19084 global liste_points_i liste_points_o
19085 set liste_points_i {}
19086 set liste_points_o {}
19087 global dico_units
19088 array set dico_units {}
19089 global liste_fichiers dico_caract_fichiers
19090 set liste_fichiers {}
19091 array set dico_caract_fichiers {}
19092
19093 global liste_cnx_in
19094 set liste_cnx_in {}
19095 global dico_cnx_out
19096 array set dico_cnx_out {}
19097
19098 #** default order in selection list
19099 global orderentity
19100 set orderentity(CONNECTION) 1
19101 set orderentity(COUPLING_FIELD) 3
19102 set orderentity(COMPONENT) 0
19103 set orderentity(FILE) 0
19104
19105 global objectselected tagselected; set objectselected ""; set tagselected ""
19106
19107 global entityselected
19108 set entityselected COMPONENT
19109 }
19110
19111 init $argc $argv
19112
19113
19114
19115
19116
19117 ret vTclWindow. (type base , optional container =0) {
19118 if {$base == ""} {
19119 set base .
19120 }
19121 ###################
19122 # CREATING WIDGETS
19123 ###################
19124 if {!$container} {
19125 wm focusmodel $base passive
19126 wm geometry $base 1x1+0+0; update
19127 wm maxsize $base 1009 738
19128 wm minsize $base 1 1
19129 wm overrideredirect $base 0
19130 wm resizable $base 1 1
19131 wm withdraw $base
19132 wm title $base "vtcl.tcl"
19133 bindtags $base "$base Vtcl.tcl all"
19134 }
19135 ###################
19136 # SETTING GEOMETRY
19137 ###################
19138 }
19139
19140 ret vTclWindow.ballon_object (type base , optional container =0) {
19141 if {$base == ""} {
19142 set base .ballon_object
19143 }
19144 if {[winfo exists $base] && (!$container)} {
19145 wm deiconify $base; return
19146 }
19147
19148 global widget
19149
19150 ###################
19151 # CREATING WIDGETS
19152 ###################
19153 if {!$container} {
19154 toplevel $base -class Toplevel \
19155 -borderwidth 1
19156 wm withdraw .ballon_object
19157 wm focusmodel $base passive
19158 wm geometry $base 1x1+0+0; update
19159 wm maxsize $base 1009 738
19160 wm minsize $base 1 1
19161 wm overrideredirect $base 1
19162 wm resizable $base 1 1
19163 wm title $base "ballon_object"
19164 }
19165 label $base.text \
19166 -background #fefed4 -font {helvetica 10} -foreground black
19167 ###################
19168 # SETTING GEOMETRY
19169 ###################
19170 pack $base.text \
19171 -in $base -anchor w -expand 0 -fill none -side left
19172 }
19173
19174 ret vTclWindow.gui (type base , optional container =0) {
19175 if {$base == ""} {
19176 set base .gui
19177 }
19178 if {[winfo exists $base] && (!$container)} {
19179 wm deiconify $base; return
19180 }
19181
19182 global widget
19183 vTcl:DefineAlias "$base.cpd17.settingbutton" "Menubutton1" vTcl:WidgetProc "$base" 1
19184 vTcl:DefineAlias "$base.pr.toolframe.cpd18.01" "Mclistbox1" vTcl:WidgetProc "$base" 1
19185 vTcl:DefineAlias "$base.pr.toolframe.toolsbox" "Frame1" vTcl:WidgetProc "$base" 1
19186 vTcl:DefineAlias "$base.pr.toolframe.toolsbox.but32" "Button2" vTcl:WidgetProc "$base" 1
19187 vTcl:DefineAlias "$base.pr.toolframe.toolsbox.but34" "Button16" vTcl:WidgetProc "$base" 1
19188 vTcl:DefineAlias "$base.pr.toolframe.toolsbox.but35" "Button17" vTcl:WidgetProc "$base" 1
19189 vTcl:DefineAlias "$base.pr.toolframe.toolsbox.fobt" "Button1" vTcl:WidgetProc "$base" 1
19190
19191 ###################
19192 # CREATING WIDGETS
19193 ###################
19194 if {!$container} {
19195 toplevel $base -class Toplevel
19196 wm focusmodel $base passive
19197 wm geometry $base 1024x695+0+48; update
19198 wm maxsize $base 1600 1200
19199 wm minsize $base 400 300
19200 wm overrideredirect $base 0
19201 wm resizable $base 1 1
19202 wm deiconify $base
19203 wm title $base "OASIS"
19204 bind $base <Button-4> {
19205 catch {%W yview scroll -1 units}
19206 }
19207 bind $base <Button-5> {
19208 catch {%W yview scroll 1 units}
19209 }
19210 bind $base <Control-Button-4> {
19211 catch {%W xview scroll -1 units}
19212 }
19213 bind $base <Control-Button-5> {
19214 catch {%W xview scroll 1 units}
19215 }
19216 bind $base <Shift-Button-4> {
19217 catch {%W yview scroll -5 units}
19218 }
19219 bind $base <Shift-Button-5> {
19220 catch {%W yview scroll 5 units}
19221 }
19222 }
19223 frame $base.cpd17 \
19224 -borderwidth 1 -relief sunken -background #e6e6e6 -height 30 \
19225 -width 30
19226 menubutton $base.cpd17.01 \
19227 -anchor w -borderwidth 2 -font {helvetica -12 bold} \
19228 -menu "$base.cpd17.01.02" -padx 4 -pady 3 -text File -underline 0 \
19229 -width 4
19230 bind $base.cpd17.01 <Enter> {
19231 .gui.pr.tools.infolabel configure -text "Open, save and print"
19232 }
19233 bind $base.cpd17.01 <Leave> {
19234 .gui.pr.tools.infolabel configure -text " "
19235 }
19236 menu $base.cpd17.01.02 \
19237 -cursor {} -tearoff 0
19238 $base.cpd17.01.02 add command \
19239 -accelerator {} -command config_new -image {} -label {New file}
19240 $base.cpd17.01.02 add command \
19241 -accelerator {} -command config_read -image {} -label {Open SCC file}
19242 $base.cpd17.01.02 add command \
19243 -accelerator {} -command sauve_tout -image {} -label {Save all (SCC and SMIOC)}
19244 $base.cpd17.01.02 add command \
19245 -accelerator {} -command sauve_scc -image {} -label {Save SCC file}
19246 $base.cpd17.01.02 add command \
19247 -accelerator {} -command sauve_smioc -image {} -label {Save SMIOC files}
19248 $base.cpd17.01.02 add separator
19249 $base.cpd17.01.02 add command \
19250 -accelerator {} -command load_XML_ad_files -image {} \
19251 -label {Load Application Descriptions}
19252 $base.cpd17.01.02 add command \
19253 -accelerator {} -command load_NetCDF_files -image {} \
19254 -label {Load NetCDF files}
19255 $base.cpd17.01.02 add separator
19256 $base.cpd17.01.02 add command \
19257 -accelerator {} \
19258 -command {printer_create .print "Oasis"
19259 printer_print .print draw_print} \
19260 -image {} -label Print
19261 $base.cpd17.01.02 add separator
19262 $base.cpd17.01.02 add command \
19263 -accelerator {} -command quit_gui_oasis -image {} -label {Quit Oasis}
19264 menubutton $base.cpd17.settingbutton \
19265 -font {helvetica -12 bold} -menu "$base.cpd17.settingbutton.m" \
19266 -padx 6 -pady 4 -text Settings -underline 0
19267 bind $base.cpd17.settingbutton <Enter> {
19268 .gui.pr.tools.infolabel configure -text "Set display options, colors"
19269 }
19270 bind $base.cpd17.settingbutton <Leave> {
19271 .gui.pr.tools.infolabel configure -text ""
19272 }
19273 menu $base.cpd17.settingbutton.m
19274 $base.cpd17.settingbutton.m add command \
19275 -accelerator {} -command experiment_settings -image {} \
19276 -label {Experiment settings ...}
19277 $base.cpd17.settingbutton.m add command \
19278 -accelerator {} -command Draw_settings -image {} \
19279 -label {Canvas settings ...}
19280 frame $base.pr \
19281 -borderwidth 2 -relief groove -height 75 -width 200
19282 frame $base.pr.tools \
19283 -height 4 -width 300
19284 bind $base.pr.tools <Configure> {
19285 set l [winfo width .gui]
19286 set l [expr ($l-10) / 7.17]
19287 .gui.pr.tools.resizescrl configure -to $l
19288 }
19289 label $base.pr.tools.infolabel \
19290 -anchor w -background grey95 -borderwidth 1 \
19291 -font {helvetica -12 bold} -relief sunken -text {}
19292 scale $base.pr.tools.resizescrl \
19293 -bigincrement 0.0 -borderwidth 0 \
19294 -command {.gui.pr.toolframe.cpd18.01 configure -width} -from 1.0 \
19295 -highlightthickness 0 -orient horizontal -relief ridge \
19296 -resolution 1.0 -showvalue 0 -sliderlength 10 -tickinterval 0.0 \
19297 -to 141.0 -troughcolor #d9d9d9 -variable largfen -width 9
19298 frame $base.pr.toolframe \
19299 -borderwidth 0 -relief sunken -height 1063 -width 125
19300 frame $base.pr.toolframe.toolsbox \
19301 -relief groove -background #e6e6e6 -height 75 \
19302 -highlightbackground #e6e6e6 -highlightcolor #000000 -width 125
19303 button $base.pr.toolframe.toolsbox.fobt \
19304 -borderwidth 2 -command config_read -text l
19305 bind $base.pr.toolframe.toolsbox.fobt <Enter> {
19306 .gui.pr.tools.infolabel configure -text {Read PrePalm file}
19307 }
19308 bind $base.pr.toolframe.toolsbox.fobt <Leave> {
19309 .gui.pr.tools.infolabel configure -text {}
19310 }
19311 button $base.pr.toolframe.toolsbox.but34 \
19312 -command load_XML_ad_files -padx 3m -text u
19313 bind $base.pr.toolframe.toolsbox.but34 <Enter> {
19314 .gui.pr.tools.infolabel configure -text {Load XML application definition}
19315 }
19316 bind $base.pr.toolframe.toolsbox.but34 <Leave> {
19317 .gui.pr.tools.infolabel configure -text {}
19318 }
19319 button $base.pr.toolframe.toolsbox.but35 \
19320 -command load_NetCDF_files -padx 3m -text u
19321 bind $base.pr.toolframe.toolsbox.but35 <Enter> {
19322 .gui.pr.tools.infolabel configure -text {Load NetCDF file}
19323 }
19324 bind $base.pr.toolframe.toolsbox.but35 <Leave> {
19325 .gui.pr.tools.infolabel configure -text {}
19326 }
19327 button $base.pr.toolframe.toolsbox.but32 \
19328 -anchor center -borderwidth 2 -command sauve_tout
19329 bind $base.pr.toolframe.toolsbox.but32 <Enter> {
19330 .gui.pr.tools.infolabel configure -text {Save all (SCC and SMIOC)}
19331 }
19332 bind $base.pr.toolframe.toolsbox.but32 <Leave> {
19333 .gui.pr.tools.infolabel configure -text {}
19334 }
19335 frame $base.pr.toolframe.entityframe \
19336 -borderwidth 2 -height 75 -width 177
19337 radiobutton $base.pr.toolframe.entityframe.comprb \
19338 -anchor w -borderwidth 2 -command {control_entity COMPONENT} \
19339 -font {helvetica -12 bold} -highlightthickness 0 -padx 1 -pady 3 \
19340 -selectcolor #b03060 -text {Applications and components } -value 0 \
19341 -variable entity_id -width 25
19342 radiobutton $base.pr.toolframe.entityframe.ficrb \
19343 -anchor w -command {control_entity FILE} -font {helvetica -12 bold} \
19344 -highlightthickness 0 -padx 1 -pady 3 -text {NetCDF files } -value 3 \
19345 -variable entity_id
19346 radiobutton $base.pr.toolframe.entityframe.cnxrb \
19347 -anchor w -command {control_entity CONNECTION} \
19348 -font {helvetica -12 bold} -highlightthickness 0 -padx 1 -pady 3 \
19349 -text Connections -value 2 -variable entity_id
19350 radiobutton $base.pr.toolframe.entityframe.fieldsrb \
19351 -anchor w -command {control_entity COUPLING_FIELD} \
19352 -font {helvetica -12 bold} -highlightthickness 0 -padx 1 -pady 3 \
19353 -text {Coupling fields} -value 1 -variable entity_id -width 27
19354 frame $base.pr.toolframe.buttonfrc \
19355 -height 75 -width 4
19356 button $base.pr.toolframe.buttonfrc.editb \
19357 -command control_edit_entity -font {helvetica -12 bold} -padx 5 \
19358 -pady 4 -text Edit
19359 button $base.pr.toolframe.buttonfrc.deleteb \
19360 -command control_delete_entity -font {helvetica -12 bold} -padx 5 \
19361 -pady 4 -state disabled -text Delete
19362 frame $base.pr.toolframe.cpd18 \
19363 -borderwidth 0 -relief raised -height 2 -width 31
19364 scrollbar $base.pr.toolframe.cpd18.02 \
19365 -borderwidth 1 -command "$base.pr.toolframe.cpd18.01 xview" \
19366 -orient horizontal -width 10
19367 scrollbar $base.pr.toolframe.cpd18.03 \
19368 -borderwidth 1 -command "$base.pr.toolframe.cpd18.01 yview" -width 11
19369 ::mclistbox::mclistbox $base.pr.toolframe.cpd18.01 \
19370 -background #d9d9d9 -borderwidth 2 -font {helvetica -12 bold} \
19371 -height 278 -labelanchor center -labelborderwidth 1 \
19372 -labelrelief raised -relief sunken -selectborderwidth 1 \
19373 -selectmode extended -width 37 \
19374 -xscrollcommand "$base.pr.toolframe.cpd18.02 set" \
19375 -yscrollcommand "$base.pr.toolframe.cpd18.03 set"
19376 bind $base.pr.toolframe.cpd18.01 <<ListboxSelect>> {
19377 control_entity_selectionChanged %W
19378 }
19379 bind $base.pr.toolframe.cpd18.01 <Key-Delete> {control_delete_entity}
19380 bind $base.pr.toolframe.cpd18.01 <Double-Button-1> {
19381 control_edit_entity
19382 }
19383 frame $base.pr.zoomframe \
19384 -relief groove -height 75 -width 125
19385 frame $base.pr.zoomframe.viewframe \
19386 -borderwidth 0 -relief groove -height 75 -width 208
19387 checkbutton $base.pr.zoomframe.viewframe.viewcommcheck \
19388 -command {update
19389 Draw_comm} -font {helvetica -12 bold} -pady 0 \
19390 -text {View connections} -variable viewcommcheck
19391 button $base.pr.zoomframe.zm \
19392 -borderwidth 0 \
19393 -command {global zoomfactor
19394 if {$zoomfactor > .4} {set zoomfactor [expr $zoomfactor-0.1]}
19395 drawall} \
19396 -padx 0 -pady 0 -relief flat -text button
19397 bind $base.pr.zoomframe.zm <Enter> {
19398 .gui.pr.tools.infolabel configure -text {Zoom -}
19399 }
19400 bind $base.pr.zoomframe.zm <Leave> {
19401 .gui.pr.tools.infolabel configure -text {}
19402 }
19403 button $base.pr.zoomframe.zp \
19404 -borderwidth 0 \
19405 -command {global zoomfactor
19406 if {$zoomfactor < 1.5} {set zoomfactor [expr $zoomfactor +0.1]}
19407 drawall} \
19408 -padx 0 -pady 0 -relief flat -text button
19409 bind $base.pr.zoomframe.zp <Enter> {
19410 .gui.pr.tools.infolabel configure -text {Zoom +}
19411 }
19412 bind $base.pr.zoomframe.zp <Leave> {
19413 .gui.pr.tools.infolabel configure -text {}
19414 }
19415 frame $base.pr.cpd22 \
19416 -borderwidth 0 -relief raised -height 30 -width 30
19417 scrollbar $base.pr.cpd22.01 \
19418 -borderwidth 1 -command "$base.pr.cpd22.03 xview" -jump 1 \
19419 -orient horizontal -width 10
19420 scrollbar $base.pr.cpd22.02 \
19421 -borderwidth 1 -command "$base.pr.cpd22.03 yview" -jump 1 -width 10
19422 canvas $base.pr.cpd22.03 \
19423 -background #fefefe -borderwidth 1 -closeenough 1.0 -height 999 \
19424 -relief ridge -scrollregion {0 0 2000 3000} -width 2000 \
19425 -xscrollcommand "$base.pr.cpd22.01 set" \
19426 -yscrollcommand "$base.pr.cpd22.02 set"
19427 bind $base.pr.cpd22.03 <B1-Motion> {
19428 unitplotmove .gui.pr.cpd22.03 %x %y
19429 }
19430 bind $base.pr.cpd22.03 <B3-Motion> {
19431 unitplotmove .gui.pr.cpd22.03 %x %y
19432 }
19433 ###################
19434 # SETTING GEOMETRY
19435 ###################
19436 pack $base.cpd17 \
19437 -in $base -anchor center -expand 0 -fill x -side top
19438 pack $base.cpd17.01 \
19439 -in $base.cpd17 -anchor center -expand 0 -fill none -side left
19440 pack $base.cpd17.settingbutton \
19441 -in $base.cpd17 -anchor center -expand 0 -fill none -side left
19442 pack $base.pr \
19443 -in $base -anchor center -expand 1 -fill x -side right
19444 pack $base.pr.tools \
19445 -in $base.pr -anchor n -expand 0 -fill x -side bottom
19446 pack $base.pr.tools.infolabel \
19447 -in $base.pr.tools -anchor w -expand 0 -fill x -ipadx 15 -side bottom
19448 pack $base.pr.tools.resizescrl \
19449 -in $base.pr.tools -anchor w -expand 1 -fill x -side left
19450 pack $base.pr.toolframe \
19451 -in $base.pr -anchor n -expand 0 -fill both -side left
19452 pack $base.pr.toolframe.toolsbox \
19453 -in $base.pr.toolframe -anchor center -expand 0 -fill x -side top
19454 pack $base.pr.toolframe.toolsbox.fobt \
19455 -in $base.pr.toolframe.toolsbox -anchor center -expand 0 -fill none \
19456 -ipadx 2 -ipady 2 -side left
19457 pack $base.pr.toolframe.toolsbox.but34 \
19458 -in $base.pr.toolframe.toolsbox -anchor center -expand 0 -fill none \
19459 -side left
19460 pack $base.pr.toolframe.toolsbox.but35 \
19461 -in $base.pr.toolframe.toolsbox -anchor center -expand 0 -fill none \
19462 -side left
19463 pack $base.pr.toolframe.toolsbox.but32 \
19464 -in $base.pr.toolframe.toolsbox -anchor s -expand 0 -fill none \
19465 -ipadx 2 -ipady 2 -side left
19466 pack $base.pr.toolframe.entityframe \
19467 -in $base.pr.toolframe -anchor nw -expand 1 -fill none -padx 5 \
19468 -pady 5 -side top
19469 grid $base.pr.toolframe.entityframe.comprb \
19470 -in $base.pr.toolframe.entityframe -column 0 -row 0 -columnspan 1 \
19471 -rowspan 1 -sticky nesw
19472 grid $base.pr.toolframe.entityframe.ficrb \
19473 -in $base.pr.toolframe.entityframe -column 0 -row 1 -columnspan 1 \
19474 -rowspan 1 -sticky nesw
19475 grid $base.pr.toolframe.entityframe.cnxrb \
19476 -in $base.pr.toolframe.entityframe -column 0 -row 3 -columnspan 1 \
19477 -rowspan 1 -sticky nesw
19478 grid $base.pr.toolframe.entityframe.fieldsrb \
19479 -in $base.pr.toolframe.entityframe -column 0 -row 2 -columnspan 1 \
19480 -rowspan 1 -sticky nesw
19481 pack $base.pr.toolframe.buttonfrc \
19482 -in $base.pr.toolframe -anchor n -expand 1 -fill x -side top
19483 pack $base.pr.toolframe.buttonfrc.editb \
19484 -in $base.pr.toolframe.buttonfrc -anchor center -expand 1 -fill x \
19485 -side left
19486 pack $base.pr.toolframe.buttonfrc.deleteb \
19487 -in $base.pr.toolframe.buttonfrc -anchor center -expand 1 -fill x \
19488 -side left
19489 pack $base.pr.toolframe.cpd18 \
19490 -in $base.pr.toolframe -anchor w -expand 0 -fill none -side top
19491 grid columnconf $base.pr.toolframe.cpd18 0 -weight 1
19492 grid rowconf $base.pr.toolframe.cpd18 0 -weight 1
19493 grid $base.pr.toolframe.cpd18.02 \
19494 -in $base.pr.toolframe.cpd18 -column 0 -row 1 -columnspan 1 \
19495 -rowspan 1 -sticky ew
19496 grid $base.pr.toolframe.cpd18.03 \
19497 -in $base.pr.toolframe.cpd18 -column 1 -row 0 -columnspan 1 \
19498 -rowspan 1 -sticky ns
19499 grid $base.pr.toolframe.cpd18.01 \
19500 -in $base.pr.toolframe.cpd18 -column 0 -row 0 -columnspan 1 \
19501 -rowspan 1
19502 pack $base.pr.zoomframe \
19503 -in $base.pr -anchor center -expand 0 -fill x -side top
19504 pack $base.pr.zoomframe.viewframe \
19505 -in $base.pr.zoomframe -anchor center -expand 0 -fill none \
19506 -side right
19507 pack $base.pr.zoomframe.viewframe.viewcommcheck \
19508 -in $base.pr.zoomframe.viewframe -anchor center -expand 0 -fill none \
19509 -ipadx 6 -side left
19510 pack $base.pr.zoomframe.zm \
19511 -in $base.pr.zoomframe -anchor center -expand 0 -fill none -side left
19512 pack $base.pr.zoomframe.zp \
19513 -in $base.pr.zoomframe -anchor center -expand 0 -fill none -side left
19514 pack $base.pr.cpd22 \
19515 -in $base.pr -anchor center -expand 0 -fill none -side left
19516 grid columnconf $base.pr.cpd22 0 -weight 1
19517 grid rowconf $base.pr.cpd22 0 -weight 1
19518 grid $base.pr.cpd22.01 \
19519 -in $base.pr.cpd22 -column 0 -row 1 -columnspan 1 -rowspan 1 \
19520 -sticky ew
19521 grid $base.pr.cpd22.02 \
19522 -in $base.pr.cpd22 -column 1 -row 0 -columnspan 1 -rowspan 1 \
19523 -sticky ns
19524 grid $base.pr.cpd22.03 \
19525 -in $base.pr.cpd22 -column 0 -row 0 -columnspan 1 -rowspan 1 \
19526 -sticky nesw
19527 }
19528
19529 Window show .
19530 Window show .ballon_object
19531 Window show .gui
19532
19533 main $argc $argv
19534