#
# $Log: not supported by cvs2svn $
# Revision 1.62  2006/03/24 20:57:11  soliday
# Modified APSAddToRecentFileList and APSGetRecentFileList so that
# if the ~/.oagrecentfiles is corrupted it will delete the file without
# returning an error message.
#
# Revision 1.61  2005/08/01 19:38:23  soliday
# Tried to fix the SDDS Command button to work with command line programs. It
# works better than before but there is still problems.
#
# Revision 1.60  2004/12/16 22:50:28  soliday
# Cleaned up the usage message for APSFileDisplayWindow
#
# Revision 1.59  2004/12/16 22:45:46  soliday
# Added the -autoWidth and -autoWidthLimit to the APSFileDisplayWindow widget.
#
# Revision 1.58  2004/10/28 15:44:59  soliday
# Added the option to add an x scrollbar to the scrolled list widget used by
# the APSFileSelectDialog.
#
# Revision 1.57  2004/08/20 21:32:46  shang
# replace the "Export SDDS data..." button on the file display window by
# "SDDS Command..." menu button that will bring up a list of commands including
# export sdds data which left-mouse is clicked on it.
#
# Revision 1.56  2004/08/09 15:10:27  soliday
# Replaced some put commands with APSAlertBox commands.
#
# Revision 1.55  2004/08/06 20:54:12  soliday
# No longer tries to add to the recent file list when the cancel button is pressed.
#
# Revision 1.54  2004/08/05 18:47:24  borland
# In APSAddToRecentFileList: if the filename is not a full filename, add the
# PWD as the pathname.
#
# Revision 1.53  2004/08/05 18:17:30  soliday
# Added APSAddToRecentFileList and APSGetRecentFileList to read and write
# the names of recently selected files.
#
# Revision 1.52  2004/08/05 16:19:23  soliday
# Added the Select Recent... option to the entry box manipulator button. This
# allows the user to select a file from a list of the 20 most recently selected
# files.
#
# Revision 1.51  2004/03/23 18:08:48  shang
# fixed the parsing arguments error when APSProceedPrinting proc is called with
# empty font passed.
#
# Revision 1.50  2004/02/09 21:02:17  borland
# Help procedure includes additional switches.
#
# Revision 1.49  2004/01/22 18:17:59  borland
# Added -reverseSort option to APSFileSelectDialog.
#
# Revision 1.48  2003/12/16 22:49:57  soliday
# Fixed a problem if the selected file and/or directory has spaces.
#
# Revision 1.47  2003/10/21 19:47:03  shang
# added following arguments to APSFileDisplayWindow
# defaultButtons -- include "print","email",etc. buttons or not
# okButton -- include "Ok" button or not
# okCommand -- command for Ok button
# cancelButton -- include "Cancel" button or not
# cancelCommand -- command for Cancel button
# closeCommand -- include "Close" button or not
#
# Revision 1.46  2003/10/20 20:06:29  shang
# made APSFileSelectDialog able to select directory without listing files.
#
# Revision 1.45  2003/10/14 16:22:44  shang
# added selectDir option to APSFileSelectDiaglog proc to be able to select a directory
#
# Revision 1.44  2003/03/07 22:45:16  soliday
# Added backward compatiblity for tcl8.3
#
# Revision 1.43  2002/09/18 18:38:27  soliday
# Changed to work with tcl/tk 8.4.0
#
# Revision 1.42  2001/09/04 15:40:30  soliday
# Fixed font problem with APSCustomPrint call.
#
# Revision 1.41  2001/02/06 19:44:22  soliday
# Fixed some tcl warning messages found with procheck
#
# Revision 1.40  2000/11/07 22:56:22  soliday
# Changed the custom print procedure so that it uses bold font if the text
# box does.
#
# Revision 1.39  2000/07/18 20:30:38  borland
# Changes by D. Blachowicz: removed the use of short, general names for
# print procedures and global variables.
#
# Revision 1.38  2000/06/27 16:20:02  soliday
# Added catch statements around all the grab commands.
#
# Revision 1.37  2000/06/14 19:49:50  borland
# Now passes the printCommand from APSFileDisplayWindow to APSCustomPrint.
#
# Revision 1.36  2000/06/07 18:21:54  borland
# Improved print... feature for APSFileDisplayWindow.
#
# Revision 1.34  1999/11/17 03:42:02  emery
# Indented code.
#
# Revision 1.33  1998/11/18 22:10:59  soliday
# Replaced exec rm and exec cp commands with
# file delete and file copy commands.
#
# Revision 1.32  1998/06/09 22:08:16  borland
# Fixed bug that occurred when pressing ../ when at, e.g., /home level.
#
# Revision 1.31  1998/02/19 23:26:01  borland
# Fixed a number of grab/focus problems that prevented proper modal operation
# of FileDisplayWindow.
#
# Revision 1.30  1997/05/01 16:12:07  borland
# Changed spelling of procedure call to APSScrolledTextEMail.
#
# Revision 1.29  1997/05/01 15:08:54  borland
# APSFileDisplayWindow now has an "Email..." button.
#
# Revision 1.28  1997/04/23 15:32:04  borland
# APSFileDisplayWindow will now accept the name of an SDDS file that can
# be used for exporting data.
#
# Revision 1.27  1997/01/23 21:29:30  borland
# Updated help for APSFileDisplayWindow.
#
# Revision 1.26  1997/01/23 21:28:33  borland
# APSFileDisplayWindow now accepts -font and -printCommand options.
#
# Revision 1.25  1996/10/04 20:25:03  saunders
# Changed Enscript button to Print.
#
# Revision 1.24  1996/10/04 19:53:04  saunders
# Added "print", "save as..", and "email..." buttons to APSAlertBox.
# In doing so, I removed functionally duplicate procedures, and created
# generic APSPrint and APSSaveDialog. Also addes "save as.." to APSExecLog.
# Removed "Enscript" buttons, since "Print" is adequate.
#
# Revision 1.23  1996/09/22 21:21:38  borland
# Removed some text from merge.
#
# Revision 1.22  1996/09/22 17:32:18  borland
# Added -modal option to FileDisplayWindow.
#
# Revision 1.21  1996/09/18 14:28:15  saunders
# Added check for $apsFileSelect(validity) before doing "file exists"
# test after "glob" in FileSelectOK.
#
# Revision 1.20  1996/07/05 17:40:51  borland
# Added Export button to APSFileSelectDialog window; added
# -height option as well.
#
# Revision 1.19  1996/04/04  17:00:20  evans
# Changed apsFileSelect(dir) to apsFileSelect(path).
#
# Revision 1.17  1996/04/04  16:32:31  evans
# Replaced listDir with path and listFilter with pattern.
# Kept old options for historical compatibility.
#
# Revision 1.16  1996/04/03  01:23:56  evans
# Modified APSFileSelect Dialog to cancel any existing one instead of
# telling the user there was one already up to solve problem with user
# aborting with title bar.
#
# Revision 1.15  1996/03/25  23:51:04  evans
# Fixed missing " in APSFileSelectDialogHelp.
#
# Revision 1.14  1996/03/25  23:46:33  evans
# Modified APSFileSelectDialogHelp.
#
# Revision 1.13  1996/03/25  23:31:48  evans
# Added APSPathConfig.  Fixed APSFileSelectDialogHelp.
#
# Revision 1.12  1996/02/28  19:54:30  saunders
# Entirely new dialog submitted by Ken Evans. Much more Motif-like.
#
# Revision 1.11  1996/01/21  21:12:47  saunders
# Added -listFilter option to APSFileSelectDialog. Improved behavior
# of dialog when various patterns are entered in File: widget.
#
# Revision 1.10  1996/01/17  17:23:12  saunders
# Added width option and made default 80, not 40. Added Print and Enscript
# buttons.
#
# Revision 1.9  1996/01/16  21:20:02  saunders
# Added Log for CVS. Should have done this a long time ago.
#
#

