-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathuiget.m
188 lines (168 loc) · 6.15 KB
/
uiget.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
function [file, path] = uiget(basepath, varargin)
% UIGET generic folder and/or file selection dialog box
%
% Syntax:
% file = uiget()
% [file, path] = uiget()
% ___ = uiget(basepath)
% ___ = uiget(basepath, Name, Value)
%
% Available Name, Value Pairs:
% MultiSelect - Specify whether a user can select multiple files or folders
% ScalarPathOutput - Specify whether a scalar path is output when using MultiSelect
% Title - Specify a custom dialog title
% ExtensionFilter - Specify a custom file extension filter
% ForceCharOutput - Force return of a cell array of char
%
% See README.md for detailed documentation and examples
%
% See also UIGETDIR, UIGETFILE
if nargin == 0
% Use current working directory if no inputs are passed
basepath = pwd;
elseif nargin == 1
% Check for existence of basepath as a directory, default to current
% directory if it doesn't exist
if ~exist(basepath, 'dir')
basepath = pwd;
end
end
% Parse additional inputs
p = buildParser();
p.parse(varargin{:});
% Initialize JFileChooser window
% https://docs.oracle.com/javase/8/docs/api/javax/swing/JFileChooser.html
jFC = javax.swing.JFileChooser(basepath);
jFC.setFileSelectionMode(jFC.FILES_AND_DIRECTORIES)
jFC.setDialogTitle(p.Results.Title)
% Build file filter
if ~isempty(p.Results.ExtensionFilter)
extensions = parsefilter(p.Results.ExtensionFilter(:, 1));
nfilters = size(p.Results.ExtensionFilter, 1);
for ii = 1:nfilters
if isempty(extensions{ii})
% Catch invalid extension specs
continue
end
jExtensionFilter = javax.swing.filechooser.FileNameExtensionFilter(p.Results.ExtensionFilter{ii, 2}, extensions{ii});
jFC.addChoosableFileFilter(jExtensionFilter)
end
tmp = jFC.getChoosableFileFilters();
jFC.setFileFilter(tmp(2))
end
if p.Results.MultiSelect
jFC.setMultiSelectionEnabled(true)
% Change title if default is being used
if any(strcmp(p.UsingDefaults, 'Title'))
jFC.setDialogTitle('Select File(s) and/or Folder(s)')
end
else
jFC.setMultiSelectionEnabled(false)
end
% Switch over possible responses from JFileChooser
returnVal = jFC.showOpenDialog([]);
switch returnVal
case jFC.APPROVE_OPTION
% Selection string will be empty if getSelectedFiles is used when
% MultiSelect is disabled
if jFC.isMultiSelectionEnabled
selectionStr = string(jFC.getSelectedFiles());
else
selectionStr = string(jFC.getSelectedFile());
end
case jFC.CANCEL_OPTION
% Short-circuit: Return empty array on cancel
file = "";
path = "";
return
otherwise
err = MException("uiget:JFileWindow:unsupportedResult", ...
"Unsupported result returned from JFileChooser: %s.\n" + ...
"Please consult the documentation for the current MATLAB Java version (%s)", ...
returnVal, string(java.lang.System.getProperty("java.version")));
err.throw()
end
npicked = numel(selectionStr);
file = strings(npicked, 1);
path = strings(npicked, 1);
for ii = 1:npicked
[path(ii), filename, ext] = fileparts(selectionStr(ii));
file(ii) = filename + ext;
% Because we can select directories, we want to have them output as a
% path and not a file
if verLessThan('matlab','9.4')
% string inputs to fullfile were silently added in R2018a, use char
% for R2017a and R2017b
tmppath = char(path(ii));
tmpfile = char(file(ii));
if exist(fullfile(tmppath, tmpfile), 'dir')
path(ii) = string(fullfile(tmppath, tmpfile));
file(ii) = "";
end
else
if exist(fullfile(path(ii), file(ii)), 'dir')
path(ii) = fullfile(path(ii), file(ii));
file(ii) = "";
end
end
end
% Since we've now adjusted file in cases where a folder was selected, warn
% the user if file is going to be empty and they're not requesting path to
% go with it
emptyfiletest = (file == '');
if nargout <= 1 && any(emptyfiletest)
warning("uiget:uiget:nopathoutputrequested", ...
"One or more paths have been selected without requesting the path output.\n" + ...
"Please specify a second output to uiget to receive these paths." ...
);
end
% Simplify path output if needed
if p.Results.ScalarPathOutput
% Check for number of unique paths
% If more than one is present, use the first & throw a warning
uniquepaths = unique(path);
nuniquepaths = numel(uniquepaths);
if nuniquepaths == 1
path = uniquepaths;
elseif nuniquepaths > 1
path = uniquepaths(1);
warning("uiget:ScalarPathOutput:multipleuniquepaths", ...
"Multiple unique paths selected, ignoring %u extra selections.", ...
nuniquepaths - 1);
end
end
% Convert to cell array of char if flag is set
if p.Results.ForceCharOutput
file = cellstr(file);
path = cellstr(path);
end
end
function p = buildParser()
% Validate input Name,Value pairs
% Initialize verbosely, since inputParser apparently doesn't have a
% constructor that takes inputs...
p = inputParser();
p.FunctionName = 'uiget';
p.CaseSensitive = false;
p.KeepUnmatched = true;
p.PartialMatching = false;
% Add Name,Value pairs
p.addParameter('MultiSelect', false, @(x)islogical(x))
p.addParameter('ScalarPathOutput', false, @(x)islogical(x))
p.addParameter('Title', 'Select File or Folder', @(x)validateattributes(x, {'char', 'string'}, {'scalartext'}))
p.addParameter('ExtensionFilter', [], @(x)validateattributes(x, {'cell'}, {'ncols', 2}))
p.addParameter('ForceCharOutput', false, @(x)islogical(x))
end
function extensions = parsefilter(incell)
% Parse the extension filter extensions into a format usable by
% javax.swing.filechooser.FileNameExtensionFilter
%
% Since we're keeping with the uigetdir-esque extension syntax
% (e.g. *.extension), we need strip off '*.' from each for compatibility
% with the Java component.
extensions = cell(size(incell));
for ii = 1:numel(incell)
exp = '\*\.(\w+)';
extensions{ii} = string(regexp(incell{ii}, exp, 'tokens'));
end
end