#
# Fileselectionbox
# ----------------------------------------------------------------------
# Implements a file selection box that allows 2 different styles.  The
# default style is similar to the OSF/Motif standard XmFileselectionbox
# composite widget.  The Fileselectionbox is composed of directory and file
# scrolled lists as well as filter and selection entry fields.
#
# ----------------------------------------------------------------------
#  AUTHOR: Mark L. Ulferts               EMAIL: mulferts@spd.dsccc.com
#          Anthony L. Parent                    tony.parent@symbios.com
#
#  @(#) $Id: fileselectionbox.itk,v 1.1.1.1 1999/03/31 20:39:39 damon Exp $
# ----------------------------------------------------------------------
#            Copyright (c) 1995 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.
# ======================================================================

#
# Default resources,
#
option add *Fileselectionbox.borderWidth 2 widgetDefault

option add *Fileselectionbox.filterLabel Filter widgetDefault
option add *Fileselectionbox.filterLabelPos nw widgetDefault
option add *Fileselectionbox.filterOn yes widgetDefault

option add *Fileselectionbox.dirsLabel Directories widgetDefault
option add *Fileselectionbox.dirsLabelPos nw widgetDefault
option add *Fileselectionbox.dirsOn yes widgetDefault

option add *Fileselectionbox.filesLabel Files widgetDefault
option add *Fileselectionbox.filesLabelPos nw widgetDefault
option add *Fileselectionbox.filesOn yes widgetDefault

option add *Fileselectionbox.selectionLabel Selection widgetDefault
option add *Fileselectionbox.selectionLabelPos nw widgetDefault
option add *Fileselectionbox.selectionOn yes widgetDefault

option add *Fileselectionbox.vscrollMode static widgetDefault
option add *Fileselectionbox.hscrollMode static widgetDefault
option add *Fileselectionbox.scrollMargin 3 widgetDefault

option add *Fileselectionbox.vertMargin 7 widgetDefault
option add *Fileselectionbox.horizMargin 7 widgetDefault

option add *Fileselectionbox.width 470 widgetDefault
option add *Fileselectionbox.height 360 widgetDefault

#
# Usual options.
#
itk::usual Fileselectionbox {
    keep -activebackground -activerelief -background -borderwidth -cursor \
         -elementborderwidth -foreground -highlightcolor -highlightthickness \
         -insertbackground -insertborderwidth -insertofftime -insertontime \
         -insertwidth -jump -labelfont -selectbackground -selectborderwidth \
         -textbackground -textfont -troughcolor
}

# ------------------------------------------------------------------
#                          FILESELECTIONBOX
# ------------------------------------------------------------------
class iwidgets::Fileselectionbox {
    inherit itk::Widget

    constructor {args} {}
    destructor {}

    itk_option define -childsitepos childSitePos Position s
    itk_option define -fileson filesOn FilesOn true
    itk_option define -dirson dirsOn DirsOn true
    itk_option define -dirsfraction dirsfraction DirsFraction 50
    itk_option define -selectionon selectionOn SelectionOn true
    itk_option define -filteron filterOn FilterOn true
    itk_option define -vertmargin vertMargin Margin 7
    itk_option define -horizmargin horizMargin Margin 7
    itk_option define -mask mask Mask {*}
    itk_option define -directory directory Directory {}
    itk_option define -nomatchstring noMatchString NoMatchString {[   ]}
    itk_option define -dirsearchcommand dirSearchCommand Command {}
    itk_option define -filesearchcommand fileSearchCommand Command {}
    itk_option define -selectioncommand selectionCommand Command {}
    itk_option define -filtercommand filterCommand Command {}
    itk_option define -selectdircommand selectDirCommand Command {}
    itk_option define -selectfilecommand selectFileCommand Command {}
    itk_option define -invalid invalid Command {bell}
    itk_option define -filetype fileType FileType {regular}
    itk_option define -width width Width 470
    itk_option define -height height Height 360
    itk_option define -style style Style motif

    public method childsite {}
    public method get {}
    public method filter {}

    public method _selectDir {}
    public method _dblSelectDir {}
    public method _selectFile {}
    public method _selectSelection {}
    public method _selectFilter {}

    protected method _packComponents {{when later}}
    protected method _updateLists {{when later}}