proc APSFileSelectDialogHelp {} {
    return "\
Usage: APSFileSelectDialog widget
\[-parent <string>\]\t
\[-noPack 1\]\t
\[-packOption <list>\]\t
\[-name <string>\]\t
\[-width <string>\]\t
\[-checkValidity 0\]\t
\[-path <string>\] (path part of the filter)\t
\[-pattern <string> (pattern part of the filter)\]\t
\[-title <string>\]\t
\[-contextHelp <string\]\t
\[-selectDir 1\]
\[-reverseSort 1\]
"
}

proc APSFileSelectDialog {widget args} {
    global apsContextHelp apsttk
    global apsFileSelect
    set parent ""
    set width 50
    set checkValidity 1
    set noPack 0
    set packOption "-side top -fill x"
    set selectDir 0
    set reverseSort 0

    if {[info exists apsttk] && ($apsttk != 0)} {
        set ttk 1
    } else {
        set ttk 0
    }
    if {[info exists apsFileSelect(path)]} {
        set path $apsFileSelect(path)
    } else {
        set path ""
    }
    if {[info exists apsFileSelect(pattern)]} {
        set pattern $apsFileSelect(pattern)
    } else {
        set pattern "*"
    }
    set title "Select File:"
    set modal 0
    set contextHelp ""

    # Historical compatibility
    set listDir $path
    set listFilter $pattern
    set path0 $path
    set pattern0 $pattern
    set labelname ""
    APSStrictParseArguments {parent width checkValidity noPack packOption \
                               path pattern title contextHelp \
                               listDir listFilter modal selectDir \
                               reverseSort labelname}
    set sortOrder -increasing
    if $reverseSort {
        set sortOrder -decreasing
    }
    if $selectDir {
        set title "Select Directory:"
    }

    # Historical compatibility
    if {![string compare $path $path0]} {
        if {[string compare $listDir $path0]} {
            set path $listDir
        }
    }
    if {![string compare $pattern $pattern0]} {
        if {[string compare $listFilter $pattern0]} {
            set pattern $listFilter
        }
    }
    
    # Check if there is an APSFileSelectDialog up
    if {[info exists apsFileSelect]} {
        if {!$apsFileSelect(done)} {
            # Cause it to cancel
            APSFileSelectDialogCancel
        }
    }

    # Set context help
    if {$contextHelp != ""} {
        set apsContextHelp($parent$widget) $contextHelp
    }

    # Set validity check
    set apsFileSelect(validity) $checkValidity
    set apsFileSelect(selectDir) $selectDir
    APSDialogBox $widget -parent $parent -name "$title" \
      -noPack $noPack -packOption $packOption -contextHelp $contextHelp
    set userFrame $parent$widget.userFrame

    # Create a read-only entry for the current directory
    #     APSLabeledOutput .dir -parent $userFrame -label Path: \
      #       -textVariable apsFileSelect(path) -width $width -contextHelp \
      #       "This displays the currently selected directory."
    #     set apsFileSelect(dirEnt) $userFrame.dir.entry

    # Create an entry for the filter. Value kept in apsFileSelect(filter).
    APSLabeledEntry .filter -parent $userFrame -label Filter: \
      -textVariable apsFileSelect(filter) -width $width -contextHelp \
      "The files that appear under Files will be those that match this\
       filter.  Typically the filter should contain wildcards.  Enter\
       the desired filter or build it by clicking in the Directories\
       list.  <Return> or the clicking Filter button will generate new\
       Directories and Files lists using the filter."
    eval pack $userFrame.filter.entry [pack info $userFrame.filter.entry] -expand 1 -fill x

    # Create a frame to hold the listboxes
    APSFrame .listFrame -parent $userFrame -relief flat \
      -packOption "-side top -fill both -expand 1"
    set w $userFrame.listFrame.frame
    eval pack $w [pack info $w] -expand 1 -fill both

    # Create a listbox to hold the directories
    APSFrame .dirlistFrame -parent $w -label Directories \
      -packOption "-side left -fill both -expand 1"
    set w1 $w.dirlistFrame.frame
    # Repack to expand
    eval pack $w1 [pack info $w1] -expand 1 -fill both

    APSScrolledList .dirList -parent $w1 -xscroll 1 \
      -contextHelp \
      "A click on a directory will add it to the\
       filter.  A double click will add it to the filter and then\
       process the filter.  If the focus is in the Directories\
       listbox then <Space> is the same as a click, and <Return>\
       is the same as a double click."
    set dirlb $w1.dirList.listbox

    # Create a listbox to hold the filenames (or directory names)
    if ![string length $labelname] {
        if !$apsFileSelect(selectDir) {
            set labelname Files
        } else {
            set labelname SubDirectories
        }
    }
    APSFrame .filelistFrame -parent $w -label $labelname \
      -packOption "-side left -fill both -expand 1"
    set w1 $w.filelistFrame.frame
    # Repack to expand
    eval pack $w1 [pack info $w1] -expand 1 -fill both

    APSScrolledList .fileList -parent $w1 \
      -contextHelp \
      "A click on a file will add it to the selection.  A\
       double click will add it to the selection and process\
       the selection.  If the focus is in the Files listbox then\
       <Space> is the same as a click, and <Return> is the same as\
       a double click."
    set filelb $w1.fileList.listbox

    # Create an entry for the selection. Value kept in apsFileSelect(selection).
    APSLabeledEntry .select -parent $userFrame -label Selection: \
      -textVariable apsFileSelect(select) -width $width -contextHelp \
      "Your selection appears here.  You may edit it or build it by\
       clicking in the Directories or Files lists.  A <Return> will\
       process the  selection.  Use the <Esc> key for filename\
       completion.  (The selection may contain wildcards when used for\
       filename completion.)  All possible completions will be displayed."
    eval pack $userFrame.select.entry [pack info $userFrame.select.entry] -expand 1 -fill x

    # Add filter button
    if {$ttk} {
        APSButton .filter -parent $parent$widget.buttonRow -text Filter -width "" \
          -packOption "-after $parent$widget.buttonRow.ok\
        -side left -pady 1" \
          -command "APSFileSelectDialogFilter $dirlb $filelb" -contextHelp \
          "Generate new Directories and Files lists using the filter."
    } else {
        APSButton .filter -parent $parent$widget.buttonRow -text Filter -width "" \
          -packOption "-after $parent$widget.buttonRow.ok\
        -side left -padx 1 -pady 1" \
          -command "APSFileSelectDialogFilter $dirlb $filelb" -contextHelp \
          "Generate new Directories and Files lists using the filter."
    }
    # Configure the OK and Cancel buttons
    $parent$widget.buttonRow.ok.button configure \
      -command "APSFileSelectDialogOK $dirlb $filelb"
    APSEnableButton $parent$widget.buttonRow.ok.button
    $parent$widget.buttonRow.cancel.button configure \
      -command APSFileSelectDialogCancel
    
    APSFileSelectDialogBindings \
      $userFrame.filter.entry $dirlb $filelb $userFrame.select.entry

    # Initialize variables and list the directory
    set apsFileSelect(sortOrder) $sortOrder
    if {[string length $path] == 0} {
        set apsFileSelect(pattern) $pattern
        set dir [pwd]
        set apsFileSelect(filter) "$dir/$pattern"
        set apsFileSelect(select) "$dir/"
    } else {
        set apsFileSelect(pattern) $pattern
        set dir $path
        if {[string compare $dir "/"]} {
            # Not top of tree
            set apsFileSelect(filter) "$dir/$pattern"
            set apsFileSelect(select) "$dir/"
        } else {
            set apsFileSelect(filter) "/$pattern"
            set apsFileSelect(select) "/"
        }
    }
    set apsFileSelect(path) {}
    set apsFileSelect(done) 0

    # Wait for the listbox to be visible
    tkwait visibility $dirlb
    tkwait visibility $filelb
    APSFileSelectDialogList $dirlb $filelb $dir

    if {$modal} {
        set grabList [grab current $parent$widget]
        focus $parent$widget
        catch {grab set $parent$widget}
    }
    tkwait variable apsFileSelect(done)
    if {$modal} {
        catch {grab set $grabList}
    }

    if {[winfo exists $parent$widget]} {
        destroy $parent$widget
    } else {
        APSFileSelectDialogCancel
    }
    
    if {[llength [string trim $apsFileSelect(select)]] == 1} {
        if {[catch {APSAddToRecentFileList -filename $apsFileSelect(select)} results]} {
            APSAlertBox [APSUniqueName .uniqueNameError] -errorMessage "APSFileSelectDialog: $results"
        }
    }
    return $apsFileSelect(select)
}

