1########################################################################
2##
3## Copyright (C) 2010-2021 The Octave Project Developers
4##
5## See the file COPYRIGHT.md in the top-level directory of this
6## distribution or <https://octave.org/copyright/>.
7##
8## This file is part of Octave.
9##
10## Octave is free software: you can redistribute it and/or modify it
11## under the terms of the GNU General Public License as published by
12## the Free Software Foundation, either version 3 of the License, or
13## (at your option) any later version.
14##
15## Octave is distributed in the hope that it will be useful, but
16## WITHOUT ANY WARRANTY; without even the implied warranty of
17## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18## GNU General Public License for more details.
19##
20## You should have received a copy of the GNU General Public License
21## along with Octave; see the file COPYING.  If not, see
22## <https://www.gnu.org/licenses/>.
23##
24########################################################################
25
26## -*- texinfo -*-
27## @deftypefn  {} {[@var{fname}, @var{fpath}, @var{fltidx}] =} uigetfile ()
28## @deftypefnx {} {[@dots{}] =} uigetfile (@var{flt})
29## @deftypefnx {} {[@dots{}] =} uigetfile (@var{flt}, @var{dialog_name})
30## @deftypefnx {} {[@dots{}] =} uigetfile (@var{flt}, @var{dialog_name}, @var{default_file})
31## @deftypefnx {} {[@dots{}] =} uigetfile (@dots{}, "Position", [@var{px} @var{py}])
32## @deftypefnx {} {[@dots{}] =} uigetfile (@dots{}, "MultiSelect", @var{mode})
33##
34## Open a GUI dialog for selecting a file and return the filename @var{fname},
35## the path to this file @var{fpath}, and the filter index @var{fltidx}.
36##
37## @var{flt} contains a (list of) file filter string(s) in one of the following
38## formats:
39##
40## @table @asis
41## @item @qcode{"/path/to/filename.ext"}
42## If a filename is given then the file extension is extracted and used as
43## filter.  In addition, the path is selected as current path in the dialog and
44## the filename is selected as default file.
45## Example: @code{uigetfile ("myfun.m")}
46##
47## @item A single file extension @qcode{"*.ext"}
48## Example: @code{uigetfile ("*.ext")}
49##
50## @item A 2-column cell array
51## containing a file extension in the first column and a brief description in
52## the second column.
53## Example: @code{uigetfile (@{"*.ext", "My Description";"*.xyz",
54## "XYZ-Format"@})}
55##
56## The filter string can also contain a semicolon separated list of filter
57## extensions.
58## Example: @code{uigetfile (@{"*.gif;*.png;*.jpg", "Supported Picture
59## Formats"@})}
60##
61## @item A directory name or path name
62## If the folder name of path name contains a trailing file separator, the
63## contents of that folder will be displayed.  If no trailing file separator
64## is present the parent directory is listed.  The substring to the right of
65## the rightmost file separator (if any) will be interpreted as a file or
66## directory name and if that file or directory exists it will be highlighted.
67## If the path name or directory name is entirely or partly nonexistent, the
68## current working directory will be displayed.
69## No filter will be active.
70## @end table
71##
72## @var{dialog_name} can be used to customize the dialog title.
73##
74## If @var{default_file} is given then it will be selected in the GUI dialog.
75## If, in addition, a path is given it is also used as current path.
76##
77## The screen position of the GUI dialog can be set using the
78## @qcode{"Position"} key and a 2-element vector containing the pixel
79## coordinates.  Two or more files can be selected when setting the
80## @qcode{"MultiSelect"} key to @qcode{"on"}.  In that case @var{fname} is a
81## cell array containing the files.
82##
83## The outputs @var{fname} and @var{fpath} are strings returning the chosen
84## name and path, respectively.  However, if the @samp{Cancel} button is
85## clicked the outputs are of type double with a value of @code{0}.
86## @var{fltidx} is the index in the list of filter extensions @var{flt} that
87## was selected.
88##
89## @seealso{uiputfile, uigetdir}
90## @end deftypefn
91
92function [retfile, retpath, retindex] = uigetfile (varargin)
93
94  if (nargin > 7)
95    error ("uigetfile: number of input arguments must be less than eight");
96  endif
97
98  ## Preset default values
99  outargs = {cell(0, 2),         # File Filter
100             "Open File",        # Dialog Title
101             "",                 # Default filename
102             [240, 120],         # Dialog Position (pixel x/y)
103             "off",              # MultiSelect on/off
104             pwd};               # Default directory
105
106  idx1 = idx2 = [];
107  has_opts = false;
108  if (nargin > 0)
109    idx1 = find (strcmpi (varargin, "multiselect"), 1);
110    idx2 = find (strcmpi (varargin, "position"), 1);
111    if (idx1 || idx2)
112      has_opts = true;
113    endif
114  endif
115
116  optidx = min ([idx1, idx2, nargin+1]);
117
118  args = varargin(1:optidx-1);
119
120  len = numel (args);
121  if (len > 0)
122    [outargs{1}, outargs{3}, defdir] = __file_filter__ ("uigetfile", args{1});
123    if (! isempty (defdir))
124      outargs{6} = defdir;
125    endif
126  else
127    outargs{1} = __file_filter__ ("uigetfile", outargs{1});
128  endif
129
130  if (len > 1)
131    if (ischar (args{2}))
132      if (! isempty (args{2}))
133        outargs{2} = args{2};
134      endif
135    elseif (! isempty (args{2}))
136      print_usage ();
137    endif
138  endif
139
140  if (len > 2)
141    if (ischar (args{3}))
142      if (isfolder (args{3}))
143        fdir = args{3};
144        fname = fext = "";
145      else
146        [fdir, fname, fext] = fileparts (varargin{3});
147      endif
148      if (! isempty (fdir))
149        outargs{6} = fdir;
150      endif
151      if (! isempty (fname) || ! isempty (fext))
152        outargs{3} = [fname fext];
153      endif
154    elseif (! isempty (args{3}))
155      print_usage ();
156    endif
157  endif
158
159  if (has_opts)
160    ## string arguments ("position" or "multiselect")
161
162    ## check for even number of remaining arguments, prop/value pair(s)
163    if (rem (nargin - optidx + 1, 2))
164      error ("uigetfile: PROPERTY/VALUE arguments must occur in pairs");
165    endif
166
167    for i = optidx : 2 : nargin
168      prop = varargin{i};
169      val = varargin{i + 1};
170      if (strcmpi (prop, "position"))
171        if (! isnumeric (val) || length (val) != 2)
172          error ('uigetfile: "Position" must be a 2-element vector');
173        endif
174        outargs{4} = val;
175      elseif (strcmpi (prop, "multiselect"))
176        if (! ischar (val))
177          error ('uigetfile: MultiSelect value must be a string ("on"/"off")');
178        endif
179        outargs{5} = tolower (val);
180      else
181        error ("uigetfile: unknown argument '%s'", prop);
182      endif
183    endfor
184  endif
185
186  if (__event_manager_enabled__ ())
187    [retfile, retpath, retindex] = __event_manager_file_dialog__ (outargs{:});
188  else
189    funcname = __get_funcname__ (mfilename ());
190    [retfile, retpath, retindex] = feval (funcname, outargs{:});
191  endif
192
193endfunction
194
195
196%!demo
197%! uigetfile ({'*.gif;*.png;*.jpg', 'Supported Picture Formats'});
198
199## Remove from test statistics.  No real tests possible.
200%!assert (1)
201