    private method _setFilter {}
    private method _setSelection {}
    private method _setDirList {}
    private method _setFileList {}

    private variable _packToken ""      ;# non-null => _packComponents pending
    private variable _updateToken ""    ;# non-null => _updateLists pending
    private variable _pwd "."           ;# present working dir
    private variable _justify "right"   ;# justification of scrolled lists
}

#
# Provide a lowercased access method for the Fileselectionbox class.
#
proc ::iwidgets::fileselectionbox {pathName args} {
    uplevel ::iwidgets::Fileselectionbox $pathName $args
}

# ------------------------------------------------------------------
#                        CONSTRUCTOR
# ------------------------------------------------------------------
body iwidgets::Fileselectionbox::constructor {args} {

    component hull configure -borderwidth 0

    #
    # Create an internal frame to contain the components.
    #
    itk_component add frame {
        frame $itk_interior.frame
    } {
        keep -background -cursor
    }
    pack $itk_component(frame) -fill both -expand yes
    pack propagate $itk_component(frame) no

    #
    # Create the child site widget.
    #
    itk_component add childsite {
        frame $itk_interior.fsbchildsite
    } {
        keep -background -cursor
    }
    set itk_interior $itk_component(childsite)

    #
    # Create the filter entry.
    #
    itk_component add filter {
        iwidgets::combobox $itk_component(frame).filter -autoclear false -unique true \
                -command [code $this _selectFilter] -exportselection 0
    } {
        keep -background -borderwidth -cursor \
                -foreground -highlightcolor \
                -highlightthickness -insertbackground -insertborderwidth \
                -insertofftime -insertontime -insertwidth -labelfont \
                -labelmargin -relief -selectbackground -selectborderwidth \
                -selectforeground -textbackground -textfont

        rename -labeltext -filterlabel filterLabel Text
        rename -labelpos -filterlabelpos filterLabelPos Position
        rename -focuscommand -filterfocuscommand \
                filterFocusCommand Command
    }

    set cmd [$itk_component(filter) cget -command]
    set cmd "$cmd;[code $this _selectFilter]"
    $itk_component(filter) configure -command "$cmd" -selectioncommand "$cmd";

    #
    # Create the upper horizontal margin frame below the filter.
    #
    itk_component add humargin {
        frame $itk_component(frame).humargin
    } {
        keep -background -cursor
    }

    #
    # Create a paned window for the directory and file lists.
    #
    itk_component add listpane {
      iwidgets::panedwindow $itk_component(frame).listpane -orient vertical
    } {
        keep -background -cursor
    }
    pack $itk_component(listpane) -fill both -expand yes

    $itk_component(listpane) add dirs;
    $itk_component(listpane) add files;
    #
    # Create the directory list.
    #
    itk_component add dirs {
        iwidgets::Scrolledlistbox [$itk_component(listpane) childsite dirs].dirs \
                -selectioncommand [code $this _selectDir] \
                -selectmode single -exportselection 0 \
                -visibleitems 1x1
    } {
        keep -activebackground -activerelief -background -borderwidth \
                -cursor -elementborderwidth -foreground \
                -highlightcolor -highlightthickness -hscrollmode\
                -jump -labelfont -labelmargin -relief -repeatdelay \
                -repeatinterval -sbwidth -scrollmargin -selectbackground \
                -selectborderwidth -selectforeground -textbackground \
                -textfont -troughcolor -vscrollmode

        rename -labeltext -dirslabel dirsLabel Text
        rename -labelpos -dirslabelpos dirsLabelPos Position
        rename -dblclickcommand -dbldirscommand dblDirsCommand Command
    }
    pack configure $itk_component(dirs) -side left -fill both -expand yes

    #
    # Create the vertical margin frame between the lists.
    #
    itk_component add vmargin {
        frame [$itk_component(listpane) childsite files].vmargin
    } {
        keep -background -cursor
    }
    pack configure $itk_component(vmargin) -side left -fill y -expand no

    #
    # Create the files list.
    #
    itk_component add files {
        iwidgets::Scrolledlistbox [$itk_component(listpane) childsite files].files \
                -selectioncommand [code $this _selectFile] \
                -selectmode single -exportselection 0 \
                -visibleitems 1x1
    } {
        keep -activebackground -activerelief -background -borderwidth \
                -cursor -elementborderwidth -foreground \
                -highlightcolor -highlightthickness -hscrollmode \
                -jump -labelfont -labelmargin -relief -repeatdelay \
                -repeatinterval -sbwidth -scrollmargin -selectbackground \
                -selectborderwidth -selectforeground -textbackground \
                -textfont -troughcolor -vscrollmode

        rename -labeltext -fileslabel filesLabel Text
        rename -labelpos -fileslabelpos filesLabelPos Position
        rename -dblclickcommand -dblfilescommand \
                dblFilesCommand Command
    }
    pack configure $itk_component(files) -side left -fill both -expand yes

    #
    # Create the lower horizontal margin frame above the selection entry.
    #
    itk_component add hlmargin {
        frame $itk_component(frame).hlmargin
    } {
        keep -background -cursor
    }

    #
    # Create the selection entry.
    #
    itk_component add selection {
      iwidgets::combobox $itk_component(frame).selection -autoclear false -unique true \
                -command [code $this _selectSelection] -exportselection 0
    } {
        keep -background -borderwidth -cursor \
                -foreground -highlightcolor \
                -highlightthickness -insertbackground -insertborderwidth \
                -insertofftime -insertontime -insertwidth -labelfont \
                -labelmargin -relief -selectbackground -selectborderwidth \
                -selectforeground -textbackground -textfont

        rename -labeltext -selectionlabel selectionLabel Text
        rename -labelpos -selectionlabelpos selectionLabelPos Position
        rename -focuscommand -selectionfocuscommand \
                selectionFocusCommand Command
    }

    #
    # Explicitly handle configs that may have been ignored earlier.
    #
    eval itk_initialize $args

    if {$itk_option(-dbldirscommand) == {}} {
        configure -dbldirscommand [code $this _dblSelectDir]
    }

    #
    # When idle, pack the components and update the lists.
    #
    _packComponents
    _updateLists
}