proc APSFileSelectDialogBindings { f dirlb filelb s } {
    global apsFileSelect
    
    # Filter bindings
    bind $f <Return> "APSFileSelectDialogFilter $dirlb $filelb"

    # Directory Listbox bindings
    bind $dirlb <space> "APSFileSelectDialogTake dir $dirlb $filelb"
    bind $dirlb <Button-1> "APSFileSelectDialogClick dir $dirlb $filelb %y"
    bind $dirlb <Return> \
      "APSFileSelectDialogTake dir $dirlb $filelb;\
       APSFileSelectDialogFilter $dirlb $filelb"
    bind $dirlb <Double-Button-1> \
      "APSFileSelectDialogDoubleClick dir $dirlb $filelb %y"

    # File Listbox bindings
    bind $filelb <space> "APSFileSelectDialogTake file $dirlb $filelb"
    bind $filelb <Button-1> "APSFileSelectDialogClick file $dirlb $filelb %y"
    bind $filelb <Return> \
      "APSFileSelectDialogTake file $dirlb $filelb;\
      APSFileSelectDialogOK $dirlb $filelb"
    bind $filelb <Double-Button-1> \
      "APSFileSelectDialogDoubleClick file $dirlb $filelb %y"

    # Selection bindings
    bind $s <Return> "APSFileSelectDialogOK $dirlb $filelb"
    bind $s <KeyPress-Escape> "APSFileSelectDialogComplete $dirlb $filelb"

    focus $s
}

