Subject: * doc/getOpenFile.n: Updated with information about -multiple.

From: ericm <[email-masked]>
Date: Fri, 23 Jun 2000 00:22:27 +0000

* library/choosedir.tcl: Tweaked to handle modified tkIconList API's.

* library/tkfbox.tcl: Preliminary implementation of multiple
selection; based on patch from [RFE: 604].  Some of the tkIconList
functions changed to support this and to make the dialog faster.

* library/xmfbox.tcl: Added support for multiple selection, from
patch in [RFE: 4999].

FossilOrigin-Name: 6d6e691ec619d1ee337f77b3c504d9d8f89a1db6
---
 ChangeLog             |  24 ++-
 doc/getOpenFile.n     |   6 +-
 library/choosedir.tcl |  17 +-
 library/tkfbox.tcl    | 546 ++++++++++++++++++++++++++++++++++++--------------
 library/xmfbox.tcl    | 256 ++++++++++++++++-------
 5 files changed, 621 insertions(+), 228 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 23de88a..f7d2a52 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,24 @@
+2000-06-22  Eric Melski  <[email-masked]>
+
+	* doc/getOpenFile.n: Updated with information about -multiple.
+
+	* library/choosedir.tcl: Tweaked to handle modified tkIconList API's.
+
+	* library/tkfbox.tcl: Preliminary implementation of multiple
+	selection; based on patch from [RFE: 604].  Some of the tkIconList
+	functions changed to support this and to make the dialog faster.
+
+	* library/xmfbox.tcl: Added support for multiple selection, from
+	patch in [RFE: 4999].
+
+2000-06-21  Eric Melski  <[email-masked]>
+
+	* library/text.tcl: Corrected behavior of text widget with respect
+	to this sequence of events:  click, shift-click.  Previously, the
+	shift-click just moved the cursor and anchor; now, the shift-click
+	will select the text between the click and the shift-click, which
+	is the behavior most users expect. [Bug: 5929].
+
 2000-06-19  Eric Melski  <[email-masked]>
 
 	* library/bgerror.tcl: Added auto-truncation for long error
@@ -6,7 +27,8 @@
 
 2000-06-15  Eric Melski  <[email-masked]>
 
-	* win/tkWinDialog.c: Patched to support tk_getOpenFile -multiple.
+	* win/tkWinDialog.c: Patched to support tk_getOpenFile
+	-multiple. [RFE: 604].
 
 2000-06-13  Eric Melski  <[email-masked]>
 
diff --git a/doc/getOpenFile.n b/doc/getOpenFile.n
index 7cfe783..bd6795f 100644
--- a/doc/getOpenFile.n
+++ b/doc/getOpenFile.n
@@ -4,7 +4,7 @@
 '\" See the file "license.terms" for information on usage and redistribution
 '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 '\" 
-'\" RCS: @(#) $Id: getOpenFile.n,v 1.6 2000/04/23 03:47:13 jingham Exp $
+'\" RCS: @(#) $Id: getOpenFile.n,v 1.7 2000/06/23 00:22:28 ericm Exp $
 '\" 
 .so man.macros
 .TH tk_getOpenFile n 4.2 Tk "Tk Built-In Commands"
@@ -72,8 +72,8 @@ option is ignored on the Macintosh platform.
 .TP
 \fB\-multiple\fR
 Allows the user to choose multiple files from the Open dialog.
-This is only available on the Macintosh, and only when Navigation
-Services are installed.
+On the Macintosh, this is only available when Navigation Services are
+installed.
 .TP
 \fB\-message\fR
 Specifies a message to include in the client area of the dialog.
diff --git a/library/choosedir.tcl b/library/choosedir.tcl
index acd6683..bae35af 100644
--- a/library/choosedir.tcl
+++ b/library/choosedir.tcl
@@ -5,7 +5,7 @@
 # Copyright (c) 1998-2000 by Scriptics Corporation.
 # All rights reserved.
 # 
-# RCS: @(#) $Id: choosedir.tcl,v 1.7 2000/04/19 23:12:56 hobbs Exp $
+# RCS: @(#) $Id: choosedir.tcl,v 1.8 2000/06/23 00:22:28 ericm Exp $
 
 # Make sure the tk::dialog namespace, in which all dialogs should live, exists
 namespace eval ::tk::dialog {}
@@ -138,6 +138,11 @@ proc ::tk::dialog::file::chooseDir::Config {dataName argList} {
 	set data(-title) "Choose Directory"
     }
 
+    # Stub out the -multiple value for the dialog; it doesn't make sense for
+    # choose directory dialogs, but we have to have something there because we
+    # share so much code with the file dialogs.
+    set data(-multiple) 0
+
     # 4: set the default directory and selection according to the -initial
     #    settings
     #