# ------------------------------------------------------------------
#                           DESTRUCTOR
# ------------------------------------------------------------------
body iwidgets::Fileselectionbox::destructor {} {
    if {$_packToken != ""} {after cancel $_packToken}
    if {$_updateToken != ""} {after cancel $_updateToken}
}

# ------------------------------------------------------------------
#                             OPTIONS
# ------------------------------------------------------------------

# ------------------------------------------------------------------
# OPTION: -style
#
# Specifies the style of the file selection box motif or notif
# (default motif)
# ------------------------------------------------------------------
configbody iwidgets::Fileselectionbox::style {
    switch $itk_option(-style) {
	motif {
	    pack forget [$itk_component(filter) component arrowBtn]
	    pack forget [$itk_component(selection) component arrowBtn]
	    set _justify right
	    $itk_component(listpane) configure -thickness 0;
	    $itk_component(listpane) configure -sashwidth 0;
	    pack $itk_component(vmargin) -side left \
		    -before $itk_component(files)
	}
	notif {
	    pack [$itk_component(filter) component arrowBtn]
	    pack [$itk_component(selection) component arrowBtn]
	    set _justify left
	    $itk_component(listpane) configure -thickness 3;
	    $itk_component(listpane) configure -sashwidth 10;
	    pack forget $itk_component(vmargin)
	}
	default {
	    error "bad style option \"$itk_option(-style)\":\
		    should be motif or notif";
	}
    }

    filter;
}

# ------------------------------------------------------------------
# OPTION: -childsitepos
#
# Specifies the position of the child site in the selection box.
# ------------------------------------------------------------------
configbody iwidgets::Fileselectionbox::childsitepos {
    _packComponents
}

# ------------------------------------------------------------------
# OPTION: -fileson
#
# Specifies whether or not to display the files list.
# ------------------------------------------------------------------
configbody iwidgets::Fileselectionbox::fileson {
    if {$itk_option(-fileson)} {
	$itk_component(listpane) show files
	set filesfraction [expr 100 - $itk_option(-dirsfraction)];
	$itk_component(listpane) fraction \
		$itk_option(-dirsfraction) $filesfraction

	pack configure $itk_component(files) -side right -fill both -expand yes

	_updateLists

    } else {
	$itk_component(listpane) hide files
    }
}