proc APSFileSelectDialogFilter { dirlb filelb } {
    global apsFileSelect
    # If the filter is a directory, add *
    if {[file isdirectory $apsFileSelect(filter)]} {
        if {[regexp {/$} $apsFileSelect(filter)]} {
            set apsFileSelect(filter) "$apsFileSelect(filter)*"
        } else {
            set apsFileSelect(filter) "$apsFileSelect(filter)/*"
        }
    }
    # Separate out a path if given and use it for the path
    set pattern [file tail $apsFileSelect(filter)]
    set dirname [file dirname $apsFileSelect(filter)]
    set pwd [pwd]
    set pwdparent [file dirname $pwd]
    # Trim ../ (the parent) out of the pathname
    if {[regsub {^\.\.} $dirname $pwdparent newpath] != 0} {
        set dirname $newpath
    }
    # Trim ./ (the cwd) out of the pathname
    if {[regsub {^\.} $dirname $pwd newpath] != 0} {
        set dirname $newpath
    }
    # If the pattern is blank, make it be *
    if {![string compare $pattern ""]} {
        set pattern *
    }
    if {[string compare $dirname "/"]} {
        # Not top of tree
        set apsFileSelect(path) $dirname
        set apsFileSelect(pattern) $pattern
        set apsFileSelect(filter) $dirname/$pattern
        set apsFileSelect(select) $dirname/
    } else {
        set apsFileSelect(path) /
        set apsFileSelect(pattern) $pattern
        set apsFileSelect(filter) /$pattern
        set apsFileSelect(select) /
    }

    APSFileSelectDialogList $dirlb $filelb $apsFileSelect(path)
}

proc APSFileSelectDialogList { dirlb filelb dir {files {}} } {
    global apsFileSelect

    set apsFileSelect(path) $dir

    # Directory
    $dirlb delete 0 end
    $filelb delete 0 end
    # Check for bogus names
    if {![file isdirectory $dir]} {
        $dirlb insert 0 "Bad Directory"
        return
    }
    # Give the user some feedback
    $dirlb insert 0 Listing...
    $filelb insert 0 Listing...
    update idletasks
    # Find files
    set dirfiles [glob -nocomplain "$dir/*"]
    $dirlb delete 0
    $dirlb insert end ./
    $dirlb insert end ../
    # Sort out the directories
    foreach f [lsort $apsFileSelect(sortOrder) $dirfiles] {
        if {[file isdirectory $f]} {
            $dirlb insert end [file tail $f]/
        }
    }
    
    # File
    # Find files
    if {[string length $files] == 0} {
        set files [glob -nocomplain $apsFileSelect(filter)]
    }
    $filelb delete 0
    # Sort out the files
    foreach f [lsort $apsFileSelect(sortOrder) $files] {
        if  !$apsFileSelect(selectDir) {
            if {[file isfile $f]} {
                $filelb insert end [file tail $f]
            }
        } else {
            if {[file isdirectory $f]} {
                $filelb insert end [file tail $f]
            }
        }
    }
}

proc APSFileSelectDialogOK { dirlb filelb} {
    global apsFileSelect

    set pwd [pwd]
    if {[string compare $pwd "/"]} {
        # Not the top level
        set pwdparent "[file dirname $pwd]/"
        set pwd "$pwd/"
    } else {
        set pwdparent /
    }
    # Trim ./ (the cwd) out of the pathname
    if {[regsub {^\./} $apsFileSelect(select) $pwd newpath] != 0} {
        set apsFileSelect(select) $newpath
        set apsFileSelect(path) [file dirname $newpath]
    }
    # Trim ../ (the parent) out of the pathname
    if {[regsub {^\.\./} $apsFileSelect(select) $pwdparent newpath] != 0} {
        set apsFileSelect(select) $newpath
        set apsFileSelect(path) [file dirname $newpath]
    }
    
    if !$apsFileSelect(selectDir) {
	# Check that it is not a directory
	if {[file isdirectory $apsFileSelect(select)]} {
	    APSAlertBox .alert -errorMessage \
		"You have choosen a directory, not a file.  Will use this\
           directory to refilter."
	    set apsFileSelect(filter) \
		[string trimright $apsFileSelect(select) /]/$apsFileSelect(pattern)
	    APSFileSelectDialogFilter $dirlb $filelb
	    return
	}
    }
    # Glob the result
    set globsel [glob -nocomplain $apsFileSelect(select)]
    if {[llength $globsel] > 1} {
	APSAlertBox .alert -errorMessage \
	    "Selection is not unique.  Will do filename completion."
	APSFileSelectDialogComplete $dirlb $filelb
	return
	} elseif {[llength $globsel] < 1} {
	    if {$apsFileSelect(validity) && ![file exists $apsFileSelect(select)]} {
		APSAlertBox .alert -errorMessage \
		    "Selection is not a valid file."
		return
	    }
	} else {
	    set apsFileSelect(select) [lindex $globsel 0]
	}
    # Check validity
    if {$apsFileSelect(validity) } {
	if {![file exists $apsFileSelect(select)]} {
	    APSAlertBox .alert -errorMessage \
		"Selection is not a valid file."
	    return
	}
    }
    # Selection is acceptable, finish up
    # All done
    set apsFileSelect(done) 1
    return
}

proc APSFileSelectDialogCancel {} {
    global apsFileSelect
    set apsFileSelect(done) 1
    set apsFileSelect(select) {}
}

proc APSFileSelectDialogDoubleClick { mode dirlb filelb y } {
    switch -exact $mode {
        dir {
            set result [$dirlb get [$dirlb nearest $y]]
            APSFileSelectDialogClick $mode $dirlb $filelb $y
            APSFileSelectDialogFilter $dirlb $filelb
        }
        file {
            set result [$filelb get [$filelb nearest $y]]
            APSFileSelectDialogClick $mode $dirlb $filelb $y
            APSFileSelectDialogOK $dirlb $filelb
        }
    }
    global apsFileSelect
}

