mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2025-12-04 15:39:34 +01:00
Allow configuring keyboard shortcuts (#9643)
Closes #2689 The design of the respective code is loosely based on KDE's KActionCollection. The ActionCollection manages all actions that can be shortcut configured. These actions are then exposed in the config and a user can assign a different shortcut. Actions inside the MainWindow have been added to the ActionCollection. --------- Co-authored-by: Jonathan White <support@dmapps.us>
This commit is contained in:
@@ -5156,34 +5156,18 @@ Are you sure you want to continue with this file?</source>
|
|||||||
<source>&New Database…</source>
|
<source>&New Database…</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Create a new database</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>&Merge From Database…</source>
|
<source>&Merge From Database…</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Merge from another KDBX database</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>&New Entry…</source>
|
<source>&New Entry…</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Add a new entry</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>&Edit Entry…</source>
|
<source>&Edit Entry…</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>View or edit entry</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>&Delete Entry…</source>
|
<source>&Delete Entry…</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
@@ -5192,10 +5176,6 @@ Are you sure you want to continue with this file?</source>
|
|||||||
<source>&New Group…</source>
|
<source>&New Group…</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Add a new group</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>&Edit Group…</source>
|
<source>&Edit Group…</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
@@ -5228,18 +5208,10 @@ Are you sure you want to continue with this file?</source>
|
|||||||
<source>Database &Reports…</source>
|
<source>Database &Reports…</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Statistics, health check, etc.</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>&Database Settings…</source>
|
<source>&Database Settings…</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Database settings</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>&Clone Entry…</source>
|
<source>&Clone Entry…</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
@@ -5248,34 +5220,18 @@ Are you sure you want to continue with this file?</source>
|
|||||||
<source>Move u&p</source>
|
<source>Move u&p</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Move entry one step up</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Move do&wn</source>
|
<source>Move do&wn</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Move entry one step down</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Copy &Username</source>
|
<source>Copy &Username</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Copy username to clipboard</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Copy &Password</source>
|
<source>Copy &Password</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Copy password to clipboard</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>&Settings</source>
|
<source>&Settings</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
@@ -5308,26 +5264,14 @@ Are you sure you want to continue with this file?</source>
|
|||||||
<source>&Title</source>
|
<source>&Title</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Copy title to clipboard</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Copy &URL</source>
|
<source>Copy &URL</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Copy URL to clipboard</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>&Notes</source>
|
<source>&Notes</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Copy notes to clipboard</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>&CSV File…</source>
|
<source>&CSV File…</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
@@ -5340,26 +5284,14 @@ Are you sure you want to continue with this file?</source>
|
|||||||
<source>KeePass 1 Database…</source>
|
<source>KeePass 1 Database…</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Import a KeePass 1 database</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>1Password Vault…</source>
|
<source>1Password Vault…</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Import a 1Password Vault</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>CSV File…</source>
|
<source>CSV File…</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Import a CSV file</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Show TOTP</source>
|
<source>Show TOTP</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
@@ -5404,10 +5336,6 @@ Are you sure you want to continue with this file?</source>
|
|||||||
<source>&Online Help</source>
|
<source>&Online Help</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Go to online documentation</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>&User Guide</source>
|
<source>&User Guide</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
@@ -5480,10 +5408,6 @@ Are you sure you want to continue with this file?</source>
|
|||||||
<source>&XML File…</source>
|
<source>&XML File…</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>XML File…</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Clear history</source>
|
<source>Clear history</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
@@ -5575,11 +5499,251 @@ We recommend you use the AppImage available on our downloads page.</source>
|
|||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Passkeys</source>
|
<source>Import Passkey</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Import Passkey</source>
|
<source>Quit Application</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Open About Dialog</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Open Database</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Create Database</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Merge From Database</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Create Entry</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Edit Entry</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Delete Entry</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Create Group</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Edit Group</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Delete Group</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Download All Favicons</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Sort Groups A-Z</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Sort Groups Z-A</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Save Database As</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Show Database Security</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Show Database Reports</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Show Database Settings</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Show Passkeys</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Clone Entry</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Move Entry Up</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Move Entry Down</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Copy Username</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Copy Password</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Show Application Settings</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Show Password Generator</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Perform Auto-Type: {USERNAME}</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Perform Auto-Type: {USERNAME}{ENTER}</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Perform Auto-Type: {PASSWORD}</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Perform Auto-Type: {PASSWORD}{ENTER}</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Perform Auto-Type: {TOTP}</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Copy Title</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Copy URL</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Copy Notes</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Export to CSV</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Export to HTML</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Import KeePass1 Database</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Import 1Password Vault</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Import CSV File</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Show TOTP QR Code</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Set up TOTP</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Empty Recycle Bin</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Open Donation Website</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Open Bug Report</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Open Online Documentation</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Open Keyboard Shortcuts Guide</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Save Database Backup</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>SSH Agent: Add Key</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>SSH Agent: Remove Key</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Toggle Compact Mode</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Set Theme: Automatic</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Set Theme: Light</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Set Theme: Dark</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Set Theme: Classic</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Toggle Show Toolbar</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Toggle Show Preview Panel</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Toggle Always on Top</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Toggle Hide Usernames</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Toggle Hide Passwords</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Export to XML</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Toggle Allow Screen Capture</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
@@ -8220,63 +8384,15 @@ Kernel: %3 %4</source>
|
|||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>AES initialization failed</source>
|
<source>Enter Shortcut</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>AES encrypt failed</source>
|
<source>Action</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Failed to store in Linux Keyring</source>
|
<source>Shortcuts</source>
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Could not locate key in keyring</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Could not read key in keyring</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>AES decrypt failed</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>No Polkit authentication agent was available</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Polkit authorization failed</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>No Quick Unlock provider is available</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Polkit returned an error: %1</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Failed to init KeePassXC crypto.</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Failed to encrypt key data.</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Failed to get Windows Hello credential.</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Failed to decrypt key data.</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Passkeys</source>
|
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
@@ -8307,6 +8423,66 @@ Kernel: %3 %4</source>
|
|||||||
<source>Resident Keys are not supported</source>
|
<source>Resident Keys are not supported</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Passkeys</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>AES initialization failed</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>AES encrypt failed</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Failed to store in Linux Keyring</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Polkit returned an error: %1</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Could not locate key in keyring</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Could not read key in keyring</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>AES decrypt failed</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>No Polkit authentication agent was available</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Polkit authorization failed</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>No Quick Unlock provider is available</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Failed to init KeePassXC crypto.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Failed to encrypt key data.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Failed to get Windows Hello credential.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Failed to decrypt key data.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>QtIOCompressor</name>
|
<name>QtIOCompressor</name>
|
||||||
@@ -9147,6 +9323,29 @@ Kernel: %3 %4</source>
|
|||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>ShortcutSettingsWidget</name>
|
||||||
|
<message>
|
||||||
|
<source>Double click an action to change its shortcut</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Shortcut Conflict</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Filter...</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Shortcut %1 conflicts with '%2'. Overwrite shortcut?</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Reset Shortcuts</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>TagModel</name>
|
<name>TagModel</name>
|
||||||
<message>
|
<message>
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ set(keepassx_SOURCES
|
|||||||
gui/styles/dark/DarkStyle.cpp
|
gui/styles/dark/DarkStyle.cpp
|
||||||
gui/styles/light/LightStyle.cpp
|
gui/styles/light/LightStyle.cpp
|
||||||
gui/AboutDialog.cpp
|
gui/AboutDialog.cpp
|
||||||
|
gui/ActionCollection.cpp
|
||||||
gui/Application.cpp
|
gui/Application.cpp
|
||||||
gui/CategoryListWidget.cpp
|
gui/CategoryListWidget.cpp
|
||||||
gui/Clipboard.cpp
|
gui/Clipboard.cpp
|
||||||
@@ -130,6 +131,7 @@ set(keepassx_SOURCES
|
|||||||
gui/SearchWidget.cpp
|
gui/SearchWidget.cpp
|
||||||
gui/SortFilterHideProxyModel.cpp
|
gui/SortFilterHideProxyModel.cpp
|
||||||
gui/SquareSvgWidget.cpp
|
gui/SquareSvgWidget.cpp
|
||||||
|
gui/ShortcutSettingsPage.cpp
|
||||||
gui/TotpSetupDialog.cpp
|
gui/TotpSetupDialog.cpp
|
||||||
gui/TotpDialog.cpp
|
gui/TotpDialog.cpp
|
||||||
gui/TotpExportSettingsDialog.cpp
|
gui/TotpExportSettingsDialog.cpp
|
||||||
@@ -180,6 +182,7 @@ set(keepassx_SOURCES
|
|||||||
gui/widgets/ElidedLabel.cpp
|
gui/widgets/ElidedLabel.cpp
|
||||||
gui/widgets/KPToolBar.cpp
|
gui/widgets/KPToolBar.cpp
|
||||||
gui/widgets/PopupHelpWidget.cpp
|
gui/widgets/PopupHelpWidget.cpp
|
||||||
|
gui/widgets/ShortcutWidget.cpp
|
||||||
gui/wizard/NewDatabaseWizard.cpp
|
gui/wizard/NewDatabaseWizard.cpp
|
||||||
gui/wizard/NewDatabaseWizardPage.cpp
|
gui/wizard/NewDatabaseWizardPage.cpp
|
||||||
gui/wizard/NewDatabaseWizardPageMetaData.cpp
|
gui/wizard/NewDatabaseWizardPageMetaData.cpp
|
||||||
@@ -319,7 +322,6 @@ set(autotype_SOURCES
|
|||||||
autotype/AutoTypeMatchView.cpp
|
autotype/AutoTypeMatchView.cpp
|
||||||
autotype/AutoTypeSelectDialog.cpp
|
autotype/AutoTypeSelectDialog.cpp
|
||||||
autotype/PickcharsDialog.cpp
|
autotype/PickcharsDialog.cpp
|
||||||
autotype/ShortcutWidget.cpp
|
|
||||||
autotype/WindowSelectComboBox.cpp)
|
autotype/WindowSelectComboBox.cpp)
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
|
|||||||
@@ -597,4 +597,28 @@ void Config::createTempFileInstance()
|
|||||||
tmpFile->setParent(m_instance);
|
tmpFile->setParent(m_instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<Config::ShortcutEntry> Config::getShortcuts() const
|
||||||
|
{
|
||||||
|
m_settings->beginGroup("Shortcuts");
|
||||||
|
const auto keys = m_settings->childKeys();
|
||||||
|
QList<ShortcutEntry> ret;
|
||||||
|
ret.reserve(keys.size());
|
||||||
|
for (const auto& key : keys) {
|
||||||
|
const auto shortcut = m_settings->value(key).toString();
|
||||||
|
ret.push_back(ShortcutEntry{key, shortcut});
|
||||||
|
}
|
||||||
|
m_settings->endGroup();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::setShortcuts(const QList<ShortcutEntry>& shortcuts)
|
||||||
|
{
|
||||||
|
m_settings->beginGroup("Shortcuts");
|
||||||
|
m_settings->remove(""); // clear previous
|
||||||
|
for (const auto& shortcutEntry : shortcuts) {
|
||||||
|
m_settings->setValue(shortcutEntry.name, shortcutEntry.shortcut);
|
||||||
|
}
|
||||||
|
m_settings->endGroup();
|
||||||
|
}
|
||||||
|
|
||||||
#undef QS
|
#undef QS
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
|
#include <QVector>
|
||||||
|
|
||||||
class QSettings;
|
class QSettings;
|
||||||
|
|
||||||
@@ -198,6 +199,12 @@ public:
|
|||||||
Deleted
|
Deleted
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ShortcutEntry
|
||||||
|
{
|
||||||
|
QString name;
|
||||||
|
QString shortcut;
|
||||||
|
};
|
||||||
|
|
||||||
~Config() override;
|
~Config() override;
|
||||||
QVariant get(ConfigKey key);
|
QVariant get(ConfigKey key);
|
||||||
QVariant getDefault(ConfigKey key);
|
QVariant getDefault(ConfigKey key);
|
||||||
@@ -208,6 +215,9 @@ public:
|
|||||||
void sync();
|
void sync();
|
||||||
void resetToDefaults();
|
void resetToDefaults();
|
||||||
|
|
||||||
|
QList<ShortcutEntry> getShortcuts() const;
|
||||||
|
void setShortcuts(const QList<ShortcutEntry>& shortcuts);
|
||||||
|
|
||||||
static Config* instance();
|
static Config* instance();
|
||||||
static void createConfigFromFile(const QString& configFileName, const QString& localConfigFileName = {});
|
static void createConfigFromFile(const QString& configFileName, const QString& localConfigFileName = {});
|
||||||
static void createTempFileInstance();
|
static void createTempFileInstance();
|
||||||
|
|||||||
123
src/gui/ActionCollection.cpp
Normal file
123
src/gui/ActionCollection.cpp
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 KeePassXC Team <team@keepassxc.org>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ActionCollection.h"
|
||||||
|
#include "core/Config.h"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
ActionCollection* ActionCollection::instance()
|
||||||
|
{
|
||||||
|
static ActionCollection ac;
|
||||||
|
return ∾
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QAction*> ActionCollection::actions() const
|
||||||
|
{
|
||||||
|
return m_actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionCollection::addAction(QAction* action)
|
||||||
|
{
|
||||||
|
if (!m_actions.contains(action)) {
|
||||||
|
m_actions << action;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionCollection::addActions(const QList<QAction*>& actions)
|
||||||
|
{
|
||||||
|
for (auto a : actions) {
|
||||||
|
addAction(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QKeySequence ActionCollection::defaultShortcut(const QAction* action) const
|
||||||
|
{
|
||||||
|
auto shortcuts = defaultShortcuts(action);
|
||||||
|
return shortcuts.isEmpty() ? QKeySequence() : shortcuts.first();
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QKeySequence> ActionCollection::defaultShortcuts(const QAction* action) const
|
||||||
|
{
|
||||||
|
return action->property("defaultShortcuts").value<QList<QKeySequence>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionCollection::setDefaultShortcut(QAction* action, const QKeySequence& shortcut)
|
||||||
|
{
|
||||||
|
setDefaultShortcuts(action, {shortcut});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionCollection::setDefaultShortcut(QAction* action,
|
||||||
|
QKeySequence::StandardKey standard,
|
||||||
|
const QKeySequence& fallback)
|
||||||
|
{
|
||||||
|
if (!QKeySequence::keyBindings(standard).isEmpty()) {
|
||||||
|
setDefaultShortcuts(action, QKeySequence::keyBindings(standard));
|
||||||
|
} else if (fallback != 0) {
|
||||||
|
setDefaultShortcut(action, QKeySequence(fallback));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionCollection::setDefaultShortcuts(QAction* action, const QList<QKeySequence>& shortcuts)
|
||||||
|
{
|
||||||
|
action->setShortcuts(shortcuts);
|
||||||
|
action->setProperty("defaultShortcuts", QVariant::fromValue(shortcuts));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionCollection::restoreShortcuts()
|
||||||
|
{
|
||||||
|
const auto shortcuts = Config::instance()->getShortcuts();
|
||||||
|
QHash<QString, QAction*> actionsByName;
|
||||||
|
for (auto action : m_actions) {
|
||||||
|
actionsByName.insert(action->objectName(), action);
|
||||||
|
}
|
||||||
|
for (const auto& shortcut : shortcuts) {
|
||||||
|
if (actionsByName.contains(shortcut.name)) {
|
||||||
|
const auto key = QKeySequence::fromString(shortcut.shortcut);
|
||||||
|
actionsByName.value(shortcut.name)->setShortcut(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionCollection::saveShortcuts()
|
||||||
|
{
|
||||||
|
QList<Config::ShortcutEntry> shortcuts;
|
||||||
|
shortcuts.reserve(m_actions.size());
|
||||||
|
for (auto a : m_actions) {
|
||||||
|
// Only store non-default shortcut assignments
|
||||||
|
if (a->shortcut() != defaultShortcut(a)) {
|
||||||
|
shortcuts << Config::ShortcutEntry{a->objectName(), a->shortcut().toString()};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Config::instance()->setShortcuts(shortcuts);
|
||||||
|
}
|
||||||
|
|
||||||
|
QAction* ActionCollection::isConflictingShortcut(const QAction* action, const QKeySequence& seq) const
|
||||||
|
{
|
||||||
|
// Empty sequences don't conflict with anything
|
||||||
|
if (seq.isEmpty()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto a : m_actions) {
|
||||||
|
if (a != action && a->shortcut() == seq) {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
61
src/gui/ActionCollection.h
Normal file
61
src/gui/ActionCollection.h
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 KeePassXC Team <team@keepassxc.org>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef KEEPASSXC_ACTION_COLLECTION_H
|
||||||
|
#define KEEPASSXC_ACTION_COLLECTION_H
|
||||||
|
|
||||||
|
#include <QAction>
|
||||||
|
#include <QKeySequence>
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class manages all actions that are shortcut configurable.
|
||||||
|
* It also allows you to access the actions inside it from anywhere
|
||||||
|
* in the gui code.
|
||||||
|
*/
|
||||||
|
class ActionCollection : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
ActionCollection() = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static ActionCollection* instance();
|
||||||
|
|
||||||
|
QList<QAction*> actions() const;
|
||||||
|
|
||||||
|
void addAction(QAction* action);
|
||||||
|
void addActions(const QList<QAction*>& actions);
|
||||||
|
|
||||||
|
QKeySequence defaultShortcut(const QAction* a) const;
|
||||||
|
QList<QKeySequence> defaultShortcuts(const QAction* a) const;
|
||||||
|
|
||||||
|
void setDefaultShortcut(QAction* a, const QKeySequence& shortcut);
|
||||||
|
void setDefaultShortcut(QAction* a, QKeySequence::StandardKey standard, const QKeySequence& fallback);
|
||||||
|
void setDefaultShortcuts(QAction* a, const QList<QKeySequence>& shortcut);
|
||||||
|
|
||||||
|
// Check if any action conflicts with @p seq and return the conflicting action
|
||||||
|
QAction* isConflictingShortcut(const QAction* action, const QKeySequence& seq) const;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void restoreShortcuts();
|
||||||
|
void saveShortcuts();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QList<QAction*> m_actions;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -21,6 +21,7 @@
|
|||||||
#include "ui_ApplicationSettingsWidgetSecurity.h"
|
#include "ui_ApplicationSettingsWidgetSecurity.h"
|
||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <QToolTip>
|
||||||
|
|
||||||
#include "config-keepassx.h"
|
#include "config-keepassx.h"
|
||||||
|
|
||||||
@@ -138,6 +139,22 @@ ApplicationSettingsWidget::ApplicationSettingsWidget(QWidget* parent)
|
|||||||
m_secUi->lockDatabaseMinimizeCheckBox->setEnabled(!state);
|
m_secUi->lockDatabaseMinimizeCheckBox->setEnabled(!state);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Set Auto-Type shortcut when changed
|
||||||
|
connect(
|
||||||
|
m_generalUi->autoTypeShortcutWidget, &ShortcutWidget::shortcutChanged, this, [this](auto key, auto modifiers) {
|
||||||
|
QString error;
|
||||||
|
if (autoType()->registerGlobalShortcut(key, modifiers, &error)) {
|
||||||
|
m_generalUi->autoTypeShortcutWidget->setStyleSheet("");
|
||||||
|
} else {
|
||||||
|
QToolTip::showText(mapToGlobal(rect().bottomLeft()), error);
|
||||||
|
m_generalUi->autoTypeShortcutWidget->setStyleSheet("background-color: #FF9696;");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
connect(m_generalUi->autoTypeShortcutWidget, &ShortcutWidget::shortcutReset, this, [this] {
|
||||||
|
autoType()->unregisterGlobalShortcut();
|
||||||
|
m_generalUi->autoTypeShortcutWidget->setStyleSheet("");
|
||||||
|
});
|
||||||
|
|
||||||
// Disable mouse wheel grab when scrolling
|
// Disable mouse wheel grab when scrolling
|
||||||
// This prevents combo box and spinner values from changing without explicit focus
|
// This prevents combo box and spinner values from changing without explicit focus
|
||||||
auto mouseWheelFilter = new MouseWheelEventFilter(this);
|
auto mouseWheelFilter = new MouseWheelEventFilter(this);
|
||||||
|
|||||||
@@ -58,8 +58,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>564</width>
|
<width>566</width>
|
||||||
<height>930</height>
|
<height>975</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_8">
|
<layout class="QVBoxLayout" name="verticalLayout_8">
|
||||||
@@ -1260,7 +1260,7 @@
|
|||||||
<customwidget>
|
<customwidget>
|
||||||
<class>ShortcutWidget</class>
|
<class>ShortcutWidget</class>
|
||||||
<extends>QLineEdit</extends>
|
<extends>QLineEdit</extends>
|
||||||
<header>autotype/ShortcutWidget.h</header>
|
<header>gui/widgets/ShortcutWidget.h</header>
|
||||||
</customwidget>
|
</customwidget>
|
||||||
</customwidgets>
|
</customwidgets>
|
||||||
<tabstops>
|
<tabstops>
|
||||||
|
|||||||
@@ -40,9 +40,11 @@
|
|||||||
#include "core/Resources.h"
|
#include "core/Resources.h"
|
||||||
#include "core/Tools.h"
|
#include "core/Tools.h"
|
||||||
#include "gui/AboutDialog.h"
|
#include "gui/AboutDialog.h"
|
||||||
|
#include "gui/ActionCollection.h"
|
||||||
#include "gui/Icons.h"
|
#include "gui/Icons.h"
|
||||||
#include "gui/MessageBox.h"
|
#include "gui/MessageBox.h"
|
||||||
#include "gui/SearchWidget.h"
|
#include "gui/SearchWidget.h"
|
||||||
|
#include "gui/ShortcutSettingsPage.h"
|
||||||
#include "gui/entry/EntryView.h"
|
#include "gui/entry/EntryView.h"
|
||||||
#include "gui/osutils/OSUtils.h"
|
#include "gui/osutils/OSUtils.h"
|
||||||
|
|
||||||
@@ -189,6 +191,11 @@ MainWindow::MainWindow()
|
|||||||
connect(m_ui->tabWidget, &DatabaseTabWidget::databaseUnlocked, this, &MainWindow::databaseUnlocked);
|
connect(m_ui->tabWidget, &DatabaseTabWidget::databaseUnlocked, this, &MainWindow::databaseUnlocked);
|
||||||
connect(m_ui->tabWidget, &DatabaseTabWidget::activeDatabaseChanged, this, &MainWindow::activeDatabaseChanged);
|
connect(m_ui->tabWidget, &DatabaseTabWidget::activeDatabaseChanged, this, &MainWindow::activeDatabaseChanged);
|
||||||
|
|
||||||
|
initViewMenu();
|
||||||
|
initActionCollection();
|
||||||
|
|
||||||
|
m_ui->settingsWidget->addSettingsPage(new ShortcutSettingsPage());
|
||||||
|
|
||||||
#ifdef WITH_XC_BROWSER
|
#ifdef WITH_XC_BROWSER
|
||||||
m_ui->settingsWidget->addSettingsPage(new BrowserSettingsPage());
|
m_ui->settingsWidget->addSettingsPage(new BrowserSettingsPage());
|
||||||
connect(
|
connect(
|
||||||
@@ -201,8 +208,6 @@ MainWindow::MainWindow()
|
|||||||
m_ui->settingsWidget->addSettingsPage(new AgentSettingsPage());
|
m_ui->settingsWidget->addSettingsPage(new AgentSettingsPage());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
initViewMenu();
|
|
||||||
|
|
||||||
#if defined(WITH_XC_KEESHARE)
|
#if defined(WITH_XC_KEESHARE)
|
||||||
KeeShare::init(this);
|
KeeShare::init(this);
|
||||||
m_ui->settingsWidget->addSettingsPage(new SettingsPageKeeShare(m_ui->tabWidget));
|
m_ui->settingsWidget->addSettingsPage(new SettingsPageKeeShare(m_ui->tabWidget));
|
||||||
@@ -262,45 +267,6 @@ MainWindow::MainWindow()
|
|||||||
connect(m_inactivityTimer, SIGNAL(inactivityDetected()), this, SLOT(lockDatabasesAfterInactivity()));
|
connect(m_inactivityTimer, SIGNAL(inactivityDetected()), this, SLOT(lockDatabasesAfterInactivity()));
|
||||||
applySettingsChanges();
|
applySettingsChanges();
|
||||||
|
|
||||||
m_ui->actionDatabaseNew->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_N);
|
|
||||||
setShortcut(m_ui->actionDatabaseOpen, QKeySequence::Open, Qt::CTRL + Qt::Key_O);
|
|
||||||
setShortcut(m_ui->actionDatabaseSave, QKeySequence::Save, Qt::CTRL + Qt::Key_S);
|
|
||||||
setShortcut(m_ui->actionDatabaseSaveAs, QKeySequence::SaveAs, Qt::CTRL + Qt::SHIFT + Qt::Key_S);
|
|
||||||
setShortcut(m_ui->actionDatabaseClose, QKeySequence::Close, Qt::CTRL + Qt::Key_W);
|
|
||||||
m_ui->actionDatabaseSettings->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_Comma);
|
|
||||||
m_ui->actionReports->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_R);
|
|
||||||
setShortcut(m_ui->actionSettings, QKeySequence::Preferences, Qt::CTRL + Qt::Key_Comma);
|
|
||||||
m_ui->actionLockDatabase->setShortcut(Qt::CTRL + Qt::Key_L);
|
|
||||||
m_ui->actionLockAllDatabases->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_L);
|
|
||||||
setShortcut(m_ui->actionQuit, QKeySequence::Quit, Qt::CTRL + Qt::Key_Q);
|
|
||||||
setShortcut(m_ui->actionEntryNew, QKeySequence::New, Qt::CTRL + Qt::Key_N);
|
|
||||||
m_ui->actionEntryEdit->setShortcut(Qt::CTRL + Qt::Key_E);
|
|
||||||
m_ui->actionEntryDelete->setShortcut(Qt::CTRL + Qt::Key_D);
|
|
||||||
m_ui->actionEntryDelete->setShortcut(Qt::Key_Delete);
|
|
||||||
m_ui->actionEntryClone->setShortcut(Qt::CTRL + Qt::Key_K);
|
|
||||||
m_ui->actionEntryTotp->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_T);
|
|
||||||
m_ui->actionEntryDownloadIcon->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_D);
|
|
||||||
m_ui->actionEntryCopyTotp->setShortcut(Qt::CTRL + Qt::Key_T);
|
|
||||||
m_ui->actionEntryCopyPasswordTotp->setShortcut(Qt::CTRL + Qt::Key_Y);
|
|
||||||
m_ui->actionEntryMoveUp->setShortcut(Qt::CTRL + Qt::ALT + Qt::Key_Up);
|
|
||||||
m_ui->actionEntryMoveDown->setShortcut(Qt::CTRL + Qt::ALT + Qt::Key_Down);
|
|
||||||
m_ui->actionEntryCopyUsername->setShortcut(Qt::CTRL + Qt::Key_B);
|
|
||||||
m_ui->actionEntryCopyPassword->setShortcut(Qt::CTRL + Qt::Key_C);
|
|
||||||
m_ui->actionEntryCopyTitle->setShortcut(Qt::CTRL + Qt::Key_I);
|
|
||||||
m_ui->actionEntryAutoTypeSequence->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_V);
|
|
||||||
m_ui->actionEntryOpenUrl->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_U);
|
|
||||||
m_ui->actionEntryCopyURL->setShortcut(Qt::CTRL + Qt::Key_U);
|
|
||||||
m_ui->actionEntryRestore->setShortcut(Qt::CTRL + Qt::Key_R);
|
|
||||||
|
|
||||||
// Prevent conflicts with global Mac shortcuts (force Control on all platforms)
|
|
||||||
#ifdef Q_OS_MAC
|
|
||||||
auto modifier = Qt::META;
|
|
||||||
#else
|
|
||||||
auto modifier = Qt::CTRL;
|
|
||||||
#endif
|
|
||||||
m_ui->actionEntryAddToAgent->setShortcut(modifier + Qt::Key_H);
|
|
||||||
m_ui->actionEntryRemoveFromAgent->setShortcut(modifier + Qt::SHIFT + Qt::Key_H);
|
|
||||||
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
|
||||||
// Qt 5.10 introduced a new "feature" to hide shortcuts in context menus
|
// Qt 5.10 introduced a new "feature" to hide shortcuts in context menus
|
||||||
// Unfortunately, Qt::AA_DontShowShortcutsInContextMenus is broken, have to manually enable them
|
// Unfortunately, Qt::AA_DontShowShortcutsInContextMenus is broken, have to manually enable them
|
||||||
@@ -1675,15 +1641,6 @@ void MainWindow::showGroupContextMenu(const QPoint& globalPos)
|
|||||||
m_ui->menuGroups->popup(globalPos);
|
m_ui->menuGroups->popup(globalPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::setShortcut(QAction* action, QKeySequence::StandardKey standard, int fallback)
|
|
||||||
{
|
|
||||||
if (!QKeySequence::keyBindings(standard).isEmpty()) {
|
|
||||||
action->setShortcuts(standard);
|
|
||||||
} else if (fallback != 0) {
|
|
||||||
action->setShortcut(QKeySequence(fallback));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::applySettingsChanges()
|
void MainWindow::applySettingsChanges()
|
||||||
{
|
{
|
||||||
int timeout = config()->get(Config::Security_LockDatabaseIdleSeconds).toInt() * 1000;
|
int timeout = config()->get(Config::Security_LockDatabaseIdleSeconds).toInt() * 1000;
|
||||||
@@ -2094,6 +2051,145 @@ void MainWindow::initViewMenu()
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::initActionCollection()
|
||||||
|
{
|
||||||
|
auto ac = ActionCollection::instance();
|
||||||
|
ac->addActions({// Database Menu
|
||||||
|
m_ui->actionDatabaseNew,
|
||||||
|
m_ui->actionDatabaseOpen,
|
||||||
|
m_ui->actionDatabaseSave,
|
||||||
|
m_ui->actionDatabaseSaveAs,
|
||||||
|
m_ui->actionDatabaseSaveBackup,
|
||||||
|
m_ui->actionDatabaseClose,
|
||||||
|
m_ui->actionLockDatabase,
|
||||||
|
m_ui->actionLockAllDatabases,
|
||||||
|
m_ui->actionDatabaseSettings,
|
||||||
|
m_ui->actionDatabaseSecurity,
|
||||||
|
m_ui->actionReports,
|
||||||
|
m_ui->actionPasskeys,
|
||||||
|
m_ui->actionDatabaseMerge,
|
||||||
|
m_ui->actionImportPasskey,
|
||||||
|
m_ui->actionImportCsv,
|
||||||
|
m_ui->actionImportOpVault,
|
||||||
|
m_ui->actionImportKeePass1,
|
||||||
|
m_ui->actionExportCsv,
|
||||||
|
m_ui->actionExportHtml,
|
||||||
|
m_ui->actionExportXML,
|
||||||
|
m_ui->actionQuit,
|
||||||
|
// Entry Menu
|
||||||
|
m_ui->actionEntryNew,
|
||||||
|
m_ui->actionEntryEdit,
|
||||||
|
m_ui->actionEntryClone,
|
||||||
|
m_ui->actionEntryDelete,
|
||||||
|
m_ui->actionEntryCopyUsername,
|
||||||
|
m_ui->actionEntryCopyPassword,
|
||||||
|
m_ui->actionEntryCopyURL,
|
||||||
|
m_ui->actionEntryCopyTitle,
|
||||||
|
m_ui->actionEntryCopyNotes,
|
||||||
|
m_ui->actionEntryTotp,
|
||||||
|
m_ui->actionEntryTotpQRCode,
|
||||||
|
m_ui->actionEntrySetupTotp,
|
||||||
|
m_ui->actionEntryCopyTotp,
|
||||||
|
m_ui->actionEntryCopyPasswordTotp,
|
||||||
|
m_ui->actionEntryAutoTypeSequence,
|
||||||
|
m_ui->actionEntryAutoTypeUsername,
|
||||||
|
m_ui->actionEntryAutoTypeUsernameEnter,
|
||||||
|
m_ui->actionEntryAutoTypePassword,
|
||||||
|
m_ui->actionEntryAutoTypePasswordEnter,
|
||||||
|
m_ui->actionEntryAutoTypeTOTP,
|
||||||
|
m_ui->actionEntryDownloadIcon,
|
||||||
|
m_ui->actionEntryOpenUrl,
|
||||||
|
m_ui->actionEntryMoveUp,
|
||||||
|
m_ui->actionEntryMoveDown,
|
||||||
|
m_ui->actionEntryAddToAgent,
|
||||||
|
m_ui->actionEntryRemoveFromAgent,
|
||||||
|
m_ui->actionEntryRestore,
|
||||||
|
// Group Menu
|
||||||
|
m_ui->actionGroupNew,
|
||||||
|
m_ui->actionGroupEdit,
|
||||||
|
m_ui->actionGroupClone,
|
||||||
|
m_ui->actionGroupDelete,
|
||||||
|
m_ui->actionGroupDownloadFavicons,
|
||||||
|
m_ui->actionGroupSortAsc,
|
||||||
|
m_ui->actionGroupSortDesc,
|
||||||
|
m_ui->actionGroupEmptyRecycleBin,
|
||||||
|
// Tools Menu
|
||||||
|
m_ui->actionPasswordGenerator,
|
||||||
|
m_ui->actionSettings,
|
||||||
|
// View Menu
|
||||||
|
m_ui->actionThemeAuto,
|
||||||
|
m_ui->actionThemeLight,
|
||||||
|
m_ui->actionThemeDark,
|
||||||
|
m_ui->actionThemeClassic,
|
||||||
|
m_ui->actionCompactMode,
|
||||||
|
m_ui->actionShowToolbar,
|
||||||
|
m_ui->actionShowPreviewPanel,
|
||||||
|
m_ui->actionAllowScreenCapture,
|
||||||
|
m_ui->actionAlwaysOnTop,
|
||||||
|
m_ui->actionHideUsernames,
|
||||||
|
m_ui->actionHidePasswords,
|
||||||
|
// Help Menu
|
||||||
|
m_ui->actionGettingStarted,
|
||||||
|
m_ui->actionUserGuide,
|
||||||
|
m_ui->actionKeyboardShortcuts,
|
||||||
|
m_ui->actionOnlineHelp,
|
||||||
|
m_ui->actionCheckForUpdates,
|
||||||
|
m_ui->actionDonate,
|
||||||
|
m_ui->actionBugReport,
|
||||||
|
m_ui->actionAbout});
|
||||||
|
|
||||||
|
// Add actions whose shortcuts were set in the .ui file
|
||||||
|
for (const auto action : ac->actions()) {
|
||||||
|
if (!action->shortcut().isEmpty()) {
|
||||||
|
ac->setDefaultShortcut(action, action->shortcut());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actions with standard shortcuts
|
||||||
|
ac->setDefaultShortcut(m_ui->actionDatabaseOpen, QKeySequence::Open, Qt::CTRL + Qt::Key_O);
|
||||||
|
ac->setDefaultShortcut(m_ui->actionDatabaseSave, QKeySequence::Save, Qt::CTRL + Qt::Key_S);
|
||||||
|
ac->setDefaultShortcut(m_ui->actionDatabaseSaveAs, QKeySequence::SaveAs, Qt::CTRL + Qt::SHIFT + Qt::Key_S);
|
||||||
|
ac->setDefaultShortcut(m_ui->actionDatabaseClose, QKeySequence::Close, Qt::CTRL + Qt::Key_W);
|
||||||
|
ac->setDefaultShortcut(m_ui->actionSettings, QKeySequence::Preferences, Qt::CTRL + Qt::Key_Comma);
|
||||||
|
ac->setDefaultShortcut(m_ui->actionQuit, QKeySequence::Quit, Qt::CTRL + Qt::Key_Q);
|
||||||
|
ac->setDefaultShortcut(m_ui->actionEntryNew, QKeySequence::New, Qt::CTRL + Qt::Key_N);
|
||||||
|
|
||||||
|
// Prevent conflicts with global Mac shortcuts (force Control on all platforms)
|
||||||
|
#ifdef Q_OS_MAC
|
||||||
|
auto modifier = Qt::META;
|
||||||
|
#else
|
||||||
|
auto modifier = Qt::CTRL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// All other actions with default shortcuts
|
||||||
|
ac->setDefaultShortcut(m_ui->actionDatabaseNew, Qt::CTRL + Qt::SHIFT + Qt::Key_N);
|
||||||
|
ac->setDefaultShortcut(m_ui->actionDatabaseSettings, Qt::CTRL + Qt::SHIFT + Qt::Key_Comma);
|
||||||
|
ac->setDefaultShortcut(m_ui->actionReports, Qt::CTRL + Qt::SHIFT + Qt::Key_R);
|
||||||
|
ac->setDefaultShortcut(m_ui->actionLockDatabase, Qt::CTRL + Qt::Key_L);
|
||||||
|
ac->setDefaultShortcut(m_ui->actionLockAllDatabases, Qt::CTRL + Qt::SHIFT + Qt::Key_L);
|
||||||
|
ac->setDefaultShortcut(m_ui->actionEntryEdit, Qt::CTRL + Qt::Key_E);
|
||||||
|
ac->setDefaultShortcut(m_ui->actionEntryDelete, Qt::CTRL + Qt::Key_D);
|
||||||
|
ac->setDefaultShortcut(m_ui->actionEntryDelete, Qt::Key_Delete);
|
||||||
|
ac->setDefaultShortcut(m_ui->actionEntryClone, Qt::CTRL + Qt::Key_K);
|
||||||
|
ac->setDefaultShortcut(m_ui->actionEntryTotp, Qt::CTRL + Qt::SHIFT + Qt::Key_T);
|
||||||
|
ac->setDefaultShortcut(m_ui->actionEntryDownloadIcon, Qt::CTRL + Qt::SHIFT + Qt::Key_D);
|
||||||
|
ac->setDefaultShortcut(m_ui->actionEntryCopyTotp, Qt::CTRL + Qt::Key_T);
|
||||||
|
ac->setDefaultShortcut(m_ui->actionEntryCopyPasswordTotp, Qt::CTRL + Qt::Key_Y);
|
||||||
|
ac->setDefaultShortcut(m_ui->actionEntryMoveUp, Qt::CTRL + Qt::ALT + Qt::Key_Up);
|
||||||
|
ac->setDefaultShortcut(m_ui->actionEntryMoveDown, Qt::CTRL + Qt::ALT + Qt::Key_Down);
|
||||||
|
ac->setDefaultShortcut(m_ui->actionEntryCopyUsername, Qt::CTRL + Qt::Key_B);
|
||||||
|
ac->setDefaultShortcut(m_ui->actionEntryCopyPassword, Qt::CTRL + Qt::Key_C);
|
||||||
|
ac->setDefaultShortcut(m_ui->actionEntryCopyTitle, Qt::CTRL + Qt::Key_I);
|
||||||
|
ac->setDefaultShortcut(m_ui->actionEntryAutoTypeSequence, Qt::CTRL + Qt::SHIFT + Qt::Key_V);
|
||||||
|
ac->setDefaultShortcut(m_ui->actionEntryOpenUrl, Qt::CTRL + Qt::SHIFT + Qt::Key_U);
|
||||||
|
ac->setDefaultShortcut(m_ui->actionEntryCopyURL, Qt::CTRL + Qt::Key_U);
|
||||||
|
ac->setDefaultShortcut(m_ui->actionEntryRestore, Qt::CTRL + Qt::Key_R);
|
||||||
|
ac->setDefaultShortcut(m_ui->actionEntryAddToAgent, modifier + Qt::Key_H);
|
||||||
|
ac->setDefaultShortcut(m_ui->actionEntryRemoveFromAgent, modifier + Qt::SHIFT + Qt::Key_H);
|
||||||
|
|
||||||
|
QTimer::singleShot(1, ac, &ActionCollection::restoreShortcuts);
|
||||||
|
}
|
||||||
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
||||||
|
|
||||||
MainWindowEventFilter::MainWindowEventFilter(QObject* parent)
|
MainWindowEventFilter::MainWindowEventFilter(QObject* parent)
|
||||||
|
|||||||
@@ -154,8 +154,6 @@ private slots:
|
|||||||
void focusSearchWidget();
|
void focusSearchWidget();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void setShortcut(QAction* action, QKeySequence::StandardKey standard, int fallback = 0);
|
|
||||||
|
|
||||||
static const QString BaseWindowTitle;
|
static const QString BaseWindowTitle;
|
||||||
|
|
||||||
void saveWindowInformation();
|
void saveWindowInformation();
|
||||||
@@ -168,6 +166,7 @@ private:
|
|||||||
void dropEvent(QDropEvent* event) override;
|
void dropEvent(QDropEvent* event) override;
|
||||||
|
|
||||||
void initViewMenu();
|
void initViewMenu();
|
||||||
|
void initActionCollection();
|
||||||
|
|
||||||
const QScopedPointer<Ui::MainWindow> m_ui;
|
const QScopedPointer<Ui::MainWindow> m_ui;
|
||||||
SignalMultiplexer m_actionMultiplexer;
|
SignalMultiplexer m_actionMultiplexer;
|
||||||
|
|||||||
@@ -443,6 +443,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&Quit</string>
|
<string>&Quit</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Quit Application</string>
|
||||||
|
</property>
|
||||||
<property name="menuRole">
|
<property name="menuRole">
|
||||||
<enum>QAction::QuitRole</enum>
|
<enum>QAction::QuitRole</enum>
|
||||||
</property>
|
</property>
|
||||||
@@ -451,6 +454,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&About</string>
|
<string>&About</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Open About Dialog</string>
|
||||||
|
</property>
|
||||||
<property name="menuRole">
|
<property name="menuRole">
|
||||||
<enum>QAction::AboutRole</enum>
|
<enum>QAction::AboutRole</enum>
|
||||||
</property>
|
</property>
|
||||||
@@ -467,6 +473,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&Open Database…</string>
|
<string>&Open Database…</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Open Database</string>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionDatabaseSave">
|
<action name="actionDatabaseSave">
|
||||||
<property name="enabled">
|
<property name="enabled">
|
||||||
@@ -489,7 +498,7 @@
|
|||||||
<string>&New Database…</string>
|
<string>&New Database…</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Create a new database</string>
|
<string>Create Database</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionDatabaseMerge">
|
<action name="actionDatabaseMerge">
|
||||||
@@ -497,7 +506,7 @@
|
|||||||
<string>&Merge From Database…</string>
|
<string>&Merge From Database…</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Merge from another KDBX database</string>
|
<string>Merge From Database</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionEntryNew">
|
<action name="actionEntryNew">
|
||||||
@@ -508,7 +517,7 @@
|
|||||||
<string>&New Entry…</string>
|
<string>&New Entry…</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Add a new entry</string>
|
<string>Create Entry</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionEntryEdit">
|
<action name="actionEntryEdit">
|
||||||
@@ -519,7 +528,7 @@
|
|||||||
<string>&Edit Entry…</string>
|
<string>&Edit Entry…</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>View or edit entry</string>
|
<string>Edit Entry</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionEntryDelete">
|
<action name="actionEntryDelete">
|
||||||
@@ -529,6 +538,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&Delete Entry…</string>
|
<string>&Delete Entry…</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Delete Entry</string>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionGroupNew">
|
<action name="actionGroupNew">
|
||||||
<property name="enabled">
|
<property name="enabled">
|
||||||
@@ -538,7 +550,7 @@
|
|||||||
<string>&New Group…</string>
|
<string>&New Group…</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Add a new group</string>
|
<string>Create Group</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionGroupEdit">
|
<action name="actionGroupEdit">
|
||||||
@@ -548,6 +560,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&Edit Group…</string>
|
<string>&Edit Group…</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Edit Group</string>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionGroupDelete">
|
<action name="actionGroupDelete">
|
||||||
<property name="enabled">
|
<property name="enabled">
|
||||||
@@ -556,6 +571,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&Delete Group…</string>
|
<string>&Delete Group…</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Delete Group</string>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionGroupDownloadFavicons">
|
<action name="actionGroupDownloadFavicons">
|
||||||
<property name="enabled">
|
<property name="enabled">
|
||||||
@@ -564,6 +582,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Download All &Favicons…</string>
|
<string>Download All &Favicons…</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Download All Favicons</string>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionGroupSortAsc">
|
<action name="actionGroupSortAsc">
|
||||||
<property name="enabled">
|
<property name="enabled">
|
||||||
@@ -572,6 +593,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Sort &A-Z</string>
|
<string>Sort &A-Z</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Sort Groups A-Z</string>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionGroupSortDesc">
|
<action name="actionGroupSortDesc">
|
||||||
<property name="enabled">
|
<property name="enabled">
|
||||||
@@ -580,6 +604,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Sort &Z-A</string>
|
<string>Sort &Z-A</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Sort Groups Z-A</string>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionDatabaseSaveAs">
|
<action name="actionDatabaseSaveAs">
|
||||||
<property name="enabled">
|
<property name="enabled">
|
||||||
@@ -588,6 +615,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Sa&ve Database As…</string>
|
<string>Sa&ve Database As…</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Save Database As</string>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionDatabaseSecurity">
|
<action name="actionDatabaseSecurity">
|
||||||
<property name="enabled">
|
<property name="enabled">
|
||||||
@@ -596,6 +626,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Database &Security…</string>
|
<string>Database &Security…</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Show Database Security</string>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionReports">
|
<action name="actionReports">
|
||||||
<property name="enabled">
|
<property name="enabled">
|
||||||
@@ -605,7 +638,7 @@
|
|||||||
<string>Database &Reports…</string>
|
<string>Database &Reports…</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Statistics, health check, etc.</string>
|
<string>Show Database Reports</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="menuRole">
|
<property name="menuRole">
|
||||||
<enum>QAction::NoRole</enum>
|
<enum>QAction::NoRole</enum>
|
||||||
@@ -619,7 +652,7 @@
|
|||||||
<string>&Database Settings…</string>
|
<string>&Database Settings…</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Database settings</string>
|
<string>Show Database Settings</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="menuRole">
|
<property name="menuRole">
|
||||||
<enum>QAction::NoRole</enum>
|
<enum>QAction::NoRole</enum>
|
||||||
@@ -633,7 +666,7 @@
|
|||||||
<string>Passkeys…</string>
|
<string>Passkeys…</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Passkeys</string>
|
<string>Show Passkeys</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="menuRole">
|
<property name="menuRole">
|
||||||
<enum>QAction::NoRole</enum>
|
<enum>QAction::NoRole</enum>
|
||||||
@@ -660,6 +693,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&Clone Entry…</string>
|
<string>&Clone Entry…</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Clone Entry</string>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionEntryMoveUp">
|
<action name="actionEntryMoveUp">
|
||||||
<property name="enabled">
|
<property name="enabled">
|
||||||
@@ -669,7 +705,7 @@
|
|||||||
<string>Move u&p</string>
|
<string>Move u&p</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Move entry one step up</string>
|
<string>Move Entry Up</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionEntryMoveDown">
|
<action name="actionEntryMoveDown">
|
||||||
@@ -680,7 +716,7 @@
|
|||||||
<string>Move do&wn</string>
|
<string>Move do&wn</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Move entry one step down</string>
|
<string>Move Entry Down</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionEntryCopyUsername">
|
<action name="actionEntryCopyUsername">
|
||||||
@@ -691,7 +727,7 @@
|
|||||||
<string>Copy &Username</string>
|
<string>Copy &Username</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Copy username to clipboard</string>
|
<string>Copy Username</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionEntryCopyPassword">
|
<action name="actionEntryCopyPassword">
|
||||||
@@ -702,7 +738,7 @@
|
|||||||
<string>Copy &Password</string>
|
<string>Copy &Password</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Copy password to clipboard</string>
|
<string>Copy Password</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionSettings">
|
<action name="actionSettings">
|
||||||
@@ -712,6 +748,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&Settings</string>
|
<string>&Settings</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Show Application Settings</string>
|
||||||
|
</property>
|
||||||
<property name="menuRole">
|
<property name="menuRole">
|
||||||
<enum>QAction::PreferencesRole</enum>
|
<enum>QAction::PreferencesRole</enum>
|
||||||
</property>
|
</property>
|
||||||
@@ -723,6 +762,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&Password Generator</string>
|
<string>&Password Generator</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Show Password Generator</string>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionEntryAutoType">
|
<action name="actionEntryAutoType">
|
||||||
<property name="enabled">
|
<property name="enabled">
|
||||||
@@ -751,7 +793,7 @@
|
|||||||
<string notr="true">{USERNAME}</string>
|
<string notr="true">{USERNAME}</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string notr="true">{USERNAME}</string>
|
<string>Perform Auto-Type: {USERNAME}</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionEntryAutoTypeUsernameEnter">
|
<action name="actionEntryAutoTypeUsernameEnter">
|
||||||
@@ -765,7 +807,7 @@
|
|||||||
<string notr="true">{USERNAME}{ENTER}</string>
|
<string notr="true">{USERNAME}{ENTER}</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string notr="true">{USERNAME}{ENTER}</string>
|
<string>Perform Auto-Type: {USERNAME}{ENTER}</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionEntryAutoTypePassword">
|
<action name="actionEntryAutoTypePassword">
|
||||||
@@ -779,7 +821,7 @@
|
|||||||
<string notr="true">{PASSWORD}</string>
|
<string notr="true">{PASSWORD}</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string notr="true">{PASSWORD}</string>
|
<string>Perform Auto-Type: {PASSWORD}</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionEntryAutoTypePasswordEnter">
|
<action name="actionEntryAutoTypePasswordEnter">
|
||||||
@@ -793,7 +835,7 @@
|
|||||||
<string notr="true">{PASSWORD}{ENTER}</string>
|
<string notr="true">{PASSWORD}{ENTER}</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string notr="true">{PASSWORD}{ENTER}</string>
|
<string>Perform Auto-Type: {PASSWORD}{ENTER}</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionEntryAutoTypeTOTP">
|
<action name="actionEntryAutoTypeTOTP">
|
||||||
@@ -807,7 +849,7 @@
|
|||||||
<string notr="true">{TOTP}</string>
|
<string notr="true">{TOTP}</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string notr="true">{TOTP}</string>
|
<string>Perform Auto-Type: {TOTP}</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionEntryDownloadIcon">
|
<action name="actionEntryDownloadIcon">
|
||||||
@@ -847,7 +889,7 @@
|
|||||||
<string>&Title</string>
|
<string>&Title</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Copy title to clipboard</string>
|
<string>Copy Title</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionEntryCopyURL">
|
<action name="actionEntryCopyURL">
|
||||||
@@ -858,7 +900,7 @@
|
|||||||
<string>Copy &URL</string>
|
<string>Copy &URL</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Copy URL to clipboard</string>
|
<string>Copy URL</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionEntryCopyNotes">
|
<action name="actionEntryCopyNotes">
|
||||||
@@ -869,7 +911,7 @@
|
|||||||
<string>&Notes</string>
|
<string>&Notes</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Copy notes to clipboard</string>
|
<string>Copy Notes</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionExportCsv">
|
<action name="actionExportCsv">
|
||||||
@@ -879,6 +921,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&CSV File…</string>
|
<string>&CSV File…</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Export to CSV</string>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionExportHtml">
|
<action name="actionExportHtml">
|
||||||
<property name="enabled">
|
<property name="enabled">
|
||||||
@@ -887,13 +932,16 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&HTML File…</string>
|
<string>&HTML File…</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Export to HTML</string>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionImportKeePass1">
|
<action name="actionImportKeePass1">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>KeePass 1 Database…</string>
|
<string>KeePass 1 Database…</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Import a KeePass 1 database</string>
|
<string>Import KeePass1 Database</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionImportOpVault">
|
<action name="actionImportOpVault">
|
||||||
@@ -901,7 +949,7 @@
|
|||||||
<string>1Password Vault…</string>
|
<string>1Password Vault…</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Import a 1Password Vault</string>
|
<string>Import 1Password Vault</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionImportCsv">
|
<action name="actionImportCsv">
|
||||||
@@ -909,7 +957,7 @@
|
|||||||
<string>CSV File…</string>
|
<string>CSV File…</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Import a CSV file</string>
|
<string>Import CSV File</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionEntryTotp">
|
<action name="actionEntryTotp">
|
||||||
@@ -921,11 +969,17 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Show QR Code</string>
|
<string>Show QR Code</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Show TOTP QR Code</string>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionEntrySetupTotp">
|
<action name="actionEntrySetupTotp">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Set up TOTP…</string>
|
<string>Set up TOTP…</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Set up TOTP</string>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionEntryCopyTotp">
|
<action name="actionEntryCopyTotp">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@@ -941,6 +995,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>E&mpty recycle bin</string>
|
<string>E&mpty recycle bin</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Empty Recycle Bin</string>
|
||||||
|
</property>
|
||||||
<property name="visible">
|
<property name="visible">
|
||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
@@ -949,11 +1006,17 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&Donate</string>
|
<string>&Donate</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Open Donation Website</string>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionBugReport">
|
<action name="actionBugReport">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Report a &Bug</string>
|
<string>Report a &Bug</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Open Bug Report</string>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionGettingStarted">
|
<action name="actionGettingStarted">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@@ -968,7 +1031,7 @@
|
|||||||
<string>&Online Help</string>
|
<string>&Online Help</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Go to online documentation</string>
|
<string>Open Online Documentation</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionUserGuide">
|
<action name="actionUserGuide">
|
||||||
@@ -983,6 +1046,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&Keyboard Shortcuts</string>
|
<string>&Keyboard Shortcuts</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Open Keyboard Shortcuts Guide</string>
|
||||||
|
</property>
|
||||||
<property name="shortcut">
|
<property name="shortcut">
|
||||||
<string notr="true">Ctrl+/</string>
|
<string notr="true">Ctrl+/</string>
|
||||||
</property>
|
</property>
|
||||||
@@ -994,16 +1060,25 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Save Database Backup…</string>
|
<string>Save Database Backup…</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Save Database Backup</string>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionEntryAddToAgent">
|
<action name="actionEntryAddToAgent">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Add key to SSH Agent</string>
|
<string>Add key to SSH Agent</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>SSH Agent: Add Key</string>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionEntryRemoveFromAgent">
|
<action name="actionEntryRemoveFromAgent">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Remove key from SSH Agent</string>
|
<string>Remove key from SSH Agent</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>SSH Agent: Remove Key</string>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionCompactMode">
|
<action name="actionCompactMode">
|
||||||
<property name="checkable">
|
<property name="checkable">
|
||||||
@@ -1012,6 +1087,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Compact Mode</string>
|
<string>Compact Mode</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Toggle Compact Mode</string>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionThemeAuto">
|
<action name="actionThemeAuto">
|
||||||
<property name="checkable">
|
<property name="checkable">
|
||||||
@@ -1023,6 +1101,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Automatic</string>
|
<string>Automatic</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Set Theme: Automatic</string>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionThemeLight">
|
<action name="actionThemeLight">
|
||||||
<property name="checkable">
|
<property name="checkable">
|
||||||
@@ -1031,6 +1112,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Light</string>
|
<string>Light</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Set Theme: Light</string>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionThemeDark">
|
<action name="actionThemeDark">
|
||||||
<property name="checkable">
|
<property name="checkable">
|
||||||
@@ -1039,6 +1123,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Dark</string>
|
<string>Dark</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Set Theme: Dark</string>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionThemeClassic">
|
<action name="actionThemeClassic">
|
||||||
<property name="checkable">
|
<property name="checkable">
|
||||||
@@ -1047,6 +1134,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Classic (Platform-native)</string>
|
<string>Classic (Platform-native)</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Set Theme: Classic</string>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionShowToolbar">
|
<action name="actionShowToolbar">
|
||||||
<property name="checkable">
|
<property name="checkable">
|
||||||
@@ -1058,6 +1148,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Show Toolbar</string>
|
<string>Show Toolbar</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Toggle Show Toolbar</string>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionShowPreviewPanel">
|
<action name="actionShowPreviewPanel">
|
||||||
<property name="checkable">
|
<property name="checkable">
|
||||||
@@ -1069,6 +1162,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Show Preview Panel</string>
|
<string>Show Preview Panel</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Toggle Show Preview Panel</string>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionAlwaysOnTop">
|
<action name="actionAlwaysOnTop">
|
||||||
<property name="checkable">
|
<property name="checkable">
|
||||||
@@ -1077,6 +1173,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Always on Top</string>
|
<string>Always on Top</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Toggle Always on Top</string>
|
||||||
|
</property>
|
||||||
<property name="shortcut">
|
<property name="shortcut">
|
||||||
<string notr="true">Ctrl+Shift+A</string>
|
<string notr="true">Ctrl+Shift+A</string>
|
||||||
</property>
|
</property>
|
||||||
@@ -1088,6 +1187,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Hide Usernames</string>
|
<string>Hide Usernames</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Toggle Hide Usernames</string>
|
||||||
|
</property>
|
||||||
<property name="shortcut">
|
<property name="shortcut">
|
||||||
<string notr="true">Ctrl+Shift+B</string>
|
<string notr="true">Ctrl+Shift+B</string>
|
||||||
</property>
|
</property>
|
||||||
@@ -1102,6 +1204,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Hide Passwords</string>
|
<string>Hide Passwords</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Toggle Hide Passwords</string>
|
||||||
|
</property>
|
||||||
<property name="shortcut">
|
<property name="shortcut">
|
||||||
<string notr="true">Ctrl+Shift+C</string>
|
<string notr="true">Ctrl+Shift+C</string>
|
||||||
</property>
|
</property>
|
||||||
@@ -1114,7 +1219,7 @@
|
|||||||
<string notr="true">{USERNAME}{TAB}{PASSWORD}{ENTER}</string>
|
<string notr="true">{USERNAME}{TAB}{PASSWORD}{ENTER}</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string notr="true">{USERNAME}{TAB}{PASSWORD}{ENTER}</string>
|
<string notr="true">Perform Auto-Type: Entry Default</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionGroupClone">
|
<action name="actionGroupClone">
|
||||||
@@ -1130,7 +1235,7 @@
|
|||||||
<string notr="true" extracomment="Translatable string with plural form set in CPP file">Restore Entry(s)</string>
|
<string notr="true" extracomment="Translatable string with plural form set in CPP file">Restore Entry(s)</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string notr="true" extracomment="Translatable string with plural form set in CPP file">Restore Entry(s)</string>
|
<string notr="true" extracomment="Translatable string with plural form set in CPP file">Restore Entry</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="shortcut">
|
<property name="shortcut">
|
||||||
<string notr="true">Ctrl+R</string>
|
<string notr="true">Ctrl+R</string>
|
||||||
@@ -1152,7 +1257,7 @@
|
|||||||
<string>&XML File…</string>
|
<string>&XML File…</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>XML File…</string>
|
<string>Export to XML</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionAllowScreenCapture">
|
<action name="actionAllowScreenCapture">
|
||||||
@@ -1162,6 +1267,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Allow Screen Capture</string>
|
<string>Allow Screen Capture</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Toggle Allow Screen Capture</string>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
|
|||||||
282
src/gui/ShortcutSettingsPage.cpp
Normal file
282
src/gui/ShortcutSettingsPage.cpp
Normal file
@@ -0,0 +1,282 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 KeePassXC Team <team@keepassxc.org>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ShortcutSettingsPage.h"
|
||||||
|
|
||||||
|
#include "core/Config.h"
|
||||||
|
#include "gui/ActionCollection.h"
|
||||||
|
#include "gui/Icons.h"
|
||||||
|
#include "gui/MessageBox.h"
|
||||||
|
#include "gui/widgets/ShortcutWidget.h"
|
||||||
|
|
||||||
|
#include <QAbstractButton>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QDialogButtonBox>
|
||||||
|
#include <QHeaderView>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QSortFilterProxyModel>
|
||||||
|
#include <QStandardItemModel>
|
||||||
|
#include <QTableView>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
|
class KeySequenceDialog final : public QDialog
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit KeySequenceDialog(QWidget* parent = nullptr)
|
||||||
|
: QDialog(parent)
|
||||||
|
, m_keySeqEdit(new ShortcutWidget(this))
|
||||||
|
, m_btnBox(new QDialogButtonBox(QDialogButtonBox::Save | QDialogButtonBox::Cancel
|
||||||
|
| QDialogButtonBox::RestoreDefaults,
|
||||||
|
this))
|
||||||
|
{
|
||||||
|
auto* l = new QVBoxLayout(this);
|
||||||
|
connect(m_btnBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
||||||
|
connect(m_btnBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||||
|
connect(m_btnBox, &QDialogButtonBox::clicked, this, &KeySequenceDialog::restoreDefault);
|
||||||
|
|
||||||
|
auto hLayout = new QHBoxLayout();
|
||||||
|
l->addLayout(hLayout);
|
||||||
|
hLayout->addWidget(new QLabel(QObject::tr("Enter Shortcut")));
|
||||||
|
hLayout->addWidget(m_keySeqEdit);
|
||||||
|
|
||||||
|
l->addStretch();
|
||||||
|
l->addWidget(m_btnBox);
|
||||||
|
|
||||||
|
setFocusProxy(m_keySeqEdit);
|
||||||
|
}
|
||||||
|
|
||||||
|
QKeySequence keySequence() const
|
||||||
|
{
|
||||||
|
return m_keySeqEdit->sequence();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool shouldRestoreDefault() const
|
||||||
|
{
|
||||||
|
return m_restoreDefault;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void restoreDefault(QAbstractButton* btn)
|
||||||
|
{
|
||||||
|
if (m_btnBox->standardButton(btn) == QDialogButtonBox::RestoreDefaults) {
|
||||||
|
m_restoreDefault = true;
|
||||||
|
reject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_restoreDefault = false;
|
||||||
|
ShortcutWidget* const m_keySeqEdit;
|
||||||
|
QDialogButtonBox* const m_btnBox;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ShortcutSettingsWidget final : public QWidget
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit ShortcutSettingsWidget(QWidget* parent = nullptr)
|
||||||
|
: QWidget(parent)
|
||||||
|
, m_tableView(new QTableView(this))
|
||||||
|
, m_filterLineEdit(new QLineEdit(this))
|
||||||
|
, m_resetShortcutsButton(new QPushButton(tr("Reset Shortcuts"), this))
|
||||||
|
{
|
||||||
|
auto h = new QHBoxLayout();
|
||||||
|
h->addWidget(m_filterLineEdit);
|
||||||
|
h->addWidget(m_resetShortcutsButton);
|
||||||
|
h->setStretch(0, 1);
|
||||||
|
|
||||||
|
auto l = new QVBoxLayout(this);
|
||||||
|
l->addWidget(new QLabel(tr("Double click an action to change its shortcut")));
|
||||||
|
l->addLayout(h);
|
||||||
|
l->addWidget(m_tableView);
|
||||||
|
|
||||||
|
m_model.setColumnCount(2);
|
||||||
|
m_model.setHorizontalHeaderLabels({QObject::tr("Action"), QObject::tr("Shortcuts")});
|
||||||
|
|
||||||
|
m_proxy.setFilterKeyColumn(-1);
|
||||||
|
m_proxy.setFilterCaseSensitivity(Qt::CaseInsensitive);
|
||||||
|
m_proxy.setSourceModel(&m_model);
|
||||||
|
|
||||||
|
m_filterLineEdit->setPlaceholderText(tr("Filter..."));
|
||||||
|
connect(m_filterLineEdit, &QLineEdit::textChanged, &m_proxy, &QSortFilterProxyModel::setFilterFixedString);
|
||||||
|
|
||||||
|
connect(m_resetShortcutsButton, &QPushButton::clicked, this, [this]() {
|
||||||
|
auto ac = ActionCollection::instance();
|
||||||
|
for (auto action : ac->actions()) {
|
||||||
|
action->setShortcut(ac->defaultShortcut(action));
|
||||||
|
}
|
||||||
|
loadSettings();
|
||||||
|
});
|
||||||
|
|
||||||
|
m_tableView->setModel(&m_proxy);
|
||||||
|
m_tableView->setSortingEnabled(true);
|
||||||
|
m_tableView->sortByColumn(0, Qt::AscendingOrder);
|
||||||
|
m_tableView->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
|
||||||
|
m_tableView->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch);
|
||||||
|
m_tableView->verticalHeader()->hide();
|
||||||
|
m_tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||||
|
m_tableView->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||||
|
m_tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||||
|
|
||||||
|
connect(m_tableView, &QTableView::doubleClicked, this, &ShortcutSettingsWidget::onDoubleClicked);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadSettings()
|
||||||
|
{
|
||||||
|
m_changedActions.clear();
|
||||||
|
m_filterLineEdit->clear();
|
||||||
|
m_model.setRowCount(0);
|
||||||
|
const auto& actions = ActionCollection::instance()->actions();
|
||||||
|
for (auto a : actions) {
|
||||||
|
auto name = a->toolTip().isEmpty() ? acceleratorsStrippedText(a->text()) : a->toolTip();
|
||||||
|
auto col1 = new QStandardItem(name);
|
||||||
|
col1->setData(QVariant::fromValue(a), Qt::UserRole);
|
||||||
|
auto col2 = new QStandardItem(a->shortcut().toString());
|
||||||
|
m_model.appendRow({col1, col2});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void saveSettings()
|
||||||
|
{
|
||||||
|
if (m_changedActions.count()) {
|
||||||
|
for (const auto& action : m_changedActions.keys()) {
|
||||||
|
action->setShortcut(m_changedActions.value(action));
|
||||||
|
}
|
||||||
|
ActionCollection::instance()->saveShortcuts();
|
||||||
|
}
|
||||||
|
m_changedActions.clear();
|
||||||
|
m_filterLineEdit->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static QString acceleratorsStrippedText(QString text)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < text.size(); ++i) {
|
||||||
|
if (text.at(i) == QLatin1Char('&') && i + 1 < text.size() && text.at(i + 1) != QLatin1Char('&')) {
|
||||||
|
text.remove(i, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
void onDoubleClicked(QModelIndex index)
|
||||||
|
{
|
||||||
|
if (index.column() != 0) {
|
||||||
|
index = index.sibling(index.row(), 0);
|
||||||
|
}
|
||||||
|
index = m_proxy.mapToSource(index);
|
||||||
|
auto action = index.data(Qt::UserRole).value<QAction*>();
|
||||||
|
|
||||||
|
KeySequenceDialog dialog(this);
|
||||||
|
int ret = dialog.exec();
|
||||||
|
|
||||||
|
QKeySequence change;
|
||||||
|
if (ret == QDialog::Accepted) {
|
||||||
|
change = dialog.keySequence();
|
||||||
|
} else if (dialog.shouldRestoreDefault()) {
|
||||||
|
change = ActionCollection::instance()->defaultShortcut(action);
|
||||||
|
} else {
|
||||||
|
// Rejected
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto conflict = ActionCollection::instance()->isConflictingShortcut(action, change);
|
||||||
|
bool hasConflict = false;
|
||||||
|
if (conflict) {
|
||||||
|
// we conflicted with an action inside action collection
|
||||||
|
// check if the conflicted action is updated here
|
||||||
|
if (!m_changedActions.contains(conflict)) {
|
||||||
|
hasConflict = true;
|
||||||
|
} else {
|
||||||
|
if (m_changedActions.value(conflict) == change) {
|
||||||
|
hasConflict = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (!change.isEmpty()) {
|
||||||
|
// we did not conflict with any shortcut inside action collection
|
||||||
|
// check if we conflict with any locally modified action
|
||||||
|
for (auto chAction : m_changedActions.keys()) {
|
||||||
|
if (m_changedActions.value(chAction) == change) {
|
||||||
|
hasConflict = true;
|
||||||
|
conflict = chAction;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasConflict) {
|
||||||
|
auto conflictName =
|
||||||
|
conflict->toolTip().isEmpty() ? acceleratorsStrippedText(conflict->text()) : conflict->toolTip();
|
||||||
|
auto conflictSeq = change.toString();
|
||||||
|
|
||||||
|
auto ans = MessageBox::question(
|
||||||
|
this,
|
||||||
|
tr("Shortcut Conflict"),
|
||||||
|
tr("Shortcut %1 conflicts with '%2'. Overwrite shortcut?").arg(conflictSeq, conflictName),
|
||||||
|
MessageBox::Overwrite | MessageBox::Discard,
|
||||||
|
MessageBox::Discard);
|
||||||
|
if (ans == MessageBox::Discard) {
|
||||||
|
// Bail out before making any changes
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset the conflict shortcut
|
||||||
|
m_changedActions[conflict] = {};
|
||||||
|
for (auto item : m_model.findItems(conflictSeq, Qt::MatchExactly, 1)) {
|
||||||
|
item->setText("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_changedActions[action] = change;
|
||||||
|
auto item = m_model.itemFromIndex(index.sibling(index.row(), 1));
|
||||||
|
item->setText(change.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
QTableView* m_tableView;
|
||||||
|
QLineEdit* m_filterLineEdit;
|
||||||
|
QPushButton* m_resetShortcutsButton;
|
||||||
|
QStandardItemModel m_model;
|
||||||
|
QSortFilterProxyModel m_proxy;
|
||||||
|
QHash<QAction*, QKeySequence> m_changedActions;
|
||||||
|
};
|
||||||
|
|
||||||
|
QString ShortcutSettingsPage::name()
|
||||||
|
{
|
||||||
|
return QObject::tr("Shortcuts");
|
||||||
|
}
|
||||||
|
|
||||||
|
QIcon ShortcutSettingsPage::icon()
|
||||||
|
{
|
||||||
|
return icons()->icon("auto-type");
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget* ShortcutSettingsPage::createWidget()
|
||||||
|
{
|
||||||
|
return new ShortcutSettingsWidget();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShortcutSettingsPage::loadSettings(QWidget* widget)
|
||||||
|
{
|
||||||
|
static_cast<ShortcutSettingsWidget*>(widget)->loadSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShortcutSettingsPage::saveSettings(QWidget* widget)
|
||||||
|
{
|
||||||
|
static_cast<ShortcutSettingsWidget*>(widget)->saveSettings();
|
||||||
|
}
|
||||||
36
src/gui/ShortcutSettingsPage.h
Normal file
36
src/gui/ShortcutSettingsPage.h
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 KeePassXC Team <team@keepassxc.org>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef KEEPASSXC_SHORTCUT_SETTINGSPAGE_H
|
||||||
|
#define KEEPASSXC_SHORTCUT_SETTINGSPAGE_H
|
||||||
|
|
||||||
|
#include "gui/ApplicationSettingsWidget.h"
|
||||||
|
|
||||||
|
class ShortcutSettingsPage : public ISettingsPage
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit ShortcutSettingsPage() = default;
|
||||||
|
~ShortcutSettingsPage() override = default;
|
||||||
|
|
||||||
|
QString name() override;
|
||||||
|
QIcon icon() override;
|
||||||
|
QWidget* createWidget() override;
|
||||||
|
void loadSettings(QWidget* widget) override;
|
||||||
|
void saveSettings(QWidget* widget) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // KEEPASSXC_BROWSERSETTINGSPAGE_H
|
||||||
@@ -20,13 +20,8 @@
|
|||||||
#include <QKeyEvent>
|
#include <QKeyEvent>
|
||||||
#include <QToolTip>
|
#include <QToolTip>
|
||||||
|
|
||||||
#include "autotype/AutoType.h"
|
|
||||||
|
|
||||||
ShortcutWidget::ShortcutWidget(QWidget* parent)
|
ShortcutWidget::ShortcutWidget(QWidget* parent)
|
||||||
: QLineEdit(parent)
|
: QLineEdit(parent)
|
||||||
, m_key(static_cast<Qt::Key>(0))
|
|
||||||
, m_modifiers(nullptr)
|
|
||||||
, m_locked(false)
|
|
||||||
{
|
{
|
||||||
setReadOnly(true);
|
setReadOnly(true);
|
||||||
}
|
}
|
||||||
@@ -41,6 +36,11 @@ Qt::KeyboardModifiers ShortcutWidget::modifiers() const
|
|||||||
return m_modifiers;
|
return m_modifiers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QKeySequence ShortcutWidget::sequence() const
|
||||||
|
{
|
||||||
|
return (m_key == Qt::Key_unknown) ? QKeySequence() : QKeySequence(m_key | m_modifiers);
|
||||||
|
}
|
||||||
|
|
||||||
void ShortcutWidget::setShortcut(Qt::Key key, Qt::KeyboardModifiers modifiers)
|
void ShortcutWidget::setShortcut(Qt::Key key, Qt::KeyboardModifiers modifiers)
|
||||||
{
|
{
|
||||||
m_key = key;
|
m_key = key;
|
||||||
@@ -48,22 +48,15 @@ void ShortcutWidget::setShortcut(Qt::Key key, Qt::KeyboardModifiers modifiers)
|
|||||||
m_locked = true;
|
m_locked = true;
|
||||||
|
|
||||||
displayShortcut(m_key, m_modifiers);
|
displayShortcut(m_key, m_modifiers);
|
||||||
|
emit shortcutChanged(m_key, m_modifiers);
|
||||||
QString error;
|
|
||||||
if (autoType()->registerGlobalShortcut(m_key, m_modifiers, &error)) {
|
|
||||||
setStyleSheet("");
|
|
||||||
} else {
|
|
||||||
QToolTip::showText(mapToGlobal(rect().bottomLeft()), error);
|
|
||||||
setStyleSheet("background-color: #FF9696;");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShortcutWidget::resetShortcut()
|
void ShortcutWidget::resetShortcut()
|
||||||
{
|
{
|
||||||
m_key = static_cast<Qt::Key>(0);
|
m_key = Qt::Key_unknown;
|
||||||
m_modifiers = nullptr;
|
m_modifiers = Qt::NoModifier;
|
||||||
m_locked = false;
|
m_locked = false;
|
||||||
autoType()->unregisterGlobalShortcut();
|
emit shortcutReset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShortcutWidget::keyPressEvent(QKeyEvent* event)
|
void ShortcutWidget::keyPressEvent(QKeyEvent* event)
|
||||||
@@ -116,13 +109,11 @@ void ShortcutWidget::keyEvent(QKeyEvent* event)
|
|||||||
setShortcut(key, modifiers);
|
setShortcut(key, modifiers);
|
||||||
} else {
|
} else {
|
||||||
resetShortcut();
|
resetShortcut();
|
||||||
setStyleSheet("");
|
|
||||||
displayShortcut(key, modifiers);
|
displayShortcut(key, modifiers);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (m_locked) {
|
if (m_locked) {
|
||||||
resetShortcut();
|
resetShortcut();
|
||||||
setStyleSheet("");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
displayShortcut(static_cast<Qt::Key>(0), modifiers);
|
displayShortcut(static_cast<Qt::Key>(0), modifiers);
|
||||||
@@ -18,6 +18,7 @@
|
|||||||
#ifndef KEEPASSX_SHORTCUTWIDGET_H
|
#ifndef KEEPASSX_SHORTCUTWIDGET_H
|
||||||
#define KEEPASSX_SHORTCUTWIDGET_H
|
#define KEEPASSX_SHORTCUTWIDGET_H
|
||||||
|
|
||||||
|
#include <QKeySequence>
|
||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
|
|
||||||
class ShortcutWidget : public QLineEdit
|
class ShortcutWidget : public QLineEdit
|
||||||
@@ -26,10 +27,17 @@ class ShortcutWidget : public QLineEdit
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ShortcutWidget(QWidget* parent = nullptr);
|
explicit ShortcutWidget(QWidget* parent = nullptr);
|
||||||
|
|
||||||
Qt::Key key() const;
|
Qt::Key key() const;
|
||||||
Qt::KeyboardModifiers modifiers() const;
|
Qt::KeyboardModifiers modifiers() const;
|
||||||
|
QKeySequence sequence() const;
|
||||||
|
|
||||||
void setShortcut(Qt::Key key, Qt::KeyboardModifiers modifiers);
|
void setShortcut(Qt::Key key, Qt::KeyboardModifiers modifiers);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void shortcutChanged(Qt::Key key, Qt::KeyboardModifiers modifiers);
|
||||||
|
void shortcutReset();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void keyPressEvent(QKeyEvent* event) override;
|
void keyPressEvent(QKeyEvent* event) override;
|
||||||
void keyReleaseEvent(QKeyEvent* event) override;
|
void keyReleaseEvent(QKeyEvent* event) override;
|
||||||
@@ -39,9 +47,9 @@ private:
|
|||||||
void displayShortcut(Qt::Key key, Qt::KeyboardModifiers modifiers);
|
void displayShortcut(Qt::Key key, Qt::KeyboardModifiers modifiers);
|
||||||
void resetShortcut();
|
void resetShortcut();
|
||||||
|
|
||||||
Qt::Key m_key;
|
Qt::Key m_key = Qt::Key_unknown;
|
||||||
Qt::KeyboardModifiers m_modifiers;
|
Qt::KeyboardModifiers m_modifiers = Qt::NoModifier;
|
||||||
bool m_locked;
|
bool m_locked = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // KEEPASSX_SHORTCUTWIDGET_H
|
#endif // KEEPASSX_SHORTCUTWIDGET_H
|
||||||
@@ -33,6 +33,7 @@
|
|||||||
#include "config-keepassx-tests.h"
|
#include "config-keepassx-tests.h"
|
||||||
#include "core/Tools.h"
|
#include "core/Tools.h"
|
||||||
#include "crypto/Crypto.h"
|
#include "crypto/Crypto.h"
|
||||||
|
#include "gui/ActionCollection.h"
|
||||||
#include "gui/ApplicationSettingsWidget.h"
|
#include "gui/ApplicationSettingsWidget.h"
|
||||||
#include "gui/CategoryListWidget.h"
|
#include "gui/CategoryListWidget.h"
|
||||||
#include "gui/CloneDialog.h"
|
#include "gui/CloneDialog.h"
|
||||||
@@ -43,6 +44,7 @@
|
|||||||
#include "gui/PasswordGeneratorWidget.h"
|
#include "gui/PasswordGeneratorWidget.h"
|
||||||
#include "gui/PasswordWidget.h"
|
#include "gui/PasswordWidget.h"
|
||||||
#include "gui/SearchWidget.h"
|
#include "gui/SearchWidget.h"
|
||||||
|
#include "gui/ShortcutSettingsPage.h"
|
||||||
#include "gui/TotpDialog.h"
|
#include "gui/TotpDialog.h"
|
||||||
#include "gui/TotpSetupDialog.h"
|
#include "gui/TotpSetupDialog.h"
|
||||||
#include "gui/databasekey/KeyFileEditWidget.h"
|
#include "gui/databasekey/KeyFileEditWidget.h"
|
||||||
@@ -1851,6 +1853,52 @@ void TestGui::testTrayRestoreHide()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestGui::testShortcutConfig()
|
||||||
|
{
|
||||||
|
// Action collection should not be empty
|
||||||
|
QVERIFY(!ActionCollection::instance()->actions().isEmpty());
|
||||||
|
|
||||||
|
// Add an action, make sure it gets added
|
||||||
|
QAction* a = new QAction(ActionCollection::instance());
|
||||||
|
a->setObjectName("MyAction1");
|
||||||
|
ActionCollection::instance()->addAction(a);
|
||||||
|
QVERIFY(ActionCollection::instance()->actions().contains(a));
|
||||||
|
|
||||||
|
const QKeySequence seq(Qt::CTRL + Qt::SHIFT + Qt::ALT + Qt::Key_N);
|
||||||
|
ActionCollection::instance()->setDefaultShortcut(a, seq);
|
||||||
|
QCOMPARE(ActionCollection::instance()->defaultShortcut(a), seq);
|
||||||
|
|
||||||
|
bool v = false;
|
||||||
|
m_mainWindow->addAction(a);
|
||||||
|
connect(a, &QAction::triggered, ActionCollection::instance(), [&v] { v = !v; });
|
||||||
|
QTest::keyClick(m_mainWindow.data(), Qt::Key_N, Qt::ControlModifier | Qt::ShiftModifier | Qt::AltModifier);
|
||||||
|
QVERIFY(v);
|
||||||
|
|
||||||
|
// Change shortcut and save
|
||||||
|
const QKeySequence newSeq(Qt::CTRL + Qt::SHIFT + Qt::ALT + Qt::Key_M);
|
||||||
|
a->setShortcut(newSeq);
|
||||||
|
QVERIFY(a->shortcut() != ActionCollection::instance()->defaultShortcut(a));
|
||||||
|
ActionCollection::instance()->saveShortcuts();
|
||||||
|
QCOMPARE(a->shortcut(), newSeq);
|
||||||
|
const auto shortcuts = Config::instance()->getShortcuts();
|
||||||
|
Config::ShortcutEntry entryForA;
|
||||||
|
for (const auto& s : shortcuts) {
|
||||||
|
if (s.name == a->objectName()) {
|
||||||
|
entryForA = s;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QCOMPARE(entryForA.name, a->objectName());
|
||||||
|
QCOMPARE(QKeySequence::fromString(entryForA.shortcut), a->shortcut());
|
||||||
|
|
||||||
|
// trigger the old shortcut
|
||||||
|
QTest::keyClick(m_mainWindow.data(), Qt::Key_N, Qt::ControlModifier | Qt::ShiftModifier | Qt::AltModifier);
|
||||||
|
QVERIFY(v); // value of v should not change
|
||||||
|
QTest::keyClick(m_mainWindow.data(), Qt::Key_M, Qt::ControlModifier | Qt::ShiftModifier | Qt::AltModifier);
|
||||||
|
QVERIFY(!v);
|
||||||
|
disconnect(a, nullptr, nullptr, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
void TestGui::testAutoType()
|
void TestGui::testAutoType()
|
||||||
{
|
{
|
||||||
// Clear entries from root group to guarantee order
|
// Clear entries from root group to guarantee order
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ private slots:
|
|||||||
void testSortGroups();
|
void testSortGroups();
|
||||||
void testAutoType();
|
void testAutoType();
|
||||||
void testTrayRestoreHide();
|
void testTrayRestoreHide();
|
||||||
|
void testShortcutConfig();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void addCannedEntries();
|
void addCannedEntries();
|
||||||
|
|||||||
Reference in New Issue
Block a user