home *** CD-ROM | disk | FTP | other *** search
Text File | 2003-09-01 | 65.4 KB | 1,984 lines |
- # Hierarchy
- # ----------------------------------------------------------------------
- # Hierarchical data viewer. Manages a list of nodes that can be
- # expanded or collapsed. Individual nodes can be highlighted.
- # Clicking with the right mouse button on any item brings up a
- # special item menu. Clicking on the background area brings up
- # a different popup menu.
- # ----------------------------------------------------------------------
- # AUTHOR: Michael J. McLennan
- # Bell Labs Innovations for Lucent Technologies
- # mmclennan@lucent.com
- #
- # Mark L. Ulferts
- # DSC Communications
- # mulferts@austin.dsccc.com
- #
- # RCS: $Id: hierarchy.itk,v 1.9 2002/09/06 16:27:03 smithc Exp $
- # ----------------------------------------------------------------------
- # Copyright (c) 1996 Lucent Technologies
- # ======================================================================
- # Permission to use, copy, modify, and distribute this software and its
- # documentation for any purpose and without fee is hereby granted,
- # provided that the above copyright notice appear in all copies and that
- # both that the copyright notice and warranty disclaimer appear in
- # supporting documentation, and that the names of Lucent Technologies
- # any of their entities not be used in advertising or publicity
- # pertaining to distribution of the software without specific, written
- # prior permission.
- #
- # Lucent Technologies disclaims all warranties with regard to this
- # software, including all implied warranties of merchantability and
- # fitness. In no event shall Lucent Technologies be liable for any
- # special, indirect or consequential damages or any damages whatsoever
- # resulting from loss of use, data or profits, whether in an action of
- # contract, negligence or other tortuous action, arising out of or in
- # connection with the use or performance of this software.
- #
- # ----------------------------------------------------------------------
- # Copyright (c) 1996 DSC Technologies Corporation
- # ======================================================================
- # Permission to use, copy, modify, distribute and license this software
- # and its documentation for any purpose, and without fee or written
- # agreement with DSC, is hereby granted, provided that the above copyright
- # notice appears in all copies and that both the copyright notice and
- # warranty disclaimer below appear in supporting documentation, and that
- # the names of DSC Technologies Corporation or DSC Communications
- # Corporation not be used in advertising or publicity pertaining to the
- # software without specific, written prior permission.
- #
- # DSC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
- # ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, AND NON-
- # INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE
- # AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE,
- # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. IN NO EVENT SHALL
- # DSC BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
- # ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
- # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTUOUS ACTION,
- # ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
- # SOFTWARE.
- # ======================================================================
-
- #
- # Usual options.
- #
- itk::usual Hierarchy {
- keep -cursor -textfont -font
- keep -background -foreground -textbackground
- keep -selectbackground -selectforeground
- }
-
- # ------------------------------------------------------------------
- # HIERARCHY
- # ------------------------------------------------------------------
- itcl::class iwidgets::Hierarchy {
- inherit iwidgets::Scrolledwidget
-
- constructor {args} {}
-
- destructor {}
-
- itk_option define -alwaysquery alwaysQuery AlwaysQuery 0
- itk_option define -closedicon closedIcon Icon {}
- itk_option define -dblclickcommand dblClickCommand Command {}
- itk_option define -expanded expanded Expanded 0
- itk_option define -filter filter Filter 0
- itk_option define -font font Font \
- -*-Courier-Medium-R-Normal--*-120-*-*-*-*-*-*
- itk_option define -height height Height 0
- itk_option define -iconcommand iconCommand Command {}
- itk_option define -icondblcommand iconDblCommand Command {}
- itk_option define -imagecommand imageCommand Command {}
- itk_option define -imagedblcommand imageDblCommand Command {}
- itk_option define -imagemenuloadcommand imageMenuLoadCommand Command {}
- itk_option define -markbackground markBackground Foreground #a0a0a0
- itk_option define -markforeground markForeground Background Black
- itk_option define -nodeicon nodeIcon Icon {}
- itk_option define -openicon openIcon Icon {}
- itk_option define -querycommand queryCommand Command {}
- itk_option define -selectcommand selectCommand Command {}
- itk_option define -selectbackground selectBackground Foreground #c3c3c3
- itk_option define -selectforeground selectForeground Background Black
- itk_option define -textmenuloadcommand textMenuLoadCommand Command {}
- itk_option define -visibleitems visibleItems VisibleItems 80x24
- itk_option define -width width Width 0
-
- public {
- method clear {}
- method collapse {node}
- method current {}
- method draw {{when -now}}
- method expand {node}
- method expanded {node}
- method expState { }
- method mark {op args}
- method prune {node}
- method refresh {node}
- method selection {op args}
- method toggle {node}
-
- method bbox {index}
- method compare {index1 op index2}
- method debug {args} {eval $args}
- method delete {first {last {}}}
- method dlineinfo {index}
- method dump {args}
- method get {index1 {index2 {}}}
- method index {index}
- method insert {args}
- method scan {option args}
- method search {args}
- method see {index}
- method tag {op args}
- method window {option args}
- method xview {args}
- method yview {args}
- }
-
- protected {
- method _contents {uid}
- method _post {x y}
- method _drawLevel {node indent}
- method _select {x y}
- method _deselectSubNodes {uid}
- method _deleteNodeInfo {uid}
- method _getParent {uid}
- method _getHeritage {uid}
- method _isInternalTag {tag}
- method _iconSelect {node icon}
- method _iconDblSelect {node icon}
- method _imageSelect {node}
- method _imageDblClick {node}
- method _imagePost {node image type x y}
- method _double {x y}
- }
-
- private {
- method _configureTags {}
-
- variable _filterCode "" ;# Compact view flag.
- variable _hcounter 0 ;# Counter for hierarchy icons
- variable _icons ;# Array of user icons by uid
- variable _images ;# Array of our icons by uid
- variable _indents ;# Array of indentation by uid
- variable _marked ;# Array of marked nodes by uid
- variable _markers "" ;# List of markers for level being drawn
- variable _nodes ;# Array of subnodes by uid
- variable _pending "" ;# Pending draw flag
- variable _posted "" ;# List of tags at posted menu position
- variable _selected ;# Array of selected nodes by uid
- variable _tags ;# Array of user tags by uid
- variable _text ;# Array of displayed text by uid
- variable _states ;# Array of selection state by uid
- variable _ucounter 0 ;# Counter for user icons
- }
- }
-
- #
- # Provide a lowercased access method for the Hierarchy class.
- #
- proc ::iwidgets::hierarchy {pathName args} {
- uplevel ::iwidgets::Hierarchy $pathName $args
- }
-
- #
- # Use option database to override default resources of base classes.
- #
- option add *Hierarchy.menuCursor arrow widgetDefault
- option add *Hierarchy.labelPos n widgetDefault
- option add *Hierarchy.tabs 30 widgetDefault
-
- # ------------------------------------------------------------------
- # CONSTRUCTOR
- # ------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::constructor {args} {
- itk_option remove iwidgets::Labeledwidget::state
-
- #
- # Our -width and -height options are slightly different than
- # those implemented by our base class, so we're going to
- # remove them and redefine our own.
- #
- itk_option remove iwidgets::Scrolledwidget::width
- itk_option remove iwidgets::Scrolledwidget::height
-
- #
- # Create a clipping frame which will provide the border for
- # relief display.
- #
- itk_component add clipper {
- frame $itk_interior.clipper
- } {
- usual
-
- keep -borderwidth -relief -highlightthickness -highlightcolor
- rename -highlightbackground -background background Background
- }
- grid $itk_component(clipper) -row 0 -column 0 -sticky nsew
- grid rowconfigure $_interior 0 -weight 1
- grid columnconfigure $_interior 0 -weight 1
-
- #
- # Create a text widget for displaying our hierarchy.
- #
- itk_component add list {
- text $itk_component(clipper).list -wrap none -cursor center_ptr \
- -state disabled -width 1 -height 1 \
- -xscrollcommand \
- [itcl::code $this _scrollWidget $itk_interior.horizsb] \
- -yscrollcommand \
- [itcl::code $this _scrollWidget $itk_interior.vertsb] \
- -borderwidth 0 -highlightthickness 0
- } {
- usual
-
- keep -spacing1 -spacing2 -spacing3 -tabs
- rename -font -textfont textFont Font
- rename -background -textbackground textBackground Background
- ignore -highlightthickness -highlightcolor
- ignore -insertbackground -insertborderwidth
- ignore -insertontime -insertofftime -insertwidth
- ignore -selectborderwidth
- ignore -borderwidth
- }
- grid $itk_component(list) -row 0 -column 0 -sticky nsew
- grid rowconfigure $itk_component(clipper) 0 -weight 1
- grid columnconfigure $itk_component(clipper) 0 -weight 1
-
- #
- # Configure the command on the vertical scroll bar in the base class.
- #
- $itk_component(vertsb) configure \
- -command [itcl::code $itk_component(list) yview]
-
- #
- # Configure the command on the horizontal scroll bar in the base class.
- #
- $itk_component(horizsb) configure \
- -command [itcl::code $itk_component(list) xview]
-
- #
- # Configure our text component's tab settings for twenty levels.
- #
- set tabs ""
- for {set i 1} {$i < 20} {incr i} {
- lappend tabs [expr {$i*12+4}]
- }
- $itk_component(list) configure -tabs $tabs
-
- #
- # Add popup menus that can be configured by the user to add
- # new functionality.
- #
- itk_component add itemMenu {
- menu $itk_component(list).itemmenu -tearoff 0
- } {
- usual
- ignore -tearoff
- rename -cursor -menucursor menuCursor Cursor
- }
-
- itk_component add bgMenu {
- menu $itk_component(list).bgmenu -tearoff 0
- } {
- usual
- ignore -tearoff
- rename -cursor -menucursor menuCursor Cursor
- }
-
- #
- # Adjust the bind tags to remove the class bindings. Also, add
- # bindings for mouse button 1 to do selection and button 3 to
- # display a popup.
- #
- bindtags $itk_component(list) [list $itk_component(list) . all]
-
- bind $itk_component(list) <ButtonPress-1> \
- [itcl::code $this _select %x %y]
-
- bind $itk_component(list) <Double-1> \
- [itcl::code $this _double %x %y]
-
- bind $itk_component(list) <ButtonPress-3> \
- [itcl::code $this _post %x %y]
-
- #
- # Initialize the widget based on the command line options.
- #
- eval itk_initialize $args
- }
-
- # ------------------------------------------------------------------
- # DESTRUCTOR
- # ------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::destructor {} {
- if {$_pending != ""} {
- after cancel $_pending
- }
- }
-
- # ------------------------------------------------------------------
- # OPTIONS
- # ------------------------------------------------------------------
-
- # ------------------------------------------------------------------
- # OPTION: -font
- #
- # Font used for text in the list.
- # ------------------------------------------------------------------
- itcl::configbody iwidgets::Hierarchy::font {
- $itk_component(list) tag configure info \
- -font $itk_option(-font) -spacing1 6
- }
-
- # ------------------------------------------------------------------
- # OPTION: -selectbackground
- #
- # Background color scheme for selected nodes.
- # ------------------------------------------------------------------
- itcl::configbody iwidgets::Hierarchy::selectbackground {
- $itk_component(list) tag configure hilite \
- -background $itk_option(-selectbackground)
- }
-
- # ------------------------------------------------------------------
- # OPTION: -selectforeground
- #
- # Foreground color scheme for selected nodes.
- # ------------------------------------------------------------------
- itcl::configbody iwidgets::Hierarchy::selectforeground {
- $itk_component(list) tag configure hilite \
- -foreground $itk_option(-selectforeground)
- }
-
- # ------------------------------------------------------------------
- # OPTION: -markbackground
- #
- # Background color scheme for marked nodes.
- # ------------------------------------------------------------------
- itcl::configbody iwidgets::Hierarchy::markbackground {
- $itk_component(list) tag configure lowlite \
- -background $itk_option(-markbackground)
- }
-
- # ------------------------------------------------------------------
- # OPTION: -markforeground
- #
- # Foreground color scheme for marked nodes.
- # ------------------------------------------------------------------
- itcl::configbody iwidgets::Hierarchy::markforeground {
- $itk_component(list) tag configure lowlite \
- -foreground $itk_option(-markforeground)
- }
-
- # ------------------------------------------------------------------
- # OPTION: -querycommand
- #
- # Command executed to query the contents of each node. If this
- # command contains "%n", it is replaced with the name of the desired
- # node. In its simpilest form it should return the children of the
- # given node as a list which will be depicted in the display.
- #
- # Since the names of the children are used as tags in the underlying
- # text widget, each child must be unique in the hierarchy. Due to
- # the unique requirement, the nodes shall be reffered to as uids
- # or uid in the singular sense.
- #
- # {uid [uid ...]}
- #
- # where uid is a unique id and primary key for the hierarchy entry
- #
- # Should the unique requirement pose a problem, the list returned
- # can take on another more extended form which enables the
- # association of text to be displayed with the uids. The uid must
- # still be unique, but the text does not have to obey the unique
- # rule. In addition, the format also allows the specification of
- # additional tags to be used on the same entry in the hierarchy
- # as the uid and additional icons to be displayed just before
- # the node. The tags and icons are considered to be the property of
- # the user in that the hierarchy widget will not depend on any of
- # their values.
- #
- # {{uid [text [tags [icons]]]} {uid [text [tags [icons]]]} ...}
- #
- # where uid is a unique id and primary key for the hierarchy entry
- # text is the text to be displayed for this uid
- # tags is a list of user tags to be applied to the entry
- # icons is a list of icons to be displayed in front of the text
- #
- # The hierarchy widget does a look ahead from each node to determine
- # if the node has a children. This can be cost some performace with
- # large hierarchies. User's can avoid this by providing a hint in
- # the user tags. A tag of "leaf" or "branch" tells the hierarchy
- # widget the information it needs to know thereby avoiding the look
- # ahead operation.
- # ------------------------------------------------------------------
- itcl::configbody iwidgets::Hierarchy::querycommand {
- clear
- draw -eventually
-
- # Added for SF ticket #596111
- _configureTags
- }
-
- # ------------------------------------------------------------------
- # OPTION: -selectcommand
- #
- # Command executed to select an item in the list. If this command
- # contains "%n", it is replaced with the name of the selected node.
- # If it contains a "%s", it is replaced with a boolean indicator of
- # the node's current selection status, where a value of 1 denotes
- # that the node is currently selected and 0 that it is not.
- # ------------------------------------------------------------------
- itcl::configbody iwidgets::Hierarchy::selectcommand {
- }
-
- # ------------------------------------------------------------------
- # OPTION: -dblclickcommand
- #
- # Command executed to double click an item in the list. If this command
- # contains "%n", it is replaced with the name of the selected node.
- # If it contains a "%s", it is replaced with a boolean indicator of
- # the node's current selection status, where a value of 1 denotes
- # that the node is currently selected and 0 that it is not.
- #
- # Douglas R. Howard, Jr.
- # ------------------------------------------------------------------
- itcl::configbody iwidgets::Hierarchy::dblclickcommand {
- }
-
- # ------------------------------------------------------------------
- # OPTION: -iconcommand
- #
- # Command executed upon selection of user icons. If this command
- # contains "%n", it is replaced with the name of the node the icon
- # belongs to. Should it contain "%i" then the icon name is
- # substituted.
- # ------------------------------------------------------------------
- itcl::configbody iwidgets::Hierarchy::iconcommand {
- }
-
- # ------------------------------------------------------------------
- # OPTION: -icondblcommand
- #
- # Command executed upon double selection of user icons. If this command
- # contains "%n", it is replaced with the name of the node the icon
- # belongs to. Should it contain "%i" then the icon name is
- # substituted.
- #
- # Douglas R. Howard, Jr.
- # ------------------------------------------------------------------
- itcl::configbody iwidgets::Hierarchy::icondblcommand {
- }
-
- # ------------------------------------------------------------------
- # OPTION: -imagecommand
- #
- # Command executed upon selection of image icons. If this command
- # contains "%n", it is replaced with the name of the node the icon
- # belongs to. Should it contain "%i" then the icon name is
- # substituted.
- #
- # Douglas R. Howard, Jr.
- # ------------------------------------------------------------------
- itcl::configbody iwidgets::Hierarchy::imagecommand {
- }
-
- # ------------------------------------------------------------------
- # OPTION: -imagedblcommand
- #
- # Command executed upon double selection of user icons. If this command
- # contains "%n", it is replaced with the name of the node the icon
- # belongs to.
- #
- # Douglas R. Howard, Jr.
- # ------------------------------------------------------------------
- itcl::configbody iwidgets::Hierarchy::imagedblcommand {
- }
-
- # ------------------------------------------------------------------
- # OPTION: -alwaysquery
- #
- # Boolean flag which tells the hierarchy widget weather or not
- # each refresh of the display should be via a new query using
- # the -querycommand option or use the values previous found the
- # last time the query was made.
- # ------------------------------------------------------------------
- itcl::configbody iwidgets::Hierarchy::alwaysquery {
- switch -- $itk_option(-alwaysquery) {
- 1 - true - yes - on {
- ;# okay
- }
- 0 - false - no - off {
- ;# okay
- }
- default {
- error "bad alwaysquery option \"$itk_option(-alwaysquery)\":\
- should be boolean"
- }
- }
- }
-
- # ------------------------------------------------------------------
- # OPTION: -filter
- #
- # When true only the branch nodes and selected items are displayed.
- # This gives a compact view of important items.
- # ------------------------------------------------------------------
- itcl::configbody iwidgets::Hierarchy::filter {
- switch -- $itk_option(-filter) {
- 1 - true - yes - on {
- set newCode {set display [info exists _selected($child)]}
- }
- 0 - false - no - off {
- set newCode {set display 1}
- }
- default {
- error "bad filter option \"$itk_option(-filter)\":\
- should be boolean"
- }
- }
- if {$newCode != $_filterCode} {
- set _filterCode $newCode
- draw -eventually
- }
- }
-
- # ------------------------------------------------------------------
- # OPTION: -expanded
- #
- # When true, the hierarchy will be completely expanded when it
- # is first displayed. A fresh display can be triggered by
- # resetting the -querycommand option.
- # ------------------------------------------------------------------
- itcl::configbody iwidgets::Hierarchy::expanded {
- switch -- $itk_option(-expanded) {
- 1 - true - yes - on {
- ;# okay
- }
- 0 - false - no - off {
- ;# okay
- }
- default {
- error "bad expanded option \"$itk_option(-expanded)\":\
- should be boolean"
- }
- }
- }
-
- # ------------------------------------------------------------------
- # OPTION: -openicon
- #
- # Specifies the open icon image to be used in the hierarchy. Should
- # one not be provided, then one will be generated, pixmap if
- # possible, bitmap otherwise.
- # ------------------------------------------------------------------
- itcl::configbody iwidgets::Hierarchy::openicon {
- if {$itk_option(-openicon) == {}} {
- if {[lsearch [image names] openFolder] == -1} {
- if {[lsearch [image types] pixmap] != -1} {
- image create pixmap openFolder -data {
- /* XPM */
- static char * dir_opened [] = {
- "16 16 4 1",
- /* colors */
- ". c grey85 m white g4 grey90",
- "b c black m black g4 black",
- "y c yellow m white g4 grey80",
- "g c grey70 m white g4 grey70",
- /* pixels */
- "................",
- "................",
- "................",
- "..bbbb..........",
- ".bggggb.........",
- "bggggggbbbbbbb..",
- "bggggggggggggb..",
- "bgbbbbbbbbbbbbbb",
- "bgbyyyyyyyyyyybb",
- "bbyyyyyyyyyyyyb.",
- "bbyyyyyyyyyyybb.",
- "byyyyyyyyyyyyb..",
- "bbbbbbbbbbbbbb..",
- "................",
- "................",
- "................"};
- }
- } else {
- image create bitmap openFolder -data {
- #define open_width 16
- #define open_height 16
- static char open_bits[] = {
- 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x42, 0x00,
- 0x81, 0x3f, 0x01, 0x20, 0xf9, 0xff, 0x0d, 0xc0,
- 0x07, 0x40, 0x03, 0x60, 0x01, 0x20, 0x01, 0x30,
- 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
- }
- }
- }
- set itk_option(-openicon) openFolder
- } else {
- if {[lsearch [image names] $itk_option(-openicon)] == -1} {
- error "bad openicon option \"$itk_option(-openicon)\":\
- should be an existing image"
- }
- }
- }
-
- # ------------------------------------------------------------------
- # OPTION: -closedicon
- #
- # Specifies the closed icon image to be used in the hierarchy.
- # Should one not be provided, then one will be generated, pixmap if
- # possible, bitmap otherwise.
- # ------------------------------------------------------------------
- itcl::configbody iwidgets::Hierarchy::closedicon {
- if {$itk_option(-closedicon) == {}} {
- if {[lsearch [image names] closedFolder] == -1} {
- if {[lsearch [image types] pixmap] != -1} {
- image create pixmap closedFolder -data {
- /* XPM */
- static char *dir_closed[] = {
- "16 16 3 1",
- ". c grey85 m white g4 grey90",
- "b c black m black g4 black",
- "y c yellow m white g4 grey80",
- "................",
- "................",
- "................",
- "..bbbb..........",
- ".byyyyb.........",
- "bbbbbbbbbbbbbb..",
- "byyyyyyyyyyyyb..",
- "byyyyyyyyyyyyb..",
- "byyyyyyyyyyyyb..",
- "byyyyyyyyyyyyb..",
- "byyyyyyyyyyyyb..",
- "byyyyyyyyyyyyb..",
- "bbbbbbbbbbbbbb..",
- "................",
- "................",
- "................"};
- }
- } else {
- image create bitmap closedFolder -data {
- #define closed_width 16
- #define closed_height 16
- static char closed_bits[] = {
- 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x84, 0x00,
- 0xfe, 0x7f, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40,
- 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40,
- 0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
- }
- }
- }
- set itk_option(-closedicon) closedFolder
- } else {
- if {[lsearch [image names] $itk_option(-closedicon)] == -1} {
- error "bad closedicon option \"$itk_option(-closedicon)\":\
- should be an existing image"
- }
- }
- }
-
- # ------------------------------------------------------------------
- # OPTION: -nodeicon
- #
- # Specifies the node icon image to be used in the hierarchy. Should
- # one not be provided, then one will be generated, pixmap if
- # possible, bitmap otherwise.
- # ------------------------------------------------------------------
- itcl::configbody iwidgets::Hierarchy::nodeicon {
- if {$itk_option(-nodeicon) == {}} {
- if {[lsearch [image names] nodeFolder] == -1} {
- if {[lsearch [image types] pixmap] != -1} {
- image create pixmap nodeFolder -data {
- /* XPM */
- static char *dir_node[] = {
- "16 16 3 1",
- ". c grey85 m white g4 grey90",
- "b c black m black g4 black",
- "y c yellow m white g4 grey80",
- "................",
- "................",
- "................",
- "...bbbbbbbbbbb..",
- "..bybyyyyyyyyb..",
- ".byybyyyyyyyyb..",
- "byyybyyyyyyyyb..",
- "bbbbbyyyyyyyyb..",
- "byyyyyyyyyyyyb..",
- "byyyyyyyyyyyyb..",
- "byyyyyyyyyyyyb..",
- "byyyyyyyyyyyyb..",
- "bbbbbbbbbbbbbb..",
- "................",
- "................",
- "................"};
- }
- } else {
- image create bitmap nodeFolder -data {
- #define node_width 16
- #define node_height 16
- static char node_bits[] = {
- 0x00, 0x00, 0x00, 0x00, 0xe0, 0x7f, 0x50, 0x40,
- 0x48, 0x40, 0x44, 0x40, 0x42, 0x40, 0x7e, 0x40,
- 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40,
- 0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
- }
- }
- }
- set itk_option(-nodeicon) nodeFolder
- } else {
- if {[lsearch [image names] $itk_option(-nodeicon)] == -1} {
- error "bad nodeicon option \"$itk_option(-nodeicon)\":\
- should be an existing image"
- }
- }
- }
-
- # ------------------------------------------------------------------
- # OPTION: -width
- #
- # Specifies the width of the hierarchy widget as an entire unit.
- # The value may be specified in any of the forms acceptable to
- # Tk_GetPixels. Any additional space needed to display the other
- # components such as labels, margins, and scrollbars force the text
- # to be compressed. A value of zero along with the same value for
- # the height causes the value given for the visibleitems option
- # to be applied which administers geometry constraints in a different
- # manner.
- # ------------------------------------------------------------------
- itcl::configbody iwidgets::Hierarchy::width {
- if {$itk_option(-width) != 0} {
- set shell [lindex [grid info $itk_component(clipper)] 1]
-
- #
- # Due to a bug in the tk4.2 grid, we have to check the
- # propagation before setting it. Setting it to the same
- # value it already is will cause it to toggle.
- #
- if {[grid propagate $shell]} {
- grid propagate $shell no
- }
-
- $itk_component(list) configure -width 1
- $shell configure \
- -width [winfo pixels $shell $itk_option(-width)]
- } else {
- configure -visibleitems $itk_option(-visibleitems)
- }
- }
-
- # ------------------------------------------------------------------
- # OPTION: -height
- #
- # Specifies the height of the hierarchy widget as an entire unit.
- # The value may be specified in any of the forms acceptable to
- # Tk_GetPixels. Any additional space needed to display the other
- # components such as labels, margins, and scrollbars force the text
- # to be compressed. A value of zero along with the same value for
- # the width causes the value given for the visibleitems option
- # to be applied which administers geometry constraints in a different
- # manner.
- # ------------------------------------------------------------------
- itcl::configbody iwidgets::Hierarchy::height {
- if {$itk_option(-height) != 0} {
- set shell [lindex [grid info $itk_component(clipper)] 1]
-
- #
- # Due to a bug in the tk4.2 grid, we have to check the
- # propagation before setting it. Setting it to the same
- # value it already is will cause it to toggle.
- #
- if {[grid propagate $shell]} {
- grid propagate $shell no
- }
-
- $itk_component(list) configure -height 1
- $shell configure \
- -height [winfo pixels $shell $itk_option(-height)]
- } else {
- configure -visibleitems $itk_option(-visibleitems)
- }
- }
-
- # ------------------------------------------------------------------
- # OPTION: -visibleitems
- #
- # Specified the widthxheight in characters and lines for the text.
- # This option is only administered if the width and height options
- # are both set to zero, otherwise they take precedence. With the
- # visibleitems option engaged, geometry constraints are maintained
- # only on the text. The size of the other components such as
- # labels, margins, and scroll bars, are additive and independent,
- # effecting the overall size of the scrolled text. In contrast,
- # should the width and height options have non zero values, they
- # are applied to the scrolled text as a whole. The text is
- # compressed or expanded to maintain the geometry constraints.
- # ------------------------------------------------------------------
- itcl::configbody iwidgets::Hierarchy::visibleitems {
- if {[regexp {^[0-9]+x[0-9]+$} $itk_option(-visibleitems)]} {
- if {($itk_option(-width) == 0) && \
- ($itk_option(-height) == 0)} {
- set chars [lindex [split $itk_option(-visibleitems) x] 0]
- set lines [lindex [split $itk_option(-visibleitems) x] 1]
-
- set shell [lindex [grid info $itk_component(clipper)] 1]
-
- #
- # Due to a bug in the tk4.2 grid, we have to check the
- # propagation before setting it. Setting it to the same
- # value it already is will cause it to toggle.
- #
- if {! [grid propagate $shell]} {
- grid propagate $shell yes
- }
-
- $itk_component(list) configure -width $chars -height $lines
- }
-
- } else {
- error "bad visibleitems option\
- \"$itk_option(-visibleitems)\": should be\
- widthxheight"
- }
- }
-
- # ------------------------------------------------------------------
- # OPTION: -textmenuloadcommand
- #
- # Dynamically loads the popup menu based on what was selected.
- #
- # Douglas R. Howard, Jr.
- # ------------------------------------------------------------------
- itcl::configbody iwidgets::Hierarchy::textmenuloadcommand {}
-
- # ------------------------------------------------------------------
- # OPTION: -imagemenuloadcommand
- #
- # Dynamically loads the popup menu based on what was selected.
- #
- # Douglas R. Howard, Jr.
- # ------------------------------------------------------------------
- itcl::configbody iwidgets::Hierarchy::imagemenuloadcommand {}
-
-
- # ------------------------------------------------------------------
- # PUBLIC METHODS
- # ------------------------------------------------------------------
-
- # ----------------------------------------------------------------------
- # PUBLIC METHOD: clear
- #
- # Removes all items from the display including all tags and icons.
- # The display will remain empty until the -filter or -querycommand
- # options are set.
- # ----------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::clear {} {
- $itk_component(list) configure -state normal -cursor watch
- $itk_component(list) delete 1.0 end
- $itk_component(list) configure -state disabled -cursor $itk_option(-cursor)
-
- # Clear the tags
- eval $itk_component(list) tag delete [$itk_component(list) tag names]
-
- catch {unset _nodes}
- catch {unset _text}
- catch {unset _tags}
- catch {unset _icons}
- catch {unset _states}
- catch {unset _images}
- catch {unset _indents}
- catch {unset _marked}
- catch {unset _selected}
- set _markers ""
- set _posted ""
- set _ucounter 0
- set _hcounter 0
-
- foreach mark [$itk_component(list) mark names] {
- $itk_component(list) mark unset $mark
- }
-
- return
- }
-
- # ----------------------------------------------------------------------
- # PUBLIC METHOD: selection option ?uid uid...?
- #
- # Handles all operations controlling selections in the hierarchy.
- # Selections may be cleared, added, removed, or queried. The add and
- # remove options accept a series of unique ids.
- # ----------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::selection {op args} {
- switch -- $op {
- clear {
- $itk_component(list) tag remove hilite 1.0 end
- catch {unset _selected}
- return
- }
- add {
- foreach node $args {
- set _selected($node) 1
- catch {
- $itk_component(list) tag add hilite \
- "$node.first" "$node.last"
- }
- }
- }
- remove {
- foreach node $args {
- catch {
- unset _selected($node)
- $itk_component(list) tag remove hilite \
- "$node.first" "$node.last"
- }
- }
- }
- get {
- return [array names _selected]
- }
- default {
- error "bad selection operation \"$op\":\
- should be add, remove, clear or get"
- }
- }
- }
-
- # ----------------------------------------------------------------------
- # PUBLIC METHOD: mark option ?arg arg...?
- #
- # Handles all operations controlling marks in the hierarchy. Marks may
- # be cleared, added, removed, or queried. The add and remove options
- # accept a series of unique ids.
- # ----------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::mark {op args} {
- switch -- $op {
- clear {
- $itk_component(list) tag remove lowlite 1.0 end
- catch {unset _marked}
- return
- }
- add {
- foreach node $args {
- set _marked($node) 1
- catch {
- $itk_component(list) tag add lowlite \
- "$node.first" "$node.last"
- }
- }
- }
- remove {
- foreach node $args {
- catch {
- unset _marked($node)
- $itk_component(list) tag remove lowlite \
- "$node.first" "$node.last"
- }
- }
- }
- get {
- return [array names _marked]
- }
- default {
- error "bad mark operation \"$op\":\
- should be add, remove, clear or get"
- }
- }
- }
-
- # ----------------------------------------------------------------------
- # PUBLIC METHOD: current
- #
- # Returns the node that was most recently selected by the right mouse
- # button when the item menu was posted. Usually used by the code
- # in the item menu to figure out what item is being manipulated.
- # ----------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::current {} {
- return $_posted
- }
-
- # ----------------------------------------------------------------------
- # PUBLIC METHOD: expand node
- #
- # Expands the hierarchy beneath the specified node. Since this can take
- # a moment for large hierarchies, the cursor will be changed to a watch
- # during the expansion.
- # ----------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::expand {node} {
- if {! [info exists _states($node)]} {
- error "bad expand node argument: \"$node\", the node doesn't exist"
- }
-
- if {!$_states($node) && \
- (([lsearch $_tags($node) branch] != -1) || \
- ([llength [_contents $node]] > 0))} {
- $itk_component(list) configure -state normal -cursor watch
- update
-
- #
- # Get the indentation level for the node.
- #
- set indent $_indents($node)
-
- set _markers ""
- $itk_component(list) mark set insert "$node:start"
- _drawLevel $node $indent
-
- #
- # Following the draw, all our markers need adjusting.
- #
- foreach {name index} $_markers {
- $itk_component(list) mark set $name $index
- }
-
- #
- # Set the image to be the open icon, denote the new state,
- # and set the cursor back to normal along with the state.
- #
- $_images($node) configure -image $itk_option(-openicon)
-
- set _states($node) 1
-
- $itk_component(list) configure -state disabled \
- -cursor $itk_option(-cursor)
- }
- }
-
- # ----------------------------------------------------------------------
- # PUBLIC METHOD: collapse node
- #
- # Collapses the hierarchy beneath the specified node. Since this can
- # take a moment for large hierarchies, the cursor will be changed to a
- # watch during the expansion.
- # ----------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::collapse {node} {
- if {! [info exists _states($node)]} {
- error "bad collapse node argument: \"$node\", the node doesn't exist"
- }
-
- if {[info exists _states($node)] && $_states($node) && \
- (([lsearch $_tags($node) branch] != -1) || \
- ([llength [_contents $node]] > 0))} {
- $itk_component(list) configure -state normal -cursor watch
- update
-
- _deselectSubNodes $node
-
- $itk_component(list) delete "$node:start" "$node:end"
-
- catch {$_images($node) configure -image $itk_option(-closedicon)}
-
- set _states($node) 0
-
- $itk_component(list) configure -state disabled \
- -cursor $itk_option(-cursor)
- }
- }
-
- # ----------------------------------------------------------------------
- # PUBLIC METHOD: toggle node
- #
- # Toggles the hierarchy beneath the specified node. If the hierarchy
- # is currently expanded, then it is collapsed, and vice-versa.
- # ----------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::toggle {node} {
- if {! [info exists _states($node)]} {
- error "bad toggle node argument: \"$node\", the node doesn't exist"
- }
-
- if {$_states($node)} {
- collapse $node
- } else {
- expand $node
- }
- }
-
- # ----------------------------------------------------------------------
- # PUBLIC METHOD: prune node
- #
- # Removes a particular node from the hierarchy.
- # ----------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::prune {node} {
- #
- # While we're working, change the state and cursor so we can
- # edit the text and give a busy visual clue.
- #
- $itk_component(list) configure -state normal -cursor watch
-
- #
- # Recursively delete all the subnode information from our internal
- # arrays and remove all the tags.
- #
- _deleteNodeInfo $node
-
- #
- # If the mark $node:end exists then the node has decendents so
- # so we'll remove from the mark $node:start to $node:end in order
- # to delete all the subnodes below it in the text.
- #
- if {[lsearch [$itk_component(list) mark names] $node:end] != -1} {
- $itk_component(list) delete $node:start $node:end
- $itk_component(list) mark unset $node:end
- }
-
- #
- # Next we need to remove the node itself. Using the ranges for
- # its tag we'll remove it from line start to the end plus one
- # character which takes us to the start of the next node.
- #
- foreach {start end} [$itk_component(list) tag ranges $node] {
- $itk_component(list) delete "$start linestart" "$end + 1 char"
- }
-
- #
- # Delete the tag for this node.
- #
- $itk_component(list) tag delete $node
-
- #
- # The node must be removed from the list of subnodes for its parent.
- # We don't really have a clean way to do upwards referencing, so
- # the dirty way will have to do. We'll cycle through each node
- # and if this node is in its list of subnodes, we'll remove it.
- #
- foreach uid [array names _nodes] {
- if {[set index [lsearch $_nodes($uid) $node]] != -1} {
- set _nodes($uid) [lreplace $_nodes($uid) $index $index]
- }
- }
-
- #
- # We're done, so change the state and cursor back to their
- # original values.
- #
- $itk_component(list) configure -state disabled -cursor $itk_option(-cursor)
- }
-
- # ----------------------------------------------------------------------
- # PUBLIC METHOD: draw ?when?
- #
- # Performs a complete draw of the entire hierarchy.
- # ----------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::draw {{when -now}} {
- if {$when == "-eventually"} {
- if {$_pending == ""} {
- set _pending [after idle [itcl::code $this draw -now]]
- }
- return
- } elseif {$when != "-now"} {
- error "bad when option \"$when\": should be -eventually or -now"
- }
- $itk_component(list) configure -state normal -cursor watch
- update
-
- $itk_component(list) delete 1.0 end
- catch {unset _images}
- set _markers ""
-
- _drawLevel "" ""
-
- foreach {name index} $_markers {
- $itk_component(list) mark set $name $index
- }
-
- $itk_component(list) configure -state disabled -cursor $itk_option(-cursor)
- set _pending ""
- }
-
- # ----------------------------------------------------------------------
- # PUBLIC METHOD: refresh node
- #
- # Performs a redraw of a specific node. If that node is currently
- # not visible, then no action is taken.
- # ----------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::refresh {node} {
- if {! [info exists _nodes($node)]} {
- error "bad refresh node argument: \"$node\", the node doesn't exist"
- }
-
-
- if {! $_states($node)} {return}
-
- foreach parent [_getHeritage $node] {
- if {! $_states($parent)} {return}
- }
-
- $itk_component(list) configure -state normal -cursor watch
- $itk_component(list) delete $node:start $node:end
-
- set _markers ""
- $itk_component(list) mark set insert "$node:start"
- set indent $_indents($node)
-
- _drawLevel $node $indent
-
- foreach {name index} $_markers {
- $itk_component(list) mark set $name $index
- }
-
- $itk_component(list) configure -state disabled -cursor $itk_option(-cursor)
- }
-
- # ------------------------------------------------------------------
- # THIN WRAPPED TEXT METHODS:
- #
- # The following methods are thin wraps of standard text methods.
- # Consult the Tk text man pages for functionallity and argument
- # documentation.
- # ------------------------------------------------------------------
-
- # ------------------------------------------------------------------
- # PUBLIC METHOD: bbox index
- #
- # Returns four element list describing the bounding box for the list
- # item at index
- # ------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::bbox {index} {
- return [$itk_component(list) bbox $index]
- }
-
- # ------------------------------------------------------------------
- # PUBLIC METHOD compare index1 op index2
- #
- # Compare indices according to relational operator.
- # ------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::compare {index1 op index2} {
- return [$itk_component(list) compare $index1 $op $index2]
- }
-
- # ------------------------------------------------------------------
- # PUBLIC METHOD delete first ?last?
- #
- # Delete a range of characters from the text.
- # ------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::delete {first {last {}}} {
- $itk_component(list) configure -state normal -cursor watch
- $itk_component(list) delete $first $last
- $itk_component(list) configure -state disabled -cursor $itk_option(-cursor)
- }
-
- # ------------------------------------------------------------------
- # PUBLIC METHOD dump ?switches? index1 ?index2?
- #
- # Returns information about the contents of the text widget from
- # index1 to index2.
- # ------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::dump {args} {
- return [eval $itk_component(list) dump $args]
- }
-
- # ------------------------------------------------------------------
- # PUBLIC METHOD dlineinfo index
- #
- # Returns a five element list describing the area occupied by the
- # display line containing index.
- # ------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::dlineinfo {index} {
- return [$itk_component(list) dlineinfo $index]
- }
-
- # ------------------------------------------------------------------
- # PUBLIC METHOD get index1 ?index2?
- #
- # Return text from start index to end index.
- # ------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::get {index1 {index2 {}}} {
- return [$itk_component(list) get $index1 $index2]
- }
-
- # ------------------------------------------------------------------
- # PUBLIC METHOD index index
- #
- # Return position corresponding to index.
- # ------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::index {index} {
- return [$itk_component(list) index $index]
- }
-
- # ------------------------------------------------------------------
- # PUBLIC METHOD insert index chars ?tagList?
- #
- # Insert text at index.
- # ------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::insert {args} {
- $itk_component(list) configure -state normal -cursor watch
- eval $itk_component(list) insert $args
- $itk_component(list) configure -state disabled -cursor $itk_option(-cursor)
- }
-
- # ------------------------------------------------------------------
- # PUBLIC METHOD scan option args
- #
- # Implements scanning on texts.
- # ------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::scan {option args} {
- eval $itk_component(list) scan $option $args
- }
-
- # ------------------------------------------------------------------
- # PUBLIC METHOD search ?switches? pattern index ?varName?
- #
- # Searches the text for characters matching a pattern.
- # ------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::search {args} {
- return [eval $itk_component(list) search $args]
- }
-
- # ------------------------------------------------------------------
- # PUBLIC METHOD see index
- #
- # Adjusts the view in the window so the character at index is
- # visible.
- # ------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::see {index} {
- $itk_component(list) see $index
- }
-
- # ------------------------------------------------------------------
- # PUBLIC METHOD tag option ?arg arg ...?
- #
- # Manipulate tags dependent on options.
- # ------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::tag {op args} {
- return [eval $itk_component(list) tag $op $args]
- }
-
- # ------------------------------------------------------------------
- # PUBLIC METHOD window option ?arg arg ...?
- #
- # Manipulate embedded windows.
- # ------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::window {option args} {
- return [eval $itk_component(list) window $option $args]
- }
-
- # ----------------------------------------------------------------------
- # PUBLIC METHOD: xview args
- #
- # Thin wrap of the text widget's xview command.
- # ----------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::xview {args} {
- return [eval itk_component(list) xview $args]
- }
-
- # ----------------------------------------------------------------------
- # PUBLIC METHOD: yview args
- #
- # Thin wrap of the text widget's yview command.
- # ----------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::yview {args} {
- return [eval $itk_component(list) yview $args]
- }
-
- # ----------------------------------------------------------------------
- # PUBLIC METHOD: expanded node
- #
- # Tells if a node is expanded or collapsed
- #
- # Douglas R. Howard, Jr.
- # ----------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::expanded {node} {
- if {! [info exists _states($node)]} {
- error "bad collapse node argument: \"$node\", the node doesn't exist"
- }
-
- return $_states($node)
- }
-
- # ----------------------------------------------------------------------
- # PUBLIC METHOD: expState
- #
- # Returns a list of all expanded nodes
- #
- # Douglas R. Howard, Jr.
- # ----------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::expState {} {
- set nodes [_contents ""]
- set open ""
- set i 0
- while {1} {
- if {[info exists _states([lindex $nodes $i])] &&
- $_states([lindex $nodes $i])} {
- lappend open [lindex $nodes $i]
- foreach child [_contents [lindex $nodes $i]] {
- lappend nodes $child
- }
- }
- incr i
- if {$i >= [llength $nodes]} {break}
- }
-
- return $open
- }
-
- # ------------------------------------------------------------------
- # PROTECTED METHODS
- # ------------------------------------------------------------------
-
- # ----------------------------------------------------------------------
- # PROTECTED METHOD: _drawLevel node indent
- #
- # Used internally by draw to draw one level of the hierarchy.
- # Draws all of the nodes under node, using the indent string to
- # indent nodes.
- # ----------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::_drawLevel {node indent} {
- lappend _markers "$node:start" [$itk_component(list) index insert]
- set bg [$itk_component(list) cget -background]
-
- #
- # Obtain the list of subnodes for this node and cycle through
- # each one displaying it in the hierarchy.
- #
- foreach child [_contents $node] {
- set _images($child) "$itk_component(list).hicon[incr _hcounter]"
-
- if {![info exists _states($child)]} {
- set _states($child) $itk_option(-expanded)
- }
-
- #
- # Check the user tags to see if they have been kind enough
- # to tell us ahead of time what type of node we are dealing
- # with branch or leaf. If they neglected to do so, then
- # get the contents of the child node to see if it has children
- # itself.
- #
- set display 0
-
- if {[lsearch $_tags($child) leaf] != -1} {
- set type leaf
- } elseif {[lsearch $_tags($child) branch] != -1} {
- set type branch
- } else {
- if {[llength [_contents $child]] == 0} {
- set type leaf
- } else {
- set type branch
- }
- }
-
- #
- # Now that we know the type of node, branch or leaf, we know
- # the type of icon to use.
- #
- if {$type == "leaf"} {
- set icon $itk_option(-nodeicon)
- eval $_filterCode
- } else {
- if {$_states($child)} {
- set icon $itk_option(-openicon)
- } else {
- set icon $itk_option(-closedicon)
- }
- set display 1
- }
-
- #
- # If display is set then we're going to be drawing this node.
- # Save off the indentation level for this node and do the indent.
- #
- if {$display} {
- set _indents($child) "$indent\t"
- $itk_component(list) insert insert $indent
-
- #
- # Add the branch or leaf icon and setup a binding to toggle
- # its expanded/collapsed state.
- #
- label $_images($child) -image $icon -background $bg
- # DRH - enhanced and added features that handle image clicking,
- # double clicking, and right clicking behavior
- bind $_images($child) <ButtonPress-1> \
- "[itcl::code $this toggle $child]; [itcl::code $this _imageSelect $child]"
- bind $_images($child) <Double-1> [itcl::code $this _imageDblClick $child]
- bind $_images($child) <ButtonPress-3> \
- [itcl::code $this _imagePost $child $_images($child) $type %x %y]
- $itk_component(list) window create insert -window $_images($child)
-
- #
- # If any user icons exist then draw them as well. The little
- # regexp is just to check and see if they've passed in a
- # command which needs to be evaluated as opposed to just
- # a variable. Also, attach a binding to call them if their
- # icon is selected.
- #
- if {[info exists _icons($child)]} {
- foreach image $_icons($child) {
- set wid "$itk_component(list).uicon[incr _ucounter]"
-
- if {[regexp {\[.*\]} $image]} {
- eval label $wid -image $image -background $bg
- } else {
- label $wid -image $image -background $bg
- }
-
- # DRH - this will bind events to the icons to allow
- # clicking, double clicking, and right clicking actions.
- bind $wid <ButtonPress-1> \
- [itcl::code $this _iconSelect $child $image]
- bind $wid <Double-1> \
- [itcl::code $this _iconDblSelect $child $image]
- bind $wid <ButtonPress-3> \
- [itcl::code $this _imagePost $child $wid $type %x %y]
- $itk_component(list) window create insert -window $wid
- }
- }
-
- #
- # Create the list of tags to be applied to the text. Start
- # out with a tag of "info" and append "hilite" if the node
- # is currently selected, finally add the tags given by the
- # user.
- #
- set texttags [list "info" $child]
-
- if {[info exists _selected($child)]} {
- lappend texttags hilite
- }
-
- # The following conditional added for SF ticket #600941.
- if {[info exists _marked($child)]} {
- lappend texttags lowlite
- }
-
- foreach tag $_tags($child) {
- lappend texttags $tag
- }
-
- #
- # Insert the text for the node along with the tags and
- # append to the markers the start of this node. The text
- # has been broken at newlines into a list. We'll make sure
- # that each line is at the same indentation position.
- #
- set firstline 1
- foreach line $_text($child) {
- if {$firstline} {
- $itk_component(list) insert insert " "
- } else {
- $itk_component(list) insert insert "$indent\t"
- }
-
- $itk_component(list) insert insert $line $texttags "\n"
- set firstline 0
- }
-
- $itk_component(list) tag raise $child
- lappend _markers "$child:start" [$itk_component(list) index insert]
-
- #
- # If the state of the node is open, proceed to draw the next
- # node below it in the hierarchy.
- #
- if {$_states($child)} {
- _drawLevel $child "$indent\t"
- }
- }
- }
-
- lappend _markers "$node:end" [$itk_component(list) index insert]
- }
-
- # ----------------------------------------------------------------------
- # PROTECTED METHOD: _contents uid
- #
- # Used internally to get the contents of a particular node. If this
- # is the first time the node has been seen or the -alwaysquery
- # option is set, the -querycommand code is executed to query the node
- # list, and the list is stored until the next time it is needed.
- #
- # The querycommand may return not only the list of subnodes for the
- # node but additional information on the tags and icons to be used.
- # The return value must be parsed based on the number of elements in
- # the list where the format is a list of lists:
- #
- # {{uid [text [tags [icons]]]} {uid [text [tags [icons]]]} ...}
- # ----------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::_contents {uid} {
- if {$itk_option(-alwaysquery)} {
- } else {
- if {[info exists _nodes($uid)]} {
- return $_nodes($uid)
- }
- }
-
- #
- # Substitute any %n's for the node name whose children we're
- # interested in obtaining.
- #
- set cmd $itk_option(-querycommand)
- regsub -all {%n} $cmd [list $uid] cmd
-
- set nodeinfolist [uplevel \#0 $cmd]
-
- #
- # Cycle through the node information returned by the query
- # command determining if additional information such as text,
- # user tags, or user icons have been provided. For text,
- # break it into a list at any newline characters.
- #
- set _nodes($uid) {}
-
- foreach nodeinfo $nodeinfolist {
- set subnodeuid [lindex $nodeinfo 0]
- lappend _nodes($uid) $subnodeuid
-
- set llen [llength $nodeinfo]
-
- if {$llen == 0 || $llen > 4} {
- error "invalid number of elements returned by query\
- command for node: \"$uid\",\
- should be uid \[text \[tags \[icons\]\]\]"
- }
-
- if {$llen == 1} {
- set _text($subnodeuid) [split $subnodeuid \n]
- }
- if {$llen > 1} {
- set _text($subnodeuid) [split [lindex $nodeinfo 1] \n]
- }
- if {$llen > 2} {
- set _tags($subnodeuid) [lindex $nodeinfo 2]
- } else {
- set _tags($subnodeuid) unknown
- }
- if {$llen > 3} {
- set _icons($subnodeuid) [lindex $nodeinfo 3]
- }
- }
-
- #
- # Return the list of nodes.
- #
- return $_nodes($uid)
- }
-
- # ----------------------------------------------------------------------
- # PROTECTED METHOD: _post x y
- #
- # Used internally to post the popup menu at the coordinate (x,y)
- # relative to the widget. If (x,y) is on an item, then the itemMenu
- # component is posted. Otherwise, the bgMenu is posted.
- # ----------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::_post {x y} {
- set rx [expr {[winfo rootx $itk_component(list)]+$x}]
- set ry [expr {[winfo rooty $itk_component(list)]+$y}]
-
- set index [$itk_component(list) index @$x,$y]
-
- #
- # The posted variable will hold the list of tags which exist at
- # this x,y position that will be passed back to the user. They
- # don't need to know about our internal tags, info, hilite, and
- # lowlite, so remove them from the list.
- #
- set _posted {}
-
- foreach tag [$itk_component(list) tag names $index] {
- if {![_isInternalTag $tag]} {
- lappend _posted $tag
- }
- }
-
- #
- # If we have tags then do the popup at this position.
- #
- if {$_posted != {}} {
- # DRH - here is where the user's function for dynamic popup
- # menu loading is done, if the user has specified to do so with the
- # "-textmenuloadcommand"
- if {$itk_option(-textmenuloadcommand) != {}} {
- eval $itk_option(-textmenuloadcommand)
- }
- tk_popup $itk_component(itemMenu) $rx $ry
- } else {
- tk_popup $itk_component(bgMenu) $rx $ry
- }
- }
-
- # ----------------------------------------------------------------------
- # PROTECTED METHOD: _imagePost node image type x y
- #
- # Used internally to post the popup menu at the coordinate (x,y)
- # relative to the widget. If (x,y) is on an image, then the itemMenu
- # component is posted.
- #
- # Douglas R. Howard, Jr.
- # ----------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::_imagePost {node image type x y} {
- set rx [expr {[winfo rootx $image]+$x}]
- set ry [expr {[winfo rooty $image]+$y}]
-
- #
- # The posted variable will hold the list of tags which exist at
- # this x,y position that will be passed back to the user. They
- # don't need to know about our internal tags, info, hilite, and
- # lowlite, so remove them from the list.
- #
- set _posted {}
-
- lappend _posted $node $type
-
- #
- # If we have tags then do the popup at this position.
- #
- if {$itk_option(-imagemenuloadcommand) != {}} {
- eval $itk_option(-imagemenuloadcommand)
- }
- tk_popup $itk_component(itemMenu) $rx $ry
- }
-
- # ----------------------------------------------------------------------
- # PROTECTED METHOD: _select x y
- #
- # Used internally to select an item at the coordinate (x,y) relative
- # to the widget. The command associated with the -selectcommand
- # option is execute following % character substitutions. If %n
- # appears in the command, the selected node is substituted. If %s
- # appears, a boolean value representing the current selection state
- # will be substituted.
- # ----------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::_select {x y} {
- if {$itk_option(-selectcommand) != {}} {
- if {[set seltags [$itk_component(list) tag names @$x,$y]] != {}} {
- foreach tag $seltags {
- if {![_isInternalTag $tag]} {
- lappend node $tag
- }
- }
-
- if {[lsearch $seltags "hilite"] == -1} {
- set selectstatus 0
- } else {
- set selectstatus 1
- }
-
- set cmd $itk_option(-selectcommand)
- regsub -all {%n} $cmd [lindex $node end] cmd
- regsub -all {%s} $cmd [list $selectstatus] cmd
-
- uplevel #0 $cmd
- }
- }
-
- return
- }
-
- # ----------------------------------------------------------------------
- # PROTECTED METHOD: _double x y
- #
- # Used internally to double click an item at the coordinate (x,y) relative
- # to the widget. The command associated with the -dblclickcommand
- # option is execute following % character substitutions. If %n
- # appears in the command, the selected node is substituted. If %s
- # appears, a boolean value representing the current selection state
- # will be substituted.
- #
- # Douglas R. Howard, Jr.
- # ----------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::_double {x y} {
- if {$itk_option(-dblclickcommand) != {}} {
- if {[set seltags [$itk_component(list) tag names @$x,$y]] != {}} {
- foreach tag $seltags {
- if {![_isInternalTag $tag]} {
- lappend node $tag
- }
- }
-
- if {[lsearch $seltags "hilite"] == -1} {
- set selectstatus 0
- } else {
- set selectstatus 1
- }
-
- set cmd $itk_option(-dblclickcommand)
- regsub -all {%n} $cmd [list $node] cmd
- regsub -all {%s} $cmd [list $selectstatus] cmd
-
- uplevel #0 $cmd
- }
- }
-
- return
- }
-
- # ----------------------------------------------------------------------
- # PROTECTED METHOD: _iconSelect node icon
- #
- # Used internally to upon selection of user icons. The -iconcommand
- # is executed after substitution of the node for %n and icon for %i.
- #
- # Douglas R. Howard, Jr.
- # ----------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::_iconSelect {node icon} {
- set cmd $itk_option(-iconcommand)
- regsub -all {%n} $cmd [list $node] cmd
- regsub -all {%i} $cmd [list $icon] cmd
-
- uplevel \#0 $cmd
-
- return {}
- }
-
- # ----------------------------------------------------------------------
- # PROTECTED METHOD: _iconDblSelect node icon
- #
- # Used internally to upon double selection of user icons. The
- # -icondblcommand is executed after substitution of the node for %n and
- # icon for %i.
- #
- # Douglas R. Howard, Jr.
- # ----------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::_iconDblSelect {node icon} {
- if {$itk_option(-icondblcommand) != {}} {
- set cmd $itk_option(-icondblcommand)
- regsub -all {%n} $cmd [list $node] cmd
- regsub -all {%i} $cmd [list $icon] cmd
-
- uplevel \#0 $cmd
- }
- return {}
- }
-
- # ----------------------------------------------------------------------
- # PROTECTED METHOD: _imageSelect node icon
- #
- # Used internally to upon selection of user icons. The -imagecommand
- # is executed after substitution of the node for %n.
- #
- # Douglas R. Howard, Jr.
- # ----------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::_imageSelect {node} {
- if {$itk_option(-imagecommand) != {}} {
- set cmd $itk_option(-imagecommand)
- regsub -all {%n} $cmd [list $node] cmd
-
- uplevel \#0 $cmd
- }
- return {}
- }
-
- # ----------------------------------------------------------------------
- # PROTECTED METHOD: _imageDblClick node
- #
- # Used internally to upon double selection of images. The
- # -imagedblcommand is executed.
- #
- # Douglas R. Howard, Jr.
- # ----------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::_imageDblClick {node} {
- if {$itk_option(-imagedblcommand) != {}} {
- set cmd $itk_option(-imagedblcommand)
- regsub -all {%n} $cmd [list $node] cmd
-
- uplevel \#0 $cmd
- }
- return {}
- }
-
- # ----------------------------------------------------------------------
- # PROTECTED METHOD: _deselectSubNodes uid
- #
- # Used internally to recursively deselect all the nodes beneath a
- # particular node.
- # ----------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::_deselectSubNodes {uid} {
- foreach node $_nodes($uid) {
- if {[array names _selected $node] != {}} {
- unset _selected($node)
- }
-
- if {[array names _nodes $node] != {}} {
- _deselectSubNodes $node
- }
- }
- }
-
- # ----------------------------------------------------------------------
- # PROTECTED METHOD: _deleteNodeInfo uid
- #
- # Used internally to recursively delete all the information about a
- # node and its decendents.
- # ----------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::_deleteNodeInfo {uid} {
- #
- # Recursively call ourseleves as we go down the hierarchy beneath
- # this node.
- #
- if {[info exists _nodes($uid)]} {
- foreach node $_nodes($uid) {
- if {[array names _nodes $node] != {}} {
- _deleteNodeInfo $node
- }
- }
- }
-
- #
- # Unset any entries in our arrays for the node.
- #
- catch {unset _nodes($uid)}
- catch {unset _text($uid)}
- catch {unset _tags($uid)}
- catch {unset _icons($uid)}
- catch {unset _states($uid)}
- catch {unset _images($uid)}
- catch {unset _indents($uid)}
- }
-
- # ----------------------------------------------------------------------
- # PROTECTED METHOD: _getParent uid
- #
- # Used internally to determine the parent for a node.
- # ----------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::_getParent {uid} {
- foreach node [array names _nodes] {
- if {[set index [lsearch $_nodes($node) $uid]] != -1} {
- return $node
- }
- }
- }
-
- # ----------------------------------------------------------------------
- # PROTECTED METHOD: _getHeritage uid
- #
- # Used internally to determine the list of parents for a node.
- # ----------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::_getHeritage {uid} {
- set parents {}
-
- if {[set parent [_getParent $uid]] != {}} {
- lappend parents $parent
- }
-
- return $parents
- }
-
- # ----------------------------------------------------------------------
- # PROTECTED METHOD (could be proc?): _isInternalTag tag
- #
- # Used internally to tags not to used for user callback commands
- # ----------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::_isInternalTag {tag} {
- set ii [expr {[lsearch -exact {info hilite lowlite unknown} $tag] != -1}];
- return $ii;
- }
-
- # ----------------------------------------------------------------------
- # PRIVATE METHOD: _configureTags
- #
- # This method added to fix SF ticket #596111. When the -querycommand
- # is reset after initial construction, the text component loses its
- # tag configuration. This method resets the hilite, lowlite, and info
- # tags. csmith: 9/5/02
- # ----------------------------------------------------------------------
- itcl::body iwidgets::Hierarchy::_configureTags {} {
- tag configure hilite -background $itk_option(-selectbackground) \
- -foreground $itk_option(-selectforeground)
- tag configure lowlite -background $itk_option(-markbackground) \
- -foreground $itk_option(-markforeground)
- tag configure info -font $itk_option(-font) -spacing1 6
- }
-