Skip to content

Commit 7929fe2

Browse files
authored
Merge pull request #139 from slootsjj/enhancement-focusable
Focusable PasswordField and ButtonLabel for FileSelector
2 parents 470e767 + 81c5f08 commit 7929fe2

File tree

4 files changed

+292
-50
lines changed

4 files changed

+292
-50
lines changed

test/+wt/+test/FileSelector.m

Lines changed: 87 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -166,14 +166,94 @@ function testRootDirectoryAndHistory(testCase)
166166

167167
end %function
168168

169+
function testButtonLabel(testCase)
170+
171+
% Get the button control
172+
buttonControl = testCase.Widget.ButtonControl;
173+
174+
% Set the value
175+
newValue = "Select File";
176+
testCase.verifySetProperty("ButtonLabel", newValue);
177+
drawnow
178+
testCase.verifyEqual(string(buttonControl.Text), newValue);
179+
180+
% Set the value
181+
newValue = "Browse";
182+
testCase.verifySetProperty("ButtonLabel", newValue);
183+
drawnow
184+
testCase.verifyEqual(string(buttonControl.Text), newValue);
185+
186+
end %function
169187

170-
% function testButton(testCase)
171-
%
172-
% % We can't test the button in this case because it triggers a
173-
% % modal dialog with no way to click on the dialog.
174-
%
175-
% end %function
188+
% Since this test-case unlocks the test figure it should be last in
189+
% line.
190+
function testButton(testCase)
191+
192+
% Get the button control
193+
buttonControl = testCase.Widget.ButtonControl;
194+
195+
% Ancestor figure
196+
fig = ancestor(buttonControl, "Figure");
197+
198+
% Make sure file dialog window is in-app by setting the
199+
% 'ShowInWebApps' value to true.
200+
201+
% Get active value to restore
202+
s = settings;
203+
curTempVal = s.matlab.ui.dialog.fileIO.ShowInWebApps.ActiveValue;
204+
205+
% Set temporary value of ShowInWebApps setting to true, so that file
206+
% selector dialog window is a component in the figure.
207+
s.matlab.ui.dialog.fileIO.ShowInWebApps.TemporaryValue = true;
208+
cleanup = onCleanup(@() localRevertShowInWebAppsSetting(s, curTempVal));
209+
210+
% While dialog window is open and blocked by waitfor, there is still
211+
% a possibility to execute code through the timer function.
212+
213+
% Set timer callback
214+
delay = 2; % seconds
215+
t = timer;
216+
t.StartDelay = delay; % starts after 2 seconds
217+
t.TimerFcn = @(s,e) localPressEscape(fig);
218+
start(t); % start the timer
219+
220+
% Now press the button
221+
tStart = tic;
222+
testCase.press(buttonControl);
223+
224+
% Wait for escape button to be pressed.
225+
tStop = toc(tStart);
226+
227+
% Time while MATLAB waits for an action should be larger than the
228+
% StartDelay. If not, MATLAB did not reach the waitfor status after
229+
% pressing the file-selection button.
230+
testCase.verifyGreaterThan(tStop, delay)
231+
232+
end %function
176233

177234
end %methods (Test)
178235

179-
end %classdef
236+
end %classdef
237+
238+
function localPressEscape(fig)
239+
240+
% Unlock the figure, otherwise escape will not work.
241+
matlab.uitest.unlock(fig);
242+
243+
% Bring focus to figure
244+
figure(fig)
245+
246+
% Press ESCAPE
247+
r = java.awt.Robot;
248+
r.keyPress(java.awt.event.KeyEvent.VK_ESCAPE);
249+
pause(0.1);
250+
r.keyRelease(java.awt.event.KeyEvent.VK_ESCAPE);
251+
252+
end
253+
254+
function localRevertShowInWebAppsSetting(s, val)
255+
256+
% Revert setting on cleanup
257+
s.matlab.ui.dialog.fileIO.ShowInWebApps.TemporaryValue = val;
258+
259+
end

test/+wt/+test/PasswordField.m

Lines changed: 70 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -34,33 +34,81 @@ function testValue(testCase)
3434
% Change the value programmatically
3535
newValue = "AbC435!";
3636
testCase.verifySetProperty("Value", newValue);
37-
testCase.verifyMatches(passField.Data, newValue);
38-
39-
40-
%testCase.verifyTypeAction(passField, newValue, "Value");
41-
% Verify callback triggered
42-
%testCase.verifyEqual(testCase.CallbackCount, 1)
37+
testCase.verifyMatches(passField.Data.Value, newValue);
4338