# ------------------------------------------------------------------
# OPTION: -dirson
#
# Specifies whether or not to display the dirs list.
# ------------------------------------------------------------------
configbody iwidgets::Fileselectionbox::dirson {
    if {$itk_option(-dirson)} {
	pack configure $itk_component(dirs) -side left -fill both -expand yes
	$itk_component(listpane) show dirs
	set filesfraction [expr 100 - $itk_option(-dirsfraction)];
	$itk_component(listpane) fraction \
		$itk_option(-dirsfraction) $filesfraction

	_updateLists
    } else {
	$itk_component(listpane) hide dirs
    }
}
# ------------------------------------------------------------------
# OPTION: -dirsfraction
#
# Specifies whether or not to display the dirs list.
# ------------------------------------------------------------------
configbody iwidgets::Fileselectionbox::dirsfraction {
    if {$itk_option(-dirson)} {
	if {[winfo manager $itk_component(listpane)] != ""} {
	    set filesfraction [expr 100 - $itk_option(-dirsfraction)];
	    $itk_component(listpane) fraction \
		    $itk_option(-dirsfraction) $filesfraction
	}
    }
}

# ------------------------------------------------------------------
# OPTION: -selectionon
#
# Specifies whether or not to display the selection entry widget.
# ------------------------------------------------------------------
configbody iwidgets::Fileselectionbox::selectionon {
    if {$itk_option(-selectionon)} {
        pack configure $itk_component(hlmargin) -side top \
                -after $itk_component(listpane)
        pack configure $itk_component(selection) -fill x \
                -after $itk_component(hlmargin) -side top
    } else {
        pack forget $itk_component(hlmargin)
        pack forget $itk_component(selection)
    }
}

# ------------------------------------------------------------------
# OPTION: -filteron
#
# Specifies whether or not to display the filter entry widget.
# ------------------------------------------------------------------
configbody iwidgets::Fileselectionbox::filteron {
    if {$itk_option(-filteron)} {
        pack configure $itk_component(humargin) -side top \
                -before $itk_component(listpane)
        pack configure $itk_component(filter) -fill x \
                -before $itk_component(humargin) -side top
    } else {
        pack forget $itk_component(humargin)
        pack forget $itk_component(filter)
    }
}

# ------------------------------------------------------------------
# OPTION: -vertmargin (depreciated)
#
# Specifies distance between the directory and file lists.
# this option really only has meaning when the -style option is set 
# to 'motif'
# ------------------------------------------------------------------
configbody iwidgets::Fileselectionbox::vertmargin {
    set pixels [winfo pixels $itk_component(vmargin) $itk_option(-vertmargin)]
    set itk_option(-vertmargin) $pixels

    $itk_component(vmargin) configure -width $pixels -height $pixels
}

# ------------------------------------------------------------------
# OPTION: -horizmargin
#
# Specifies distance between the lists and filter/selection entries.
# ------------------------------------------------------------------
configbody iwidgets::Fileselectionbox::horizmargin {
    set pixels [winfo pixels $itk_component(humargin) \
            $itk_option(-horizmargin)]
    set itk_option(-horizmargin) $pixels

    $itk_component(humargin) configure -width $pixels -height $pixels
    $itk_component(hlmargin) configure -width $pixels -height $pixels
}

# ------------------------------------------------------------------
# OPTION: -mask
#
# Specifies the initial file mask string.
# ------------------------------------------------------------------
configbody iwidgets::Fileselectionbox::mask {
    global tcl_platform
    set prefix $_pwd

    #
    # Remove automounter paths.
    #
    if {$tcl_platform(platform) == "unix"} {
	    regsub {^/(tmp_mnt|export)} $prefix {} prefix;
    }

    set curFilter $itk_option(-mask);
    $itk_component(filter) delete entry 0 end
    $itk_component(filter) insert entry 0 [file join $_pwd $itk_option(-mask)]

    #
    # Make sure the right most text is visable.
    #
    [$itk_component(filter) component entry] xview moveto 1
}