proc APSFileSelectDialogClick { mode dirlb filelb y } {
    # Take the item the user clicked on
    global apsFileSelect
    
    switch -exact $mode {
        dir {
            set result [$dirlb get [$dirlb nearest $y]]
            if {![string compare $result "./"]} {
                # Is the current directory
                set apsFileSelect(filter)  \
                  $apsFileSelect(path)/$apsFileSelect(pattern)
            } elseif {![string compare $result "../"]} {
                # Is the parent directory
                set dirname [file dirname $apsFileSelect(path)]
                if {[string compare $dirname "/"]} {
                    # Not top of tree
                    set apsFileSelect(filter) \
                      $dirname/$apsFileSelect(pattern)
                } else {
                    set apsFileSelect(filter) /$apsFileSelect(pattern)
                }
            } elseif {[regexp {/$} $result]} {
                # Is a subdirectory
                set dirname [file dirname $apsFileSelect(path)]
                if {[string compare $dirname "/"]} {
                    # Not top of tree
                    set apsFileSelect(filter) \
                      $apsFileSelect(path)/$result$apsFileSelect(pattern)
                } else {
                    set path /$result
                    if {![file exists $result]} {
                        set path $apsFileSelect(path)/$result
                    }
                    set apsFileSelect(filter) $path$apsFileSelect(pattern)
                }
            }
        }
        file {
            set result [$filelb get [$filelb nearest $y]]
            set dirname $apsFileSelect(path)
            if {[string compare $dirname "/"]} {
                # Not top of tree
                set apsFileSelect(select) $apsFileSelect(path)/$result
            } else {
                set apsFileSelect(select) /$result
            }
        }
    }
}

proc APSFileSelectDialogTake { mode dirlb filelb } {
    # Take the currently selected list item
    global apsFileSelect
    
    switch -exact $mode {
        dir {
            set result [$dirlb get [$dirlb curselection]]
            if {![string compare $result "./"]} {     
                # Is the current directory
                set apsFileSelect(filter) \
                  $apsFileSelect(path)/$apsFileSelect(pattern)
            } elseif {![string compare $result "../"]} {     
                # Is the parent directory
                set dirname [file dirname $apsFileSelect(path)]
                if {[string compare $dirname "/"]} {     
                    # Not top of tree
                    set apsFileSelect(filter) $dirname/$apsFileSelect(pattern)
                } else {
                    set apsFileSelect(filter) /$apsFileSelect(pattern)
                }
            } elseif {[regexp {/$} $result]} {     
                # Is a subdirectory
                set dirname [file dirname $apsFileSelect(path)]
                if {[string compare $dirname "/"]} {
                    # Not top of tree
                    set apsFileSelect(filter) \
                      $apsFileSelect(path)/$result$apsFileSelect(pattern)
                } else {
                    set apsFileSelect(filter) /$result$apsFileSelect(pattern)
                }
            }
        }
        file {
            set result [$filelb get [$filelb curselection]]
            set dirname $apsFileSelect(path)
            if {[string compare $dirname "/"]} {
                # Not top of tree
                set apsFileSelect(select) $apsFileSelect(path)/$result
            } else {
                set apsFileSelect(select) /$result
            }
        }
    }
}

proc APSFileSelectDialogComplete { dirlb filelb } {
    # Do file name completion
    global apsFileSelect
    
    # See what files are there
    set globlist [glob -nocomplain $apsFileSelect(select)*]
    if {[llength $globlist] == 0} {
        # No match
        $filelb delete 0 end
        return
    }
    if {[llength $globlist] == 1} {
        # Matched a single file
        set apsFileSelect(select) $globlist
    }
    set dir [file dirname $apsFileSelect(select)]
    APSFileSelectDialogList $dirlb $filelb $dir $globlist
}

proc APSFileDisplayWindowHelp {} {
    return "Usage: APSFileDisplayWindow widget \n\[-parent <string>\]\t\n\[-noPack 1\]\t\n\[-packOption <list>\]\t\n\[-comment <string>\]\t\n\[-fileName <string>\]\t\n\[-deleteOnClose 1\]\t\n\[-width <string>\]\t\n\[-contextHelp <string\]\t\n\[-modal 1\]\t\n\[-printCommand <string>\]\t\n\[-font <string>\]\t\n\[-autoWidth 1\]\t\n\[-autoWidthLimit <integer>\]\t\n\nCreates\t\$parent\$widget.\n\tuserFrame\n\tuserFrame.file.text\n\tbuttonRow.close.button\n"
}

