Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Here's that Motif-like File Selector

26 views
Skip to first unread message

Matthew Rice

unread,
Nov 4, 1994, 10:25:17 AM11/4/94
to
As promised it a baby file selector.
The filter works using the tcl glob command so set your
filters accrodingly.

As this was the first thing I ever wrote in tk/tcl (and I haven't
had time to look at it since) the widget doesn't look very nice
or have any docs. I will be looking at it soon and creating some
more Motif-like widgets/stuff (can anyone say "paned-windows").

A few words first.
Known bugs-
1) sometimes (or all the time unsure) directories and files will show
up twice (most likely a globbing prob).
2) report any problems here.

Future enhancements -
1) when selecting a single file add the option that the file
need not exist. (eg. for a save as call)
2) insert you opinions here. (I'm receptive)


BEGIN----------- CUT HERE ---------------
#@package: gipsi-FileSelectors gp_FileSelectorDialog \
gp_FileSelectorBox gp_SingleFileSelectorBox \
gp_SingleFileSelectorDialog

proc gp_SingleFileSelectorDialog {w script {title {file selector dialog}} \
{filter {}}} {
gp_FileSelectorDialog $w $script $title $filter 0
}

proc gp_FileSelectorDialog {w script {title {file selector dialog}} \
{filter {}} {MultipleFiles {1}}} {

gp_MakeFileSelector $w $title $filter $MultipleFiles
gp_FillFileSelector $w
$w.ok configure -command "gp_CheckDialogList $w \"$script\""
$w.cancel configure -command "destroy $w"
}

proc gp_SingleFileSelectorBox {w {title {file selector box}} \
{filter {}}} {
return [gp_FileSelectorBox $w $title $filter 0]
}

proc gp_FileSelectorBox {w {title {file selector box}} \
{filter {}} {MultipleFiles {1}}} {

# 1. Set up the file selector and assign commands to the OK and
# Cancel buttons.

global gp_priv
gp_MakeFileSelector $w $title $filter $MultipleFiles
gp_FillFileSelector $w
$w.ok configure -command "gp_CheckBoxList $w"
$w.cancel configure -command "set gp_priv(filelist) {}"

# 2. Set a grab and claim the focus.

set oldfocus [focus]
grab $w
focus $w

# 3. Wait for a response, then restore focus and return the filelist.

tkwait variable gp_priv(filelist)
destroy $w
focus $oldfocus
return $gp_priv(filelist)
}

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# The routines below this line should not be called from outside
# this file.

proc gp_CheckBoxList w {
global gp_priv
set list [gp_CheckFileList $w]
if {$list != ""} {
set gp_priv(filelist) $list
}
}

proc gp_CheckDialogList {w script} {
set result [gp_CheckFileList $w]
if {$result != ""} {
destroy $w
regsub -all %F $script $result newscript
eval $newscript
}
}

proc gp_CheckFileList w {
set filelist {}
set choice {}

if {[$w.dirs.list curselection] != ""} {
set choice [selection get]
} elseif {[$w.file.list curselection] != ""} {
$w.selection.value delete 0 end
foreach el [$w.file.list curselection] {
lappend filelist [$w.file.list get $el]
}
} else {
set choice [$w.selection.value get]
if {$choice == ""} {
tk_dialog .d "File Selector Error" "Nothing has been selected." \
error 0 OK
}
}
if {$choice != ""} {
if [file isfile $choice] {
set filelist $choice
} elseif [file isdir $choice] {
cd $choice
gp_FillFileSelector $w
$w.selection.value delete 0 end
} elseif ![file exists $choice] {
tk_dialog .d "File Selector Error" \
"$choice doesn't exist or is unreadable." error 0 OK
} else {
tk_dialog .d "File Selector Error" \
"$choice is not a file or directory." error 0 OK
}
}
return $filelist
}

proc gp_MakeFileSelector {w title filter MultipleFiles} {

# 1. Create the toplevel window and a top and bottom frame.

catch {destroy $w}
toplevel $w
wm title $w $title
frame $w.t -relief groove -bd 2
frame $w.b -relief groove -bd 2

# 2. Create the filter and selection labels and entries. As well
# as the frame for the listboxes.

frame $w.lists
gp_LabelledEntry $w.filter "Filter"
gp_LabelledEntry $w.selection "Selection"
$w.filter.value insert end $filter

# 3. Create the listboxes with labels and pack everything into $w.t.

gp_ScrolledList $w.dirs Directories
gp_ScrolledList $w.file Files

tk_listboxSingleSelect $w.dirs.list
if !$MultipleFiles {
tk_listboxSingleSelect $w.file.list
}

pack $w.dirs $w.file -in $w.lists -side left -padx 1m
pack $w.filter -in $w.t -fill x -pady 4m
pack $w.lists -in $w.t -fill x
pack $w.selection -in $w.t -fill x -pady 4m

# 4. Create the OK, Filter and Cancel buttons.

frame $w.default -relief sunken -bd 1
button $w.ok -text OK ; # No command specified. This is set later.
button $w.filt -text Filter -command "gp_FillFileSelector $w"
button $w.cancel -text Cancel ; # No commandspecified. This is set later.

pack $w.ok -in $w.default -expand 1 -ipadx 1m -ipady 1m -padx 1.5m -pady 1m
pack $w.default $w.filt $w.cancel -in $w.b -side left -expand 1 \
-ipadx 1m -ipady 1m -padx 3m -pady 3m

# 5. Add some extra bindings.
# 5a. Pressing <Return> or <KP_Enter> in the entry will invoke
# either the OK button for the selection or the Filter button
# for the filter.

bind $w.filter.value <KP_Enter> "$w.filt flash; $w.filt invoke"
bind $w.selection.value <KP_Enter> "$w.ok flash; $w.ok invoke"
bind $w.filter.value <Return> "$w.filt flash; $w.filt invoke"
bind $w.selection.value <Return> "$w.ok flash; $w.ok invoke"

# 5b. These were added to remove the focus from either of the
# Entries when selecting from the Listboxes.

bind $w.file.list <1> {
%W select from [%W nearest %y]
focus %W
}
bind $w.dirs.list <1> {
%W select from [%W nearest %y]
focus %W
}

# 5c. A couple of quick invocations of the OK button.

bind $w.file.list <Double-Button-1> "$w.ok flash; $w.ok invoke"
bind $w.dirs.list <Double-Button-1> "$w.ok flash; $w.ok invoke"
bind $w.file.list <Return> "$w.ok flash; $w.ok invoke"
bind $w.dirs.list <Return> "$w.ok flash; $w.ok invoke"
bind $w.file.list <KP_Enter> "$w.ok flash; $w.ok invoke"
bind $w.dirs.list <KP_Enter> "$w.ok flash; $w.ok invoke"

# 6. Pack the top and bottom frames

pack $w.t $w.b -fill both
}

proc gp_FillFileSelector w {
$w.dirs.list delete 0 end
$w.dirs.list insert end ./
$w.dirs.list insert end ../
foreach j [glob -nocomplain */] {
if {$j != ""} {$w.dirs.list insert end $j}
}

regsub -all \; [$w.filter.value get] { } filter
$w.file.list delete 0 end

if {$filter == ""} {
set filter *
}
foreach i $filter {
set files [glob -nocomplain $i]
if {$files == ""} continue
foreach j $files {
if [file isfile $j] {
$w.file.list insert end $j
} elseif [file isdir $j] {
$w.dirs.list insert end $j
}
}
}
}

proc gp_ScrolledList {w {title {}} {anchor w}} {
catch {destroy $w}
frame $w
frame $w.top
frame $w.bot
frame $w.priv

if {$title != ""} {
label $w.label -text $title
}
listbox $w.list -relief sunken -bd 2 -yscrollcommand "$w.vscroll set" \
-xscrollcommand "$w.hscroll set"

scrollbar $w.vscroll -relief sunken -bd 2 -command "$w.list yview"
scrollbar $w.hscroll -relief sunken -bd 2 -command "$w.list xview" \
-orient horizontal

if {$title != ""} {
pack $w.label -anchor $anchor
}
pack $w.vscroll -in $w.top -side right -fill y -pady 3
pack $w.list -in $w.top -padx 3 -pady 3

set width [expr [lindex [$w.vscroll config -width] 4] +\
[lindex [$w.vscroll config -bd] 4] *2]
$w.priv config -width $width
pack $w.priv -in $w.bot -side right
pack $w.hscroll -in $w.bot -fill x -padx 3
pack $w.top $w.bot -fill x
}

proc gp_LabelledEntry {w title {readonly 0} {side top}} {
catch {destroy $w}
frame $w
label $w.label -text $title -anchor w
if $readonly {
label $w.value -relief sunken -width 15
} else {
entry $w.value -relief sunken
}
pack $w.label $w.value -side $side -fill x -padx 3m
}
END----------- CUT HERE ---------------

--
Matthew

-- I speak for everybody, but I type for myself.

Przemek Klosowski

unread,
Nov 4, 1994, 4:31:18 PM11/4/94
to
Neat file selector---nice addition to my toolbox. Incidentally the
'duplicated filenames' bug is because you include things twice in the
directory column: once at the beginning when you search for */, and
second time when you check [file isdir $j]. I think that the proper
fix is thus to omit processing directories when you glob the filter
(procedure gp_FillFileSelector)

....


foreach j $files {
if [file isfile $j] {
$w.file.list insert end $j
} elseif [file isdir $j] {

--> # we don't need "$w.dirs.list insert end $j"; dirs already in
}
....
--
przemek klosowski (prz...@rrdstrad.nist.gov)
Reactor Division (bldg. 235), E111
National Institute of Standards and Technology
Gaithersburg, MD 20899, USA

(301) 975 6249

Matthew Rice

unread,
Nov 7, 1994, 9:42:03 AM11/7/94
to
Przemek Klosowski (prz...@rrdjazz.nist.gov) wrote:
: Neat file selector---nice addition to my toolbox. Incidentally the

: 'duplicated filenames' bug is because you include things twice in the
: directory column: once at the beginning when you search for */, and
: second time when you check [file isdir $j]. I think that the proper
: fix is thus to omit processing directories when you glob the filter
: (procedure gp_FillFileSelector)

: ....
: foreach j $files {
: if [file isfile $j] {
: $w.file.list insert end $j
: } elseif [file isdir $j] {
: --> # we don't need "$w.dirs.list insert end $j"; dirs already in
: }
: ....
: --

I don't think the solution is that simple. For example if you are in the
directory /usr/home/matt, you can set the filter to "/usr/local/{lib,bin}/*".

Just processing all of the directories then ignoring the filtered ones
will miss all of the directories from the filter.

What should happen here ? Should directories be allowed in the filter ?
Or should the filtered dirs be ignored ? Or should I just allow both
and filter out duplicate entries ?

I lean more towards allowing both and filtering out dups.

0 new messages