# ------------------------------------------------------------------
# OPTION: -directory
#
# Specifies the initial default directory.
# ------------------------------------------------------------------
configbody iwidgets::Fileselectionbox::directory {
    if {$itk_option(-directory) != {}} {
        if {! [file exists $itk_option(-directory)]} {
            error "bad directory option \"$itk_option(-directory)\":\
                    directory does not exist"
        }

        set olddir [pwd]
        cd $itk_option(-directory)
        set _pwd [pwd]
        cd $olddir

        configure -mask $itk_option(-mask)
        _selectFilter
    }
}

# ------------------------------------------------------------------
# OPTION: -nomatchstring
#
# Specifies the string to be displayed in the files list should
# not regular files exist in the directory.
# ------------------------------------------------------------------
configbody iwidgets::Fileselectionbox::nomatchstring {
}

# ------------------------------------------------------------------
# OPTION: -dirsearchcommand
#
# Specifies a command to be executed to perform a directory search.
# The command will receive the current working directory and filter
# mask as arguments.  The command should return a list of files which
# will be placed into the directory list.
# ------------------------------------------------------------------
configbody iwidgets::Fileselectionbox::dirsearchcommand {
}

# ------------------------------------------------------------------
# OPTION: -filesearchcommand
#
# Specifies a command to be executed to perform a file search.
# The command will receive the current working directory and filter
# mask as arguments.  The command should return a list of files which
# will be placed into the file list.
# ------------------------------------------------------------------
configbody iwidgets::Fileselectionbox::filesearchcommand {
}

# ------------------------------------------------------------------
# OPTION: -selectioncommand
#
# Specifies a command to be executed upon pressing return in the
# selection entry widget.
# ------------------------------------------------------------------
configbody iwidgets::Fileselectionbox::selectioncommand {
}

# ------------------------------------------------------------------
# OPTION: -filtercommand
#
# Specifies a command to be executed upon pressing return in the
# filter entry widget.
# ------------------------------------------------------------------
configbody iwidgets::Fileselectionbox::filtercommand {
}

# ------------------------------------------------------------------
# OPTION: -selectdircommand
#
# Specifies a command to be executed following selection of a
# directory in the directory list.
# ------------------------------------------------------------------
configbody iwidgets::Fileselectionbox::selectdircommand {
}

# ------------------------------------------------------------------
# OPTION: -selectfilecommand
#
# Specifies a command to be executed following selection of a
# file in the files list.
# ------------------------------------------------------------------
configbody iwidgets::Fileselectionbox::selectfilecommand {
}

# ------------------------------------------------------------------
# OPTION: -invalid
#
# Specify a command to executed should the filter contents be
# proven invalid.
# ------------------------------------------------------------------
configbody iwidgets::Fileselectionbox::invalid {
}

# ------------------------------------------------------------------
# OPTION: -filetype
#
# Specify the type of files which may appear in the file list.
# ------------------------------------------------------------------
configbody iwidgets::Fileselectionbox::filetype {
    switch $itk_option(-filetype) {
        regular -
        directory -
        any {
        }
        default {
            error "bad filetype option \"$itk_option(-filetype)\":\
                    should be regular, directory, or any"
        }
    }

    _updateLists
}

# ------------------------------------------------------------------
# OPTION: -width
#
# Specifies the width of the file selection box.  The value may be
# specified in any of the forms acceptable to Tk_GetPixels.
# ------------------------------------------------------------------
configbody iwidgets::Fileselectionbox::width {
    set pixels \
            [winfo pixels $itk_component(frame) $itk_option(-width)]

    $itk_component(frame) config -width $pixels
}

# ------------------------------------------------------------------
# OPTION: -height
#
# Specifies the height of the file selection box.  The value may be
# specified in any of the forms acceptable to Tk_GetPixels.
# ------------------------------------------------------------------
configbody iwidgets::Fileselectionbox::height {
    set pixels [winfo pixels $itk_component(frame) $itk_option(-height)]

    $itk_component(frame) config -height $pixels
}

# ------------------------------------------------------------------
#                            METHODS
# ------------------------------------------------------------------

# ------------------------------------------------------------------
# METHOD: childsite
#
# Returns the path name of the child site widget.
# ------------------------------------------------------------------
body iwidgets::Fileselectionbox::childsite {} {
    return $itk_component(childsite)
}

