# # $Id: filedialog.icn,v 1.4 2004/02/15 22:10:54 rparlett Exp $ # # This file is in the public domain. # # Author: Robert Parlett (parlett@dial.pipex.com) # package gui link graphics $include "guih.icn" $ifdef _MS_WINDOWS_NT $define PATHCHAR "\\" $else $define PATHCHAR "/" $endif # # # File dialog class. This class provides a standard file dialog. # # @example # @ d := FileDialog() # @ d.show() # @ write(d.get_result() | "cancelled") # class FileDialog : Dialog( init_dir, # Initial directory name init_file, # Initial file name res, # Resulting file path dir, # TextField directory file, # TextField filename dlist, # TextList of directories flist, # TextList of files okay, # cancel # ) # # Get the directory part of the result # method get_directory() return directory_name(\self.res) end # # Get the result, (will fail if cancel was pressed). # method get_result() return \self.res end # # Set the initial directory. # method set_directory(s) return self.init_dir := s end # # Set the initial file # method set_file(s) return self.init_file := s end # # Set the initial file/directory from a whole path. # method set_path(s) self.init_dir := directory_name(s) self.init_file := file_name(s) return s end # # Set the result # # @p method set_result() self.res := self.get_std_dir() || file.get_contents() end # # Get the directory TextField contents standardized with a trailing / # # @p method get_std_dir() s := dir.get_contents() if (s[-1] ~== PATHCHAR) then s ||:= PATHCHAR return s end method on_okay() self.set_result() self.dispose() end method on_file() # # If return pressed in file TextField, same as okay # self.set_result() self.dispose() end method on_dlist() # # Clicked in the directory list; get the item clicked on. # value := dlist.get_contents()[dlist.get_selections()[1]] s := self.get_std_dir() # # Go to parent directory (unless at root directory) # if value == (".." || PATHCHAR) then { if s ~== PATHCHAR then { s[-1] := "" while s[-1] ~== PATHCHAR do s[-1] := "" } dir.set_contents(s) } else dir.set_contents(s ||:= value) # # Update directory and file lists. # l := get_directory_list(s) dlist.set_contents(l[1]) dlist.goto_pos(1, 0) dlist.clear_selections() flist.set_contents(l[2]) flist.goto_pos(1, 0) flist.clear_selections() file.set_contents("") end method on_flist() # # Clicked in file list; set TextField # file.set_contents(flist.get_contents()[flist.get_selections()[1]]) end method on_dir() # # Return pressed in directory TextField; update lists. # dir.set_contents(s := self.get_std_dir()) l := get_directory_list(s) dlist.set_contents(l[1]) dlist.goto_pos(1, 0) dlist.clear_selections() flist.set_contents(l[2]) flist.goto_pos(1, 0) flist.clear_selections() file.set_contents("") end method init_dialog() self.set_focus(file) end method component_setup() local l # # Defaults if none set by caller. # if /init_dir | (init_dir == "") then { init_dir := chdir() | PATHCHAR } /init_file := "" if (init_dir[-1] ~== PATHCHAR) then init_dir ||:= PATHCHAR l := Label("pos=25,25", "align=l,c", "label=Directory") self.add(l) dir := TextField("pos=100,25", "size=100%-150", "align=l,c", "accel=d") dir.connect(self, "on_dir", ACTION_EVENT) dir.set_contents(init_dir) self.add(dir) l.set_linked_accel(dir) l := Label("pos=25,75", "align=l,c", "label=File") self.add(l) file := TextField("pos=100,75", "size=100%-150", "align=l,c", "accel=f") file.connect(self, "on_file", ACTION_EVENT) file.set_contents(init_file) self.add(file) l.set_linked_accel(file) l := get_directory_list(init_dir) dlist := TextList("pos=25,110", "size=50%-38,100%-170", "select_one", "selection_on_key_moves=f") dlist.connect(self, "on_dlist", SELECTION_CHANGED_EVENT) dlist.set_contents(l[1]) self.add(dlist) flist := TextList("pos=50%+12,110", "size=50%-38,100%-170", "select_one", "selection_on_key_moves=f") flist.connect(self, "on_flist", SELECTION_CHANGED_EVENT) flist.set_contents(l[2]) self.add(flist) okay := TextButton("pos=33%,100%-30", "align=c,c", "label=Okay", "accel=o") okay.connect(self, "on_okay", ACTION_EVENT) self.add(okay) cancel := TextButton("pos=66%,100%-30", "align=c,c", "label=Cancel", "accel=c") cancel.connect(self, "dispose", ACTION_EVENT) self.add(cancel) end initially(a[]) self.Dialog.initially() # # Set attrib before calling set_fields, so these settings can # be overridden. # attrib("size=420,370", "resize=on", "label=Select File") set_fields(a) end # # Read a directory. # procedure get_directory_list(s) local dir_list, file_list /fatal_error := stop $ifdef _MS_WINDOWS_NT s := map(s,"/","\\") if (*s > 1) & (s[-1] == PATHCHAR) & (map(s,&letters,repl("a",52)) ~== "a:\\") then s[-1] := "" $else if (*s > 1) & (s[-1] == PATHCHAR) then s[-1] := "" $endif p := open(s) | { write(&errout, "get_directory_list: can't open ", image(s)) fail } if not (s[-1] == PATHCHAR) then s ||:= PATHCHAR dir_list := [] file_list := [] while s2 := read(p) do { sr := stat(s||s2) | { write(&errout, "get_directory_list: can't stat ", image(s2)) fail } if sr.mode[1] == "d" then put(dir_list, s2 || PATHCHAR) else put(file_list, s2) } close(p) return [sort(dir_list), sort(file_list)] end # # Return the directory name of the file name s, including the trailing / # procedure directory_name(s) local i every i := find(PATHCHAR, s) return s[1:\i + 1] | "" end # # Return the file name of s # procedure file_name(s) local i every i := find(PATHCHAR, s) return s[\i + 1:0] | s end