proc APSFileDisplayWindow {widget args} {
    global apsContextHelp apsttk
    set parent ""
    set noPack 0
    set packOption "-side top"
    set comment ""
    set fileName ""
    set file ""
    set deleteOnClose 0
    set width 80
    set contextHelp ""
    set height 15
    set modal 0
    set printCommand "enscript"
    set font ""
    set sddsExportableFile ""
    set defaultButtons 1
    set closeButton 1
    set okButton 0
    set cancelButton 0
    set okCommand ""
    set cancelCommand ""
    set autoWidth 0
    set autoWidthLimit 150
    APSStrictParseArguments {parent comment noPack packOption fileName file font \
                               deleteOnClose width contextHelp height modal \
                               printCommand sddsExportableFile \
                               defaultButtons closeButton \
                               okButton cancelButton okCommand cancelCommand autoWidth autoWidthLimit}

    if {[llength $file]} {
        set fileName $file
    }
    if {[info exists apsttk] && ($apsttk != 0)} {
        set ttkPrefix ttk::
    } else {
        set ttkPrefix ""
    }
    if {$contextHelp != ""} {
        set apsContextHelp($parent$widget) $contextHelp
    }

    set name "Display File: $comment ($fileName)"
    APSWindow $widget -parent $parent -name $name -closeButton $closeButton
    
    APSScrolledText .file -parent $parent$widget.userFrame -width $width \
      -height $height -font $font
    set text $parent$widget.userFrame.file.text
    
    if $okButton {
        APSDialogBoxAddButton .ok -parent $parent$widget -text Ok \
          -command "$okCommand" 
    }
    if $cancelButton {
        APSDialogBoxAddButton .cancel -parent $parent$widget -text Cancel \
          -command "$cancelCommand"
    }
    if $defaultButtons {
        APSDialogBoxAddButton .print -parent $parent$widget -text Print \
          -command "APSPrint -cmd \"$printCommand\" -textWidget $text" \
          -contextHelp "Print contents of window using enscript command."
        
        APSDialogBoxAddButton .printC -parent $parent$widget -text "Print..." \
          -command "APSCustomPrint -fileName $fileName -modal $modal -widget $parent$widget -printCommand \"$printCommand\" -font \"$font\"" \
          -contextHelp "Print contents of window using enscript or lp command."
        
        APSDialogBoxAddButton .tofile -parent $parent$widget -text "Export text..." \
          -command "APSFileDisplayExport $fileName" \
          -contextHelp "Export contents of window to a file."
        
        APSDialogBoxAddButton .tomail -parent $parent$widget -text "Email..." \
          -command "APSScrolledTextEMail -width $width -textWidget $text -modal 1" \
          -contextHelp "Send the contents of window as an email message."
    }
   
    if {[string length $sddsExportableFile]} {
        set apsFileDisplaySDDSCommandList [list "sddsExportData -dataFileList $sddsExportableFile" "sddsedit $sddsExportableFile" "quickSDDSplot -dataFileList $sddsExportableFile" "quickSDDSFit -filename $sddsExportableFile" "quickSDDSDSP -filename $sddsExportableFile" "quickSDDSStatistics -filename $sddsExportableFile" "xemacs $sddsExportableFile" "dtpad $sddsExportableFile" "sddsquery $sddsExportableFile" "sdds2stream -rows $sddsExportableFile"]
        set useExecLog "0 0 0 0 0 0 0 0 1 1"

        set parentWidget $parent$widget.tosddsfile
        menubutton $parent$widget.buttonRow.sddscommand -indicatoron 0 \
          -text "SDDS Command..." \
          -menu $parent$widget.buttonRow.sddscommand.menu \
          -state normal \
          -takefocus 1 \
          -highlightthickness 1 \
          -relief raised \
          -borderwidth 1
        menu $parent$widget.buttonRow.sddscommand.menu -tearoff 0
        pack $parent${widget}.buttonRow.sddscommand -side left
        $parent${widget}.buttonRow.sddscommand.menu insert 1 separator
        foreach program $apsFileDisplaySDDSCommandList useEL $useExecLog {
            if {$useEL} {
                $parent${widget}.buttonRow.sddscommand.menu insert end command \
                  -label "$program"  \
                  -command "APSExecLog .commandButtonExecLog -width 100 -unixCommand \"$program\""
            } else {
                $parent${widget}.buttonRow.sddscommand.menu insert end command \
                  -label "$program"  \
                  -command "exec $program"
            }
        }
        set apsContextHelp($parent$widget.buttonRow.sddscommand) "Bring up a list of execution commands for processing [file tail $sddsExportableFile] file, such as\n\nExport SDDS data ...\nsddsedit...\nquickSDDSplot ...\n..."
    }

    set f [open $fileName r]
    while {![eof $f]} {
        $text insert end [read $f 1000]
    }
    close $f
    if {$autoWidth} {
        set maxlength 0
        foreach line [split [$text get 1.0 end] \n] {
            if {$maxlength < [string length $line]} {
                set maxlength [string length $line]
            }
        }
        if {$maxlength > $autoWidthLimit} {
            set maxlength $autoWidthLimit
        }
        $text configure -width $maxlength
    }

    if {$modal} {
        set grabList [grab current $parent$widget]
        focus $parent$widget
        catch {grab set $parent$widget}
        tkwait window $parent$widget
        catch {grab set $grabList}
        if {$deleteOnClose && $closeButton} {
            catch {file delete -- $fileName}
            if {[winfo exists $parent$widget]} {
                destroy $parent$widget
            }
        }
    } else {
        # Add file deletion to close button callback
        if {$deleteOnClose && $closeButton} {
            set cmd {
                catch {file delete -- $fileName}
                destroy $parent$widget
            }
            $parent$widget.buttonRow.close.button configure -command \
              [subst $cmd]
        } 
    }
}