@@ -177,8 +182,9 @@ proc ::tk::dialog::file::chooseDir::OkCmd {w} {
     # 4b.   If the value is different from the current directory, change to
     #       that directory.
 
-    set iconText [tkIconList_Get $data(icons)]
-    if { ![string equal $iconText ""] } {
+    set selection [tkIconList_Curselection $data(icons)]
+    if { [llength $selection] != 0 } {
+	set iconText [tkIconList_Get $data(icons) [lindex $selection 0]]
 	set iconText [file join $data(selectPath) $iconText]
 	::tk::dialog::file::chooseDir::Done $w $iconText
     } else {
@@ -214,8 +220,9 @@ proc ::tk::dialog::file::chooseDir::OkCmd {w} {
 
 proc ::tk::dialog::file::chooseDir::DblClick {w} {
     upvar ::tk::dialog::file::[winfo name $w] data
-    set text [tkIconList_Get $data(icons)]
-    if {[string compare $text ""]} {
+    set selection [tkIconList_Curselection $data(icons)]
+    if { [llength $selection] != 0 } {
+	set text [tkIconList_Get $data(icons) [lindex $selection 0]]
 	set file $data(selectPath)
 	if {[file isdirectory $file]} {
 	    ::tk::dialog::file::ListInvoke $w $text
diff --git a/library/tkfbox.tcl b/library/tkfbox.tcl
index 3bd59d6..9987abe 100644
--- a/library/tkfbox.tcl
+++ b/library/tkfbox.tcl
@@ -11,7 +11,7 @@
 #	files by clicking on the file icons or by entering a filename
 #	in the "Filename:" entry.
 #
-# RCS: @(#) $Id: tkfbox.tcl,v 1.19 2000/04/19 23:12:56 hobbs Exp $
+# RCS: @(#) $Id: tkfbox.tcl,v 1.20 2000/06/23 00:22:28 ericm Exp $
 #
 # Copyright (c) 1994-1998 Sun Microsystems, Inc.
 #
@@ -39,6 +39,150 @@ proc tkIconList {w args} {
     tkIconList_Create $w
 }
 
+proc tkIconList_Index {w i} {
+    upvar #0 $w data
+    upvar #0 $w:itemList itemList
+    switch -regexp -- $i {
+	"^[0-9]+$" {
+	    return $i
+	}
+	"^active$" {
+	    return $data(index,active)
+	}
+	"^anchor$" {
+	    return $data(index,anchor)
+	}
+	"^end$" {
+	    return [llength $data(list)]
+	}
+	"@-?[0-9]+,-?[0-9]+" {
+	    foreach {x y} [scan $i "@%d,%d"] {
+		break
+	    }
+	    set item [$data(canvas) find closest $x $y]
+	    return [lindex [$data(canvas) itemcget $item -tags] 1]
+	}
+    }
+}
+
+proc tkIconList_Selection {w op args} {
+    upvar #0 $w data
+    switch -exact -- $op {
+	"anchor" {
+	    if { [llength $args] == 1 } {
+		set data(index,anchor) [lindex $args 0]
+	    } else {
+		return $data(index,anchor)
+	    }
+	}
+	"clear" {
+	    if { [llength $args] == 2 } {
+		foreach {first last} $args {
+		    break
+		}
+	    } elseif { [llength $args] == 1 } {
+		set first [set last [lindex $args 0]]
+	    } else {
+		error "wrong # args: should be tkIconList_Selection path\
+			clear first ?last?"
+	    }
+	    set first [tkIconList_Index $w $first]
+	    set last [tkIconList_Index $w $last]
+	    if { $first > $last } {
+		set tmp $first
+		set first $last
+		set last $tmp
+	    }
+	    set ind 0
+	    foreach item $data(selection) {
+		if { $item >= $first } {
+		    set first $ind
+		    break
+		}
+	    }
+	    set ind [expr {[llength $data(selection)] - 1}]
+	    for {} {$ind >= 0} {incr ind -1} {
+		set item [lindex $data(selection) $ind]
+		if { $item <= $last } {
+		    set last $ind
+		    break
+		}
+	    }
+
+	    if { $first > $last } {
+		return
+	    }
+	    set data(selection) [lreplace $data(selection) $first $last]
+	    event generate $w <<ListboxSelect>>
+	    tkIconList_DrawSelection $w
+	}
+	"includes" {
+	    set index [lsearch -exact $data(selection) [lindex $args 0]]
+	    return [expr {$index != -1}]
+	}
+	"set" {
+	    if { [llength $args] == 2 } {
+		foreach {first last} $args {
+		    break
+		}
+	    } elseif { [llength $args] == 1 } {
+		set last [set first [lindex $args 0]]
+	    } else {
+		error "wrong # args: should be tkIconList_Selection path\
+			set first ?last?"
+	    }
+
+	    set first [tkIconList_Index $w $first]
+	    set last [tkIconList_Index $w $last]
+	    if { $first > $last } {
+		set tmp $first
+		set first $last
+		set last $tmp
+	    }
+	    for {set i $first} {$i <= $last} {incr i} {
+		lappend data(selection) $i
+	    }
+	    set data(selection) [lsort -integer -unique $data(selection)]
+	    event generate $w <<ListboxSelect>>
+	    tkIconList_DrawSelection $w
+	}
+    }
+}
+
+proc tkIconList_Curselection {w} {
+    upvar #0 $w data
+    return $data(selection)
+}
+
+proc tkIconList_DrawSelection {w} {
+    upvar #0 $w data
+    upvar #0 $w:itemList itemList
+
+    $data(canvas) delete selection
+    foreach item $data(selection) {
+	set rTag [lindex [lindex $data(list) $item] 2]
+	foreach {iTag tTag text serial} $itemList($rTag) {
+	    break
+	}
+
+	set bbox [$data(canvas) bbox $tTag]
+        $data(canvas) create rect $bbox -fill \#a0a0ff -outline \#a0a0ff \
+		-tags selection
+    }
+    $data(canvas) lower selection
+    return
+}
+
+proc tkIconList_Get {w item} {
+    upvar #0 $w data
+    upvar #0 $w:itemList itemList
+    set rTag [lindex [lindex $data(list) $item] 2]
+    foreach {iTag tTag text serial} $itemList($rTag) {
+	break
+    }
+    return $text
+}
+
 # tkIconList_Config --
 #
 #	Configure the widget variables of IconList, according to the command
@@ -50,8 +194,8 @@ proc tkIconList_Config {w argList} {
     # 1: the configuration specs
     #
     set specs {
-	{-browsecmd "" "" ""}
 	{-command "" "" ""}
+	{-multiple "" "" "0"}
     }
 
     # 2: parse the arguments
@@ -88,6 +232,8 @@ proc tkIconList_Create {w} {
     set data(numItems) 0
     set data(curItem)  {}
     set data(noScroll) 1
+    set data(selection) {}
+    set data(index,anchor) ""
 
     # Creates the event bindings.
     #
@@ -96,6 +242,8 @@ proc tkIconList_Create {w} {
     bind $data(canvas) <1>		[list tkIconList_Btn1 $w %x %y]
     bind $data(canvas) <B1-Motion>	[list tkIconList_Motion1 $w %x %y]
     bind $data(canvas) <B1-Leave>	[list tkIconList_Leave1 $w %x %y]
+    bind $data(canvas) <Control-1>	[list tkIconList_CtrlBtn1 $w %x %y]
+    bind $data(canvas) <Shift-1>	[list tkIconList_ShiftBtn1 $w %x %y]
     bind $data(canvas) <B1-Enter>	[list tkCancelRepeat]
     bind $data(canvas) <ButtonRelease-1> [list tkCancelRepeat]
     bind $data(canvas) <Double-ButtonRelease-1> \
@@ -111,6 +259,7 @@ proc tkIconList_Create {w} {
     bind $data(canvas) <Alt-KeyPress>	";"
 
     bind $data(canvas) <FocusIn>	[list tkIconList_FocusIn $w]
+    bind $data(canvas) <FocusOut>	[list tkIconList_FocusOut $w]
 
     return $w
 }
@@ -172,46 +321,57 @@ proc tkIconList_DeleteAll {w} {
     set data(numItems) 0
     set data(curItem)  {}
     set data(noScroll) 1
+    set data(selection) {}
+    set data(index,anchor) ""
     $data(sbar) set 0.0 1.0
     $data(canvas) xview moveto 0
 }
 
 # Adds an icon into the IconList with the designated image and text
 #
-proc tkIconList_Add {w image text} {
+proc tkIconList_Add {w image items} {
     upvar #0 $w data
     upvar #0 $w:itemList itemList
     upvar #0 $w:textList textList
 
-    set iTag [$data(canvas) create image 0 0 -image $image -anchor nw]
-    set tTag [$data(canvas) create text  0 0 -text  $text  -anchor nw \
-	-font $data(font)]
-    set rTag [$data(canvas) create rect  0 0 0 0 -fill "" -outline ""]
+    foreach text $items {
+	set iTag [$data(canvas) create image 0 0 -image $image -anchor nw \
+		-tags [list icon $data(numItems)]]
+	set tTag [$data(canvas) create text  0 0 -text  $text  -anchor nw \
+		-font $data(font) -tags [list text $data(numItems)]]
+	set rTag [$data(canvas) create rect  0 0 0 0 -fill "" -outline "" \
+		-tags [list rect $data(numItems)]]
+	
+	foreach {x1 y1 x2 y2} [$data(canvas) bbox $iTag] {
+	    break
+	}
+	set iW [expr {$x2 - $x1}]
+	set iH [expr {$y2 - $y1}]
+	if {$data(maxIW) < $iW} {
+	    set data(maxIW) $iW
+	}
+	if {$data(maxIH) < $iH} {
+	    set data(maxIH) $iH
+	}
     
-    set b [$data(canvas) bbox $iTag]
-    set iW [expr {[lindex $b 2]-[lindex $b 0]}]
-    set iH [expr {[lindex $b 3]-[lindex $b 1]}]
-    if {$data(maxIW) < $iW} {
-	set data(maxIW) $iW
-    }
-    if {$data(maxIH) < $iH} {
-	set data(maxIH) $iH
-    }
+	foreach {x1 y1 x2 y2} [$data(canvas) bbox $tTag] {
+	    break
+	}
+	set tW [expr {$x2 - $x1}]
+	set tH [expr {$y2 - $y1}]
+	if {$data(maxTW) < $tW} {
+	    set data(maxTW) $tW
+	}
+	if {$data(maxTH) < $tH} {
+	    set data(maxTH) $tH
+	}
     
-    set b [$data(canvas) bbox $tTag]
-    set tW [expr {[lindex $b 2]-[lindex $b 0]}]
-    set tH [expr {[lindex $b 3]-[lindex $b 1]}]
-    if {$data(maxTW) < $tW} {
-	set data(maxTW) $tW
+	lappend data(list) [list $iTag $tTag $rTag $iW $iH $tW \
+		$tH $data(numItems)]
+	set itemList($rTag) [list $iTag $tTag $text $data(numItems)]
+	set textList($data(numItems)) [string tolower $text]
+	incr data(numItems)
     }
-    if {$data(maxTH) < $tH} {
-	set data(maxTH) $tH
-    }
-    
-    lappend data(list) [list $iTag $tTag $rTag $iW $iH $tW $tH $data(numItems)]
-    set itemList($rTag) [list $iTag $tTag $text $data(numItems)]
-    set textList($data(numItems)) [string tolower $text]
-    incr data(numItems)
 }
 
 # Places the icons in a column-major arrangement.
@@ -252,20 +412,15 @@ proc tkIconList_Arrange {w} {
     set usedColumn 0
     foreach sublist $data(list) {
 	set usedColumn 1
-	set iTag [lindex $sublist 0]
-	set tTag [lindex $sublist 1]
-	set rTag [lindex $sublist 2]
-	set iW   [lindex $sublist 3]
-	set iH   [lindex $sublist 4]
-	set tW   [lindex $sublist 5]
-	set tH   [lindex $sublist 6]
+	foreach {iTag tTag rTag iW iH tW tH} $sublist {
+	    break
+	}
 
 	set i_dy [expr {($dy - $iH)/2}]
 	set t_dy [expr {($dy - $tH)/2}]
 
 	$data(canvas) coords $iTag $x                    [expr {$y + $i_dy}]
 	$data(canvas) coords $tTag [expr {$x + $shift}]  [expr {$y + $t_dy}]
-	$data(canvas) coords $tTag [expr {$x + $shift}]  [expr {$y + $t_dy}]
 	$data(canvas) coords $rTag $x $y [expr {$x+$dx}] [expr {$y+$dy}]
 
 	incr y $dy
@@ -309,7 +464,7 @@ proc tkIconList_Arrange {w} {
 proc tkIconList_Invoke {w} {
     upvar #0 $w data
 
-    if {$data(-command) != "" && [info exists data(selected)]} {
+    if {$data(-command) != "" && [llength $data(selection)]} {
 	uplevel #0 $data(-command)
     }
 }
@@ -367,88 +522,70 @@ proc tkIconList_See {w rTag} {
     }
 }
 
-proc tkIconList_SelectAtXY {w x y} {
-    upvar #0 $w data
-
-    tkIconList_Select $w [$data(canvas) find closest \
-	    [$data(canvas) canvasx $x] [$data(canvas) canvasy $y]]
-}
-
-proc tkIconList_Select {w rTag {callBrowse 1}} {
+proc tkIconList_Btn1 {w x y} {
     upvar #0 $w data
-    upvar #0 $w:itemList itemList
-
-    if {![info exists itemList($rTag)]} {
-	return
-    }
-    set iTag   [lindex $itemList($rTag) 0]
-    set tTag   [lindex $itemList($rTag) 1]
-    set text   [lindex $itemList($rTag) 2]
-    set serial [lindex $itemList($rTag) 3]
-
-    if {![info exists data(rect)]} {
-        set data(rect) [$data(canvas) create rect 0 0 0 0 \
-		-fill #a0a0ff -outline #a0a0ff]
-    }
-    $data(canvas) lower $data(rect)
-    set bbox [$data(canvas) bbox $tTag]
-    eval [list $data(canvas) coords $data(rect)] $bbox
-
-    set data(curItem) $serial
-    set data(selected) $text
 
-    if {$callBrowse && $data(-browsecmd) != ""} {
-	eval $data(-browsecmd) [list $text]
-    }
+    focus $data(canvas)
+    set x [expr {int([$data(canvas) canvasx $x])}]
+    set y [expr {int([$data(canvas) canvasy $y])}]
+    set i [tkIconList_Index $w @${x},${y}]
+    tkIconList_Selection $w clear 0 end
+    tkIconList_Selection $w set $i
+    tkIconList_Selection $w anchor $i
 }
 
-proc tkIconList_Unselect {w} {
+proc tkIconList_CtrlBtn1 {w x y} {
     upvar #0 $w data
-
-    if {[info exists data(rect)]} {
-	$data(canvas) delete $data(rect)
-	unset data(rect)
-    }
-    if {[info exists data(selected)]} {
-	unset data(selected)
+    
+    if { $data(-multiple) } {
+	focus $data(canvas)
+	set x [expr {int([$data(canvas) canvasx $x])}]
+	set y [expr {int([$data(canvas) canvasy $y])}]
+	set i [tkIconList_Index $w @${x},${y}]
+	if { [tkIconList_Selection $w includes $i] } {
+	    tkIconList_Selection $w clear $i
+	} else {
+	    tkIconList_Selection $w set $i
+	    tkIconList_Selection $w anchor $i
+	}
     }
-    #set data(curItem)  {}
 }
 
-# Returns the selected item
-#
-proc tkIconList_Get {w} {
+proc tkIconList_ShiftBtn1 {w x y} {
     upvar #0 $w data
-
-    if {[info exists data(selected)]} {
-	return $data(selected)
-    } else {
-	return ""
+    
+    if { $data(-multiple) } {
+	focus $data(canvas)
+	set x [expr {int([$data(canvas) canvasx $x])}]
+	set y [expr {int([$data(canvas) canvasy $y])}]
+	set i [tkIconList_Index $w @${x},${y}]
+	set a [tkIconList_Index $w anchor]
+	if { [string equal $a ""] } {
+	    set a $i
+	}
+	tkIconList_Selection $w clear 0 end
+	tkIconList_Selection $w set $a $i
     }
 }
 
-
-proc tkIconList_Btn1 {w x y} {
-    upvar #0 $w data
-
-    focus $data(canvas)
-    tkIconList_SelectAtXY $w $x $y
-}
-
 # Gets called on button-1 motions
 #
 proc tkIconList_Motion1 {w x y} {
+    upvar #0 $w data
     global tkPriv
     set tkPriv(x) $x
     set tkPriv(y) $y
-
-    tkIconList_SelectAtXY $w $x $y
+    set x [expr {int([$data(canvas) canvasx $x])}]
+    set y [expr {int([$data(canvas) canvasy $y])}]
+    set i [tkIconList_Index $w @${x},${y}]
+    tkIconList_Selection $w clear 0 end
+    tkIconList_Selection $w set $i
 }
 
 proc tkIconList_Double1 {w x y} {
     upvar #0 $w data
 
-    if {[string compare $data(curItem) {}]} {
+    if {[llength $data(selection)]} {
 	tkIconList_Invoke $w
     }
 }
@@ -472,11 +609,15 @@ proc tkIconList_FocusIn {w} {
 	return
     }
 
-    if {[string compare $data(curItem) {}]} {
-	tkIconList_Select $w [lindex [lindex $data(list) $data(curItem)] 2] 1
+    if {[llength $data(selection)]} {
+	tkIconList_DrawSelection $w
     }
 }
 
+proc tkIconList_FocusOut {w} {
+    tkIconList_Selection $w clear 0 end
+}
+
 # tkIconList_UpDown --
 #
 # Moves the active element up or down by one element
@@ -665,6 +806,7 @@ proc ::tk::dialog::file::tkFDialog {type args} {
 	set data(typeMenu) $data(typeMenuBtn).m
 	set data(okBtn) $w.f2.ok
 	set data(cancelBtn) $w.f3.cancel
+	::tk::dialog::file::SetSelectMode $w $data(-multiple)
     }
     wm transient $w $data(-parent)
 
@@ -759,6 +901,12 @@ proc ::tk::dialog::file::Config {dataName type argList} {
 	{-title "" "" ""}
     }
 
+    # The "-multiple" option is only available for the "open" file dialog.
+    #
+    if { [string equal $type "open"] } {
+	lappend specs {-multiple "" "" "0"}
+    }
+
     # 2: default values depending on the type of the dialog
     #
     if {![info exists data(selectPath)]} {
@@ -802,6 +950,18 @@ proc ::tk::dialog::file::Config {dataName type argList} {
     if {![winfo exists $data(-parent)]} {
 	error "bad window path name \"$data(-parent)\""
     }
+
+    # Set -multiple to a one or zero value (not other boolean types
+    # like "yes") so we can use it in tests more easily.
+    if {![string compare $type save]} {
+	set data(-multiple) 0
+    } else {
+	if {$data(-multiple)} { 
+	    set data(-multiple) 1 
+	} else {
+	    set data(-multiple) 0
+	}
+    }
 }
 
 proc ::tk::dialog::file::Create {w class} {
@@ -841,7 +1001,11 @@ static char updir_bits[] = {
     # data(icons): the IconList that list the files and directories.
     #
     if { [string equal $class TkFDialog] } {
-	set fNameCaption "File name:"
+	if { $data(-multiple) } {
+	    set fNameCaption "File names:"
+	} else {
+	    set fNameCaption "File name:"
+	}
 	set fNameUnder 5
 	set iconListCommand [list ::tk::dialog::file::OkCmd $w]
     } else {
@@ -850,8 +1014,10 @@ static char updir_bits[] = {
 	set iconListCommand [list ::tk::dialog::file::chooseDir::DblClick $w]
     }
     set data(icons) [tkIconList $w.icons \
-	-browsecmd [list ::tk::dialog::file::ListBrowse $w] \
-	-command   $iconListCommand]
+	    -command	$iconListCommand \
+	    -multiple	$data(-multiple)]
+    bind $data(icons) <<ListboxSelect>> \
+	    [list ::tk::dialog::file::ListBrowse $w]
 
     # f2: the frame with the OK button and the "file name" field
     #
@@ -959,6 +1125,33 @@ static char updir_bits[] = {
     tkFocusGroup_BindOut $w $data(ent) [list ::tk::dialog::file::EntFocusOut $w]
 }
 
+# ::tk::dialog::file::SetSelectMode --
+#
+#	Set the select mode of the dialog to single select or multi-select.
+#
+# Arguments:
+#	w		The dialog path.
+#	multi		1 if the dialog is multi-select; 0 otherwise.
+#
+# Results:
+#	None.
+
+proc ::tk::dialog::file::SetSelectMode {w multi} {
+    set dataName __tk_filedialog
+    upvar ::tk::dialog::file::$dataName data
+    if { $multi } {
+	set fNameCaption "File names:"
+    } else {
+	set fNameCaption "File name:"
+    }
+    set fNameUnder 5
+    set iconListCommand [list ::tk::dialog::file::OkCmd $w]
+    $w.f2.lab configure -text $fNameCaption -under $fNameUnder
+    tkIconList_Config $data(icons) \
+	    [list -multiple $multi -command $iconListCommand]
+    return
+}
+
 # ::tk::dialog::file::UpdateWhenIdle --
 #
 #	Creates an idle event handler which updates the dialog in idle
@@ -1039,7 +1232,9 @@ rSASvJTGhnhcV3EJlo3kh53ltF5nAhQAOw==}]
 
     # Make the dir list
     #
-    foreach f [lsort -dictionary [glob -nocomplain .* *]] {
+    set completeFileList [lsort -dictionary -unique [glob -nocomplain .* *]]
+    set dirList {}
+    foreach f $completeFileList {
 	if {[string equal $f .]} {
 	    continue
 	}
@@ -1047,31 +1242,30 @@ rSASvJTGhnhcV3EJlo3kh53ltF5nAhQAOw==}]
 	    continue
 	}
 	if {[file isdir ./$f]} {
-	    if {![info exists hasDoneDir($f)]} {
-		tkIconList_Add $data(icons) $folder $f
-		set hasDoneDir($f) 1
-	    }
+	    lappend dirList $f
 	}
     }
+    tkIconList_Add $data(icons) $folder $dirList
     if { [string equal $class TkFDialog] } {
 	# Make the file list if this is a File Dialog
 	#
 	if {[string equal $data(filter) *]} {
-	    set files [lsort -dictionary \
-		    [glob -nocomplain .* *]]
+	    set files $completeFileList
 	} else {
-	    set files [lsort -dictionary \
-		    [eval glob -nocomplain $data(filter)]]
+	    set files {}
+	    foreach f $completeFileList {
+		if { [string match $data(filter) $f] } {
+		    lappend files $f
+		}
+	    }
 	}
-	
+	set fileList {}
 	foreach f $files {
 	    if {![file isdir ./$f]} {
-		if {![info exists hasDoneFile($f)]} {
-		    tkIconList_Add $data(icons) $file $f
-		    set hasDoneFile($f) 1
-		}
+		lappend fileList $f
 	    }
 	}
+	tkIconList_Add $data(icons) $file $fileList
     }
 
     tkIconList_Arrange $data(icons)
@@ -1264,8 +1458,6 @@ proc ::tk::dialog::file::EntFocusIn {w} {
 	$data(ent) selection clear
     }
 
-    tkIconList_Unselect $data(icons)
-
     if { [string equal [winfo class $w] TkFDialog] } {
 	# If this is a File Dialog, make sure the buttons are labeled right.
 	if {[string equal $data(type) open]} {
@@ -1287,13 +1479,28 @@ proc ::tk::dialog::file::EntFocusOut {w} {
 #
 proc ::tk::dialog::file::ActivateEnt {w} {
     upvar ::tk::dialog::file::[winfo name $w] data
+    
+    set text [$data(ent) get]
+    if {$data(-multiple)} {
+	set data(selectFile) ""
+	foreach fname $text {
+	    ::tk::dialog::file::VerifyFileName $w $fname
+	}
+    } else {
+	::tk::dialog::file::VerifyFileName $w $text
+    }
+}
 
-    set text [string trim [$data(ent) get]]
-    set list [::tk::dialog::file::ResolveFile $data(selectPath) $text \
-		  $data(-defaultextension)]
-    set flag [lindex $list 0]
-    set path [lindex $list 1]
-    set file [lindex $list 2]
+# Verification procedure
+#
+proc ::tk::dialog::file::VerifyFileName {w filename} {
+    upvar ::tk::dialog::file::[winfo name $w] data
+
+    set list [::tk::dialog::file::ResolveFile $data(selectPath) $filename \
+	    $data(-defaultextension)]
+    foreach {flag path file} $list {
+	break
+    }
 
     switch -- $flag {
 	OK {
@@ -1303,7 +1510,11 @@ proc ::tk::dialog::file::ActivateEnt {w} {
 		$data(ent) delete 0 end
 	    } else {
 		::tk::dialog::file::SetPathSilently $w $path
-		set data(selectFile) $file
+		if {$data(-multiple)} {
+		    lappend data(selectFile) $file
+		} else {
+		    set data(selectFile) $file
+		}
 		::tk::dialog::file::Done $w
 	    }
 	}
@@ -1319,7 +1530,11 @@ proc ::tk::dialog::file::ActivateEnt {w} {
 		$data(ent) icursor end
 	    } else {
 		::tk::dialog::file::SetPathSilently $w $path
-		set data(selectFile) $file
+		if {$data(-multiple)} {
+		    lappend data(selectFile) $file
+		} else {
+		    set data(selectFile) $file
+		}
 		::tk::dialog::file::Done $w
 	    }
 	}
@@ -1377,15 +1592,18 @@ proc ::tk::dialog::file::JoinFile {path file} {
     }
 }
 
-
-
 # Gets called when user presses the "OK" button
 #
 proc ::tk::dialog::file::OkCmd {w} {
     upvar ::tk::dialog::file::[winfo name $w] data
 
-    set text [tkIconList_Get $data(icons)]
-    if {[string compare $text ""]} {
+    set text {}
+    foreach item [tkIconList_Curselection $data(icons)] {
+	lappend text [tkIconList_Get $data(icons) $item]
+    }
+
+    if {[llength $text] && !$data(-multiple)} {
+	set text [lindex $text 0]
 	set file [::tk::dialog::file::JoinFile $data(selectPath) $text]
 	if {[file isdirectory $file]} {
 	    ::tk::dialog::file::ListInvoke $w $text
@@ -1408,15 +1626,32 @@ proc ::tk::dialog::file::CancelCmd {w} {
 # Gets called when user browses the IconList widget (dragging mouse, arrow
 # keys, etc)
 #
-proc ::tk::dialog::file::ListBrowse {w text} {
+proc ::tk::dialog::file::ListBrowse {w} {
     upvar ::tk::dialog::file::[winfo name $w] data
 
-    if {[string equal $text ""]} {
+    set text {}
+    foreach item [tkIconList_Curselection $data(icons)] {
+	lappend text [tkIconList_Get $data(icons) $item]
+    }
+    if {[llength $text] == 0} {
 	return
     }
-
-    set file [::tk::dialog::file::JoinFile $data(selectPath) $text]
-    if {![file isdirectory $file]} {
+    if { [llength $text] > 1 } {
+	set newtext {}
+	foreach file $text {
+	    set fullfile [::tk::dialog::file::JoinFile $data(selectPath) $file]
+	    if { ![file isdirectory $fullfile] } {
+		lappend newtext $file
+	    }
+	}
+	set text $newtext
+	set isDir 0
+    } else {
+	set text [lindex $text 0]
+	set file [::tk::dialog::file::JoinFile $data(selectPath) $text]
+	set isDir [file isdirectory $file]
+    }
+    if {!$isDir} {
 	$data(ent) delete 0 end
 	$data(ent) insert 0 $text
 
@@ -1440,11 +1675,13 @@ proc ::tk::dialog::file::ListBrowse {w text} {
 proc ::tk::dialog::file::ListInvoke {w text} {
     upvar ::tk::dialog::file::[winfo name $w] data
 
-    if {[string equal $text ""]} {
+    if {[llength $text] == 0} {
 	return
     }
 
-    set file [::tk::dialog::file::JoinFile $data(selectPath) $text]
+    set file [::tk::dialog::file::JoinFile $data(selectPath) \
+	    [lindex $text 0]]
+    
     set class [winfo class $w]
     if {[string equal $class TkChooseDir] || [file isdirectory $file]} {
 	set appPWD [pwd]
@@ -1457,7 +1694,11 @@ proc ::tk::dialog::file::ListInvoke {w text} {
 	    set data(selectPath) $file
 	}
     } else {
-	set data(selectFile) $file
+	if {$data(-multiple)} {
+	    set data(selectFile) $text
+	} else {
+	    set data(selectFile) $file
+	}
 	::tk::dialog::file::Done $w
     }
 }
@@ -1475,18 +1716,29 @@ proc ::tk::dialog::file::Done {w {selectFilePath ""}} {
     global tkPriv
 
     if {[string equal $selectFilePath ""]} {
-	set selectFilePath [::tk::dialog::file::JoinFile $data(selectPath) \
-		$data(selectFile)]
+	if {$data(-multiple)} {
+	    set selectFilePath {}
+	    foreach f $data(selectFile) {
+		lappend selectFilePath [::tk::dialog::file::JoinFile \
+		    $data(selectPath) $f]
+	    }
+	} else {
+	    set selectFilePath [::tk::dialog::file::JoinFile \
+		    $data(selectPath) $data(selectFile)]
+	}
+	
 	set tkPriv(selectFile)     $data(selectFile)
 	set tkPriv(selectPath)     $data(selectPath)
 
-	if {[file exists $selectFilePath] && [string equal $data(type) save]} {
-	    set reply [tk_messageBox -icon warning -type yesno\
-		    -parent $w -message "File\
-		    \"$selectFilePath\" already exists.\nDo\
-		    you want to overwrite it?"]
-	    if {[string equal $reply "no"]} {
-		return
+	if {[string equal $data(type) save]} {
+	    if {[file exists $selectFilePath]} {
+		set reply [tk_messageBox -icon warning -type yesno\
+			-parent $w -message "File\
+			\"$selectFilePath\" already exists.\nDo\
+			you want to overwrite it?"]
+		if {[string equal $reply "no"]} {
+		    return
+		}
 	    }
 	}
     }
diff --git a/library/xmfbox.tcl b/library/xmfbox.tcl
index d202a02..3ed5000 100644
--- a/library/xmfbox.tcl
+++ b/library/xmfbox.tcl
@@ -4,7 +4,7 @@
 #	Unix platform. This implementation is used only if the
 #	"tk_strictMotif" flag is set.
 #
-# RCS: @(#) $Id: xmfbox.tcl,v 1.11 2000/03/24 19:38:57 ericm Exp $
+# RCS: @(#) $Id: xmfbox.tcl,v 1.12 2000/06/23 00:22:28 ericm Exp $
 #
 # Copyright (c) 1996 Sun Microsystems, Inc.
 # Copyright (c) 1998-2000 Scriptics Corporation
@@ -26,10 +26,14 @@ namespace eval ::tk::dialog::file {}
 #	args		Options parsed by the procedure.
 #
 # Results:
-#	A list of two members. The first member is the absolute
-#	pathname of the selected file or "" if user hits cancel. The
-#	second member is the name of the selected file type, or ""
-#	which stands for "default file type"
+#	When -multiple is set to 0, this returns the absolute pathname
+#	of the selected file. (NOTE: This is not the same as a single
+#	element list.)
+# 
+#	When -multiple is set to > 0, this returns a Tcl list of absolute
+#       pathnames. The argument for -multiple is ignored, but for consistency
+#       with Windows it defines the maximum amount of memory to allocate for
+#       the returned filenames.
 
 proc tkMotifFDialog {type args} {
     global tkPriv
@@ -102,9 +106,11 @@ proc tkMotifFDialog_Create {dataName type argList} {
 	set data(filterBtn) $w.bot.filter
 	set data(cancelBtn) $w.bot.cancel
     }
+    tkMotifFDialog_SetListMode $w
 
     wm transient $w $data(-parent)
 
+    tkMotifFDialog_FileTypes $w
     tkMotifFDialog_Update $w
 
     # Withdraw the window, then update all the geometry information
@@ -117,6 +123,74 @@ proc tkMotifFDialog_Create {dataName type argList} {
     return $w
 }
 
+# tkMotifFDialog_FileTypes --
+#
+#	Checks the -filetypes option. If present this adds a list of radio-
+#	buttons to pick the file types from.
+#
+# Arguments:
+#	w		Pathname of the tk_get*File dialogue.
+#
+# Results:
+#	none
+
+proc tkMotifFDialog_FileTypes {w} {
+    upvar ::tk::dialog::file::[winfo name $w] data
+
+    set f $w.top.f3.types
+    catch {destroy $f}
+
+    # No file types: use "*" as the filter and display no radio-buttons
+    if {$data(-filetypes) == ""} {
+	set data(filter) *
+	return
+    }
+
+    # The filetypes radiobuttons
+    # set data(fileType) $data(-defaulttype)
+    set data(fileType) 0
+
+    tkMotifFDialog_SetFilter $w [lindex $data(-filetypes) $data(fileType)]
+
+    #don't produce radiobuttons for only one filetype
+    if {[llength $data(-filetypes)] == 1} {
+	return
+    }
+
+    frame $f
+    set cnt 0
+    if {$data(-filetypes) != {}} {
+	foreach type $data(-filetypes) {
+	    set title  [lindex [lindex $type 0] 0]
+	    set filter [lindex $type 1]
+	    radiobutton $f.b$cnt \
+		-text $title \
+		-variable [winfo name $w](fileType) \
+		-value $cnt \
+		-command "[list tkMotifFDialog_SetFilter $w $type]"
+	    pack $f.b$cnt -side left
+	    incr cnt
+	}
+    }
+    $f.b$data(fileType) invoke
+
+    pack $f -side bottom -fill both
+
+    return
+}
+
+# This proc gets called whenever data(filter) is set
+#
+proc tkMotifFDialog_SetFilter {w type} {
+    upvar ::tk::dialog::file::[winfo name $w] data
+    global tkpriv
+
+    set data(filter) [lindex $type 1]
+    set tkpriv(selectFileType) [lindex [lindex $type 0] 0]
+
+    tkMotifFDialog_Update $w
+}
+
 # tkMotifFDialog_Config --
 #
 #	Iterates over the optional arguments to determine the option
@@ -143,6 +217,7 @@ proc tkMotifFDialog_Config {dataName type argList} {
 	{-initialfile "" "" ""}
 	{-parent "" "" "."}
 	{-title "" "" ""}
+	{-multiple "" "" "0"}
     }
 
     # 2: default values depending on the type of the dialog
@@ -159,7 +234,11 @@ proc tkMotifFDialog_Config {dataName type argList} {
 
     if {[string equal $data(-title) ""]} {
 	if {[string equal $type "open"]} {
-	    set data(-title) "Open"
+	    if {$data(-multiple) != 0} {
+		set data(-title) "Open Multiple Files"
+	    } else {
+		set data(-title) "Open"
+	    }
 	} else {
 	    set data(-title) "Save As"
 	}
@@ -170,7 +249,7 @@ proc tkMotifFDialog_Config {dataName type argList} {
     #
     if {[string compare $data(-initialdir) ""]} {
 	if {[file isdirectory $data(-initialdir)]} {
-	    set data(selectPath) [glob $data(-initialdir)]
+	    set data(selectPath) [lindex [glob $data(-initialdir)] 0]
 	} else {
 	    set data(selectPath) [pwd]
 	}
@@ -290,6 +369,18 @@ proc tkMotifFDialog_BuildUI {w} {
     wm protocol $w WM_DELETE_WINDOW [list tkMotifFDialog_CancelCmd $w]
 }
 
+proc tkMotifFDialog_SetListMode {w} {
+    upvar ::tk::dialog::file::[winfo name $w] data
+
+    if {$data(-multiple) != 0} {
+	set selectmode extended
+    } else {
+	set selectmode browse
+    }
+    set f $w.top.f2.b
+    $f.l configure -selectmode $selectmode
+}
+
 # tkMotifFDialog_MakeSList --
 #
 #	Create a scrolled-listbox and set the keyboard accelerator
@@ -307,7 +398,7 @@ proc tkMotifFDialog_BuildUI {w} {
 
 proc tkMotifFDialog_MakeSList {w f label under cmdPrefix} {
     label $f.lab -text $label -under $under -anchor w
-    listbox $f.l -width 12 -height 5 -selectmode browse -exportselection 0\
+    listbox $f.l -width 12 -height 5 -exportselection 0\
 	-xscrollcommand [list $f.h set]	-yscrollcommand [list $f.v set]
     scrollbar $f.v -orient vertical   -takefocus 0 -command [list $f.l yview]
     scrollbar $f.h -orient horizontal -takefocus 0 -command [list $f.l xview]
@@ -324,14 +415,10 @@ proc tkMotifFDialog_MakeSList {w f label under cmdPrefix} {
     # bindings for the listboxes
     #
     set list $f.l
-    bind $list <Up>		[list tkMotifFDialog_Browse$cmdPrefix $w]
-    bind $list <Down>		[list tkMotifFDialog_Browse$cmdPrefix $w]
-    bind $list <space>		[list tkMotifFDialog_Browse$cmdPrefix $w]
-    bind $list <1>		[list tkMotifFDialog_Browse$cmdPrefix $w]
-    bind $list <B1-Motion>	[list tkMotifFDialog_Browse$cmdPrefix $w]
+    bind $list <<ListboxSelect>> [list tkMotifFDialog_Browse$cmdPrefix $w]
     bind $list <Double-ButtonRelease-1> \
 	    [list tkMotifFDialog_Activate$cmdPrefix $w]
-    bind $list <Return>    "tkMotifFDialog_Browse$cmdPrefix [list $w]; \
+    bind $list <Return>	"tkMotifFDialog_Browse$cmdPrefix [list $w]; \
 	    tkMotifFDialog_Activate$cmdPrefix [list $w]"
 
     bindtags $list [list Listbox $list [winfo toplevel $list] all]
@@ -455,32 +542,31 @@ proc tkMotifFDialog_LoadFiles {w} {
 	return
     }
 
-    # Make the dir list
+    # Make the dir and file lists
     #
-    foreach f [lsort -dictionary [glob -nocomplain .* *]] {
-	if {[file isdir ./$f]} {
-	    $data(dList) insert end $f
-	}
-    }
-    # Make the file list
+    # For speed we only have one glob, which reduces the file system
+    # calls (good for slow NFS networks).
+    #
+    # We also do two smaller sorts (files + dirs) instead of one large sort,
+    # which gives a small speed increase.
     #
-    if {[string equal $data(filter) *]} {
-	set files [lsort -dictionary [glob -nocomplain .* *]]
-    } else {
-	set files [lsort -dictionary \
-	    [glob -nocomplain $data(filter)]]
-    }
-
     set top 0
-    foreach f $files {
-	if {![file isdir ./$f]} {
-	    regsub {^[.]/} $f "" f
-	    $data(fList) insert end $f
-	    if {[string match .* $f]} {
-		incr top
+    set dlist ""
+    set flist ""
+    foreach f [glob -nocomplain .* *] {
+	if {[file isdir ./$f]} {
+	    lappend dlist $f
+	} else {
+	    if {[string match $data(filter) $f]} {
+		if {[string match .* $f]} {
+		    incr top
+		}
+		lappend flist $f
 	    }
 	}
     }
+    eval $data(dList) insert end [lsort -dictionary $dlist]
+    eval $data(fList) insert end [lsort -dictionary $flist]
 
     # The user probably doesn't want to see the . files. We adjust the view
     # so that the listbox displays all the non-dot files
@@ -489,7 +575,7 @@ proc tkMotifFDialog_LoadFiles {w} {
     cd $appPWD
 }
 
-# tkMotifFDialog_BrowseFList --
+# tkMotifFDialog_BrowseDList --
 #
 #	This procedure is called when the directory list is browsed
 #	(clicked-over) by the user.
@@ -598,23 +684,30 @@ proc tkMotifFDialog_BrowseFList {w} {
     upvar ::tk::dialog::file::[winfo name $w] data
 
     focus $data(fList)
-    if {[string equal [$data(fList) curselection] ""]} {
-	return
+    set data(selectFile) ""
+    foreach item [$data(fList) curselection] {
+	lappend data(selectFile) [$data(fList) get $item]
     }
-    set data(selectFile) [$data(fList) get [$data(fList) curselection]]
-    if {[string equal $data(selectFile) ""]} {
+    if {[llength $data(selectFile)] == 0} {
 	return
     }
 
     $data(dList) selection clear 0 end
 
     $data(fEnt) delete 0 end
-    $data(fEnt) insert 0 [::tk::dialog::file::JoinFile $data(selectPath) $data(filter)]
+    $data(fEnt) insert 0 [::tk::dialog::file::JoinFile $data(selectPath) \
+	    $data(filter)]
     $data(fEnt) xview end
  
+    # if it's a multiple selection box, just put in the filenames 
+    # otherwise put in the full path as usual 
     $data(sEnt) delete 0 end
-    $data(sEnt) insert 0 [::tk::dialog::file::JoinFile $data(selectPath) \
-	    $data(selectFile)]
+    if {$data(-multiple) != 0} {
+	$data(sEnt) insert 0 $data(selectFile)
+    } else {
+	$data(sEnt) insert 0 [::tk::dialog::file::JoinFile $data(selectPath) \
+				  [lindex $data(selectFile) 0]]
+    }
     $data(sEnt) xview end
 }
 
@@ -683,55 +776,64 @@ proc tkMotifFDialog_ActivateSEnt {w} {
     upvar ::tk::dialog::file::[winfo name $w] data
 
     set selectFilePath [string trim [$data(sEnt) get]]
-    set selectFile     [file tail    $selectFilePath]
-    set selectPath     [file dirname $selectFilePath]
 
     if {[string equal $selectFilePath ""]} {
 	tkMotifFDialog_FilterCmd $w
 	return
     }
 
-    if {[file isdirectory $selectFilePath]} {
-	set data(selectPath) [glob $selectFilePath]
-	set data(selectFile) ""
-	tkMotifFDialog_Update $w
-	return
+    if {$data(-multiple) == 0} {
+	set selectFilePath [list $selectFilePath]
     }
 
-    if {[string compare [file pathtype $selectFilePath] "absolute"]} {
-	tk_messageBox -icon warning -type ok \
-	    -message "\"$selectFilePath\" must be an absolute pathname"
-	return
-    }
-
-    if {![file exists $selectPath]} {
-	tk_messageBox -icon warning -type ok \
-	    -message "Directory \"$selectPath\" does not exist."
+    if {[file isdirectory [lindex $selectFilePath 0]]} {
+	set data(selectPath) [lindex [glob $selectFilePath] 0]
+	set data(selectFile) ""
+	tkMotifFDialog_Update $w
 	return
     }
 
-    if {![file exists $selectFilePath]} {
-	if {[string equal $data(type) open]} {
+    set newFileList ""
+    foreach item $selectFilePath {
+	if {[string compare [file pathtype $item] "absolute"]} {
+	    set item [file join $data(selectPath) $item]
+	} elseif {![file exists [file dirname $item]]} {
 	    tk_messageBox -icon warning -type ok \
-		-message "File \"$selectFilePath\" does not exist."
+		-message "Directory \"[file dirname $item]\" does not exist."
 	    return
 	}
-    } else {
-	if {[string equal $data(type) save]} {
-	    set message [format %s%s \
-		"File \"$selectFilePath\" already exists.\n\n" \
-		"Replace existing file?"]
-	    set answer [tk_messageBox -icon warning -type yesno \
-		-message $message]
-	    if {[string equal $answer "no"]} {
+
+	if {![file exists $item]} {
+	    if {[string equal $data(type) open]} {
+		tk_messageBox -icon warning -type ok \
+		    -message "File \"$item\" does not exist."
 		return
 	    }
+	} else {
+	    if {[string equal $data(type) save]} {
+		set message [format %s%s \
+				 "File \"$item\" already exists.\n\n" \
+				 "Replace existing file?"]
+		set answer [tk_messageBox -icon warning -type yesno \
+				-message $message]
+		if {[string equal $answer "no"]} {
+		    return
+		}
+	    }
 	}
+	
+	lappend newFileList $item
     }
 
-    set tkPriv(selectFilePath) $selectFilePath
-    set tkPriv(selectFile)     $selectFile
-    set tkPriv(selectPath)     $selectPath
+    if {$data(-multiple) != 0} {
+	set tkPriv(selectFilePath) $newFileList
+    } else {
+	set tkPriv(selectFilePath) [lindex $newFileList 0]
+    }
+
+    # Set selectFile and selectPath to first item in list
+    set tkPriv(selectFile)     [file tail    [lindex $newFileList 0]]
+    set tkPriv(selectPath)     [file dirname [lindex $newFileList 0]]
 }

@@ -786,6 +888,9 @@ proc tkListBoxKeyAccel_Unset {w} {
 proc tkListBoxKeyAccel_Key {w key} {
     global tkPriv
 
+    if { $key == "" } {
+	return
+    }
     append tkPriv(lbAccel,$w) $key
     tkListBoxKeyAccel_Goto $w $tkPriv(lbAccel,$w)
     catch {
@@ -818,6 +923,7 @@ proc tkListBoxKeyAccel_Goto {w string} {
 	$w selection set $theIndex $theIndex
 	$w activate $theIndex
 	$w see $theIndex
+	event generate $w <<ListboxSelect>>
     }
 }
 
@@ -827,3 +933,9 @@ proc tkListBoxKeyAccel_Reset {w} {
     catch {unset tkPriv(lbAccel,$w)}
 }
 
+
+proc tk_getFileType {} {
+    global tkpriv
+
+    return $tkpriv(selectFileType)
+}
-- 
cgit v0.12