home *** CD-ROM | disk | FTP | other *** search
/ PC World 2005 June / PCWorld_2005-06_cd.bin / software / vyzkuste / firewally / firewally.exe / framework-2.3.exe / hierarchy.itk < prev    next >
Text File  |  2003-09-01  |  67KB  |  1,984 lines

  1. # Hierarchy
  2. # ----------------------------------------------------------------------
  3. # Hierarchical data viewer.  Manages a list of nodes that can be
  4. # expanded or collapsed.  Individual nodes can be highlighted.
  5. # Clicking with the right mouse button on any item brings up a
  6. # special item menu.  Clicking on the background area brings up
  7. # a different popup menu.
  8. # ----------------------------------------------------------------------
  9. #   AUTHOR:  Michael J. McLennan
  10. #            Bell Labs Innovations for Lucent Technologies
  11. #            mmclennan@lucent.com
  12. #
  13. #            Mark L. Ulferts
  14. #            DSC Communications
  15. #            mulferts@austin.dsccc.com
  16. #
  17. #      RCS:  $Id: hierarchy.itk,v 1.9 2002/09/06 16:27:03 smithc Exp $
  18. # ----------------------------------------------------------------------
  19. #                Copyright (c) 1996  Lucent Technologies
  20. # ======================================================================
  21. # Permission to use, copy, modify, and distribute this software and its
  22. # documentation for any purpose and without fee is hereby granted,
  23. # provided that the above copyright notice appear in all copies and that
  24. # both that the copyright notice and warranty disclaimer appear in
  25. # supporting documentation, and that the names of Lucent Technologies
  26. # any of their entities not be used in advertising or publicity
  27. # pertaining to distribution of the software without specific, written
  28. # prior permission.
  29. #
  30. # Lucent Technologies disclaims all warranties with regard to this
  31. # software, including all implied warranties of merchantability and
  32. # fitness.  In no event shall Lucent Technologies be liable for any
  33. # special, indirect or consequential damages or any damages whatsoever
  34. # resulting from loss of use, data or profits, whether in an action of
  35. # contract, negligence or other tortuous action, arising out of or in
  36. # connection with the use or performance of this software.
  37. #
  38. # ----------------------------------------------------------------------
  39. #            Copyright (c) 1996 DSC Technologies Corporation
  40. # ======================================================================
  41. # Permission to use, copy, modify, distribute and license this software 
  42. # and its documentation for any purpose, and without fee or written 
  43. # agreement with DSC, is hereby granted, provided that the above copyright 
  44. # notice appears in all copies and that both the copyright notice and 
  45. # warranty disclaimer below appear in supporting documentation, and that 
  46. # the names of DSC Technologies Corporation or DSC Communications 
  47. # Corporation not be used in advertising or publicity pertaining to the 
  48. # software without specific, written prior permission.
  49. # DSC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 
  50. # ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, AND NON-
  51. # INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE
  52. # AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, 
  53. # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. IN NO EVENT SHALL 
  54. # DSC BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 
  55. # ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 
  56. # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTUOUS ACTION,
  57. # ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 
  58. # SOFTWARE.
  59. # ======================================================================
  60.  
  61. #
  62. # Usual options.
  63. #
  64. itk::usual Hierarchy {
  65.     keep -cursor -textfont -font
  66.     keep -background -foreground -textbackground 
  67.     keep -selectbackground -selectforeground 
  68. }
  69.  
  70. # ------------------------------------------------------------------
  71. #                            HIERARCHY
  72. # ------------------------------------------------------------------
  73. itcl::class iwidgets::Hierarchy {
  74.     inherit iwidgets::Scrolledwidget
  75.  
  76.     constructor {args} {}
  77.  
  78.     destructor {}
  79.  
  80.     itk_option define -alwaysquery alwaysQuery AlwaysQuery 0
  81.     itk_option define -closedicon closedIcon Icon {}
  82.     itk_option define -dblclickcommand dblClickCommand Command {}
  83.     itk_option define -expanded expanded Expanded 0 
  84.     itk_option define -filter filter Filter 0 
  85.     itk_option define -font font Font \
  86.     -*-Courier-Medium-R-Normal--*-120-*-*-*-*-*-* 
  87.     itk_option define -height height Height 0
  88.     itk_option define -iconcommand iconCommand Command {}
  89.     itk_option define -icondblcommand iconDblCommand Command {}
  90.     itk_option define -imagecommand imageCommand Command {}
  91.     itk_option define -imagedblcommand imageDblCommand Command {}
  92.     itk_option define -imagemenuloadcommand imageMenuLoadCommand Command {}
  93.     itk_option define -markbackground markBackground Foreground #a0a0a0 
  94.     itk_option define -markforeground markForeground Background Black 
  95.     itk_option define -nodeicon nodeIcon Icon {}
  96.     itk_option define -openicon openIcon Icon {}
  97.     itk_option define -querycommand queryCommand Command {}
  98.     itk_option define -selectcommand selectCommand Command {}
  99.     itk_option define -selectbackground selectBackground Foreground #c3c3c3 
  100.     itk_option define -selectforeground selectForeground Background Black 
  101.     itk_option define -textmenuloadcommand textMenuLoadCommand Command {}
  102.     itk_option define -visibleitems visibleItems VisibleItems 80x24
  103.     itk_option define -width width Width 0
  104.  
  105.     public {
  106.     method clear {}
  107.     method collapse {node}
  108.     method current {}
  109.     method draw {{when -now}}
  110.     method expand {node}
  111.     method expanded {node}
  112.     method expState { }
  113.     method mark {op args}
  114.     method prune {node}
  115.     method refresh {node}
  116.     method selection {op args}
  117.     method toggle {node}
  118.     
  119.     method bbox {index} 
  120.     method compare {index1 op index2} 
  121.     method debug {args} {eval $args}
  122.     method delete {first {last {}}} 
  123.     method dlineinfo {index} 
  124.     method dump {args}
  125.     method get {index1 {index2 {}}} 
  126.     method index {index} 
  127.     method insert {args} 
  128.     method scan {option args} 
  129.     method search {args} 
  130.     method see {index} 
  131.     method tag {op args} 
  132.     method window {option args} 
  133.     method xview {args}
  134.     method yview {args}
  135.     }
  136.  
  137.     protected {
  138.     method _contents {uid}
  139.     method _post {x y}
  140.     method _drawLevel {node indent}
  141.     method _select {x y}
  142.     method _deselectSubNodes {uid}
  143.     method _deleteNodeInfo {uid}
  144.     method _getParent {uid}
  145.     method _getHeritage {uid}
  146.     method _isInternalTag {tag}
  147.     method _iconSelect {node icon}
  148.     method _iconDblSelect {node icon}
  149.     method _imageSelect {node}
  150.     method _imageDblClick {node}
  151.     method _imagePost {node image type x y}
  152.     method _double {x y}
  153.     }
  154.     
  155.     private {
  156.         method _configureTags {}
  157.  
  158.     variable _filterCode ""  ;# Compact view flag.
  159.     variable _hcounter 0     ;# Counter for hierarchy icons
  160.     variable _icons          ;# Array of user icons by uid
  161.     variable _images         ;# Array of our icons by uid
  162.     variable _indents        ;# Array of indentation by uid
  163.     variable _marked         ;# Array of marked nodes by uid
  164.     variable _markers ""     ;# List of markers for level being drawn
  165.     variable _nodes          ;# Array of subnodes by uid
  166.     variable _pending ""     ;# Pending draw flag
  167.     variable _posted ""      ;# List of tags at posted menu position
  168.     variable _selected       ;# Array of selected nodes by uid
  169.     variable _tags           ;# Array of user tags by uid
  170.     variable _text           ;# Array of displayed text by uid
  171.     variable _states         ;# Array of selection state by uid
  172.     variable _ucounter 0     ;# Counter for user icons
  173.     }
  174. }
  175.  
  176. #
  177. # Provide a lowercased access method for the Hierarchy class.
  178. proc ::iwidgets::hierarchy {pathName args} {
  179.     uplevel ::iwidgets::Hierarchy $pathName $args
  180. }
  181.  
  182. #
  183. # Use option database to override default resources of base classes.
  184. #
  185. option add *Hierarchy.menuCursor arrow widgetDefault
  186. option add *Hierarchy.labelPos n widgetDefault
  187. option add *Hierarchy.tabs 30 widgetDefault
  188.  
  189. # ------------------------------------------------------------------
  190. #                        CONSTRUCTOR
  191. # ------------------------------------------------------------------
  192. itcl::body iwidgets::Hierarchy::constructor {args} {
  193.     itk_option remove iwidgets::Labeledwidget::state
  194.  
  195.     #
  196.     # Our -width and -height options are slightly different than
  197.     # those implemented by our base class, so we're going to
  198.     # remove them and redefine our own.
  199.     #
  200.     itk_option remove iwidgets::Scrolledwidget::width
  201.     itk_option remove iwidgets::Scrolledwidget::height
  202.  
  203.     #
  204.     # Create a clipping frame which will provide the border for
  205.     # relief display.
  206.     #
  207.     itk_component add clipper {
  208.     frame $itk_interior.clipper
  209.     } {
  210.     usual
  211.  
  212.     keep -borderwidth -relief -highlightthickness -highlightcolor
  213.     rename -highlightbackground -background background Background
  214.     }    
  215.     grid $itk_component(clipper) -row 0 -column 0 -sticky nsew
  216.     grid rowconfigure $_interior 0 -weight 1
  217.     grid columnconfigure $_interior 0 -weight 1
  218.  
  219.     #
  220.     # Create a text widget for displaying our hierarchy.
  221.     #
  222.     itk_component add list {
  223.     text $itk_component(clipper).list -wrap none -cursor center_ptr \
  224.                 -state disabled -width 1 -height 1 \
  225.             -xscrollcommand \
  226.         [itcl::code $this _scrollWidget $itk_interior.horizsb] \
  227.         -yscrollcommand \
  228.         [itcl::code $this _scrollWidget $itk_interior.vertsb] \
  229.             -borderwidth 0 -highlightthickness 0
  230.     } {
  231.     usual
  232.  
  233.     keep -spacing1 -spacing2 -spacing3 -tabs
  234.     rename -font -textfont textFont Font
  235.     rename -background -textbackground textBackground Background
  236.     ignore -highlightthickness -highlightcolor
  237.     ignore -insertbackground -insertborderwidth
  238.     ignore -insertontime -insertofftime -insertwidth
  239.     ignore -selectborderwidth
  240.     ignore -borderwidth
  241.     }
  242.     grid $itk_component(list) -row 0 -column 0 -sticky nsew
  243.     grid rowconfigure $itk_component(clipper) 0 -weight 1
  244.     grid columnconfigure $itk_component(clipper) 0 -weight 1
  245.     
  246.     # 
  247.     # Configure the command on the vertical scroll bar in the base class.
  248.     #
  249.     $itk_component(vertsb) configure \
  250.     -command [itcl::code $itk_component(list) yview]
  251.  
  252.     #
  253.     # Configure the command on the horizontal scroll bar in the base class.
  254.     #
  255.     $itk_component(horizsb) configure \
  256.         -command [itcl::code $itk_component(list) xview]
  257.     
  258.     #
  259.     # Configure our text component's tab settings for twenty levels.
  260.     #
  261.     set tabs ""
  262.     for {set i 1} {$i < 20} {incr i} {
  263.     lappend tabs [expr {$i*12+4}]
  264.     }
  265.     $itk_component(list) configure -tabs $tabs
  266.  
  267.     #
  268.     # Add popup menus that can be configured by the user to add
  269.     # new functionality.
  270.     #
  271.     itk_component add itemMenu {
  272.     menu $itk_component(list).itemmenu -tearoff 0
  273.     } {
  274.     usual
  275.     ignore -tearoff
  276.     rename -cursor -menucursor menuCursor Cursor
  277.     }
  278.  
  279.     itk_component add bgMenu {
  280.     menu $itk_component(list).bgmenu -tearoff 0
  281.     } {
  282.     usual
  283.     ignore -tearoff
  284.     rename -cursor -menucursor menuCursor Cursor
  285.     }
  286.  
  287.     #
  288.     # Adjust the bind tags to remove the class bindings.  Also, add
  289.     # bindings for mouse button 1 to do selection and button 3 to 
  290.     # display a popup.
  291.     #
  292.     bindtags $itk_component(list) [list $itk_component(list) . all]
  293.     
  294.     bind $itk_component(list) <ButtonPress-1> \
  295.             [itcl::code $this _select %x %y]
  296.  
  297.     bind $itk_component(list) <Double-1> \
  298.             [itcl::code $this _double %x %y]
  299.  
  300.     bind $itk_component(list) <ButtonPress-3> \
  301.             [itcl::code $this _post %x %y]
  302.     
  303.     #
  304.     # Initialize the widget based on the command line options.
  305.     #
  306.     eval itk_initialize $args
  307. }
  308.  
  309. # ------------------------------------------------------------------
  310. #                           DESTRUCTOR
  311. # ------------------------------------------------------------------
  312. itcl::body iwidgets::Hierarchy::destructor {} {
  313.     if {$_pending != ""} {
  314.     after cancel $_pending
  315.     }
  316. }
  317.  
  318. # ------------------------------------------------------------------
  319. #                             OPTIONS
  320. # ------------------------------------------------------------------
  321.  
  322. # ------------------------------------------------------------------
  323. # OPTION: -font
  324. #
  325. # Font used for text in the list.
  326. # ------------------------------------------------------------------
  327. itcl::configbody iwidgets::Hierarchy::font {
  328.     $itk_component(list) tag configure info \
  329.             -font $itk_option(-font) -spacing1 6
  330. }
  331.  
  332. # ------------------------------------------------------------------
  333. # OPTION: -selectbackground
  334. #
  335. # Background color scheme for selected nodes.
  336. # ------------------------------------------------------------------
  337. itcl::configbody iwidgets::Hierarchy::selectbackground {
  338.     $itk_component(list) tag configure hilite \
  339.             -background $itk_option(-selectbackground)
  340. }
  341.  
  342. # ------------------------------------------------------------------
  343. # OPTION: -selectforeground
  344. #
  345. # Foreground color scheme for selected nodes.
  346. # ------------------------------------------------------------------
  347. itcl::configbody iwidgets::Hierarchy::selectforeground {
  348.     $itk_component(list) tag configure hilite \
  349.             -foreground $itk_option(-selectforeground)
  350. }
  351.  
  352. # ------------------------------------------------------------------
  353. # OPTION: -markbackground
  354. #
  355. # Background color scheme for marked nodes.
  356. # ------------------------------------------------------------------
  357. itcl::configbody iwidgets::Hierarchy::markbackground {
  358.     $itk_component(list) tag configure lowlite \
  359.             -background $itk_option(-markbackground)
  360. }
  361.  
  362. # ------------------------------------------------------------------
  363. # OPTION: -markforeground
  364. #
  365. # Foreground color scheme for marked nodes.
  366. # ------------------------------------------------------------------
  367. itcl::configbody iwidgets::Hierarchy::markforeground {
  368.     $itk_component(list) tag configure lowlite \
  369.             -foreground $itk_option(-markforeground)
  370. }
  371.  
  372. # ------------------------------------------------------------------
  373. # OPTION: -querycommand
  374. #
  375. # Command executed to query the contents of each node.  If this 
  376. # command contains "%n", it is replaced with the name of the desired 
  377. # node.  In its simpilest form it should return the children of the 
  378. # given node as a list which will be depicted in the display.
  379. #
  380. # Since the names of the children are used as tags in the underlying 
  381. # text widget, each child must be unique in the hierarchy.  Due to
  382. # the unique requirement, the nodes shall be reffered to as uids 
  383. # or uid in the singular sense.
  384. #   {uid [uid ...]}
  385. #
  386. #   where uid is a unique id and primary key for the hierarchy entry
  387. #
  388. # Should the unique requirement pose a problem, the list returned
  389. # can take on another more extended form which enables the 
  390. # association of text to be displayed with the uids.  The uid must
  391. # still be unique, but the text does not have to obey the unique
  392. # rule.  In addition, the format also allows the specification of
  393. # additional tags to be used on the same entry in the hierarchy
  394. # as the uid and additional icons to be displayed just before
  395. # the node.  The tags and icons are considered to be the property of
  396. # the user in that the hierarchy widget will not depend on any of 
  397. # their values.
  398. #
  399. #   {{uid [text [tags [icons]]]} {uid [text [tags [icons]]]} ...}
  400. #
  401. #   where uid is a unique id and primary key for the hierarchy entry
  402. #         text is the text to be displayed for this uid
  403. #         tags is a list of user tags to be applied to the entry
  404. #         icons is a list of icons to be displayed in front of the text
  405. #
  406. # The hierarchy widget does a look ahead from each node to determine
  407. # if the node has a children.  This can be cost some performace with
  408. # large hierarchies.  User's can avoid this by providing a hint in
  409. # the user tags.  A tag of "leaf" or "branch" tells the hierarchy
  410. # widget the information it needs to know thereby avoiding the look
  411. # ahead operation.
  412. # ------------------------------------------------------------------
  413. itcl::configbody iwidgets::Hierarchy::querycommand {
  414.     clear
  415.     draw -eventually
  416.  
  417.     # Added for SF ticket #596111
  418.     _configureTags
  419. }
  420.  
  421. # ------------------------------------------------------------------
  422. # OPTION: -selectcommand
  423. #
  424. # Command executed to select an item in the list.  If this command
  425. # contains "%n", it is replaced with the name of the selected node.  
  426. # If it contains a "%s", it is replaced with a boolean indicator of 
  427. # the node's current selection status, where a value of 1 denotes
  428. # that the node is currently selected and 0 that it is not.
  429. # ------------------------------------------------------------------
  430. itcl::configbody iwidgets::Hierarchy::selectcommand {
  431. }
  432.  
  433. # ------------------------------------------------------------------
  434. # OPTION: -dblclickcommand
  435. #
  436. # Command executed to double click an item in the list.  If this command
  437. # contains "%n", it is replaced with the name of the selected node.  
  438. # If it contains a "%s", it is replaced with a boolean indicator of 
  439. # the node's current selection status, where a value of 1 denotes
  440. # that the node is currently selected and 0 that it is not.
  441. #
  442. # Douglas R. Howard, Jr.
  443. # ------------------------------------------------------------------
  444. itcl::configbody iwidgets::Hierarchy::dblclickcommand {
  445. }
  446.  
  447. # ------------------------------------------------------------------
  448. # OPTION: -iconcommand
  449. #
  450. # Command executed upon selection of user icons.  If this command 
  451. # contains "%n", it is replaced with the name of the node the icon
  452. # belongs to.  Should it contain "%i" then the icon name is 
  453. # substituted.
  454. # ------------------------------------------------------------------
  455. itcl::configbody iwidgets::Hierarchy::iconcommand {
  456. }
  457.  
  458. # ------------------------------------------------------------------
  459. # OPTION: -icondblcommand
  460. #
  461. # Command executed upon double selection of user icons.  If this command 
  462. # contains "%n", it is replaced with the name of the node the icon
  463. # belongs to.  Should it contain "%i" then the icon name is 
  464. # substituted.
  465. #
  466. # Douglas R. Howard, Jr.
  467. # ------------------------------------------------------------------
  468. itcl::configbody iwidgets::Hierarchy::icondblcommand {
  469. }
  470.  
  471. # ------------------------------------------------------------------
  472. # OPTION: -imagecommand
  473. #
  474. # Command executed upon selection of image icons.  If this command 
  475. # contains "%n", it is replaced with the name of the node the icon
  476. # belongs to.  Should it contain "%i" then the icon name is 
  477. # substituted.
  478. #
  479. # Douglas R. Howard, Jr.
  480. # ------------------------------------------------------------------
  481. itcl::configbody iwidgets::Hierarchy::imagecommand {
  482. }
  483.  
  484. # ------------------------------------------------------------------
  485. # OPTION: -imagedblcommand
  486. #
  487. # Command executed upon double selection of user icons.  If this command 
  488. # contains "%n", it is replaced with the name of the node the icon
  489. # belongs to.
  490. #
  491. # Douglas R. Howard, Jr.
  492. # ------------------------------------------------------------------
  493. itcl::configbody iwidgets::Hierarchy::imagedblcommand {
  494. }
  495.  
  496. # ------------------------------------------------------------------
  497. # OPTION: -alwaysquery
  498. #
  499. # Boolean flag which tells the hierarchy widget weather or not
  500. # each refresh of the display should be via a new query using
  501. # the -querycommand option or use the values previous found the
  502. # last time the query was made.
  503. # ------------------------------------------------------------------
  504. itcl::configbody iwidgets::Hierarchy::alwaysquery {
  505.     switch -- $itk_option(-alwaysquery) {
  506.         1 - true - yes - on {
  507.             ;# okay
  508.         }
  509.         0 - false - no - off {
  510.             ;# okay
  511.         }
  512.         default {
  513.             error "bad alwaysquery option \"$itk_option(-alwaysquery)\":\
  514.                     should be boolean"
  515.         }
  516.     }
  517. }
  518.  
  519. # ------------------------------------------------------------------
  520. # OPTION: -filter
  521. #
  522. # When true only the branch nodes and selected items are displayed.
  523. # This gives a compact view of important items.
  524. # ------------------------------------------------------------------
  525. itcl::configbody iwidgets::Hierarchy::filter {
  526.     switch -- $itk_option(-filter) {
  527.         1 - true - yes - on {
  528.             set newCode {set display [info exists _selected($child)]}
  529.         }
  530.         0 - false - no - off {
  531.             set newCode {set display 1}
  532.         }
  533.         default {
  534.             error "bad filter option \"$itk_option(-filter)\":\
  535.                    should be boolean"
  536.         }
  537.     }
  538.     if {$newCode != $_filterCode} {
  539.         set _filterCode $newCode
  540.         draw -eventually
  541.     }
  542. }
  543.  
  544. # ------------------------------------------------------------------
  545. # OPTION: -expanded
  546. #
  547. # When true, the hierarchy will be completely expanded when it
  548. # is first displayed.  A fresh display can be triggered by
  549. # resetting the -querycommand option.
  550. # ------------------------------------------------------------------
  551. itcl::configbody iwidgets::Hierarchy::expanded {
  552.     switch -- $itk_option(-expanded) {
  553.         1 - true - yes - on {
  554.             ;# okay
  555.         }
  556.         0 - false - no - off {
  557.             ;# okay
  558.         }
  559.         default {
  560.             error "bad expanded option \"$itk_option(-expanded)\":\
  561.                    should be boolean"
  562.         }
  563.     }
  564. }
  565.     
  566. # ------------------------------------------------------------------
  567. # OPTION: -openicon
  568. #
  569. # Specifies the open icon image to be used in the hierarchy.  Should
  570. # one not be provided, then one will be generated, pixmap if 
  571. # possible, bitmap otherwise.
  572. # ------------------------------------------------------------------
  573. itcl::configbody iwidgets::Hierarchy::openicon {
  574.     if {$itk_option(-openicon) == {}} {
  575.     if {[lsearch [image names] openFolder] == -1} {
  576.         if {[lsearch [image types] pixmap] != -1} {
  577.         image create pixmap openFolder -data {
  578.             /* XPM */
  579.             static char * dir_opened [] = {
  580.             "16 16 4 1",
  581.             /* colors */
  582.             ". c grey85 m white g4 grey90",
  583.             "b c black  m black g4 black",
  584.             "y c yellow m white g4 grey80",
  585.             "g c grey70 m white g4 grey70",
  586.             /* pixels */
  587.             "................",
  588.             "................",
  589.             "................",
  590.             "..bbbb..........",
  591.             ".bggggb.........",
  592.             "bggggggbbbbbbb..",
  593.             "bggggggggggggb..",
  594.             "bgbbbbbbbbbbbbbb",
  595.             "bgbyyyyyyyyyyybb",
  596.             "bbyyyyyyyyyyyyb.",
  597.             "bbyyyyyyyyyyybb.",
  598.             "byyyyyyyyyyyyb..",
  599.             "bbbbbbbbbbbbbb..",
  600.             "................",
  601.             "................",
  602.             "................"};
  603.         }
  604.         } else {
  605.         image create bitmap openFolder -data {
  606.             #define open_width 16
  607.             #define open_height 16
  608.             static char open_bits[] = {
  609.             0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x42, 0x00, 
  610.             0x81, 0x3f, 0x01, 0x20, 0xf9, 0xff, 0x0d, 0xc0, 
  611.             0x07, 0x40, 0x03, 0x60, 0x01, 0x20, 0x01, 0x30,
  612.             0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  613.         }
  614.         }
  615.     }
  616.     set itk_option(-openicon) openFolder
  617.     } else {
  618.     if {[lsearch [image names] $itk_option(-openicon)] == -1} {
  619.         error "bad openicon option \"$itk_option(-openicon)\":\
  620.                    should be an existing image"
  621.     }
  622.     }
  623. }
  624.  
  625. # ------------------------------------------------------------------
  626. # OPTION: -closedicon
  627. #
  628. # Specifies the closed icon image to be used in the hierarchy.  
  629. # Should one not be provided, then one will be generated, pixmap if 
  630. # possible, bitmap otherwise.
  631. # ------------------------------------------------------------------
  632. itcl::configbody iwidgets::Hierarchy::closedicon {
  633.     if {$itk_option(-closedicon) == {}} {
  634.     if {[lsearch [image names] closedFolder] == -1} {
  635.         if {[lsearch [image types] pixmap] != -1} {
  636.         image create pixmap closedFolder -data {
  637.             /* XPM */
  638.             static char *dir_closed[] = {
  639.             "16 16 3 1",
  640.             ". c grey85 m white g4 grey90",
  641.             "b c black  m black g4 black",
  642.             "y c yellow m white g4 grey80",
  643.             "................",
  644.             "................",
  645.             "................",
  646.             "..bbbb..........",
  647.             ".byyyyb.........",
  648.             "bbbbbbbbbbbbbb..",
  649.             "byyyyyyyyyyyyb..",
  650.             "byyyyyyyyyyyyb..",
  651.             "byyyyyyyyyyyyb..",
  652.             "byyyyyyyyyyyyb..",
  653.             "byyyyyyyyyyyyb..",
  654.             "byyyyyyyyyyyyb..",
  655.             "bbbbbbbbbbbbbb..",
  656.             "................",
  657.             "................",
  658.             "................"};    
  659.         }
  660.         } else {
  661.         image create bitmap closedFolder -data {
  662.             #define closed_width 16
  663.             #define closed_height 16
  664.             static char closed_bits[] = {
  665.             0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x84, 0x00, 
  666.             0xfe, 0x7f, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 
  667.             0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40,
  668.             0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  669.         }
  670.         }
  671.     }
  672.     set itk_option(-closedicon) closedFolder
  673.     } else {
  674.     if {[lsearch [image names] $itk_option(-closedicon)] == -1} {
  675.         error "bad closedicon option \"$itk_option(-closedicon)\":\
  676.                    should be an existing image"
  677.     }
  678.     }
  679. }
  680.  
  681. # ------------------------------------------------------------------
  682. # OPTION: -nodeicon
  683. #
  684. # Specifies the node icon image to be used in the hierarchy.  Should 
  685. # one not be provided, then one will be generated, pixmap if 
  686. # possible, bitmap otherwise.
  687. # ------------------------------------------------------------------
  688. itcl::configbody iwidgets::Hierarchy::nodeicon {
  689.     if {$itk_option(-nodeicon) == {}} {
  690.     if {[lsearch [image names] nodeFolder] == -1} {
  691.         if {[lsearch [image types] pixmap] != -1} {
  692.         image create pixmap nodeFolder -data {
  693.             /* XPM */
  694.             static char *dir_node[] = {
  695.             "16 16 3 1",
  696.             ". c grey85 m white g4 grey90",
  697.             "b c black  m black g4 black",
  698.             "y c yellow m white g4 grey80",
  699.             "................",
  700.             "................",
  701.             "................",
  702.             "...bbbbbbbbbbb..",
  703.             "..bybyyyyyyyyb..",
  704.             ".byybyyyyyyyyb..",
  705.             "byyybyyyyyyyyb..",
  706.             "bbbbbyyyyyyyyb..",
  707.             "byyyyyyyyyyyyb..",
  708.             "byyyyyyyyyyyyb..",
  709.             "byyyyyyyyyyyyb..",
  710.             "byyyyyyyyyyyyb..",
  711.             "bbbbbbbbbbbbbb..",
  712.             "................",
  713.             "................",
  714.             "................"};    
  715.         }
  716.         } else {
  717.         image create bitmap nodeFolder -data {
  718.             #define node_width 16
  719.             #define node_height 16
  720.             static char node_bits[] = {
  721.             0x00, 0x00, 0x00, 0x00, 0xe0, 0x7f, 0x50, 0x40, 
  722.             0x48, 0x40, 0x44, 0x40, 0x42, 0x40, 0x7e, 0x40, 
  723.             0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40,
  724.             0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  725.         }
  726.         }
  727.     }
  728.     set itk_option(-nodeicon) nodeFolder
  729.     } else {
  730.     if {[lsearch [image names] $itk_option(-nodeicon)] == -1} {
  731.         error "bad nodeicon option \"$itk_option(-nodeicon)\":\
  732.                    should be an existing image"
  733.     }
  734.     }
  735. }
  736.  
  737. # ------------------------------------------------------------------
  738. # OPTION: -width
  739. #
  740. # Specifies the width of the hierarchy widget as an entire unit.
  741. # The value may be specified in any of the forms acceptable to 
  742. # Tk_GetPixels.  Any additional space needed to display the other
  743. # components such as labels, margins, and scrollbars force the text
  744. # to be compressed.  A value of zero along with the same value for 
  745. # the height causes the value given for the visibleitems option 
  746. # to be applied which administers geometry constraints in a different
  747. # manner.
  748. # ------------------------------------------------------------------
  749. itcl::configbody iwidgets::Hierarchy::width {
  750.     if {$itk_option(-width) != 0} {
  751.     set shell [lindex [grid info $itk_component(clipper)] 1]
  752.  
  753.     #
  754.     # Due to a bug in the tk4.2 grid, we have to check the 
  755.     # propagation before setting it.  Setting it to the same
  756.     # value it already is will cause it to toggle.
  757.     #
  758.     if {[grid propagate $shell]} {
  759.         grid propagate $shell no
  760.     }
  761.     
  762.     $itk_component(list) configure -width 1
  763.     $shell configure \
  764.         -width [winfo pixels $shell $itk_option(-width)] 
  765.     } else {
  766.     configure -visibleitems $itk_option(-visibleitems)
  767.     }
  768. }
  769.  
  770. # ------------------------------------------------------------------
  771. # OPTION: -height
  772. #
  773. # Specifies the height of the hierarchy widget as an entire unit.
  774. # The value may be specified in any of the forms acceptable to 
  775. # Tk_GetPixels.  Any additional space needed to display the other
  776. # components such as labels, margins, and scrollbars force the text
  777. # to be compressed.  A value of zero along with the same value for 
  778. # the width causes the value given for the visibleitems option 
  779. # to be applied which administers geometry constraints in a different
  780. # manner.
  781. # ------------------------------------------------------------------
  782. itcl::configbody iwidgets::Hierarchy::height {
  783.     if {$itk_option(-height) != 0} {
  784.     set shell [lindex [grid info $itk_component(clipper)] 1]
  785.  
  786.     #
  787.     # Due to a bug in the tk4.2 grid, we have to check the 
  788.     # propagation before setting it.  Setting it to the same
  789.     # value it already is will cause it to toggle.
  790.     #
  791.     if {[grid propagate $shell]} {
  792.         grid propagate $shell no
  793.     }
  794.     
  795.     $itk_component(list) configure -height 1
  796.     $shell configure \
  797.         -height [winfo pixels $shell $itk_option(-height)] 
  798.     } else {
  799.     configure -visibleitems $itk_option(-visibleitems)
  800.     }
  801. }
  802.  
  803. # ------------------------------------------------------------------
  804. # OPTION: -visibleitems
  805. #
  806. # Specified the widthxheight in characters and lines for the text.
  807. # This option is only administered if the width and height options
  808. # are both set to zero, otherwise they take precedence.  With the
  809. # visibleitems option engaged, geometry constraints are maintained
  810. # only on the text.  The size of the other components such as 
  811. # labels, margins, and scroll bars, are additive and independent, 
  812. # effecting the overall size of the scrolled text.  In contrast,
  813. # should the width and height options have non zero values, they
  814. # are applied to the scrolled text as a whole.  The text is 
  815. # compressed or expanded to maintain the geometry constraints.
  816. # ------------------------------------------------------------------
  817. itcl::configbody iwidgets::Hierarchy::visibleitems {
  818.     if {[regexp {^[0-9]+x[0-9]+$} $itk_option(-visibleitems)]} {
  819.     if {($itk_option(-width) == 0) && \
  820.         ($itk_option(-height) == 0)} {
  821.         set chars [lindex [split $itk_option(-visibleitems) x] 0]
  822.         set lines [lindex [split $itk_option(-visibleitems) x] 1]
  823.         
  824.         set shell [lindex [grid info $itk_component(clipper)] 1]
  825.  
  826.         #
  827.         # Due to a bug in the tk4.2 grid, we have to check the 
  828.         # propagation before setting it.  Setting it to the same
  829.         # value it already is will cause it to toggle.
  830.         #
  831.         if {! [grid propagate $shell]} {
  832.         grid propagate $shell yes
  833.         }
  834.         
  835.         $itk_component(list) configure -width $chars -height $lines
  836.     }
  837.     
  838.     } else {
  839.     error "bad visibleitems option\
  840.         \"$itk_option(-visibleitems)\": should be\
  841.         widthxheight"
  842.     }
  843. }
  844.  
  845. # ------------------------------------------------------------------
  846. # OPTION: -textmenuloadcommand
  847. #
  848. # Dynamically loads the popup menu based on what was selected.
  849. #
  850. # Douglas R. Howard, Jr.
  851. # ------------------------------------------------------------------
  852. itcl::configbody iwidgets::Hierarchy::textmenuloadcommand {}
  853.  
  854. # ------------------------------------------------------------------
  855. # OPTION: -imagemenuloadcommand
  856. #
  857. # Dynamically loads the popup menu based on what was selected.
  858. #
  859. # Douglas R. Howard, Jr.
  860. # ------------------------------------------------------------------
  861. itcl::configbody iwidgets::Hierarchy::imagemenuloadcommand {}
  862.  
  863.  
  864. # ------------------------------------------------------------------
  865. #                         PUBLIC METHODS
  866. # ------------------------------------------------------------------
  867.  
  868. # ----------------------------------------------------------------------
  869. # PUBLIC METHOD: clear
  870. #
  871. # Removes all items from the display including all tags and icons.  
  872. # The display will remain empty until the -filter or -querycommand 
  873. # options are set.
  874. # ----------------------------------------------------------------------
  875. itcl::body iwidgets::Hierarchy::clear {} {
  876.     $itk_component(list) configure -state normal -cursor watch
  877.     $itk_component(list) delete 1.0 end
  878.     $itk_component(list) configure -state disabled -cursor $itk_option(-cursor)
  879.  
  880.     # Clear the tags
  881.     eval $itk_component(list) tag delete [$itk_component(list) tag names]
  882.     
  883.     catch {unset _nodes}
  884.     catch {unset _text}
  885.     catch {unset _tags}
  886.     catch {unset _icons}
  887.     catch {unset _states}
  888.     catch {unset _images}
  889.     catch {unset _indents}
  890.     catch {unset _marked}
  891.     catch {unset _selected}
  892.     set _markers  ""
  893.     set _posted   ""
  894.     set _ucounter 0
  895.     set _hcounter 0 
  896.  
  897.     foreach mark [$itk_component(list) mark names] {
  898.         $itk_component(list) mark unset $mark
  899.     }
  900.  
  901.     return
  902. }
  903.  
  904. # ----------------------------------------------------------------------
  905. # PUBLIC METHOD: selection option ?uid uid...?
  906. #
  907. # Handles all operations controlling selections in the hierarchy.
  908. # Selections may be cleared, added, removed, or queried.  The add and
  909. # remove options accept a series of unique ids.
  910. # ----------------------------------------------------------------------
  911. itcl::body iwidgets::Hierarchy::selection {op args} {
  912.     switch -- $op {
  913.         clear {
  914.             $itk_component(list) tag remove hilite 1.0 end
  915.             catch {unset _selected}
  916.         return
  917.         }
  918.         add {
  919.             foreach node $args {
  920.                 set _selected($node) 1
  921.                 catch {
  922.                     $itk_component(list) tag add hilite \
  923.                 "$node.first" "$node.last"
  924.                 }
  925.             }
  926.         }
  927.         remove {
  928.             foreach node $args {
  929.                 catch {
  930.                     unset _selected($node)
  931.                     $itk_component(list) tag remove hilite \
  932.                 "$node.first" "$node.last"
  933.                 }
  934.             }
  935.         }
  936.     get {
  937.         return [array names _selected]
  938.     }
  939.         default {
  940.             error "bad selection operation \"$op\":\
  941.                    should be add, remove, clear or get"
  942.         }
  943.     }
  944. }
  945.  
  946. # ----------------------------------------------------------------------
  947. # PUBLIC METHOD: mark option ?arg arg...?
  948. #
  949. # Handles all operations controlling marks in the hierarchy.  Marks may 
  950. # be cleared, added, removed, or queried.  The add and remove options 
  951. # accept a series of unique ids.
  952. # ----------------------------------------------------------------------
  953. itcl::body iwidgets::Hierarchy::mark {op args} {
  954.     switch -- $op {
  955.         clear {
  956.             $itk_component(list) tag remove lowlite 1.0 end
  957.             catch {unset _marked}
  958.         return
  959.         }
  960.         add {
  961.             foreach node $args {
  962.                 set _marked($node) 1
  963.                 catch {
  964.                     $itk_component(list) tag add lowlite \
  965.                 "$node.first" "$node.last"
  966.                 }
  967.             }
  968.         }
  969.         remove {
  970.             foreach node $args {
  971.                 catch {
  972.                     unset _marked($node)
  973.                     $itk_component(list) tag remove lowlite \
  974.                 "$node.first" "$node.last"
  975.                 }
  976.             }
  977.         }
  978.     get {
  979.         return [array names _marked]
  980.     }
  981.         default {
  982.             error "bad mark operation \"$op\":\
  983.                    should be add, remove, clear or get"
  984.         }
  985.     }
  986. }
  987.  
  988. # ----------------------------------------------------------------------
  989. # PUBLIC METHOD: current
  990. #
  991. # Returns the node that was most recently selected by the right mouse
  992. # button when the item menu was posted.  Usually used by the code
  993. # in the item menu to figure out what item is being manipulated.
  994. # ----------------------------------------------------------------------
  995. itcl::body iwidgets::Hierarchy::current {} {
  996.     return $_posted
  997. }
  998.  
  999. # ----------------------------------------------------------------------
  1000. # PUBLIC METHOD: expand node
  1001. #
  1002. # Expands the hierarchy beneath the specified node.  Since this can take
  1003. # a moment for large hierarchies, the cursor will be changed to a watch
  1004. # during the expansion.
  1005. # ----------------------------------------------------------------------
  1006. itcl::body iwidgets::Hierarchy::expand {node} {
  1007.     if {! [info exists _states($node)]} {
  1008.     error "bad expand node argument: \"$node\", the node doesn't exist"
  1009.     }
  1010.  
  1011.     if {!$_states($node) && \
  1012.         (([lsearch $_tags($node) branch] != -1) || \
  1013.          ([llength [_contents $node]] > 0))} {
  1014.         $itk_component(list) configure -state normal -cursor watch
  1015.         update
  1016.  
  1017.     #
  1018.     # Get the indentation level for the node.
  1019.     #
  1020.         set indent $_indents($node)
  1021.  
  1022.         set _markers ""
  1023.         $itk_component(list) mark set insert "$node:start"
  1024.         _drawLevel $node $indent
  1025.  
  1026.     #
  1027.     # Following the draw, all our markers need adjusting.
  1028.     #
  1029.         foreach {name index} $_markers {
  1030.             $itk_component(list) mark set $name $index
  1031.         }
  1032.  
  1033.     #
  1034.     # Set the image to be the open icon, denote the new state,
  1035.     # and set the cursor back to normal along with the state.
  1036.     #
  1037.     $_images($node) configure -image $itk_option(-openicon)
  1038.  
  1039.         set _states($node) 1
  1040.  
  1041.         $itk_component(list) configure -state disabled \
  1042.         -cursor $itk_option(-cursor)
  1043.     }
  1044. }
  1045.  
  1046. # ----------------------------------------------------------------------
  1047. # PUBLIC METHOD: collapse node
  1048. #
  1049. # Collapses the hierarchy beneath the specified node.  Since this can 
  1050. # take a moment for large hierarchies, the cursor will be changed to a 
  1051. # watch during the expansion.
  1052. # ----------------------------------------------------------------------
  1053. itcl::body iwidgets::Hierarchy::collapse {node} {
  1054.     if {! [info exists _states($node)]} {
  1055.     error "bad collapse node argument: \"$node\", the node doesn't exist"
  1056.     }
  1057.  
  1058.     if {[info exists _states($node)] && $_states($node) && \
  1059.         (([lsearch $_tags($node) branch] != -1) || \
  1060.          ([llength [_contents $node]] > 0))} {
  1061.         $itk_component(list) configure -state normal -cursor watch
  1062.     update
  1063.  
  1064.     _deselectSubNodes $node
  1065.  
  1066.         $itk_component(list) delete "$node:start" "$node:end"
  1067.  
  1068.     catch {$_images($node) configure -image $itk_option(-closedicon)}
  1069.  
  1070.         set _states($node) 0
  1071.  
  1072.         $itk_component(list) configure -state disabled \
  1073.         -cursor $itk_option(-cursor)
  1074.     }
  1075. }
  1076.  
  1077. # ----------------------------------------------------------------------
  1078. # PUBLIC METHOD: toggle node
  1079. #
  1080. # Toggles the hierarchy beneath the specified node.  If the hierarchy
  1081. # is currently expanded, then it is collapsed, and vice-versa.
  1082. # ----------------------------------------------------------------------
  1083. itcl::body iwidgets::Hierarchy::toggle {node} {
  1084.     if {! [info exists _states($node)]} {
  1085.     error "bad toggle node argument: \"$node\", the node doesn't exist"
  1086.     }
  1087.  
  1088.     if {$_states($node)} {
  1089.         collapse $node
  1090.     } else {
  1091.         expand $node
  1092.     }
  1093. }
  1094.  
  1095. # ----------------------------------------------------------------------
  1096. # PUBLIC METHOD: prune node
  1097. #
  1098. # Removes a particular node from the hierarchy.
  1099. # ----------------------------------------------------------------------
  1100. itcl::body iwidgets::Hierarchy::prune {node} {
  1101.     #
  1102.     # While we're working, change the state and cursor so we can
  1103.     # edit the text and give a busy visual clue.
  1104.     #
  1105.     $itk_component(list) configure -state normal -cursor watch
  1106.  
  1107.     #
  1108.     # Recursively delete all the subnode information from our internal
  1109.     # arrays and remove all the tags.  
  1110.     #
  1111.     _deleteNodeInfo $node
  1112.  
  1113.     #
  1114.     # If the mark $node:end exists then the node has decendents so
  1115.     # so we'll remove from the mark $node:start to $node:end in order 
  1116.     # to delete all the subnodes below it in the text.  
  1117.     # 
  1118.     if {[lsearch [$itk_component(list) mark names] $node:end] != -1} {
  1119.     $itk_component(list) delete $node:start $node:end
  1120.     $itk_component(list) mark unset $node:end
  1121.     } 
  1122.  
  1123.     #
  1124.     # Next we need to remove the node itself.  Using the ranges for
  1125.     # its tag we'll remove it from line start to the end plus one
  1126.     # character which takes us to the start of the next node.
  1127.     #
  1128.     foreach {start end} [$itk_component(list) tag ranges $node] {
  1129.     $itk_component(list) delete "$start linestart" "$end + 1 char"
  1130.     }
  1131.  
  1132.     #
  1133.     # Delete the tag for this node.
  1134.     #
  1135.     $itk_component(list) tag delete $node
  1136.  
  1137.     #
  1138.     # The node must be removed from the list of subnodes for its parent.
  1139.     # We don't really have a clean way to do upwards referencing, so
  1140.     # the dirty way will have to do.  We'll cycle through each node
  1141.     # and if this node is in its list of subnodes, we'll remove it.
  1142.     #
  1143.     foreach uid [array names _nodes] {
  1144.     if {[set index [lsearch $_nodes($uid) $node]] != -1} {
  1145.         set _nodes($uid) [lreplace $_nodes($uid) $index $index]
  1146.     }
  1147.     }
  1148.  
  1149.     #
  1150.     # We're done, so change the state and cursor back to their 
  1151.     # original values.
  1152.     #
  1153.     $itk_component(list) configure -state disabled -cursor $itk_option(-cursor)
  1154. }
  1155.  
  1156. # ----------------------------------------------------------------------
  1157. # PUBLIC METHOD: draw ?when?
  1158. #
  1159. # Performs a complete draw of the entire hierarchy.
  1160. # ----------------------------------------------------------------------
  1161. itcl::body iwidgets::Hierarchy::draw {{when -now}} {
  1162.     if {$when == "-eventually"} {
  1163.         if {$_pending == ""} {
  1164.             set _pending [after idle [itcl::code $this draw -now]]
  1165.         }
  1166.         return
  1167.     } elseif {$when != "-now"} {
  1168.         error "bad when option \"$when\": should be -eventually or -now"
  1169.     }
  1170.     $itk_component(list) configure -state normal -cursor watch
  1171.     update
  1172.  
  1173.     $itk_component(list) delete 1.0 end
  1174.     catch {unset _images}
  1175.     set _markers ""
  1176.  
  1177.     _drawLevel "" ""
  1178.  
  1179.     foreach {name index} $_markers {
  1180.         $itk_component(list) mark set $name $index
  1181.     }
  1182.  
  1183.     $itk_component(list) configure -state disabled -cursor $itk_option(-cursor)
  1184.     set _pending ""
  1185. }
  1186.  
  1187. # ----------------------------------------------------------------------
  1188. # PUBLIC METHOD: refresh node
  1189. #
  1190. # Performs a redraw of a specific node.  If that node is currently 
  1191. # not visible, then no action is taken.
  1192. # ----------------------------------------------------------------------
  1193. itcl::body iwidgets::Hierarchy::refresh {node} {
  1194.     if {! [info exists _nodes($node)]} {
  1195.     error "bad refresh node argument: \"$node\", the node doesn't exist"
  1196.     }
  1197.  
  1198.     
  1199.     if {! $_states($node)} {return}
  1200.  
  1201.     foreach parent [_getHeritage $node] {
  1202.     if {! $_states($parent)} {return}
  1203.     }
  1204.  
  1205.     $itk_component(list) configure -state normal -cursor watch
  1206.     $itk_component(list) delete $node:start $node:end
  1207.  
  1208.     set _markers ""
  1209.     $itk_component(list) mark set insert "$node:start"
  1210.     set indent $_indents($node)
  1211.  
  1212.     _drawLevel $node $indent
  1213.  
  1214.     foreach {name index} $_markers {
  1215.         $itk_component(list) mark set $name $index
  1216.     }
  1217.  
  1218.     $itk_component(list) configure -state disabled -cursor $itk_option(-cursor)
  1219. }
  1220.  
  1221. # ------------------------------------------------------------------
  1222. # THIN WRAPPED TEXT METHODS:
  1223. #
  1224. # The following methods are thin wraps of standard text methods.
  1225. # Consult the Tk text man pages for functionallity and argument
  1226. # documentation.
  1227. # ------------------------------------------------------------------
  1228.  
  1229. # ------------------------------------------------------------------
  1230. # PUBLIC METHOD: bbox index
  1231. #
  1232. # Returns four element list describing the bounding box for the list
  1233. # item at index
  1234. # ------------------------------------------------------------------
  1235. itcl::body iwidgets::Hierarchy::bbox {index} {
  1236.     return [$itk_component(list) bbox $index]
  1237. }
  1238.  
  1239. # ------------------------------------------------------------------
  1240. # PUBLIC METHOD compare index1 op index2
  1241. #
  1242. # Compare indices according to relational operator.
  1243. # ------------------------------------------------------------------
  1244. itcl::body iwidgets::Hierarchy::compare {index1 op index2} {
  1245.     return [$itk_component(list) compare $index1 $op $index2]
  1246. }
  1247.  
  1248. # ------------------------------------------------------------------
  1249. # PUBLIC METHOD delete first ?last?
  1250. #
  1251. # Delete a range of characters from the text.
  1252. # ------------------------------------------------------------------
  1253. itcl::body iwidgets::Hierarchy::delete {first {last {}}} {
  1254.     $itk_component(list) configure -state normal -cursor watch
  1255.     $itk_component(list) delete $first $last
  1256.     $itk_component(list) configure -state disabled -cursor $itk_option(-cursor)
  1257. }
  1258.  
  1259. # ------------------------------------------------------------------
  1260. # PUBLIC METHOD dump ?switches? index1 ?index2?
  1261. #
  1262. # Returns information about the contents of the text widget from 
  1263. # index1 to index2.
  1264. # ------------------------------------------------------------------
  1265. itcl::body iwidgets::Hierarchy::dump {args} {
  1266.     return [eval $itk_component(list) dump $args]
  1267. }
  1268.  
  1269. # ------------------------------------------------------------------
  1270. # PUBLIC METHOD dlineinfo index
  1271. #
  1272. # Returns a five element list describing the area occupied by the
  1273. # display line containing index.
  1274. # ------------------------------------------------------------------
  1275. itcl::body iwidgets::Hierarchy::dlineinfo {index} {
  1276.     return [$itk_component(list) dlineinfo $index]
  1277. }
  1278.  
  1279. # ------------------------------------------------------------------
  1280. # PUBLIC METHOD get index1 ?index2?
  1281. #
  1282. # Return text from start index to end index.
  1283. # ------------------------------------------------------------------
  1284. itcl::body iwidgets::Hierarchy::get {index1 {index2 {}}} {
  1285.     return [$itk_component(list) get $index1 $index2]
  1286. }
  1287.  
  1288. # ------------------------------------------------------------------
  1289. # PUBLIC METHOD index index
  1290. #
  1291. # Return position corresponding to index.
  1292. # ------------------------------------------------------------------
  1293. itcl::body iwidgets::Hierarchy::index {index} {
  1294.     return [$itk_component(list) index $index]
  1295. }
  1296.  
  1297. # ------------------------------------------------------------------
  1298. # PUBLIC METHOD insert index chars ?tagList?
  1299. #
  1300. # Insert text at index.
  1301. # ------------------------------------------------------------------
  1302. itcl::body iwidgets::Hierarchy::insert {args} {
  1303.     $itk_component(list) configure -state normal -cursor watch
  1304.     eval $itk_component(list) insert $args
  1305.     $itk_component(list) configure -state disabled -cursor $itk_option(-cursor)
  1306. }
  1307.  
  1308. # ------------------------------------------------------------------
  1309. # PUBLIC METHOD scan option args
  1310. #
  1311. # Implements scanning on texts.
  1312. # ------------------------------------------------------------------
  1313. itcl::body iwidgets::Hierarchy::scan {option args} {
  1314.     eval $itk_component(list) scan $option $args
  1315. }
  1316.  
  1317. # ------------------------------------------------------------------
  1318. # PUBLIC METHOD search ?switches? pattern index ?varName?
  1319. #
  1320. # Searches the text for characters matching a pattern.
  1321. # ------------------------------------------------------------------
  1322. itcl::body iwidgets::Hierarchy::search {args} {
  1323.     return [eval $itk_component(list) search $args]
  1324. }
  1325.  
  1326. # ------------------------------------------------------------------
  1327. # PUBLIC METHOD see index
  1328. #
  1329. # Adjusts the view in the window so the character at index is 
  1330. # visible.
  1331. # ------------------------------------------------------------------
  1332. itcl::body iwidgets::Hierarchy::see {index} {
  1333.     $itk_component(list) see $index
  1334. }
  1335.  
  1336. # ------------------------------------------------------------------
  1337. # PUBLIC METHOD tag option ?arg arg ...?
  1338. #
  1339. # Manipulate tags dependent on options.
  1340. # ------------------------------------------------------------------
  1341. itcl::body iwidgets::Hierarchy::tag {op args} {
  1342.     return [eval $itk_component(list) tag $op $args]
  1343. }
  1344.  
  1345. # ------------------------------------------------------------------
  1346. # PUBLIC METHOD window option ?arg arg ...?
  1347. #
  1348. # Manipulate embedded windows.
  1349. # ------------------------------------------------------------------
  1350. itcl::body iwidgets::Hierarchy::window {option args} {
  1351.     return [eval $itk_component(list) window $option $args]
  1352. }
  1353.  
  1354. # ----------------------------------------------------------------------
  1355. # PUBLIC METHOD: xview args
  1356. #
  1357. # Thin wrap of the text widget's xview command.
  1358. # ----------------------------------------------------------------------
  1359. itcl::body iwidgets::Hierarchy::xview {args} {
  1360.     return [eval itk_component(list) xview $args]
  1361. }
  1362.  
  1363. # ----------------------------------------------------------------------
  1364. # PUBLIC METHOD: yview args
  1365. #
  1366. # Thin wrap of the text widget's yview command.
  1367. # ----------------------------------------------------------------------
  1368. itcl::body iwidgets::Hierarchy::yview {args} {
  1369.     return [eval $itk_component(list) yview $args]
  1370. }
  1371.  
  1372. # ----------------------------------------------------------------------
  1373. # PUBLIC METHOD: expanded node
  1374. #
  1375. # Tells if a node is expanded or collapsed
  1376. #
  1377. # Douglas R. Howard, Jr.
  1378. # ----------------------------------------------------------------------
  1379. itcl::body iwidgets::Hierarchy::expanded {node} {
  1380.     if {! [info exists _states($node)]} {
  1381.     error "bad collapse node argument: \"$node\", the node doesn't exist"
  1382.     }
  1383.     
  1384.     return $_states($node)
  1385. }
  1386.  
  1387. # ----------------------------------------------------------------------
  1388. # PUBLIC METHOD: expState
  1389. #
  1390. # Returns a list of all expanded nodes
  1391. #
  1392. # Douglas R. Howard, Jr.
  1393. # ----------------------------------------------------------------------
  1394. itcl::body iwidgets::Hierarchy::expState {} {
  1395.     set nodes [_contents ""]
  1396.     set open ""
  1397.     set i 0
  1398.     while {1} {
  1399.     if {[info exists _states([lindex $nodes $i])] &&
  1400.     $_states([lindex $nodes $i])} {
  1401.         lappend open [lindex $nodes $i]
  1402.         foreach child [_contents [lindex $nodes $i]] {
  1403.         lappend nodes $child
  1404.         }
  1405.     }
  1406.     incr i
  1407.     if {$i >= [llength $nodes]} {break}
  1408.     }
  1409.     
  1410.     return $open
  1411. }
  1412.  
  1413. # ------------------------------------------------------------------
  1414. #                       PROTECTED METHODS
  1415. # ------------------------------------------------------------------
  1416.  
  1417. # ----------------------------------------------------------------------
  1418. # PROTECTED METHOD: _drawLevel node indent
  1419. #
  1420. # Used internally by draw to draw one level of the hierarchy.
  1421. # Draws all of the nodes under node, using the indent string to
  1422. # indent nodes.
  1423. # ----------------------------------------------------------------------
  1424. itcl::body iwidgets::Hierarchy::_drawLevel {node indent} {
  1425.     lappend _markers "$node:start" [$itk_component(list) index insert]
  1426.     set bg [$itk_component(list) cget -background]
  1427.  
  1428.     #
  1429.     # Obtain the list of subnodes for this node and cycle through
  1430.     # each one displaying it in the hierarchy.
  1431.     #
  1432.     foreach child [_contents $node] {
  1433.     set _images($child) "$itk_component(list).hicon[incr _hcounter]"
  1434.  
  1435.         if {![info exists _states($child)]} {
  1436.             set _states($child) $itk_option(-expanded)
  1437.         }
  1438.  
  1439.     #
  1440.     # Check the user tags to see if they have been kind enough
  1441.     # to tell us ahead of time what type of node we are dealing
  1442.     # with branch or leaf.  If they neglected to do so, then
  1443.     # get the contents of the child node to see if it has children
  1444.     # itself.
  1445.     #
  1446.     set display 0
  1447.  
  1448.     if {[lsearch $_tags($child) leaf] != -1} {
  1449.         set type leaf
  1450.     } elseif {[lsearch $_tags($child) branch] != -1} {
  1451.         set type branch
  1452.     } else {
  1453.         if {[llength [_contents $child]] == 0} {
  1454.         set type leaf
  1455.         } else {
  1456.         set type branch
  1457.         }
  1458.     }
  1459.  
  1460.     #
  1461.     # Now that we know the type of node, branch or leaf, we know
  1462.     # the type of icon to use.
  1463.     #
  1464.     if {$type == "leaf"} {
  1465.             set icon $itk_option(-nodeicon)
  1466.             eval $_filterCode
  1467.     } else {
  1468.             if {$_states($child)} {
  1469.                 set icon $itk_option(-openicon)
  1470.             } else {
  1471.                 set icon $itk_option(-closedicon)
  1472.             }
  1473.             set display 1
  1474.     }
  1475.  
  1476.     #
  1477.     # If display is set then we're going to be drawing this node.
  1478.     # Save off the indentation level for this node and do the indent.
  1479.     #
  1480.     if {$display} {
  1481.         set _indents($child) "$indent\t"
  1482.         $itk_component(list) insert insert $indent
  1483.  
  1484.         #
  1485.         # Add the branch or leaf icon and setup a binding to toggle
  1486.         # its expanded/collapsed state.
  1487.         #
  1488.         label $_images($child) -image $icon -background $bg 
  1489.         # DRH - enhanced and added features that handle image clicking,
  1490.         # double clicking, and right clicking behavior
  1491.         bind $_images($child) <ButtonPress-1> \
  1492.           "[itcl::code $this toggle $child]; [itcl::code $this _imageSelect $child]"
  1493.         bind $_images($child) <Double-1> [itcl::code $this _imageDblClick $child]
  1494.         bind $_images($child) <ButtonPress-3> \
  1495.           [itcl::code $this _imagePost $child $_images($child) $type %x %y]
  1496.         $itk_component(list) window create insert -window $_images($child)
  1497.  
  1498.         #
  1499.         # If any user icons exist then draw them as well.  The little
  1500.         # regexp is just to check and see if they've passed in a
  1501.         # command which needs to be evaluated as opposed to just
  1502.         # a variable.  Also, attach a binding to call them if their
  1503.         # icon is selected.
  1504.         #
  1505.         if {[info exists _icons($child)]} {
  1506.         foreach image $_icons($child) {
  1507.             set wid "$itk_component(list).uicon[incr _ucounter]"
  1508.  
  1509.             if {[regexp {\[.*\]} $image]} {
  1510.             eval label $wid -image $image -background $bg 
  1511.             } else {
  1512.             label $wid -image $image -background $bg 
  1513.             }
  1514.  
  1515.             # DRH - this will bind events to the icons to allow
  1516.             # clicking, double clicking, and right clicking actions.
  1517.             bind $wid <ButtonPress-1> \
  1518.                 [itcl::code $this _iconSelect $child $image]
  1519.             bind $wid <Double-1> \
  1520.                 [itcl::code $this _iconDblSelect $child $image]
  1521.             bind $wid <ButtonPress-3> \
  1522.                 [itcl::code $this _imagePost $child $wid $type %x %y]
  1523.             $itk_component(list) window create insert -window $wid
  1524.         }
  1525.         }
  1526.  
  1527.         #
  1528.         # Create the list of tags to be applied to the text.  Start
  1529.         # out with a tag of "info" and append "hilite" if the node
  1530.         # is currently selected, finally add the tags given by the
  1531.         # user.
  1532.         #
  1533.         set texttags [list "info" $child]
  1534.  
  1535.         if {[info exists _selected($child)]} {
  1536.         lappend texttags hilite
  1537.         } 
  1538.  
  1539.             # The following conditional added for SF ticket #600941.
  1540.             if {[info exists _marked($child)]} { 
  1541.                 lappend texttags lowlite 
  1542.             } 
  1543.  
  1544.         foreach tag $_tags($child) {
  1545.         lappend texttags $tag
  1546.         }
  1547.  
  1548.         #
  1549.         # Insert the text for the node along with the tags and 
  1550.         # append to the markers the start of this node.  The text
  1551.         # has been broken at newlines into a list.  We'll make sure
  1552.         # that each line is at the same indentation position.
  1553.         #
  1554.         set firstline 1
  1555.         foreach line $_text($child) {
  1556.         if {$firstline} {
  1557.             $itk_component(list) insert insert " "
  1558.         } else {
  1559.             $itk_component(list) insert insert "$indent\t"
  1560.         }
  1561.  
  1562.         $itk_component(list) insert insert $line $texttags "\n"
  1563.         set firstline 0
  1564.         }
  1565.  
  1566.         $itk_component(list) tag raise $child
  1567.         lappend _markers "$child:start" [$itk_component(list) index insert]
  1568.  
  1569.         #
  1570.         # If the state of the node is open, proceed to draw the next 
  1571.         # node below it in the hierarchy.
  1572.         #
  1573.         if {$_states($child)} {
  1574.         _drawLevel $child "$indent\t"
  1575.         }
  1576.     }
  1577.     }
  1578.  
  1579.     lappend _markers "$node:end" [$itk_component(list) index insert]
  1580. }
  1581.  
  1582. # ----------------------------------------------------------------------
  1583. # PROTECTED METHOD: _contents uid
  1584. #
  1585. # Used internally to get the contents of a particular node.  If this
  1586. # is the first time the node has been seen or the -alwaysquery
  1587. # option is set, the -querycommand code is executed to query the node 
  1588. # list, and the list is stored until the next time it is needed.
  1589. #
  1590. # The querycommand may return not only the list of subnodes for the 
  1591. # node but additional information on the tags and icons to be used.  
  1592. # The return value must be parsed based on the number of elements in 
  1593. # the list where the format is a list of lists:
  1594. #
  1595. # {{uid [text [tags [icons]]]} {uid [text [tags [icons]]]} ...}
  1596. # ----------------------------------------------------------------------
  1597. itcl::body iwidgets::Hierarchy::_contents {uid} {
  1598.     if {$itk_option(-alwaysquery)} {
  1599.     } else {
  1600.       if {[info exists _nodes($uid)]} {
  1601.           return $_nodes($uid)
  1602.       }
  1603.     }
  1604.  
  1605.     # 
  1606.     # Substitute any %n's for the node name whose children we're
  1607.     # interested in obtaining.
  1608.     #
  1609.     set cmd $itk_option(-querycommand)
  1610.     regsub -all {%n} $cmd [list $uid] cmd
  1611.  
  1612.     set nodeinfolist [uplevel \#0 $cmd]
  1613.  
  1614.     #
  1615.     # Cycle through the node information returned by the query
  1616.     # command determining if additional information such as text,
  1617.     # user tags, or user icons have been provided.  For text,
  1618.     # break it into a list at any newline characters.
  1619.     #
  1620.     set _nodes($uid) {}
  1621.  
  1622.     foreach nodeinfo $nodeinfolist {
  1623.     set subnodeuid [lindex $nodeinfo 0]
  1624.     lappend _nodes($uid) $subnodeuid
  1625.  
  1626.     set llen [llength $nodeinfo] 
  1627.  
  1628.     if {$llen == 0 || $llen > 4} {
  1629.         error "invalid number of elements returned by query\
  1630.                        command for node: \"$uid\",\
  1631.                        should be uid \[text \[tags \[icons\]\]\]"
  1632.     }
  1633.  
  1634.     if {$llen == 1} {
  1635.         set _text($subnodeuid) [split $subnodeuid \n]
  1636.     } 
  1637.     if {$llen > 1} {
  1638.         set _text($subnodeuid) [split [lindex $nodeinfo 1] \n]
  1639.     }
  1640.     if {$llen > 2} {
  1641.         set _tags($subnodeuid) [lindex $nodeinfo 2]
  1642.     } else {
  1643.         set _tags($subnodeuid) unknown
  1644.     }
  1645.     if {$llen > 3} {
  1646.         set _icons($subnodeuid) [lindex $nodeinfo 3]
  1647.     }
  1648.     }
  1649.           
  1650.     #
  1651.     # Return the list of nodes.
  1652.     #
  1653.     return $_nodes($uid)
  1654. }
  1655.  
  1656. # ----------------------------------------------------------------------
  1657. # PROTECTED METHOD: _post x y
  1658. #
  1659. # Used internally to post the popup menu at the coordinate (x,y)
  1660. # relative to the widget.  If (x,y) is on an item, then the itemMenu
  1661. # component is posted.  Otherwise, the bgMenu is posted.
  1662. # ----------------------------------------------------------------------
  1663. itcl::body iwidgets::Hierarchy::_post {x y} {
  1664.     set rx [expr {[winfo rootx $itk_component(list)]+$x}]
  1665.     set ry [expr {[winfo rooty $itk_component(list)]+$y}]
  1666.  
  1667.     set index [$itk_component(list) index @$x,$y]
  1668.  
  1669.     #
  1670.     # The posted variable will hold the list of tags which exist at
  1671.     # this x,y position that will be passed back to the user.  They
  1672.     # don't need to know about our internal tags, info, hilite, and
  1673.     # lowlite, so remove them from the list.
  1674.     # 
  1675.     set _posted {}
  1676.  
  1677.     foreach tag [$itk_component(list) tag names $index] {
  1678.         if {![_isInternalTag $tag]} {
  1679.             lappend _posted $tag
  1680.         }
  1681.     }
  1682.  
  1683.     #
  1684.     # If we have tags then do the popup at this position.
  1685.     #
  1686.     if {$_posted != {}} {
  1687.     # DRH - here is where the user's function for dynamic popup
  1688.     # menu loading is done, if the user has specified to do so with the
  1689.     # "-textmenuloadcommand"
  1690.     if {$itk_option(-textmenuloadcommand) != {}} {
  1691.         eval $itk_option(-textmenuloadcommand)
  1692.     }
  1693.     tk_popup $itk_component(itemMenu) $rx $ry
  1694.     } else {
  1695.     tk_popup $itk_component(bgMenu) $rx $ry
  1696.     }
  1697. }
  1698.  
  1699. # ----------------------------------------------------------------------
  1700. # PROTECTED METHOD: _imagePost node image type x y
  1701. #
  1702. # Used internally to post the popup menu at the coordinate (x,y)
  1703. # relative to the widget.  If (x,y) is on an image, then the itemMenu
  1704. # component is posted.
  1705. #
  1706. # Douglas R. Howard, Jr.
  1707. # ----------------------------------------------------------------------
  1708. itcl::body iwidgets::Hierarchy::_imagePost {node image type x y} {
  1709.     set rx [expr {[winfo rootx $image]+$x}]
  1710.     set ry [expr {[winfo rooty $image]+$y}]
  1711.  
  1712.     #
  1713.     # The posted variable will hold the list of tags which exist at
  1714.     # this x,y position that will be passed back to the user.  They
  1715.     # don't need to know about our internal tags, info, hilite, and
  1716.     # lowlite, so remove them from the list.
  1717.     # 
  1718.     set _posted {}
  1719.  
  1720.     lappend _posted $node $type
  1721.  
  1722.     #
  1723.     # If we have tags then do the popup at this position.
  1724.     #
  1725.     if {$itk_option(-imagemenuloadcommand) != {}} {
  1726.     eval $itk_option(-imagemenuloadcommand)
  1727.     }
  1728.     tk_popup $itk_component(itemMenu) $rx $ry
  1729. }
  1730.  
  1731. # ----------------------------------------------------------------------
  1732. # PROTECTED METHOD: _select x y
  1733. #
  1734. # Used internally to select an item at the coordinate (x,y) relative 
  1735. # to the widget.  The command associated with the -selectcommand
  1736. # option is execute following % character substitutions.  If %n
  1737. # appears in the command, the selected node is substituted.  If %s
  1738. # appears, a boolean value representing the current selection state
  1739. # will be substituted.
  1740. # ----------------------------------------------------------------------
  1741. itcl::body iwidgets::Hierarchy::_select {x y} {
  1742.     if {$itk_option(-selectcommand) != {}} {
  1743.     if {[set seltags [$itk_component(list) tag names @$x,$y]] != {}} {
  1744.         foreach tag $seltags {
  1745.         if {![_isInternalTag $tag]} {
  1746.             lappend node $tag
  1747.         }
  1748.         }
  1749.  
  1750.         if {[lsearch $seltags "hilite"] == -1} {
  1751.         set selectstatus 0
  1752.         } else {
  1753.         set selectstatus 1
  1754.         }
  1755.  
  1756.         set cmd $itk_option(-selectcommand)
  1757.         regsub -all {%n} $cmd [lindex $node end] cmd
  1758.         regsub -all {%s} $cmd [list $selectstatus] cmd
  1759.  
  1760.         uplevel #0 $cmd
  1761.     }
  1762.     }
  1763.  
  1764.     return
  1765. }
  1766.  
  1767. # ----------------------------------------------------------------------
  1768. # PROTECTED METHOD: _double x y
  1769. #
  1770. # Used internally to double click an item at the coordinate (x,y) relative 
  1771. # to the widget.  The command associated with the -dblclickcommand
  1772. # option is execute following % character substitutions.  If %n
  1773. # appears in the command, the selected node is substituted.  If %s
  1774. # appears, a boolean value representing the current selection state
  1775. # will be substituted.
  1776. #
  1777. # Douglas R. Howard, Jr.
  1778. # ----------------------------------------------------------------------
  1779. itcl::body iwidgets::Hierarchy::_double {x y} {
  1780.     if {$itk_option(-dblclickcommand) != {}} {
  1781.     if {[set seltags [$itk_component(list) tag names @$x,$y]] != {}} {
  1782.         foreach tag $seltags {
  1783.         if {![_isInternalTag $tag]} {
  1784.             lappend node $tag
  1785.         }
  1786.         }
  1787.  
  1788.         if {[lsearch $seltags "hilite"] == -1} {
  1789.         set selectstatus 0
  1790.         } else {
  1791.         set selectstatus 1
  1792.         }
  1793.  
  1794.         set cmd $itk_option(-dblclickcommand)
  1795.         regsub -all {%n} $cmd [list $node] cmd
  1796.         regsub -all {%s} $cmd [list $selectstatus] cmd
  1797.  
  1798.         uplevel #0 $cmd
  1799.     }
  1800.     }
  1801.  
  1802.     return
  1803. }
  1804.  
  1805. # ----------------------------------------------------------------------
  1806. # PROTECTED METHOD: _iconSelect node icon
  1807. #
  1808. # Used internally to upon selection of user icons.  The -iconcommand
  1809. # is executed after substitution of the node for %n and icon for %i.
  1810. #
  1811. # Douglas R. Howard, Jr.
  1812. # ----------------------------------------------------------------------
  1813. itcl::body iwidgets::Hierarchy::_iconSelect {node icon} {
  1814.     set cmd $itk_option(-iconcommand)
  1815.     regsub -all {%n} $cmd [list $node] cmd
  1816.     regsub -all {%i} $cmd [list $icon] cmd
  1817.  
  1818.     uplevel \#0 $cmd
  1819.  
  1820.     return {}
  1821. }
  1822.  
  1823. # ----------------------------------------------------------------------
  1824. # PROTECTED METHOD: _iconDblSelect node icon
  1825. #
  1826. # Used internally to upon double selection of user icons.  The 
  1827. # -icondblcommand is executed after substitution of the node for %n and 
  1828. # icon for %i.
  1829. #
  1830. # Douglas R. Howard, Jr.
  1831. # ----------------------------------------------------------------------
  1832. itcl::body iwidgets::Hierarchy::_iconDblSelect {node icon} {
  1833.     if {$itk_option(-icondblcommand) != {}} {
  1834.     set cmd $itk_option(-icondblcommand)
  1835.     regsub -all {%n} $cmd [list $node] cmd
  1836.     regsub -all {%i} $cmd [list $icon] cmd
  1837.     
  1838.     uplevel \#0 $cmd
  1839.     }
  1840.     return {}
  1841. }
  1842.  
  1843. # ----------------------------------------------------------------------
  1844. # PROTECTED METHOD: _imageSelect node icon
  1845. #
  1846. # Used internally to upon selection of user icons.  The -imagecommand
  1847. # is executed after substitution of the node for %n.
  1848. #
  1849. # Douglas R. Howard, Jr.
  1850. # ----------------------------------------------------------------------
  1851. itcl::body iwidgets::Hierarchy::_imageSelect {node} {
  1852.     if {$itk_option(-imagecommand) != {}} {
  1853.     set cmd $itk_option(-imagecommand)
  1854.     regsub -all {%n} $cmd [list $node] cmd
  1855.     
  1856.     uplevel \#0 $cmd
  1857.     }
  1858.     return {}
  1859. }
  1860.  
  1861. # ----------------------------------------------------------------------
  1862. # PROTECTED METHOD: _imageDblClick node
  1863. #
  1864. # Used internally to upon double selection of images.  The 
  1865. # -imagedblcommand is executed.
  1866. #
  1867. # Douglas R. Howard, Jr.
  1868. # ----------------------------------------------------------------------
  1869. itcl::body iwidgets::Hierarchy::_imageDblClick {node} {
  1870.     if {$itk_option(-imagedblcommand) != {}} {
  1871.     set cmd $itk_option(-imagedblcommand)
  1872.     regsub -all {%n} $cmd [list $node] cmd
  1873.     
  1874.     uplevel \#0 $cmd
  1875.     }
  1876.     return {}
  1877. }
  1878.  
  1879. # ----------------------------------------------------------------------
  1880. # PROTECTED METHOD: _deselectSubNodes uid
  1881. #
  1882. # Used internally to recursively deselect all the nodes beneath a 
  1883. # particular node.
  1884. # ----------------------------------------------------------------------
  1885. itcl::body iwidgets::Hierarchy::_deselectSubNodes {uid} {
  1886.     foreach node $_nodes($uid) {
  1887.     if {[array names _selected $node] != {}} {
  1888.         unset _selected($node)
  1889.     }
  1890.     
  1891.     if {[array names _nodes $node] != {}} {
  1892.         _deselectSubNodes $node
  1893.     }
  1894.     }
  1895. }
  1896.  
  1897. # ----------------------------------------------------------------------
  1898. # PROTECTED METHOD: _deleteNodeInfo uid
  1899. #
  1900. # Used internally to recursively delete all the information about a
  1901. # node and its decendents.
  1902. # ----------------------------------------------------------------------
  1903. itcl::body iwidgets::Hierarchy::_deleteNodeInfo {uid} {
  1904.     #
  1905.     # Recursively call ourseleves as we go down the hierarchy beneath
  1906.     # this node.
  1907.     #
  1908.     if {[info exists _nodes($uid)]} {
  1909.     foreach node $_nodes($uid) {
  1910.         if {[array names _nodes $node] != {}} {
  1911.         _deleteNodeInfo $node
  1912.         }
  1913.     }
  1914.     }
  1915.  
  1916.     #
  1917.     # Unset any entries in our arrays for the node.
  1918.     #
  1919.     catch {unset _nodes($uid)}
  1920.     catch {unset _text($uid)}
  1921.     catch {unset _tags($uid)}
  1922.     catch {unset _icons($uid)}
  1923.     catch {unset _states($uid)}
  1924.     catch {unset _images($uid)}
  1925.     catch {unset _indents($uid)}
  1926. }
  1927.  
  1928. # ----------------------------------------------------------------------
  1929. # PROTECTED METHOD: _getParent uid
  1930. #
  1931. # Used internally to determine the parent for a node.
  1932. # ----------------------------------------------------------------------
  1933. itcl::body iwidgets::Hierarchy::_getParent {uid} {
  1934.     foreach node [array names _nodes] {
  1935.     if {[set index [lsearch $_nodes($node) $uid]] != -1} {
  1936.         return $node
  1937.     }
  1938.     }
  1939. }
  1940.  
  1941. # ----------------------------------------------------------------------
  1942. # PROTECTED METHOD: _getHeritage uid
  1943. #
  1944. # Used internally to determine the list of parents for a node.
  1945. # ----------------------------------------------------------------------
  1946. itcl::body iwidgets::Hierarchy::_getHeritage {uid} {
  1947.     set parents {}
  1948.  
  1949.     if {[set parent [_getParent $uid]] != {}} {
  1950.     lappend parents $parent
  1951.     }
  1952.  
  1953.     return $parents
  1954. }
  1955.  
  1956. # ----------------------------------------------------------------------
  1957. # PROTECTED METHOD (could be proc?): _isInternalTag tag
  1958. #
  1959. # Used internally to tags not to used for user callback commands
  1960. # ----------------------------------------------------------------------
  1961. itcl::body iwidgets::Hierarchy::_isInternalTag {tag} {
  1962.    set ii [expr {[lsearch -exact {info hilite lowlite unknown} $tag] != -1}];
  1963.    return $ii;
  1964. }
  1965.  
  1966. # ----------------------------------------------------------------------
  1967. # PRIVATE METHOD: _configureTags
  1968. #
  1969. # This method added to fix SF ticket #596111.  When the -querycommand
  1970. # is reset after initial construction, the text component loses its
  1971. # tag configuration.  This method resets the hilite, lowlite, and info
  1972. # tags.  csmith: 9/5/02
  1973. # ----------------------------------------------------------------------
  1974. itcl::body iwidgets::Hierarchy::_configureTags {} {
  1975.   tag configure hilite -background $itk_option(-selectbackground) \
  1976.     -foreground $itk_option(-selectforeground)
  1977.   tag configure lowlite -background $itk_option(-markbackground) \
  1978.     -foreground $itk_option(-markforeground)
  1979.   tag configure info -font $itk_option(-font) -spacing1 6
  1980. }
  1981.