4439
end %function
4540

4641

47-
%RAJ - Unfortunately, can't type in a uihtml
4842

49-
% function testTyping(testCase)
50-
%
51-
% % Get the password field
52-
% passField = testCase.Widget.PasswordControl;
53-
%
54-
% % Type a new value
55-
% newValue = "PasswordABC123";
56-
% testCase.verifyTypeAction(passField, newValue, "Value");
57-
% testCase.verifyMatches(passField.Data, newValue);
58-
%
59-
% % Verify callback triggered
60-
% testCase.verifyEqual(testCase.CallbackCount, 1)
61-
%
62-
% end %function
43+
function testTyping(testCase)
44+
45+
% Get the password field
46+
passField = testCase.Widget.PasswordControl;
47+
newValue = "AbC435!";
48+
testCase.verifySetProperty("Value", newValue);
49+
50+
% Allow for some time for the widget and HTML code to catch up
51+
pause(.5)
52+
focus(testCase.Widget)
53+
pause(.5)
54+
55+
% Type a new value
56+
newValue = "PasswordABC123";
57+
simulateTyping(newValue);
58+
simulateTyping('ENTER')
59+
60+
% Allow for some time for the widget to catch up
61+
pause(.5)
62+
testCase.verifyMatches(passField.Data.Value, newValue);
63+
64+
% Verify callback triggered
65+
testCase.verifyEqual(testCase.CallbackCount, 1)
66+
67+
end %function
6368

6469
end %methods (Test)
6570

66-
end %classdef
71+
end %classdef
72+
73+
function simulateTyping(S)
74+
% Simulate typing actions
75+
76+
% Convert to chars
77+
S = convertStringsToChars(S);
78+
79+
%Initialize the java engine
80+
import java.awt.*;
81+
import java.awt.event.*;
82+
83+
%Create a Robot-object to do the key-pressing
84+
rob = Robot;
85+
86+
% Request to press ENTER?
87+
if strcmpi(S, 'enter')
88+
rob.keyPress(KeyEvent.VK_ENTER);
89+
rob.keyRelease(KeyEvent.VK_ENTER);
90+
return
91+
end
92+
93+
% Execute each letter/number individually
94+
for idx = 1:strlength(S)
95+
96+
% Get key event ID
97+
p = ['VK_' upper(S(idx))];
98+
99+
% For capital letters, press SHIFT
100+
if ~strcmp(lower(S(idx)), S(idx))
101+
rob.keyPress(KeyEvent.VK_SHIFT);
102+
end
103+
104+
% Press/release key
105+
rob.keyPress(KeyEvent.(p))
106+
rob.keyRelease(KeyEvent.(p))
107+
108+
% For capital letters, release SHIFT
109+
if ~strcmp(lower(S(idx)), S(idx))
110+
rob.keyRelease(KeyEvent.VK_SHIFT);
111+
end
112+
end
113+
114+
end

widgets/+wt/FileSelector.m

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@
3636

3737
properties (AbortSet)
3838

39+
% Button text that appears on the button
40+
ButtonLabel (1,1) string = ""
41+
3942
% Selection type: (get)file, folder, putfile
4043
SelectionType (1,1) wt.enum.FileFolderState = wt.enum.FileFolderState.file
4144

@@ -174,6 +177,25 @@ function update(obj)
174177
showWarn = strlength(obj.Value) && ~obj.ValueIsValidPath;
175178
obj.WarnImage.Visible = showWarn;
176179

180+
% Set tooltip
181+
if showWarn
182+
if obj.SelectionType == "file"
183+
obj.WarnImage.Tooltip = 'File does not exist.';
184+
elseif obj.SelectionType == "putfile"
185+
obj.WarnImage.Tooltip = 'Folder for file storage does not exist.';
186+
else
187+
obj.WarnImage.Tooltip = 'Folder does not exist.';
188+
end
189+
end
190+
191+
% Update button appearance
192+
obj.ButtonControl.Text = obj.ButtonLabel;
193+
if strlength(obj.ButtonLabel)
194+
obj.Grid.ColumnWidth{4} = 125;
195+
else
196+
obj.Grid.ColumnWidth{4} = 25;
197+
end
198+
177199
end %function
178200

179201

0 commit comments

Comments
 (0)