Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/openvpn3_indicator/dialogs/credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ def construct_credentials_dialog(name, user_inputs, allow_store=True, on_connect
entries = list()
default_store = False
can_store = False
focus_entry = None
for user_input in user_inputs:
label = Gtk.Label(label=user_input.name, hexpand=True, xalign=0, margin_right=10)
grid.attach(label, 0, row, 1, 1)
Expand All @@ -62,9 +63,11 @@ def construct_credentials_dialog(name, user_inputs, allow_store=True, on_connect
entry.set_visibility(False)
if user_input.can_store:
can_store = True
if user_input.value is not None:
if user_input.value:
entry.set_text(user_input.value)
default_store = True
elif focus_entry is None:
focus_entry = entry
entry.set_activates_default(True)
grid.attach(entry, 1, row, 1, 1)
entries.append(entry)
Expand Down Expand Up @@ -108,6 +111,8 @@ def on_schedule():
default.set_can_default(True)
default.grab_default()
dialog.show_all()
if focus_entry is not None:
focus_entry.grab_focus()
if remain_active is not None:
GLib.timeout_add(1000, on_schedule)
return dialog
56 changes: 55 additions & 1 deletion src/openvpn3_indicator/tests/credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,58 @@
from openvpn3_indicator.about import APPLICATION_ID
from openvpn3_indicator.dialogs.credentials import construct_credentials_dialog, CredentialsUserInput

# name, mask, value, can_store, and the field we expect to end up focused.
# '' means there's a saved value that's just empty. None means nothing was ever saved.
# OTP is never saved, so it's always None.
FOCUS_SCENARIOS = [
('nothing stored', [
CredentialsUserInput('Username', False, None, True),
CredentialsUserInput('Password', True, None, True),
CredentialsUserInput('OTP', True, None, False),
], 'Username'),
('username stored only', [
CredentialsUserInput('Username', False, 'user', True),
CredentialsUserInput('Password', True, '', True),
CredentialsUserInput('OTP', True, None, False),
], 'Password'),
('password stored only', [
CredentialsUserInput('Username', False, '', True),
CredentialsUserInput('Password', True, 'secret', True),
CredentialsUserInput('OTP', True, None, False),
], 'Username'),
('username and password stored', [
CredentialsUserInput('Username', False, 'user', True),
CredentialsUserInput('Password', True, 'secret', True),
CredentialsUserInput('OTP', True, None, False),
], 'OTP'),
]


def focused_field_label(dialog):
focused = dialog.get_focus()
grid = next((child for child in dialog.get_content_area().get_children()
if isinstance(child, Gtk.Grid)), None)
if not isinstance(focused, Gtk.Entry) or grid is None:
return None
row = grid.child_get_property(focused, 'top-attach')
for child in grid.get_children():
if (isinstance(child, Gtk.Label)
and grid.child_get_property(child, 'left-attach') == 0
and grid.child_get_property(child, 'top-attach') == row):
return child.get_text()
return None


def verify_focus():
for name, user_inputs, expected in FOCUS_SCENARIOS:
dialog = construct_credentials_dialog(name, user_inputs)
while Gtk.events_pending(): # realize widgets so the focus is applied
Gtk.main_iteration_do(False)
got = focused_field_label(dialog)
print(f"[{'PASS' if got == expected else 'FAIL'}] {name}: focus on {got!r} (expected {expected!r})")
dialog.destroy()


class Test(Gtk.Application):
def __init__(self):
Gtk.Application.__init__(self,
Expand All @@ -24,12 +76,14 @@ def on_activate(self, *args, **kwargs):
def on_startup(self, *args, **kwargs):
self.hold()

verify_focus()

user_inputs = [
CredentialsUserInput(name='Username', mask=False, value='user', can_store=True),
CredentialsUserInput(name='Password', mask=True, value=None, can_store=True),
CredentialsUserInput(name='Other', mask=True, value='rehto', can_store=True),
]

dialog = construct_credentials_dialog('Test', user_inputs, on_connect=self.action_connect, on_cancel=self.action_quit)
dialog.set_visible(True)

Expand Down