# ------------------------------------------------------------------
# METHOD: get
#
# Returns the current selection.
# ------------------------------------------------------------------
body iwidgets::Fileselectionbox::get {} {
    set curFilter [$itk_component(filter) get]
    if {[lsearch -exact [$itk_component(filter) cget -items] \
	    $curFilter] != -1} {
	$itk_component(filter) insert list end "$curFilter"
    }

    set selection [$itk_component(selection) get]
    if {[lsearch -exact [$itk_component(selection) cget -items] \
	    $selection] != -1} {
	$itk_component(selection) insert list 0 "$selection"
    }

    $itk_component(selection) delete entry 0 end
    $itk_component(selection) insert entry 0 $selection
    $itk_component(filter) delete entry 0 end
    $itk_component(filter) insert entry 0 $curFilter

    #
    # Make sure the right most text is visable.
    #
    [$itk_component(filter) component entry] xview moveto 1

    return $selection
}

# ------------------------------------------------------------------
# METHOD: filter
#
# The user has pressed Return in the filter.  Make sure the contents
# contain a valid directory before setting default to directory.
# Use the invalid option to warn the user of any problems.
# ------------------------------------------------------------------
body iwidgets::Fileselectionbox::filter {} {
    set newdir [file dirname [$itk_component(filter) get]]

    if {! [file exists $newdir]} {
	uplevel #0 "$itk_option(-invalid)"
	return
    }

    set _pwd $newdir;
    if {$_pwd == "."} {set _pwd [pwd]};

    _updateLists
}

# ------------------------------------------------------------------
# PRIVATE METHOD: _updateLists ?now?
#
# Updates the contents of both the file and directory lists, as well
# resets the positions of the filter, and lists.
# ------------------------------------------------------------------
body iwidgets::Fileselectionbox::_updateLists {{when "later"}} {
    switch -- $when {
        later {
            if {$_updateToken == ""} {
                set _updateToken [after idle [code $this _updateLists now]]
            }
        }
        now {
            if {$itk_option(-dirson)} {_setDirList}
            if {$itk_option(-fileson)} {_setFileList}

            if {$itk_option(-filteron)} {
              _setFilter
            }
            if {$itk_option(-selectionon)} {
                $itk_component(selection) icursor end
            }
            if {$itk_option(-dirson)} {
                $itk_component(dirs) justify $_justify
            }
            if {$itk_option(-fileson)} {
                $itk_component(files) justify $_justify
            }
            set _updateToken ""
        }
        default {
            error "bad option \"$when\": should be later or now"
        }
    }
}

# ------------------------------------------------------------------
# PRIVATE METHOD: _setFilter
#
# Set the filter to the current selection in the directory list plus
# any existing mask in the filter.  Translate the two special cases
# of '.', and '..' directory names to full path names..
# ------------------------------------------------------------------
body iwidgets::Fileselectionbox::_setFilter {} {
    global tcl_platform
    set prefix [$itk_component(dirs) getcurselection]
    set curFilter [file tail [$itk_component(filter) get]]

    while {[regexp {\.$} $prefix]} {
	if {[file tail $prefix] == "."} {
	    if {$prefix == "."} {
		if {$_pwd == "."} {
		    set _pwd [pwd]
		} elseif {$_pwd == ".."} {
		    set _pwd [file dirname [pwd]]
		}
		set prefix $_pwd
	    } else {
		set prefix [file dirname $prefix]
	    }
	} elseif {[file tail $prefix] == ".."} {
	    if {$prefix != ".."} {
		set prefix [file dirname [file dirname $prefix]]
	    } else {
		if {$_pwd == "."} {
		    set _pwd [pwd]
		} elseif {$_pwd == ".."} {
		    set _pwd [file dirname [pwd]]
		}
		set prefix [file dirname $_pwd]
	    }
	} else {
	    break
	}
    }

    if { [file pathtype $prefix] != "absolute" } {
        set prefix [file join $_pwd $prefix]
    }

    #
    # Remove automounter paths.
    #
    if {$tcl_platform(platform) == "unix"} {
	    regsub {^/(tmp_mnt|export)} $prefix {} prefix
    }

    $itk_component(filter) delete entry 0 end
    $itk_component(filter) insert entry 0 [file join $prefix $curFilter]

    #
    # Make sure insertion cursor is at the end.
    #
    $itk_component(filter) icursor end

    #
    # Make sure the right most text is visable.
    #
    [$itk_component(filter) component entry] xview moveto 1
}

