Skip to content

Commit 58430c9

Browse files
committed
Changed Shortcuts dialog, added warning dialog when closing with dirty configuration
1 parent c9b58b5 commit 58430c9

File tree

4 files changed

+87
-190
lines changed

4 files changed

+87
-190
lines changed
Lines changed: 41 additions & 148 deletions
Original file line numberDiff line numberDiff line change
@@ -1,159 +1,52 @@
11
using Gtk 4.0;
22
using Adw 1;
33

4-
template $KeyboardShortcutsDialog: Adw.Dialog {
5-
Adw.ToastOverlay toast_overlay {
6-
Adw.ToolbarView {
7-
width-request: 680;
8-
height-request: 250;
9-
vexpand: false;
10-
valign: start;
4+
Adw.ShortcutsDialog keyboard_shortcuts_dialog {
5+
width-request: 680;
6+
height-request: 380;
7+
Adw.ShortcutsSection {
8+
title: _("General");
119

12-
[top]
13-
Adw.HeaderBar {
14-
[title]
15-
Adw.WindowTitle { title: _("Keyboard Shortcuts"); }
16-
}
17-
18-
content: Adw.Clamp {
19-
margin-top: 24;
20-
margin-bottom: 24;
21-
margin-start: 24;
22-
margin-end: 24;
23-
vexpand: false;
24-
valign: start;
25-
26-
Adw.PreferencesPage {
27-
Adw.PreferencesGroup {
28-
title: _("Global Shortcuts");
29-
description: _("Application-wide keyboard shortcuts");
30-
31-
Adw.ActionRow {
32-
title: _("Open SSH Config File");
33-
subtitle: _("Open a different SSH configuration file");
34-
[suffix] Label { label: "Ctrl+O"; css-classes: ["keyboard-shortcut"]; }
35-
}
36-
Adw.ActionRow {
37-
title: _("Save Configuration");
38-
subtitle: _("Save current changes to SSH config");
39-
[suffix] Label { label: "Ctrl+S"; css-classes: ["keyboard-shortcut"]; }
40-
}
41-
Adw.ActionRow {
42-
title: _("Reload Configuration");
43-
subtitle: _("Reload SSH config from disk");
44-
[suffix] Label { label: "Ctrl+R"; css-classes: ["keyboard-shortcut"]; }
45-
}
46-
Adw.ActionRow {
47-
title: _("Search");
48-
subtitle: _("Focus the search bar");
49-
[suffix] Label { label: "Ctrl+F"; css-classes: ["keyboard-shortcut"]; }
50-
}
51-
Adw.ActionRow {
52-
title: _("Toggle Sidebar");
53-
subtitle: _("Show or hide the host editor panel");
54-
[suffix] Label { label: "F9"; css-classes: ["keyboard-shortcut"]; }
55-
}
56-
Adw.ActionRow {
57-
title: _("Preferences");
58-
subtitle: _("Open application preferences");
59-
[suffix] Label { label: "Ctrl+,"; css-classes: ["keyboard-shortcut"]; }
60-
}
61-
Adw.ActionRow {
62-
title: _("SSH Key Manager");
63-
subtitle: _("Open SSH key management dialog");
64-
[suffix] Label { label: "Ctrl+K"; css-classes: ["keyboard-shortcut"]; }
65-
}
66-
}
67-
68-
Adw.PreferencesGroup {
69-
title: _("Host Management");
70-
description: _("Shortcuts for managing SSH hosts");
10+
Adw.ShortcutsItem { title: _("Open Menu"); accelerator: "F10"; }
11+
Adw.ShortcutsItem { title: _("Open SSH Config File"); accelerator: "<Ctrl>O"; }
12+
Adw.ShortcutsItem { title: _("Save Configuration"); accelerator: "<Ctrl>S"; }
13+
Adw.ShortcutsItem { title: _("Reload Configuration"); accelerator: "<Ctrl>R"; }
14+
Adw.ShortcutsItem { title: _("Search"); accelerator: "<Ctrl>F"; }
15+
Adw.ShortcutsItem { title: _("Toggle Sidebar"); accelerator: "F9"; }
16+
Adw.ShortcutsItem { title: _("Preferences"); accelerator: "<Ctrl>comma"; }
17+
Adw.ShortcutsItem { title: _("SSH Key Manager"); accelerator: "<Ctrl>K"; }
18+
}
7119

72-
Adw.ActionRow {
73-
title: _("Add New Host");
74-
subtitle: _("Create a new SSH host configuration");
75-
[suffix] Label { label: "Ctrl+N"; css-classes: ["keyboard-shortcut"]; }
76-
}
77-
Adw.ActionRow {
78-
title: _("Duplicate Host");
79-
subtitle: _("Create a copy of the selected host");
80-
[suffix] Label { label: "Ctrl+D"; css-classes: ["keyboard-shortcut"]; }
81-
}
82-
Adw.ActionRow {
83-
title: _("Delete Host");
84-
subtitle: _("Remove the selected host");
85-
[suffix] Label { label: "Ctrl+Delete"; css-classes: ["keyboard-shortcut"]; }
86-
}
87-
Adw.ActionRow {
88-
title: _("Edit Host");
89-
subtitle: _("Edit the selected host configuration");
90-
[suffix] Label { label: "Enter, F2"; css-classes: ["keyboard-shortcut"]; }
91-
}
92-
}
20+
Adw.ShortcutsSection {
21+
title: _("Host Management");
9322

94-
Adw.PreferencesGroup {
95-
title: _("Navigation");
96-
description: _("Shortcuts for navigating the interface");
23+
Adw.ShortcutsItem { title: _("Add New Host"); accelerator: "<Ctrl>N"; }
24+
Adw.ShortcutsItem { title: _("Duplicate Host"); accelerator: "<Ctrl>D"; }
25+
Adw.ShortcutsItem { title: _("Delete Host"); accelerator: "<Ctrl>Delete"; }
26+
Adw.ShortcutsItem { title: _("Edit Host"); accelerator: "Return"; }
27+
Adw.ShortcutsItem { title: _("Edit Host"); accelerator: "F2"; }
28+
}
9729

98-
Adw.ActionRow {
99-
title: _("Navigate Host List");
100-
subtitle: _("Move up and down through hosts");
101-
[suffix] Label { label: "↑, ↓"; css-classes: ["keyboard-shortcut"]; }
102-
}
103-
Adw.ActionRow {
104-
title: _("Jump to First Host");
105-
subtitle: _("Select the first host in the list");
106-
[suffix] Label { label: "Home"; css-classes: ["keyboard-shortcut"]; }
107-
}
108-
Adw.ActionRow {
109-
title: _("Jump to Last Host");
110-
subtitle: _("Select the last host in the list");
111-
[suffix] Label { label: "End"; css-classes: ["keyboard-shortcut"]; }
112-
}
113-
Adw.ActionRow {
114-
title: _("Page Navigation");
115-
subtitle: _("Navigate by 10 hosts at a time");
116-
[suffix] Label { label: "Page Up, Page Down"; css-classes: ["keyboard-shortcut"]; }
117-
}
118-
Adw.ActionRow {
119-
title: _("Form Navigation");
120-
subtitle: _("Move between form fields");
121-
[suffix] Label { label: "Tab, Shift+Tab"; css-classes: ["keyboard-shortcut"]; }
122-
}
123-
Adw.ActionRow {
124-
title: _("Clear Focus");
125-
subtitle: _("Remove focus from current field");
126-
[suffix] Label { label: "Escape"; css-classes: ["keyboard-shortcut"]; }
127-
}
128-
}
30+
Adw.ShortcutsSection {
31+
title: _("Navigation");
32+
33+
Adw.ShortcutsItem { title: _("Move Selection Up"); accelerator: "Up"; }
34+
Adw.ShortcutsItem { title: _("Move Selection Down"); accelerator: "Down"; }
35+
Adw.ShortcutsItem { title: _("Jump to First Host"); accelerator: "Home"; }
36+
Adw.ShortcutsItem { title: _("Jump to Last Host"); accelerator: "End"; }
37+
Adw.ShortcutsItem { title: _("Page Up"); accelerator: "Page_Up"; }
38+
Adw.ShortcutsItem { title: _("Page Down"); accelerator: "Page_Down"; }
39+
Adw.ShortcutsItem { title: _("Next Field"); accelerator: "Tab"; }
40+
Adw.ShortcutsItem { title: _("Previous Field"); accelerator: "<Shift>Tab"; }
41+
Adw.ShortcutsItem { title: _("Clear Focus"); accelerator: "Escape"; }
42+
}
12943

130-
Adw.PreferencesGroup {
131-
title: _("Dialog Shortcuts");
132-
description: _("Shortcuts available in dialogs");
44+
Adw.ShortcutsSection {
45+
title: _("Dialog Shortcuts");
13346

134-
Adw.ActionRow {
135-
title: _("Close Dialog");
136-
subtitle: _("Close any open dialog");
137-
[suffix] Label { label: "Escape"; css-classes: ["keyboard-shortcut"]; }
138-
}
139-
Adw.ActionRow {
140-
title: _("Generate Key");
141-
subtitle: _("Create new SSH key (in Key Manager)");
142-
[suffix] Label { label: "Ctrl+N"; css-classes: ["keyboard-shortcut"]; }
143-
}
144-
Adw.ActionRow {
145-
title: _("Import Key");
146-
subtitle: _("Import existing SSH key (in Key Manager)");
147-
[suffix] Label { label: "Ctrl+I"; css-classes: ["keyboard-shortcut"]; }
148-
}
149-
Adw.ActionRow {
150-
title: _("Delete Key");
151-
subtitle: _("Delete selected key (in Key Manager)");
152-
[suffix] Label { label: "Delete"; css-classes: ["keyboard-shortcut"]; }
153-
}
154-
}
155-
}
156-
};
157-
}
47+
Adw.ShortcutsItem { title: _("Close Dialog"); accelerator: "Escape"; }
48+
Adw.ShortcutsItem { title: _("Generate Key"); accelerator: "<Ctrl>N"; }
49+
Adw.ShortcutsItem { title: _("Import Key"); accelerator: "<Ctrl>I"; }
50+
Adw.ShortcutsItem { title: _("Delete Key"); accelerator: "Delete"; }
15851
}
15952
}

po/POTFILES

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,10 @@ data/ui/host_editor.blp
88
data/ui/host_list.blp
99
data/ui/main_window.blp
1010
data/ui/preferences_dialog.blp
11+
data/ui/test_connection_dialog.blp
12+
data/ui/ssh_key_manager_dialog.blp
13+
data/ui/generate_key_dialog.blp
14+
data/ui/key_picker_dialog.blp
15+
data/ui/keyboard_shortcuts_dialog.blp
16+
data/ui/welcome_view.blp
17+
data/ui/unsaved_changes_dialog.blp

src/ui/keyboard_shortcuts_dialog.py

Lines changed: 22 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,44 +6,38 @@
66
from gettext import gettext as _
77

88

9-
@Gtk.Template(
10-
resource_path="/io/github/BuddySirJava/SSH-Studio/ui/keyboard_shortcuts_dialog.ui"
11-
)
12-
class KeyboardShortcutsDialog(Adw.Dialog):
13-
"""Dialog showing keyboard shortcuts for SSH Studio."""
14-
15-
__gtype_name__ = "KeyboardShortcutsDialog"
9+
class KeyboardShortcutsDialog:
1610

1711
def __init__(self, parent=None):
18-
super().__init__()
19-
self._parent = parent
20-
try:
21-
self.set_title(_("Keyboard Shortcuts"))
22-
except Exception:
23-
pass
24-
try:
25-
self.set_default_size(680, 250)
26-
except Exception:
27-
pass
12+
builder = Gtk.Builder.new_from_resource(
13+
"/io/github/BuddySirJava/SSH-Studio/ui/keyboard_shortcuts_dialog.ui"
14+
)
2815
try:
29-
if hasattr(self, "set_content_width"):
30-
self.set_content_width(680)
31-
if hasattr(self, "set_content_height"):
32-
self.set_content_height(540)
16+
builder.set_translation_domain("ssh-studio")
3317
except Exception:
3418
pass
19+
self._dialog = builder.get_object("keyboard_shortcuts_dialog")
20+
if parent is not None:
21+
try:
22+
self._dialog.set_transient_for(parent)
23+
except Exception:
24+
pass
3525

36-
self._setup_keyboard_shortcuts()
37-
38-
def _setup_keyboard_shortcuts(self):
39-
"""Setup keyboard shortcuts for the shortcuts dialog."""
4026
key_controller = Gtk.EventControllerKey.new()
4127
key_controller.connect("key-pressed", self._on_key_pressed)
42-
self.add_controller(key_controller)
28+
self._dialog.add_controller(key_controller)
4329

4430
def _on_key_pressed(self, controller, keyval, keycode, state):
45-
"""Handle key presses in the shortcuts dialog."""
4631
if keyval == Gdk.KEY_Escape:
47-
self.close()
32+
self._dialog.close()
4833
return True
4934
return False
35+
36+
def present(self, parent=None):
37+
if parent is not None:
38+
self._dialog.present(parent)
39+
else:
40+
self._dialog.present()
41+
42+
def close(self):
43+
self._dialog.close()

src/ui/main_window.py

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -397,11 +397,12 @@ def _reselect_current_host(self):
397397
break
398398
except Exception:
399399
continue
400-
if selected is None:
400+
if selected is None and self.parser.config.hosts:
401401
selected = self.parser.config.hosts[0]
402-
self.host_list.select_host(selected)
403-
self.host_editor.load_host(selected)
404-
self._set_host_editor_visible(True)
402+
if selected:
403+
self.host_editor.load_host(selected)
404+
self.host_list.select_host(selected)
405+
self._set_host_editor_visible(True)
405406
except Exception:
406407
pass
407408

@@ -430,10 +431,7 @@ def _on_window_focus_changed(self, window, param):
430431

431432
def _on_close_request(self, window):
432433
"""Handle window close request - check for unsaved changes."""
433-
if (
434-
hasattr(self.host_editor, "is_host_dirty")
435-
and self.host_editor.is_host_dirty()
436-
):
434+
if self.is_dirty:
437435
return self._show_unsaved_changes_dialog()
438436
return False
439437

@@ -442,6 +440,10 @@ def _show_unsaved_changes_dialog(self):
442440
builder = Gtk.Builder.new_from_resource(
443441
"/io/github/BuddySirJava/SSH-Studio/ui/unsaved_changes_dialog.ui"
444442
)
443+
try:
444+
builder.set_translation_domain("ssh-studio")
445+
except Exception:
446+
pass
445447
dialog = builder.get_object("unsaved_changes_dialog")
446448
dialog.set_close_response("cancel")
447449
dialog.add_response("discard", _("Discard Changes"))
@@ -454,15 +456,11 @@ def _show_unsaved_changes_dialog(self):
454456
def on_response(dialog, response):
455457
if response == "save":
456458
try:
457-
if (
458-
hasattr(self.host_editor, "unsaved_banner")
459-
and self.host_editor.unsaved_banner
460-
):
461-
self.host_editor._on_save_clicked(None)
459+
self._on_save_clicked(None)
462460
dialog.close()
463461
GLib.timeout_add(200, self._delayed_close)
464462
except Exception as e:
465-
self.show_toast(_(f"Failed to save: {e}"))
463+
self.show_toast(_("Failed to save: {}").format(e))
466464
elif response == "discard":
467465
dialog.close()
468466
self.destroy()
@@ -501,6 +499,7 @@ def _on_save_clicked(self, button):
501499
self.parser.parse()
502500

503501
self.host_list.load_hosts(self.parser.config.hosts)
502+
self._reselect_current_host()
504503
self.is_dirty = False
505504
try:
506505
self.host_list.set_undo_enabled(False)
@@ -537,6 +536,10 @@ def _on_host_selected(self, host_list, host):
537536
except Exception:
538537
pass
539538
if hasattr(self, "content_nav") and self.content_nav:
539+
visible_page = self.content_nav.get_visible_page()
540+
if hasattr(visible_page, "get_tag") and visible_page.get_tag() == "host-editor":
541+
return
542+
540543
try:
541544
pages = self.content_nav.get_pages()
542545
for page in pages:

0 commit comments

Comments
 (0)