proc APSCustomPrint {args} {
     set fileName ""
     set modal 0
     set widget ""
     set printCommand lpr
     set font ""
     APSStrictParseArguments {fileName modal widget printCommand font}

     global env apsCustomPrintMode apsCustomPrintCommandMode apsCustomPrintPage
     global apsCustomPrintPrinterName apsCustomPrintManualCommand 
     global apsCustomPrintFirstPage apsCustomPrintLastPage
     set apsCustomPrintManualCommand $printCommand

    if {[winfo exists .printBox]} {
         destroy .printBox
     }
    if {[info exists env(PRINTER)]} {
         set apsCustomPrintPrinterName $env(PRINTER)
     }
    if {$modal} {
         set grabList [grab current $widget]
     }
     set okCommand "APSProceedPrinting -fileName $fileName -font \"$font\"; "
     APSDialogBox .printBox -name "Print Setup" -width 50 \
        -okCommand $okCommand -contextHelp ""
     pack [frame .printBox.userFrame.top -relief groove] -side top -expand yes
     pack [frame .printBox.userFrame.frame1 -relief groove] -side top -expand yes
     set w1 .printBox.userFrame.frame1 
     set apsCustomPrintCommandMode 0
     APSRadioButtonFrame .commandMode -parent .printBox.userFrame.top \
        -label "Command:   " -commandList {"APSCustomPrintDisableCommand 1" "APSCustomPrintDisableCommand 0"}\
        -variable apsCustomPrintCommandMode -buttonList {"Default      " "Manual      "} -valueList {0 1} \
	-orientation horizontal -contextHelp ""

#     pack [label $w1.lab1 -text "Default:" -font {courier 12 bold underline}] -fill both -expand false
     APSLabeledEntry .printerName -parent $w1 -textVariable apsCustomPrintPrinterName \
        -width 30 -label "Printer Name: " -contextHelp ""
     pack forget $w1.printerName.entry
     pack $w1.printerName.entry -side left -fill x -expand yes
     set apsCustomPrintMode -r
     APSRadioButtonFrame .printMode -parent $w1 -label "Print Mode:   " \
        -variable apsCustomPrintMode -buttonList {Landscape Portrait} -valueList {-r -R} \
	-orientation horizontal -contextHelp "" 
     set apsCustomPrintPage 0
     APSRadioButtonFrame .printPage -parent $w1 -label "Print Page:   " \
        -variable apsCustomPrintPage -buttonList {All Select} -valueList {0 1} \
	-commandList {"APSCustomPrintDisablePageInput 0" "APSCustomPrintDisablePageInput 1"} \
	-orientation horizontal -contextHelp ""

     pack [frame $w1.select2 -relief ridge] -side top -expand no
     pack [label $w1.select2.select1 -text "Print Page Selection:" \
		    -font {courier 12 bold}] -fill both -expand false
     set w2 $w1.select2
     set apsCustomPrintFirstPage 1
     set apsCustomPrintLastPage 1
     APSLabeledEntry .firstPage -parent $w2 -textVariable apsCustomPrintFirstPage \
        -width 15 -label "From : " -packOption "-side left" -contextHelp ""
     APSLabeledEntry .lastPage -parent $w2 -textVariable apsCustomPrintLastPage \
        -width 15 -label "  To : " -packOption "-side right" -contextHelp ""

#     pack [label .printBox.userFrame.lab2 -text "Manual:" -font {courier 12 bold underline}] -fill both -expand false

     APSLabeledEntry .manual -parent .printBox.userFrame -textVariable apsCustomPrintManualCommand \
        -width 60 -label "Manual command: " -contextHelp ""

     APSCustomPrintDisableCommand 1
     APSCustomPrintDisablePageInput 0

    if {$modal} {
         catch {tkwait visibility .printBox}
	 grab release $widget
         focus .printBox
         catch {grab set .printBox}
         set cmdOK {
            APSProceedPrinting -fileName $fileName -font \"$font\"
	    grab release .printBox
	    focus $grabList
            catch {grab set $grabList}
            destroy .printBox
         }
         set cmdCancel {
	    grab release .printBox
	    focus $grabList
            catch {grab set $grabList}
            destroy .printBox
         }
         .printBox.buttonRow.ok.button configure -command \
              [subst $cmdOK]
         .printBox.buttonRow.cancel.button configure -command \
              [subst $cmdCancel]
     }
}

proc APSCustomPrintDisableCommand {mode} {
     global apsCustomPrintPage
    if {!$mode} {
#        .printBox.userFrame.frame1.printerName.entry configure -bg grey -state disable
#        .printBox.userFrame.manual.entry configure -bg white -state normal
        if {$apsCustomPrintPage} {
            APSCustomPrintDisablePageInput 0
        }
	 pack forget .printBox.userFrame.frame1
	 pack .printBox.userFrame.manual -side top -expand yes
     } else {
#        .printBox.userFrame.frame1.printerName.entry configure -bg white -state normal
#        .printBox.userFrame.manual.entry configure -bg grey -state disable
	 if {$apsCustomPrintPage} {
            APSCustomPrintDisablePageInput 1
        }
	 pack forget .printBox.userFrame.manual
	 pack .printBox.userFrame.frame1 -side top -expand yes
     }
}

proc APSCustomPrintDisablePageInput {mode} {
    global apsCustomPrintCommandMode
    if {!$mode} {
	global tcl_version
	if {[string range $tcl_version 0 2] <= 8.3} {
	    .printBox.userFrame.frame1.select2.firstPage.entry configure \
		-background grey -state disabled
	    .printBox.userFrame.frame1.select2.lastPage.entry configure \
		-background grey -state disabled
	} else {
	    .printBox.userFrame.frame1.select2.firstPage.entry configure \
		-background grey -state readonly
	    .printBox.userFrame.frame1.select2.lastPage.entry configure \
		-background grey -state readonly
	}
     } else {
	 if {!$apsCustomPrintCommandMode} {
            .printBox.userFrame.frame1.select2.firstPage.entry configure \
				       -background white -state normal
            .printBox.userFrame.frame1.select2.lastPage.entry configure \
				       -background white -state normal
        }
     }
}

proc APSProceedPrinting {args} {
     set fileName ""
     set font ""
     APSStrictParseArguments {fileName font}

     global apsCustomPrintMode apsCustomPrintCommandMode apsCustomPrintPage
     global apsCustomPrintPrinterName apsCustomPrintManualCommand 
     global apsCustomPrintFirstPage apsCustomPrintLastPage
    
    if {$apsCustomPrintPage} {
        if {[string length $apsCustomPrintFirstPage] && [string length $apsCustomPrintLastPage]} {
            set begin $apsCustomPrintFirstPage
	    set end $apsCustomPrintLastPage
        } else {
            APSAlertBox [APSUniqueName .uniqueNameError] -errorMessage "Print Pages are not selected." 
        }            
     } else {
        set begin 0
	set end ""
     } 

    if {[string first bold $font] != -1} {
	set font -fCourier-Bold9
    } else {
	set font ""
    }

    if {[file exists $fileName]} {
	if {!$apsCustomPrintCommandMode} {
	    set header [list |%W|Page $% of $=]
	    if {[catch {eval exec enscript $font -P${apsCustomPrintPrinterName} {"--header=$header"} \
			$apsCustomPrintMode -a ${begin}-${end} $fileName} result]} {
                APSAlertBox [APSUniqueName .uniqueNameError] -errorMessage "$result"
	    }
	 } else {
	     if {[string length $apsCustomPrintManualCommand]} {
		if {[catch {eval exec $apsCustomPrintManualCommand $fileName} result]} {
                    APSAlertBox [APSUniqueName .uniqueNameError] -errorMessage "$result"
		}
	    } else {
                APSAlertBox [APSUniqueName .uniqueNameError] -errorMessage "No manual command."
            }
         }
     } else {
         APSAlertBox [APSUniqueName .uniqueNameError] -errorMessage "Printout file does not exists."
     }
}