# ------------------------------------------------------------------
# PRIVATE METHOD: _setSelection
#
# Set the contents of the selection entry to either the current
# selection of the file or directory list dependent on which lists
# are currently mapped.  For the file list, avoid seleciton of the
# no match string.  As for the directory list, translate file names.
# ------------------------------------------------------------------
body iwidgets::Fileselectionbox::_setSelection {} {
    global tcl_platform
    $itk_component(selection) delete entry 0 end

    if {$itk_option(-fileson)} {
        set selection [$itk_component(files) getcurselection]

        if {[file pathtype $selection] != "absolute"} {
	    set selection [file join $_pwd $selection]
        }

	#
        # Remove automounter paths.
	#
        if {$tcl_platform(platform) == "unix"} {
          regsub {^/(tmp_mnt|export)} $selection {} selection;
        }

        if {$selection != $itk_option(-nomatchstring)} {
	    $itk_component(selection) insert entry 0 $selection
        }

    } else {
        set selection [$itk_component(dirs) getcurselection]

	if {[file tail $selection] == "."} {
	    if {$selection != "."} {
		set selection [file dirname $selection]
	    } else {
		set selection $_pwd
	    }
	} elseif {[file tail $selection] == ".."} {
	    if {$selection != ".."} {
		set selection [file dirname [file dirname $selection]]
	    } else {
		set selection [file join $_pwd ..]
	    }
	}

	#
        # Remove automounter paths.
	#
        if {$tcl_platform(platform) == "unix"} {
            regsub {^/(tmp_mnt|export)} $selection {} selection;
        }

        $itk_component(selection) insert entry 0 $selection
    }

    $itk_component(selection) icursor end

    #
    # Make sure the right most text is visable.
    #
    [$itk_component(selection) component entry] xview moveto 1
}

# ------------------------------------------------------------------
# PRIVATE METHOD: _setDirList
#
# Clear the directory list and dependent on whether the user has
# defined their own search procedure or not fill the list with their
# results or those of a glob.  Select the first element if it exists.
# ------------------------------------------------------------------
body iwidgets::Fileselectionbox::_setDirList {} {
    $itk_component(dirs) clear

    if {$itk_option(-dirsearchcommand) == {}} {
        set cwd $_pwd

        foreach i [lsort [glob -nocomplain [file join $cwd .*] [file join $cwd *]]] {
            if {[file isdirectory $i]} {
		switch $itk_option(-style) {
		    motif { set insert "$i"}
		    notif { set insert "[file tail $i]";}
		    default {
			set insert "$i";
			error "bad style option \"$itk_option(-style)\":\
				should be motif or notif";
		    }
		}
		$itk_component(dirs) insert end "$insert"
            }
        }

    } else {
        set mask [file tail [$itk_component(filter) get]]

        foreach file [uplevel #0 $itk_option(-dirsearchcommand) $_pwd $mask] {
            $itk_component(dirs) insert end $file
        }
    }

    if {[$itk_component(dirs) size]} {
        $itk_component(dirs) selection clear 0 end
        $itk_component(dirs) selection set 0
    }
}

# ------------------------------------------------------------------
# PRIVATE METHOD: _setFileList
#
# Clear the file list and dependent on whether the user has defined
# their own search procedure or not fill the list with their results
# or those of a 'glob'.  If the files list has no contents, then set
# the files list to the 'nomatchstring'.  Clear all selections.
# ------------------------------------------------------------------
body iwidgets::Fileselectionbox::_setFileList {} {
    $itk_component(files) clear
    set mask [file tail [$itk_component(filter) get]]

    if {$itk_option(-filesearchcommand) == {}} {
        foreach i [lsort [glob -nocomplain [file join $_pwd $mask]]] {
            if {($itk_option(-filetype) == "regular" && \
		    ! [file isdirectory $i]) || \
		    ($itk_option(-filetype) == "directory" && \
		    [file isdirectory $i]) || \
		    ($itk_option(-filetype) == "any")} {
		switch $itk_option(-style) {
		    motif { set insert "$i"}
		    notif { set insert "[file tail $i]"}
		    default {
			set insert "$i";
			error "bad style option \"$itk_option(-style)\":\
				should be motif or notif";
		    }
		}

		$itk_component(files) insert end "$insert"
            }
        }

    } else {
        foreach file [uplevel #0 $itk_option(-filesearchcommand) $_pwd $mask] {
            $itk_component(files) insert end $file
        }
    }

    if {[$itk_component(files) size] == 0} {
        $itk_component(files) insert end $itk_option(-nomatchstring)
    }

    $itk_component(files) selection clear 0 end
}

