itclHullCmds.tcl 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562
  1. #
  2. # itclHullCmds.tcl
  3. # ----------------------------------------------------------------------
  4. # Invoked automatically upon startup to customize the interpreter
  5. # for [incr Tcl] when one of setupcomponent or createhull is called.
  6. # ----------------------------------------------------------------------
  7. # AUTHOR: Arnulf P. Wiedemann
  8. #
  9. # ----------------------------------------------------------------------
  10. # Copyright (c) 2008 Arnulf P. Wiedemann
  11. # ======================================================================
  12. # See the file "license.terms" for information on usage and
  13. # redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  14. package require Tk 8.6
  15. namespace eval ::itcl::internal::commands {
  16. # ======================= widgetDeleted ===========================
  17. proc widgetDeleted {oldName newName op} {
  18. # The widget is beeing deleted, so we have to delete the object
  19. # which had the widget as itcl_hull too!
  20. # We have to get the real name from for example
  21. # ::itcl::internal::widgets::hull1.lw
  22. # we need only .lw here
  23. #puts stderr "widgetDeleted!$oldName!$newName!$op!"
  24. set cmdName [namespace tail $oldName]
  25. set flds [split $cmdName {.}]
  26. set cmdName .[join [lrange $flds 1 end] {.}]
  27. #puts stderr "DELWIDGET![namespace current]!$cmdName![::info command $cmdName]!"
  28. rename $cmdName {}
  29. }
  30. }
  31. namespace eval ::itcl::builtin {
  32. # ======================= createhull ===========================
  33. # the hull widget is a tk widget which is the (mega) widget handled behind the itcl
  34. # extendedclass/itcl widget.
  35. # It is created be renaming the itcl class object to a temporary name <itcl object name>_
  36. # creating the widget with the
  37. # appropriate options and the installing that as the "hull" widget (the container)
  38. # All the options in args and the options delegated to component itcl_hull are used
  39. # Then a unique name (hull_widget_name) in the itcl namespace is created for widget:
  40. # ::itcl::internal::widgets::hull<unique number><namespace tail path>
  41. # and widget is renamed to that name
  42. # Finally the <itcl object name>_ is renamed to the original <itcl object name> again
  43. # Component itcl_hull is created if not existent
  44. # itcl_hull is set to the hull_widget_name and the <itcl object name>
  45. # is returned to the caller
  46. # ==============================================================
  47. proc createhull {widget_type path args} {
  48. variable hullCount
  49. upvar this this
  50. upvar win win
  51. #puts stderr "il-1![::info level -1]!$this!"
  52. #puts stderr "createhull!$widget_type!$path!$args!$this![::info command $this]!"
  53. #puts stderr "ns1![uplevel 1 namespace current]!"
  54. #puts stderr "ns2![uplevel 2 namespace current]!"
  55. #puts stderr "ns3![uplevel 3 namespace current]!"
  56. #puts stderr "level-1![::info level -1]!"
  57. #puts stderr "level-2![::info level -2]!"
  58. # set my_this [namespace tail $this]
  59. set my_this $this
  60. set tmp $my_this
  61. #puts stderr "II![::info command $this]![::info command $tmp]!"
  62. #puts stderr "rename1!rename $my_this ${tmp}_!"
  63. rename ::$my_this ${tmp}_
  64. set options [list]
  65. foreach {option_name value} $args {
  66. switch -glob -- $option_name {
  67. -class {
  68. lappend options $option_name [namespace tail $value]
  69. }
  70. -* {
  71. lappend options $option_name $value
  72. }
  73. default {
  74. return -code error "bad option name\"$option_name\" options must start with a \"-\""
  75. }
  76. }
  77. }
  78. set my_win [namespace tail $path]
  79. set cmd [list $widget_type $my_win]
  80. #puts stderr "my_win!$my_win!cmd!$cmd!$path!"
  81. if {[llength $options] > 0} {
  82. lappend cmd {*}$options
  83. }
  84. set widget [uplevel 1 $cmd]
  85. #puts stderr "widget!$widget!"
  86. trace add command $widget delete ::itcl::internal::commands::widgetDeleted
  87. set opts [uplevel 1 info delegated options]
  88. foreach entry $opts {
  89. foreach {optName compName} $entry break
  90. if {$compName eq "itcl_hull"} {
  91. set optInfos [uplevel 1 info delegated option $optName]
  92. set realOptName [lindex $optInfos 4]
  93. # strip off the "-" at the beginning
  94. set myOptName [string range $realOptName 1 end]
  95. set my_opt_val [option get $my_win $myOptName *]
  96. if {$my_opt_val ne ""} {
  97. $my_win configure -$myOptName $my_opt_val
  98. }
  99. }
  100. }
  101. set idx 1
  102. while {1} {
  103. set widgetName ::itcl::internal::widgets::hull${idx}$my_win
  104. #puts stderr "widgetName!$widgetName!"
  105. if {[string length [::info command $widgetName]] == 0} {
  106. break
  107. }
  108. incr idx
  109. }
  110. #puts stderr "rename2!rename $widget $widgetName!"
  111. set dorename 0
  112. rename $widget $widgetName
  113. #puts stderr "rename3!rename ${tmp}_ $tmp![::info command ${tmp}_]!my_this!$my_this!"
  114. rename ${tmp}_ ::$tmp
  115. set exists [uplevel 1 ::info exists itcl_hull]
  116. if {!$exists} {
  117. # that does not yet work, beacause of problems with resolving
  118. ::itcl::addcomponent $my_this itcl_hull
  119. }
  120. upvar itcl_hull itcl_hull
  121. ::itcl::setcomponent $my_this itcl_hull $widgetName
  122. #puts stderr "IC![::info command $my_win]!"
  123. set exists [uplevel 1 ::info exists itcl_interior]
  124. if {!$exists} {
  125. # that does not yet work, beacause of problems with resolving
  126. ::itcl::addcomponent $this itcl_interior
  127. }
  128. upvar itcl_interior itcl_interior
  129. set itcl_interior $my_win
  130. #puts stderr "hull end!win!$win!itcl_hull!$itcl_hull!itcl_interior!$itcl_interior!"
  131. return $my_win
  132. }
  133. # ======================= addToItclOptions ===========================
  134. proc addToItclOptions {my_class my_win myOptions argsDict} {
  135. upvar win win
  136. upvar itcl_hull itcl_hull
  137. set opt_lst [list configure]
  138. foreach opt [lsort $myOptions] {
  139. #puts stderr "IOPT!$opt!$my_class!$my_win![::itcl::is class $my_class]!"
  140. set isClass [::itcl::is class $my_class]
  141. set found 0
  142. if {$isClass} {
  143. if {[catch {
  144. set resource [namespace eval $my_class info option $opt -resource]
  145. set class [namespace eval $my_class info option $opt -class]
  146. set default_val [uplevel 2 info option $opt -default]
  147. set found 1
  148. } msg]} {
  149. # puts stderr "MSG!$opt!$my_class!$msg!"
  150. }
  151. } else {
  152. set tmp_win [uplevel #0 $my_class .___xx]
  153. set my_info [$tmp_win configure $opt]
  154. set resource [lindex $my_info 1]
  155. set class [lindex $my_info 2]
  156. set default_val [lindex $my_info 3]
  157. uplevel #0 destroy $tmp_win
  158. set found 1
  159. }
  160. if {$found} {
  161. if {[catch {
  162. set val [uplevel #0 ::option get $win $resource $class]
  163. } msg]} {
  164. set val ""
  165. }
  166. if {[::dict exists $argsDict $opt]} {
  167. # we have an explicitly set option
  168. set val [::dict get $argsDict $opt]
  169. } else {
  170. if {[string length $val] == 0} {
  171. set val $default_val
  172. }
  173. }
  174. set ::itcl::internal::variables::${my_win}::itcl_options($opt) $val
  175. set ::itcl::internal::variables::${my_win}::__itcl_option_infos($opt) [list $resource $class $default_val]
  176. #puts stderr "OPT1!$opt!$val!"
  177. # uplevel 1 [list set itcl_options($opt) [list $val]]
  178. if {[catch {uplevel 1 $win configure $opt [list $val]} msg]} {
  179. #puts stderr "addToItclOptions ERR!$msg!$my_class!$win!configure!$opt!$val!"
  180. }
  181. }
  182. }
  183. }
  184. # ======================= setupcomponent ===========================
  185. proc setupcomponent {comp using widget_type path args} {
  186. upvar this this
  187. upvar win win
  188. upvar itcl_hull itcl_hull
  189. #puts stderr "setupcomponent!$comp!$widget_type!$path!$args!$this!$win!$itcl_hull!"
  190. #puts stderr "CONT![uplevel 1 info context]!"
  191. #puts stderr "ns1![uplevel 1 namespace current]!"
  192. #puts stderr "ns2![uplevel 2 namespace current]!"
  193. #puts stderr "ns3![uplevel 3 namespace current]!"
  194. set my_comp_object [lindex [uplevel 1 info context] 1]
  195. if {[::info exists ::itcl::internal::component_objects($my_comp_object)]} {
  196. set my_comp_object [set ::itcl::internal::component_objects($my_comp_object)]
  197. } else {
  198. set ::itcl::internal::component_objects($path) $my_comp_object
  199. }
  200. set options [list]
  201. foreach {option_name value} $args {
  202. switch -glob -- $option_name {
  203. -* {
  204. lappend options $option_name $value
  205. }
  206. default {
  207. return -code error "bad option name\"$option_name\" options must start with a \"-\""
  208. }
  209. }
  210. }
  211. if {[llength $args]} {
  212. set argsDict [dict create {*}$args]
  213. } else {
  214. set argsDict [dict create]
  215. }
  216. set cmd [list $widget_type $path]
  217. if {[llength $options] > 0} {
  218. lappend cmd {*}$options
  219. }
  220. #puts stderr "cmd0![::info command $widget_type]!$path![::info command $path]!"
  221. #puts stderr "cmd1!$cmd!"
  222. # set my_comp [uplevel 3 $cmd]
  223. set my_comp [uplevel #0 $cmd]
  224. #puts stderr 111![::info command $path]!
  225. ::itcl::setcomponent $this $comp $my_comp
  226. set opts [uplevel 1 info delegated options]
  227. foreach entry $opts {
  228. foreach {optName compName} $entry break
  229. if {$compName eq $my_comp} {
  230. set optInfos [uplevel 1 info delegated option $optName]
  231. set realOptName [lindex $optInfos 4]
  232. # strip off the "-" at the beginning
  233. set myOptName [string range $realOptName 1 end]
  234. set my_opt_val [option get $my_win $myOptName *]
  235. if {$my_opt_val ne ""} {
  236. $my_comp configure -$myOptName $my_opt_val
  237. }
  238. }
  239. }
  240. set my_class $widget_type
  241. set my_parent_class [uplevel 1 namespace current]
  242. if {[catch {
  243. set myOptions [namespace eval $my_class {info classoptions}]
  244. } msg]} {
  245. set myOptions [list]
  246. }
  247. foreach entry [$path configure] {
  248. foreach {opt dummy1 dummy2 dummy3} $entry break
  249. lappend myOptions $opt
  250. }
  251. #puts stderr "OPTS!$myOptions!"
  252. addToItclOptions $widget_type $my_comp_object $myOptions $argsDict
  253. #puts stderr END!$path![::info command $path]!
  254. }
  255. proc itcl_initoptions {args} {
  256. puts stderr "ITCL_INITOPT!$args!"
  257. }
  258. # ======================= initoptions ===========================
  259. proc initoptions {args} {
  260. upvar win win
  261. upvar itcl_hull itcl_hull
  262. upvar itcl_option_components itcl_option_components
  263. #puts stderr "INITOPT!!$win!"
  264. if {[llength $args]} {
  265. set argsDict [dict create {*}$args]
  266. } else {
  267. set argsDict [dict create]
  268. }
  269. set my_class [uplevel 1 namespace current]
  270. set myOptions [namespace eval $my_class {info classoptions}]
  271. if {[dict exists $::itcl::internal::dicts::classComponents $my_class]} {
  272. set class_info_dict [dict get $::itcl::internal::dicts::classComponents $my_class]
  273. # set myOptions [lsort -unique [namespace eval $my_class {info options}]]
  274. foreach comp [uplevel 1 info components] {
  275. if {[dict exists $class_info_dict $comp -keptoptions]} {
  276. foreach my_opt [dict get $class_info_dict $comp -keptoptions] {
  277. if {[lsearch $myOptions $my_opt] < 0} {
  278. #puts stderr "KEOPT!$my_opt!"
  279. lappend myOptions $my_opt
  280. }
  281. }
  282. }
  283. }
  284. } else {
  285. set class_info_dict [list]
  286. }
  287. #puts stderr "OPTS!$win!$my_class![join [lsort $myOptions]] \n]!"
  288. set opt_lst [list configure]
  289. set my_win $win
  290. foreach opt [lsort $myOptions] {
  291. set found 0
  292. if {[catch {
  293. set resource [uplevel 1 info option $opt -resource]
  294. set class [uplevel 1 info option $opt -class]
  295. set default_val [uplevel 1 info option $opt -default]
  296. set found 1
  297. } msg]} {
  298. # puts stderr "MSG!$opt!$msg!"
  299. }
  300. #puts stderr "OPT!$opt!$found!"
  301. if {$found} {
  302. if {[catch {
  303. set val [uplevel #0 ::option get $my_win $resource $class]
  304. } msg]} {
  305. set val ""
  306. }
  307. if {[::dict exists $argsDict $opt]} {
  308. # we have an explicitly set option
  309. set val [::dict get $argsDict $opt]
  310. } else {
  311. if {[string length $val] == 0} {
  312. set val $default_val
  313. }
  314. }
  315. set ::itcl::internal::variables::${win}::itcl_options($opt) $val
  316. set ::itcl::internal::variables::${win}::__itcl_option_infos($opt) [list $resource $class $default_val]
  317. #puts stderr "OPT1!$opt!$val!"
  318. # uplevel 1 [list set itcl_options($opt) [list $val]]
  319. if {[catch {uplevel 1 $my_win configure $opt [list $val]} msg]} {
  320. puts stderr "initoptions ERR!$msg!$my_class!$my_win!configure!$opt!$val!"
  321. }
  322. }
  323. foreach comp [dict keys $class_info_dict] {
  324. #puts stderr "OPT1!$opt!$comp![dict get $class_info_dict $comp]!"
  325. if {[dict exists $class_info_dict $comp -keptoptions]} {
  326. if {[lsearch [dict get $class_info_dict $comp -keptoptions] $opt] >= 0} {
  327. if {$found == 0} {
  328. # we use the option value of the first component for setting
  329. # the option, as the components are traversed in the dict
  330. # depending on the ordering of the component creation!!
  331. set my_info [uplevel 1 \[set $comp\] configure $opt]
  332. set resource [lindex $my_info 1]
  333. set class [lindex $my_info 2]
  334. set default_val [lindex $my_info 3]
  335. set found 2
  336. set val [uplevel #0 ::option get $my_win $resource $class]
  337. if {[::dict exists $argsDict $opt]} {
  338. # we have an explicitly set option
  339. set val [::dict get $argsDict $opt]
  340. } else {
  341. if {[string length $val] == 0} {
  342. set val $default_val
  343. }
  344. }
  345. #puts stderr "OPT2!$opt!$val!"
  346. set ::itcl::internal::variables::${win}::itcl_options($opt) $val
  347. set ::itcl::internal::variables::${win}::__itcl_option_infos($opt) [list $resource $class $default_val]
  348. # uplevel 1 [list set itcl_options($opt) [list $val]]
  349. }
  350. if {[catch {uplevel 1 \[set $comp\] configure $opt [list $val]} msg]} {
  351. puts stderr "initoptions ERR2!$msg!$my_class!$comp!configure!$opt!$val!"
  352. }
  353. if {![uplevel 1 info exists itcl_option_components($opt)]} {
  354. set itcl_option_components($opt) [list]
  355. }
  356. if {[lsearch [set itcl_option_components($opt)] $comp] < 0} {
  357. if {![catch {
  358. set optval [uplevel 1 [list set itcl_options($opt)]]
  359. } msg3]} {
  360. uplevel 1 \[set $comp\] configure $opt $optval
  361. }
  362. lappend itcl_option_components($opt) $comp
  363. }
  364. }
  365. }
  366. }
  367. }
  368. # uplevel 1 $opt_lst
  369. }
  370. # ======================= setoptions ===========================
  371. proc setoptions {args} {
  372. #puts stderr "setOPT!!$args!"
  373. if {[llength $args]} {
  374. set argsDict [dict create {*}$args]
  375. } else {
  376. set argsDict [dict create]
  377. }
  378. set my_class [uplevel 1 namespace current]
  379. set myOptions [namespace eval $my_class {info options}]
  380. #puts stderr "OPTS!$win!$my_class![join [lsort $myOptions]] \n]!"
  381. set opt_lst [list configure]
  382. foreach opt [lsort $myOptions] {
  383. set found 0
  384. if {[catch {
  385. set resource [uplevel 1 info option $opt -resource]
  386. set class [uplevel 1 info option $opt -class]
  387. set default_val [uplevel 1 info option $opt -default]
  388. set found 1
  389. } msg]} {
  390. # puts stderr "MSG!$opt!$msg!"
  391. }
  392. #puts stderr "OPT!$opt!$found!"
  393. if {$found} {
  394. set val ""
  395. if {[::dict exists $argsDict $opt]} {
  396. # we have an explicitly set option
  397. set val [::dict get $argsDict $opt]
  398. } else {
  399. if {[string length $val] == 0} {
  400. set val $default_val
  401. }
  402. }
  403. set myObj [uplevel 1 set this]
  404. #puts stderr "myObj!$myObj!"
  405. set ::itcl::internal::variables::${myObj}::itcl_options($opt) $val
  406. set ::itcl::internal::variables::${myObj}::__itcl_option_infos($opt) [list $resource $class $default_val]
  407. #puts stderr "OPT1!$opt!$val!"
  408. uplevel 1 [list set itcl_options($opt) [list $val]]
  409. # if {[catch {uplevel 1 $myObj configure $opt [list $val]} msg]} {
  410. #puts stderr "initoptions ERR!$msg!$my_class!$my_win!configure!$opt!$val!"
  411. # }
  412. }
  413. }
  414. # uplevel 1 $opt_lst
  415. }
  416. # ========================= keepcomponentoption ======================
  417. # Invoked by Tcl during evaluating constructor whenever
  418. # the "keepcomponentoption" command is invoked to list the options
  419. # to be kept when an ::itcl::extendedclass component has been setup
  420. # for an object.
  421. #
  422. # It checks, for all arguments, if the opt is an option of that class
  423. # and of that component. If that is the case it adds the component name
  424. # to the list of components for that option.
  425. # The variable is the object variable: itcl_option_components($opt)
  426. #
  427. # Handles the following syntax:
  428. #
  429. # keepcomponentoption <componentName> <optionName> ?<optionName> ...?
  430. #
  431. # ======================================================================
  432. proc keepcomponentoption {args} {
  433. upvar win win
  434. upvar itcl_hull itcl_hull
  435. set usage "wrong # args, should be: keepcomponentoption componentName optionName ?optionName ...?"
  436. #puts stderr "KEEP!$args![uplevel 1 namespace current]!"
  437. if {[llength $args] < 2} {
  438. puts stderr $usage
  439. return -code error
  440. }
  441. set my_hull [uplevel 1 set itcl_hull]
  442. set my_class [uplevel 1 namespace current]
  443. set comp [lindex $args 0]
  444. set args [lrange $args 1 end]
  445. set class_info_dict [dict get $::itcl::internal::dicts::classComponents $my_class]
  446. if {![dict exists $class_info_dict $comp]} {
  447. puts stderr "keepcomponentoption cannot find component \"$comp\""
  448. return -code error
  449. }
  450. set class_comp_dict [dict get $class_info_dict $comp]
  451. if {![dict exists $class_comp_dict -keptoptions]} {
  452. dict set class_comp_dict -keptoptions [list]
  453. }
  454. foreach opt $args {
  455. #puts stderr "KEEP!$opt!"
  456. if {[string range $opt 0 0] ne "-"} {
  457. puts stderr "keepcomponentoption: option must begin with a \"-\"!"
  458. return -code error
  459. }
  460. if {[lsearch [dict get $class_comp_dict -keptoptions] $opt] < 0} {
  461. dict lappend class_comp_dict -keptoptions $opt
  462. }
  463. }
  464. if {![info exists ::itcl::internal::component_objects([lindex [uplevel 1 info context] 1])]} {
  465. set comp_object $::itcl::internal::component_objects([lindex [uplevel 1 info context] 1])
  466. } else {
  467. set comp_object "unknown_comp_obj_$comp!"
  468. }
  469. dict set class_info_dict $comp $class_comp_dict
  470. dict set ::itcl::internal::dicts::classComponents $my_class $class_info_dict
  471. puts stderr "CLDI!$class_comp_dict!"
  472. addToItclOptions $my_class $comp_object $args [list]
  473. }
  474. proc ignorecomponentoption {args} {
  475. puts stderr "IGNORE_COMPONENT_OPTION!$args!"
  476. }
  477. proc renamecomponentoption {args} {
  478. puts stderr "rename_COMPONENT_OPTION!$args!"
  479. }
  480. proc addoptioncomponent {args} {
  481. puts stderr "ADD_OPTION_COMPONENT!$args!"
  482. }
  483. proc ignoreoptioncomponent {args} {
  484. puts stderr "IGNORE_OPTION_COMPONENT!$args!"
  485. }
  486. proc renameoptioncomponent {args} {
  487. puts stderr "RENAME_OPTION_COMPONENT!$args!"
  488. }
  489. proc getEclassOptions {args} {
  490. upvar win win
  491. #puts stderr "getEclassOptions!$args!$win![uplevel 1 namespace current]!"
  492. #parray ::itcl::internal::variables::${win}::itcl_options
  493. set result [list]
  494. foreach opt [array names ::itcl::internal::variables::${win}::itcl_options] {
  495. if {[catch {
  496. foreach {res cls def} [set ::itcl::internal::variables::${win}::__itcl_option_infos($opt)] break
  497. lappend result [list $opt $res $cls $def [set ::itcl::internal::variables::${win}::itcl_options($opt)]]
  498. } msg]} {
  499. }
  500. }
  501. return $result
  502. }
  503. proc eclassConfigure {args} {
  504. upvar win win
  505. #puts stderr "+++ eclassConfigure!$args!"
  506. if {[llength $args] > 1} {
  507. foreach {opt val} $args break
  508. if {[::info exists ::itcl::internal::variables::${win}::itcl_options($opt)]} {
  509. set ::itcl::internal::variables::${win}::itcl_options($opt) $val
  510. return
  511. }
  512. } else {
  513. foreach {opt} $args break
  514. if {[::info exists ::itcl::internal::variables::${win}::itcl_options($opt)]} {
  515. #puts stderr "OP![set ::itcl::internal::variables::${win}::itcl_options($opt)]!"
  516. foreach {res cls def} [set ::itcl::internal::variables::${win}::__itcl_option_infos($opt)] break
  517. return [list $opt $res $cls $def [set ::itcl::internal::variables::${win}::itcl_options($opt)]]
  518. }
  519. }
  520. return -code error
  521. }
  522. }