proc APSFileDisplayExport {input} {
    global apsInfoDialogChoice
    set filename ""

    while 1 {
        set filename [APSInfoDialog [APSUniqueName .] -name "File export dialog" \
                        -width 80 -infoMessage \
                        "Enter the file name to export the text to:" ]
        if {[string compare $apsInfoDialogChoice CANCEL]==0} {
            return
        }
        if {[string length $filename]==0} {
            APSAlertBox [APSUniqueName .] -errorMessage \
              "Enter a valid filename"
            continue
        }
        if {[string length $filename] && [file exists $filename]} {
            catch {APSMultipleChoice [APSUniqueName .] -question \
                     "File $filename exists.  What do you want to do?" \
                     -labelList {Overwrite Cancel "Choose again"} \
                     -returnList {Overwrite Cancel Choose}} choice
            if {[string compare $choice Cancel]==0} { return }
            if {[string compare $choice Choose]==0} {
                continue
            }
            if {[string compare $choice Overwrite]==0} { 
                if {[catch {file delete -- $filename} result]} {
                    APSAlertBox [APSUniqueName .] -errorMessage \
                      "Can't delete $filename:\n$result\nChoose another file." 
                }
            }
        }
        if {[catch {file copy -force -- $input $filename} result]} {
            APSAlertBox [APSUniqueName .] -errorMessage \
              "Can't copy to $filename:\n$result\nChoose another file."
        } else {
            return
        }
    }
}

proc APSRecentFileSelectDialogHelp {} {
    return "\
Usage: APSRecentFileSelectDialogHelp widget
\[-parent <string>\]\t
\[-packOption <list>\]\t
\[-width <string>\]\t
\[-title <string>\]\t
\[-contextHelp <string\]
"
}

proc APSRecentFileSelectDialog {widget args} {
    global apsContextHelp
    global apsRecentFileSelect

    set parent ""
    set contextHelp ""
    set title "Select Recent File:"
    set width 50
    set packOption "-side top -fill x"
    APSStrictParseArguments {parent contextHelp title width packOption}

    if {$contextHelp != ""} {
        set apsContextHelp($parent$widget) $contextHelp
    }
    APSDialogBox $widget \
      -parent $parent \
      -name "$title" \
      -packOption $packOption \
      -contextHelp $contextHelp \
      -okCommand {set apsFileSelect(done) 1}
    set userFrame $parent$widget.userFrame

    set recentfiles [APSGetRecentFileList]

    APSScrolledList .recentList \
      -parent $userFrame \
      -width $width \
      -itemList $recentfiles \
      -selectMode single \
      -contextHelp "A click on a file to select it."

    $parent$widget.buttonRow.ok.button configure \
      -command {set apsRecentFileSelect(done) 1}
    $parent$widget.buttonRow.cancel.button configure \
      -command {set apsRecentFileSelect(done) 2}

    tkwait variable apsRecentFileSelect(done)
    
    if {$apsRecentFileSelect(done) == 1} {
        set curselection [$userFrame.recentList.listbox curselection]
        if {[llength $curselection] == 1} {
            set filename [$userFrame.recentList.listbox get $curselection]
            if {[catch {APSAddToRecentFileList -filename $filename} results]} {
                APSAlertBox [APSUniqueName .uniqueNameError] -errorMessage "APSRecentFileSelectDialog: $results"
            }
        } else {
            set filename ""
        }
    } else {
        set filename ""
    }
    destroy $parent$widget
    return $filename
}

proc APSAddToRecentFileListHelp {} {
    return "\
Usage: APSAddToRecentFileList
\[-filename <string>\]\t
\[-limit <integer>\]\t

Add filenames to the list of
recently selected files.
"
}

proc APSAddToRecentFileList {args} {
    set filename ""
    set limit 20
    APSStrictParseArguments {filename limit}

    global env
    set filename [string trim $filename]
    if {[llength $filename] != 1} {
        return -code error "APSAddToRecentFileList: invalid filename passed"
    }
    if [string compare [file dirname $filename] .]==0 {
        set filename [file join [pwd] $filename]
    }
    if {![info exists env(HOME)]} {
        return -code error "APSAddToRecentFileList: environment variable HOME is not defined"
    }
    if {[file exists ${env(HOME)}/.oagrecentfiles]} {
        if {[catch {exec sdds2stream ${env(HOME)}/.oagrecentfiles -column=RecentFile} recentfiles]} {
            file delete -force ${env(HOME)}/.oagrecentfiles
            return
        } else {
            set i [lsearch -exact $recentfiles $filename]
            if {$i != -1} {
                set recentfiles [lreplace $recentfiles $i $i]
            }
            incr limit -1
            set recentfiles [join [lrange [linsert $recentfiles 0 $filename] 0 $limit] ","]
            if {[catch {exec sddsmakedataset ${env(HOME)}/.oagrecentfiles -column=RecentFile,type=string -data=$recentfiles -noWarnings -ascii} results]} {
                return -code error "APSAddToRecentFileList: $results"
            }
        }
    } else {
        if {[catch {exec sddsmakedataset ${env(HOME)}/.oagrecentfiles -column=RecentFile,type=string -data=$filename -noWarnings -ascii} results]} {
            return -code error "APSAddToRecentFileList: $results"
        }
    }
}

proc APSGetRecentFileListHelp {} {
    return "\
Usage: APSGetRecentFileList

Returns a list of recently
selected files.
"
}

proc APSGetRecentFileList {args} {
    global env
    if {[info exists env(HOME)]} {
        if {[file exists ${env(HOME)}/.oagrecentfiles]} {
            if {[catch {exec sdds2stream ${env(HOME)}/.oagrecentfiles -column=RecentFile} recentfiles]} {
                file delete -force ${env(HOME)}/.oagrecentfiles
                set recentfiles ""
            }
        } else {
            set recentfiles ""
        }
        return [join $recentfiles]
    }
    return ""
}