# ------------------------------------------------------------------
# PRIVATE METHOD: _selectDir
#
# For a selection in the directory list, set the filter and possibly
# the selection entry based on the fileson option.
# ------------------------------------------------------------------
body iwidgets::Fileselectionbox::_selectDir {} {
    _setFilter

    if {$itk_option(-fileson)} {} {
        _setSelection
    }

    if {$itk_option(-selectdircommand) != {}} {
        uplevel #0 $itk_option(-selectdircommand)
    }
}

# ------------------------------------------------------------------
# PRIVATE METHOD: _dblSelectDir
#
# For a double click event in the directory list, select the
# directory, set the default to the selection, and update both the
# file and directory lists.
# ------------------------------------------------------------------
body iwidgets::Fileselectionbox::_dblSelectDir {} {
    filter
}

# ------------------------------------------------------------------
# PRIVATE METHOD: _selectFile
#
# The user has selected a file.  Put the current selection in the
# file list in the selection entry widget.
# ------------------------------------------------------------------
body iwidgets::Fileselectionbox::_selectFile {} {
    _setSelection

    if {$itk_option(-selectfilecommand) != {}} {
        uplevel #0 $itk_option(-selectfilecommand)
    }
}

# ------------------------------------------------------------------
# PRIVATE METHOD: _selectSelection
#
# The user has pressed Return in the selection entry widget.  Call
# the defined selection command if it exists.
# ------------------------------------------------------------------
body iwidgets::Fileselectionbox::_selectSelection {} {
    if {$itk_option(-selectioncommand) != {}} {
        uplevel #0 $itk_option(-selectioncommand)
    }
}

# ------------------------------------------------------------------
# PRIVATE METHOD: _selectFilter
#
# The user has pressed Return in the filter entry widget.  Call the
# defined selection command if it exists, otherwise just filter.
# ------------------------------------------------------------------
body iwidgets::Fileselectionbox::_selectFilter {} {
    if {$itk_option(-filtercommand) != {}} {
        uplevel #0 $itk_option(-filtercommand)
    } else {
        filter
    }
}

# ------------------------------------------------------------------
# PRIVATE METHOD: _packComponents
#
# Pack the selection, items, and child site widgets based on options.
# Using the -in option of pack, put the childsite around the frame
# in the hull for n, s, e, and w positions.  Make sure and raise 
# the child site since using the 'in' option may obscure the site.
# ------------------------------------------------------------------
body iwidgets::Fileselectionbox::_packComponents {{when "later"}} {
    if {$when == "later"} {
        if {$_packToken == ""} {
            set _packToken [after idle [code $this _packComponents now]]
        }
        return
    } elseif {$when != "now"} {
        error "bad option \"$when\": should be now or later"
    }

    set _packToken ""

    switch $itk_option(-childsitepos) {
        n {
            pack configure $itk_component(childsite) -side top \
                    -in $itk_component(hull)
            pack configure $itk_component(frame) -side top \
                    -after $itk_component(childsite)
        }

        w {
            pack configure $itk_component(frame) -side right
            pack configure $itk_component(childsite) -side left \
                    -after $itk_component(frame) \
                    -in $itk_component(hull)
        }

        s {
            pack configure $itk_component(frame) -side top
            pack configure $itk_component(childsite) -side top \
                    -after $itk_component(frame) \
                    -in $itk_component(hull)
        }

        e {
            pack configure $itk_component(frame) -side left
            pack configure $itk_component(childsite) -side right \
                    -before $itk_component(frame) \
                    -in $itk_component(hull)
        }

        default {
            error "bad childsitepos option \"$itk_option(-childsitepos)\":\
                    should be n, e, s, or w"
        }
    }

    raise $itk_component(childsite)
}
