/* A file dialog presents a list of files for selection.
  The dialog returns a string defining the file to be loaded.
  File Dialog objects can be used repeatedly, sending the
  runModal message to them whenever desired.  They will remember
  the directory and filter, without resetting the current directory. */!!

inherit(Dialog, #FileDialog,
#(startDir  /* Initial path specification */
loadFile  /* nil if cancelled, true otherwise */
fileSpec  /* Filter for files, e.g. "*.*" */
pathSpec  /* Contains the current DOS directory */
helpEntry /* The context id for help */), 2, nil)!!

now(class(FileDialog))!!

/* Create and a new file loader dialog object. The dialog's fileSpec
  instance variable is specified by the file argument. For example,
  new(FileDialog, "\*.*") would create a file dialog object that would list
  all the files and subdirectories in the root directory, setting pathSpec
  to "C:\" in the process. */
Def new(self, file | theDlg)
{ theDlg := new(self:Behavior);
  setFileSpec(theDlg, (size(file) > 0 cand file) cor "*.*");
  ^theDlg;
}!!

now(FileDialog)!!

/* set the help entry to use */
Def setHelpEntry(self, hEntry)
{
  helpEntry := hEntry;
}!!

/* Handle file dialog events (OK, Cancel, Help, etc.). Selecting Open
  will always do something, if only to reload the lists according
  to the current filter. */
Def command(self, wP, lP | action)
{ action := high(lP);
  select
    case wP == IDCANCEL
    is resetDir(self);
      end(self, 0);
    endCase
    case wP == FILE_LB and action = LBN_SELCHANGE
    is sendDlgItemMessage(self, FILE_DIRLB, LB_SETCURSEL, -1, 0);
    endCase
    case wP == FILE_DIRLB and action = LBN_SELCHANGE
    is sendDlgItemMessage(self, FILE_LB, CB_SETCURSEL, -1, 0);
      setItemText(self, FILE_LB, getLoadDir(self) + fileSpec);
    endCase
    case (wP == FILE_DIRLB and action = LBN_DBLCLK)
      cor (wP == IDOK and getLBSel(self, FILE_DIRLB))
    is newDir(self);
    endCase
    case wP == FILE_LB and action = LBN_DBLCLK
    is
      if getLoadFile(self)
      then resetDir(self);
        end(self, IDOK);
      endif;
    endCase
    case wP == IDOK
    is open(self)
    endCase
    case wP = IDHELP
       is contextNumber(TheHelpObject, hWnd, helpEntry);
    endCase        
  endSelect;
  ^1;
}!!

/* Return the loadFile instance variable. */
Def getFile(self)
{ ^loadFile;
}!!

/* Return the selected directory from the listbox. Assumes that a
  selection has been made in the list box. */
Def getLoadDir(self | sel)
{ Call DlgDirSelect(getHWnd(self), sel := new(String, 20), FILE_DIRLB);
  ^removeNulls(sel);
}!!

/* Get the selected file from the listbox, if any, and set
  loadFile. Assumes that a selection has been made
  in the list box. */
Def getLoadFile(self | ans, sel)
{ Call DlgDirSelectComboBox(getHWnd(self), sel := new(String, 20), FILE_LB);
  sel := removeNulls(sel);
  ^loadFile := pathString(self, sel);
}!!

/* Initialize the file loader dialog. */
Def initDialog(self, wp, lp)
{ Call DlgDirListComboBox(hWnd, asciiz("*.*"), FILE_LB, FILE_DIR, 0);
  startDir := getItemText(self, FILE_DIR);
  if not(pathSpec)
  then pathSpec := startDir;
  endif;
  fileSpec := pathString(self, fileSpec);
  loadList(self);
  if (CLIULibraryClass$Inst) then
     if (not(helpEntry)) then
        /* make sure helpEntry is set to Something */
        helpEntry := HELP_CONTENTS;
     endif;
     registerF1Help(CLIULibraryClass$Inst, HI_FILE_DLG,
        getHWnd(self), helpEntry);
  endif;
  ^1;
}!!

/* Return the loadFile instance variable. */
Def loadFile(self)
{ ^loadFile;
}!!

/* Load the listbox based on fileSpec instance variable,
  update pathSpec instance variable. Return true if successfull. */
Def loadList(self | str)
{ str := asciiz(fileSpec);
  if (Call DlgDirListComboBox(hWnd, str, FILE_LB, 0, 0x0000L) = 0)
  then ^nil;
  endif;
  Call DlgDirList(hWnd, str, FILE_DIRLB, FILE_DIR, 0xC010L);
  fileSpec := removeNulls(str);
  setItemText(self, FILE_LB, fileSpec);
  pathSpec := getItemText(self, FILE_DIR);
}!!

/* Select new directory. */
Def newDir(self | fs)
{  fs := fileSpec;    /* save present fileSpec */
  fileSpec := getItemText(self, FILE_LB);
  if not(indexOf(fileSpec, '*', 0) cor indexOf(fileSpec, '?', 0))
  then beep();
    fileSpec := fileSpec + "*";
    setItemFocus(self, FILE_LB);
  endif;
  if not(loadList(self))
  then fileSpec := fs;
  endif;
}!!

/* Respond to Open button being pushed or CR being pushed. If a
  valid file is selected, exit dialog. Otherwise, switch to new
  directory, filter, etc.  */
Def open(self | fs)
{ fs := fileSpec;
  fileSpec := getItemText(self, FILE_LB);
  if size(fileSpec) = 0
  then fileSpec := "*.*";
  endif;
  if exists(File, pathString(self, fileSpec), 0)
  then loadFile := pathString(self, fileSpec);
    fileSpec := fs;
    resetDir(self);
    end(self, IDOK);
  else
    if not(indexOf(fileSpec, '*', 0) cor indexOf(fileSpec, '?', 0))
    then beep();
      setItemFocus(self, FILE_LB);
    endif;
    if not(loadList(self))
    then fileSpec := fs;
    endif;
  endif;
}!!

/* Return a string representing currently selected path. Sometimes pathSpec
  already ends with a backslash. */
Def pathString(self, file)
{ select
    case (size(file) > 3) cand file[1] == ':'
    is ^file;
    endCase
    case pathSpec[size(pathSpec)-1] == '\'
    is ^pathSpec + file;
    endCase
    default ^pathSpec + "\" + file;
  endSelect;
}!!

/* Reset the original directory, which is stored in
  the startDir instance variable. */
Def resetDir(self)
{ Call DlgDirListComboBox(getHWnd(self), asciiz(startDir), 0, 0, 0);
}!!

/* Set and return fileSpec instance variable. */
Def setFileSpec(self, fs)
{ ^fileSpec := fs;
}!!
