diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..15af85b --- /dev/null +++ b/.travis.yml @@ -0,0 +1,19 @@ +os: + - linux + - osx +compiler: + - gcc + - clang +language: cpp +install: + - if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get -qq update; fi + - if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get -qq install cmake libqt4-dev libgcrypt11-dev zlib1g-dev libxtst-dev; fi + - if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew update; fi + - if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew install cmake qt libgcrypt; fi +before_script: mkdir build && pushd build +script: + - cmake -DCMAKE_BUILD_TYPE=Debug -DWITH_GUI_TESTS=ON .. + - make + - if [ "$TRAVIS_OS_NAME" = "linux" ]; then make test ARGS+="-E testgui"; fi + - if [ "$TRAVIS_OS_NAME" = "linux" ]; then xvfb-run -a --server-args="-screen 0 800x600x24" make test ARGS+="-R testgui"; fi + - if [ "$TRAVIS_OS_NAME" = "osx" ]; then make test; fi diff --git a/.tx/config b/.tx/config new file mode 100644 index 0000000..015acf4 --- /dev/null +++ b/.tx/config @@ -0,0 +1,8 @@ +[main] +host = https://www.transifex.com + +[keepassx.keepassx_ents] +source_file = share/translations/keepassx_en.ts +file_filter = share/translations/keepassx_.ts +source_lang = en +type = QT diff --git a/CHANGELOG b/CHANGELOG index 2ffae87..b61597b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,4 @@ -2.0 Alpha 6 (2014-04-06) +2.0 Alpha 6 (2014-04-12) ========================= - Add option to lock databases after user inactivity [#62] diff --git a/CMakeLists.txt b/CMakeLists.txt index 35642eb..3532c46 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,7 +32,7 @@ include(CheckCXXSourceCompiles) option(WITH_TESTS "Enable building of unit tests" ON) option(WITH_GUI_TESTS "Enable building of GUI tests" OFF) option(WITH_LTO "Enable Link Time Optimization (LTO)" OFF) -option(WITH_CXX11 "Build with the C++ 11 standard" OFF) +option(WITH_CXX11 "Build with the C++ 11 standard" ON) set(KEEPASSX_VERSION "2.0 alpha 6") set(KEEPASSX_VERSION_NUM "1.9.85") @@ -165,6 +165,9 @@ endif() find_package(Qt4 4.6.0 REQUIRED ${QT_REQUIRED_MODULES}) include(${QT_USE_FILE}) +# Debian sets the the build type to None for package builds. +# Make sure we don't enable asserts there. +set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_NONE QT_NO_DEBUG) find_package(Gcrypt REQUIRED) if(NOT (${GCRYPT_VERSION_STRING} VERSION_LESS "1.6.0")) diff --git a/INSTALL b/INSTALL index 028ccff..bde991b 100644 --- a/INSTALL +++ b/INSTALL @@ -2,7 +2,7 @@ Building: ========= mkdir build cd build -cmake .. [CMAKE PARAMETERS] +cmake [CMAKE PARAMETERS] .. make [-jX] Common cmake parameters: diff --git a/share/CMakeLists.txt b/share/CMakeLists.txt index 7069c6c..0e2b7fa 100644 --- a/share/CMakeLists.txt +++ b/share/CMakeLists.txt @@ -13,6 +13,8 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +add_subdirectory(translations) + file(GLOB DATABASE_ICONS icons/database/*.png) install(FILES ${DATABASE_ICONS} DESTINATION ${DATA_INSTALL_DIR}/icons/database) diff --git a/share/translations/CMakeLists.txt b/share/translations/CMakeLists.txt new file mode 100644 index 0000000..b1aa878 --- /dev/null +++ b/share/translations/CMakeLists.txt @@ -0,0 +1,26 @@ +# Copyright (C) 2014 Felix Geyer +# +# 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 2 or (at your option) +# version 3 of the License. +# +# 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 . + +file(GLOB TRANSLATION_FILES *.ts) +get_filename_component(TRANSLATION_EN_ABS keepassx_en.ts ABSOLUTE) +list(REMOVE_ITEM TRANSLATION_FILES keepassx_en.ts) +list(REMOVE_ITEM TRANSLATION_FILES ${TRANSLATION_EN_ABS}) +message(STATUS ${TRANSLATION_FILES}) + +qt4_add_translation(QM_FILES ${TRANSLATION_FILES}) + +install(FILES ${QM_FILES} DESTINATION ${DATA_INSTALL_DIR}/translations) +add_custom_target(translations DEPENDS ${QM_FILES}) +add_dependencies(${PROGNAME} translations) diff --git a/share/translations/keepassx_de.ts b/share/translations/keepassx_de.ts new file mode 100644 index 0000000..5433c3c --- /dev/null +++ b/share/translations/keepassx_de.ts @@ -0,0 +1,1177 @@ + + + AboutDialog + + About KeePassX + Über KeePassX + + + KeePassX is distributed under the term of the GNU General Public License (GPL) version 2 or (at your option) version 3. + KeePassX ist unter der GNU General Public License (GPL) version 2 (version 3) veröffentlicht. + + + + AutoType + + Auto-Type - KeePassX + Auto-Type - KeePassX + + + Couldn't find an entry that matches the window title. + Konnte dem Fenstertitel keinen passenden Eintrag zuordnen. + + + + AutoTypeAssociationsModel + + Window + Fenster + + + Sequence + Reihenfolge + + + Default sequence + Standardreihenfolge + + + + AutoTypeSelectDialog + + Auto-Type - KeePassX + Auto-Type - KeePassX + + + Select entry to Auto-Type: + Wählen Sie einen Eintrag für Auto-Type: + + + + ChangeMasterKeyWidget + + Password + Passwort + + + Enter password: + Passwort eingeben: + + + Repeat password: + Passwort wiederholen: + + + Key file + Schlüsseldatei + + + Browse + Durchsuchen + + + Create + Erstellen + + + Key files + Schlüsseldateien + + + All files + Alle Dateien + + + Create Key File... + Erzeuge eine Schlüsseldatei... + + + Error + Fehler + + + Unable to create Key File : + Erzeugen der Schlüsseldatei nicht möglich: + + + Select a key file + Schlüsseldatei auswählen + + + Question + Frage + + + Do you really want to use an empty string as password? + Wollen Sie wirklich eine leere Zeichenkette als Passwort verwenden? + + + Different passwords supplied. + Unterschiedliche Passwörter eingegeben. + + + + DatabaseOpenWidget + + Enter master key + Hauptschlüssel eingeben + + + Key File: + Schlüsseldatei: + + + Password: + Passwort: + + + Browse + Durchsuchen + + + Error + Fehler + + + Unable to open the database. + Öffnen der Datenbank nicht möglich. + + + Can't open key file + Schlüsseldatein kann nicht geöffnet werden + + + All files + Alle Dateien + + + Key files + Schlüsseldateien + + + Select key file + Schlüsseldatei auswählen + + + + DatabaseSettingsWidget + + Database name: + Datenbankname: + + + Database description: + Datenbankbeschreibung: + + + Transform rounds: + Verschlüsselungsdurchläufe: + + + Default username: + Standardbenutzername: + + + Use recycle bin: + Verwende Papierkorb: + + + MiB + MiB + + + Benchmark + Benchmark + + + Max. history items: + Max Einträge im Verlauf: + + + Max. history size: + Max. Verlaufsgröße: + + + + DatabaseTabWidget + + Root + Root + + + KeePass 2 Database + KeePass 2 Datenbank + + + All files + Alle Dateien + + + Open database + Datenbank öffnen + + + Warning + Warnung + + + File not found! + Datei nicht gefunden! + + + Open KeePass 1 database + KeePass 1 Datenbank öffnen + + + KeePass 1 database + KeePass 1 Datenbank + + + All files (*) + Alle Dateien (*) + + + Close? + Schließen? + + + "%1" is in edit mode. +Close anyway? + "%1" wird bearbeitet. +Trotzdem schließen? + + + Save changes? + Änderungen speichern? + + + "%1" was modified. +Save changes? + "%1" wurde geändert. +Änderungen speichern? + + + Error + Fehler + + + Writing the database failed. + Schreiben der Datenbank fehlgeschlagen. + + + Save database as + Datenbank speichern unter + + + New database + Neue Datenbank + + + locked + gesperrt + + + + DatabaseWidget + + Change master key + Hauptschlüssel ändern + + + Delete entry? + Eintrag löschen? + + + Do you really want to delete the entry "%1" for good? + Wollen Sie den Eintrag "%1" wirklich löschen? + + + Delete entries? + Einträge löschen? + + + Do you really want to delete %1 entries for good? + Wollen Sie die Einträge "%1" wirklich löschen? + + + Move entries to recycle bin? + Einträge in den Papierkorb verschieben? + + + Do you really want to move %n entry(s) to the recycle bin? + Wollen Sie wirklich %n Eintrag in den Papierkorb verschieben?Wollen Sie wirklich %n Einträge in den Papierkorb verschieben? + + + Delete group? + Gruppe löschen? + + + Do you really want to delete the group "%1" for good? + Wollen Sie die Gruppe "%1" wirklich löschen? + + + Current group + Aktuelle Gruppe + + + + EditEntryWidget + + Entry + Eintrag + + + Advanced + Fortgeschritten + + + Icon + Symbol + + + Auto-Type + Auto-Type + + + Properties + Eigenschaften + + + History + Verlauf + + + Entry history + Eintragsverlauf + + + Add entry + Eintrag hinzufügen + + + Edit entry + Eintrag bearbeiten + + + Error + Fehler + + + Different passwords supplied. + Unterschiedliche Passwörter eingegeben. + + + New attribute + Neue Eigenschaft + + + Select file + Datei wählen + + + Unable to open file + Öffnen der Datei nicht möglich + + + Save attachment + Anhang speichern + + + Unable to save the attachment: + + Speichern des Anhangs nicht möglich: + + + Tomorrow + Morgen + + + %n week(s) + %n Woche%n Wochen + + + %n month(s) + %n Monat%n Monaten + + + 1 year + 1 Jahr + + + + EditEntryWidgetAdvanced + + Additional attributes + Zusätzliche Eigenschaften + + + Add + Hinzufügen + + + Edit + Bearbeiten + + + Remove + Entfernen + + + Attachments + Anhänge + + + Save + Speichern + + + + EditEntryWidgetAutoType + + Enable Auto-Type for this entry + Auto-Type für diesen Eintrag aktivieren + + + Inherit default Auto-Type sequence from the group + Standard-Auto-Type-Sequenz von der Gruppe erben + + + Use custom Auto-Type sequence: + Benutzerdefinierte Auto-Type-Sequenz benutzen: + + + + + + + + + - + - + + + Window title: + Fenstertitel: + + + Use default sequence + Standardsequenz benutzen + + + Set custom sequence: + Benutzerdefinierte Sequenz verwenden: + + + + EditEntryWidgetHistory + + Show + Anzeigen + + + Restore + Wiederherstellen + + + Delete + Löschen + + + Delete all + Alle löschen + + + + EditEntryWidgetMain + + Title: + Titel: + + + Username: + Benutzername: + + + Password: + Passwort: + + + Repeat: + Wiederholen: + + + Gen. + Gen. + + + URL: + URL: + + + Expires + Erlischt + + + Presets + Vorgaben + + + Notes: + Notizen: + + + + EditGroupWidget + + Group + Gruppe + + + Icon + Symbol + + + Properties + Eigenschaften + + + Add group + Gruppe hinzufügen + + + Edit group + Gruppe bearbeiten + + + Enable + Aktivieren + + + Disable + Deaktivieren + + + Inherit from parent group (%1) + Von der übergeordneten Gruppe (%1) erben + + + + EditGroupWidgetMain + + Name + Name + + + Notes + Notizen + + + Expires + Erlischt + + + Search + Suche + + + Auto-type + Auto-type + + + + EditWidgetIcons + + Use default icon + Standardsymbol verwenden + + + Use custom icon + Benutzerdefiniertes Symbol verwenden + + + Add custom icon + Benutzerdefiniertes Symbol hinzufügen + + + Delete custom icon + Benutzerdefiniertes Symbol löschen + + + Images + Bilder + + + All files + Alle Dateien + + + Select Image + Bild auswählen + + + Can't delete icon! + Symbol kann nicht gelöscht werden! + + + Can't delete icon. Still used by %n item(s). + Symbol kann nicht gelöscht werden. Es wird von %n Eintrag verwendet.Symbol kann nicht gelöscht werden. Es wird von %n Einträgen verwendet. + + + + EditWidgetProperties + + Created: + Erstellt: + + + Modified: + Bearbeitet: + + + Accessed: + Zugegriffen: + + + Uuid: + Uuid: + + + + EntryAttributesModel + + Name + Name + + + + EntryHistoryModel + + Last modified + Zuletzt geändert + + + Title + Titel + + + Username + Benutzername + + + URL + URL + + + + EntryModel + + Group + Gruppe + + + Title + Titel + + + Username + Benutzername + + + URL + URL + + + + Group + + Recycle Bin + Papierkorb + + + + KeePass1OpenWidget + + Import KeePass1 database + KeePass 1 Datenbank importieren + + + Error + Fehler + + + Unable to open the database. + Öffnen der Datenbank nicht möglich. + + + + KeePass1Reader + + Unable to read keyfile. + Lesen der Schlüsseldatei nicht möglich. + + + Not a KeePass database. + Keine KeePass-Datenbank. + + + Unsupported encryption algorithm. + Nicht unterstützter Verschlüsselungsalgorithmus. + + + Unsupported KeePass database version. + Nicht unterstützte KeePass-Datenbankversion. + + + Root + Root + + + + KeePass2Reader + + Not a KeePass database. + Keine KeePass-Datenbank. + + + Unsupported KeePass database version. + Nicht unterstützte KeePass-Datenbankversion. + + + Wrong key or database file is corrupt. + Falscher Schlüssel oder die Datei ist beschädigt. + + + + MainWindow + + Database + Datenbank + + + Recent databases + Aktuelle Datenbanken + + + Help + Hilfe + + + Entries + Einträge + + + Copy attribute to clipboard + Eingenschaft in die Zwischenablage kopieren + + + Groups + Gruppen + + + Extras + Extras + + + View + Ansicht + + + Quit + Beenden + + + About + Über + + + Open database + Datenbank öffnen + + + Save database + Datenbank speichern + + + Close database + Datenbank schließen + + + New database + Neue Datenbank + + + Add new entry + Neuen Eintrag hinzufügen + + + View/Edit entry + Eintrag anzeigen/bearbeiten + + + Delete entry + Eintrag löschen + + + Add new group + Neue Gruppe hinzufügen + + + Edit group + Gruppe bearbeiten + + + Delete group + Gruppe löschen + + + Save database as + Datenbank speichern als + + + Change master key + Hauptschlüssel ändern + + + Database settings + Datenbankeinstellungen + + + Import KeePass 1 database + KeePass 1 Datenbank importieren + + + Clone entry + Eintrag klonen + + + Find + Suchen + + + Username + Benutzername + + + Copy username to clipboard + Benutzername in die Zwischenablage kopieren + + + Password + Passwort + + + Copy password to clipboard + Passwort in die Zwischenablage kopieren + + + Settings + Einstellungen + + + Perform Auto-Type + Auto-Type ausführen + + + Open URL + URL öffnen + + + Lock databases + Datenbank sperren + + + Title + Titel + + + URL + URL + + + Notes + Notizen + + + Show toolbar + Symbolleiste anzeigen + + + read-only + Nur Lesezugriff + + + + PasswordGeneratorWidget + + Password: + Passwort: + + + Length: + Länge: + + + Character Types + Zeichenarten + + + Upper Case Letters + Großbuchstaben + + + Lower Case Letters + Kleinbuchstaben + + + Numbers + Zahlen + + + Special Characters + Sonderzeichen + + + Exclude look-alike characters + Gleich aussehende Zeichen ausschließen + + + Ensure that the password contains characters from every group + Sicher stellen, dass das Passwort Zeichen aller Gruppen enthält + + + Accept + Akzeptieren + + + + QCommandLineParser + + Displays version information. + Versionsinformationen anzeigen. + + + Displays this help. + Zeigt diese Hilfe an. + + + Unknown option '%1'. + Unbekannte Option '%1'. + + + Unknown options: %1. + Unbekannte Optionen: '%1'. + + + Missing value after '%1'. + Fehlender Wert nach '%1'. + + + Unexpected value after '%1'. + Unerwarteter Wert nach '%1'. + + + [options] + [Optionen] + + + Usage: %1 + Verwendung: %1 + + + Options: + Optionen: + + + Arguments: + Argumente: + + + + QSaveFile + + Existing file %1 is not writable + Bestehende Datei(en) %1 ist nicht schreibbar + + + Writing canceled by application + Schreiben von der Applikation abgebrochen + + + Partial write. Partition full? + Unvollständiger Schreibvorgang. Partition voll? + + + + QtIOCompressor + + Internal zlib error when compressing: + Interner Fehler in zlib beim komprimieren: + + + Error writing to underlying device: + Fehler beim Schreiben auf das zugrunde liegende Gerät: + + + Error opening underlying device: + Fehler beim Öffnen des zugrunde liegenden Gerätes: + + + Error reading data from underlying device: + Fehler beim Lesen von Daten auf dem zugrunde liegenden Gerät: + + + Internal zlib error when decompressing: + Interner Fehler in zlib beim dekomprimieren: + + + + QtIOCompressor::open + + The gzip format not supported in this version of zlib. + Das gzip-Format wird von dieser zlib Version nicht unterstützt. + + + Internal zlib error: + Interner Fehler in zlib: + + + + SearchWidget + + Find: + Suchen nach: + + + Case sensitive + Groß-/Kleinschreibung unterscheiden + + + Current group + Aktuelle Gruppe + + + Root group + Root-Gruppe + + + + SettingsWidget + + Application Settings + Anwendungseinstellungen + + + General + Allgemein + + + Security + Sicherheit + + + + SettingsWidgetGeneral + + Remember last databases + Letzte Datenbank merken + + + Open previous databases on startup + Letzte Datenbank beim Starten öffnen + + + Mark as modified on expanded state changes + Als erweiterte Zustandsänderungen makieren + + + Automatically save on exit + Automatisch speichern beim Schließen + + + Automatically save after every change + Automatisch nach jeder Änderung speichern + + + Minimize when copying to clipboard + Minimieren beim Kopieren in die Zwischenablage + + + Use group icon on entry creation + Gruppensymbol für das Erstellen neuer Einträge verwenden + + + Global Auto-Type shortcut + Globale Tastenkombination für Auto-Type + + + Use entry title to match windows for global auto-type + Verwende den Eintragstitel für entsprechende Fenster für den globale Auto-Typ + + + + SettingsWidgetSecurity + + Clear clipboard after + Zwischenablage leeren nach + + + sec + sek + + + Lock databases after inactivity of + Datenbank sperren nach einer Inaktivität von + + + Show passwords in cleartext by default + Passwort standartmäßig in Klartext anzeigen + + + Always ask before performing auto-type + Immer vor einem Auto-type fragen + + + + UnlockDatabaseWidget + + Unlock database + Datenbank entsperren + + + Error + Fehler + + + Wrong key. + Falscher Schlüssel. + + + + WelcomeWidget + + Welcome! + Willkommen! + + + + main + + KeePassX - cross-platform password manager + KeePassX - plattformübergreifender Passwortmanager + + + filename of the password database to open (*.kdbx) + Dateiname für die zu öffnende Passwortdatenbank (*.kdbx) + + + path to a custom config file + Pfad zu einer benutzerdefinierten Konfigurationsdatei + + + password of the database (DANGEROUS!) + Passwort der Datenbank (GEFÄHRLICH!) + + + key file of the database + Schlüsseldatei der Datenbank + + + \ No newline at end of file diff --git a/share/translations/keepassx_en.ts b/share/translations/keepassx_en.ts new file mode 100644 index 0000000..a7b5b10 --- /dev/null +++ b/share/translations/keepassx_en.ts @@ -0,0 +1,1216 @@ + + + + + AboutDialog + + About KeePassX + + + + KeePassX is distributed under the term of the GNU General Public License (GPL) version 2 or (at your option) version 3. + + + + + AutoType + + Auto-Type - KeePassX + + + + Couldn't find an entry that matches the window title: + + + + + AutoTypeAssociationsModel + + Window + + + + Sequence + + + + Default sequence + + + + + AutoTypeSelectDialog + + Auto-Type - KeePassX + + + + Select entry to Auto-Type: + + + + + ChangeMasterKeyWidget + + Password + + + + Enter password: + + + + Repeat password: + + + + Key file + + + + Browse + + + + Create + + + + Key files + + + + All files + + + + Create Key File... + + + + Error + + + + Unable to create Key File : + + + + Select a key file + + + + Question + + + + Do you really want to use an empty string as password? + + + + Different passwords supplied. + + + + + DatabaseOpenWidget + + Enter master key + + + + Key File: + + + + Password: + + + + Browse + + + + Error + + + + Unable to open the database. + + + + Can't open key file + + + + All files + + + + Key files + + + + Select key file + + + + + DatabaseSettingsWidget + + Database name: + + + + Database description: + + + + Transform rounds: + + + + Default username: + + + + Use recycle bin: + + + + MiB + + + + Benchmark + + + + Max. history items: + + + + Max. history size: + + + + + DatabaseTabWidget + + Root + + + + KeePass 2 Database + + + + All files + + + + Open database + + + + Warning + + + + File not found! + + + + Open KeePass 1 database + + + + KeePass 1 database + + + + All files (*) + + + + Close? + + + + "%1" is in edit mode. +Close anyway? + + + + Save changes? + + + + "%1" was modified. +Save changes? + + + + Error + + + + Writing the database failed. + + + + Save database as + + + + New database + + + + locked + + + + + DatabaseWidget + + Change master key + + + + Delete entry? + + + + Do you really want to delete the entry "%1" for good? + + + + Delete entries? + + + + Do you really want to delete %1 entries for good? + + + + Move entries to recycle bin? + + + + Do you really want to move %n entry(s) to the recycle bin? + + + + + + + Delete group? + + + + Do you really want to delete the group "%1" for good? + + + + Current group + + + + + EditEntryWidget + + Entry + + + + Advanced + + + + Icon + + + + Auto-Type + + + + Properties + + + + History + + + + Entry history + + + + Add entry + + + + Edit entry + + + + Error + + + + Different passwords supplied. + + + + New attribute + + + + Select file + + + + Unable to open file + + + + Save attachment + + + + Unable to save the attachment: + + + + + Tomorrow + + + + %n week(s) + + + + + + + %n month(s) + + + + + + + 1 year + + + + + EditEntryWidgetAdvanced + + Additional attributes + + + + Add + + + + Edit + + + + Remove + + + + Attachments + + + + Save + + + + + EditEntryWidgetAutoType + + Enable Auto-Type for this entry + + + + Inherit default Auto-Type sequence from the group + + + + Use custom Auto-Type sequence: + + + + + + + + + - + + + + Window title: + + + + Use default sequence + + + + Set custom sequence: + + + + + EditEntryWidgetHistory + + Show + + + + Restore + + + + Delete + + + + Delete all + + + + + EditEntryWidgetMain + + Title: + + + + Username: + + + + Password: + + + + Repeat: + + + + Gen. + + + + URL: + + + + Expires + + + + Presets + + + + Notes: + + + + + EditGroupWidget + + Group + + + + Icon + + + + Properties + + + + Add group + + + + Edit group + + + + Enable + + + + Disable + + + + Inherit from parent group (%1) + + + + + EditGroupWidgetMain + + Name + + + + Notes + + + + Expires + + + + Search + + + + Auto-type + + + + + EditWidgetIcons + + Use default icon + + + + Use custom icon + + + + Add custom icon + + + + Delete custom icon + + + + Images + + + + All files + + + + Select Image + + + + Can't delete icon! + + + + Can't delete icon. Still used by %n item(s). + + + + + + + + EditWidgetProperties + + Created: + + + + Modified: + + + + Accessed: + + + + Uuid: + + + + + EntryAttributesModel + + Name + + + + + EntryHistoryModel + + Last modified + + + + Title + + + + Username + + + + URL + + + + + EntryModel + + Group + + + + Title + + + + Username + + + + URL + + + + + Group + + Recycle Bin + + + + + KeePass1OpenWidget + + Import KeePass1 database + + + + Error + + + + Unable to open the database. + + + + + KeePass1Reader + + Unable to read keyfile. + + + + Not a KeePass database. + + + + Unsupported encryption algorithm. + + + + Unsupported KeePass database version. + + + + Root + + + + + KeePass2Reader + + Not a KeePass database. + + + + Unsupported KeePass database version. + + + + Wrong key or database file is corrupt. + + + + + Main + + Fatal error while testing the cryptographic functions. + + + + KeePassX - Error + + + + + MainWindow + + Database + + + + Recent databases + + + + Help + + + + Entries + + + + Copy attribute to clipboard + + + + Groups + + + + Extras + + + + View + + + + Quit + + + + About + + + + Open database + + + + Save database + + + + Close database + + + + New database + + + + Add new entry + + + + View/Edit entry + + + + Delete entry + + + + Add new group + + + + Edit group + + + + Delete group + + + + Save database as + + + + Change master key + + + + Database settings + + + + Import KeePass 1 database + + + + Clone entry + + + + Find + + + + Username + + + + Copy username to clipboard + + + + Password + + + + Copy password to clipboard + + + + Settings + + + + Perform Auto-Type + + + + Open URL + + + + Lock databases + + + + Title + + + + URL + + + + Notes + + + + Show toolbar + + + + read-only + + + + Toggle window + + + + + PasswordGeneratorWidget + + Password: + + + + Length: + + + + Character Types + + + + Upper Case Letters + + + + Lower Case Letters + + + + Numbers + + + + Special Characters + + + + Exclude look-alike characters + + + + Ensure that the password contains characters from every group + + + + Accept + + + + + QCommandLineParser + + Displays version information. + + + + Displays this help. + + + + Unknown option '%1'. + + + + Unknown options: %1. + + + + Missing value after '%1'. + + + + Unexpected value after '%1'. + + + + [options] + + + + Usage: %1 + + + + Options: + + + + Arguments: + + + + + QSaveFile + + Existing file %1 is not writable + + + + Writing canceled by application + + + + Partial write. Partition full? + + + + + QtIOCompressor + + Internal zlib error when compressing: + + + + Error writing to underlying device: + + + + Error opening underlying device: + + + + Error reading data from underlying device: + + + + Internal zlib error when decompressing: + + + + + QtIOCompressor::open + + The gzip format not supported in this version of zlib. + + + + Internal zlib error: + + + + + SearchWidget + + Find: + + + + Case sensitive + + + + Current group + + + + Root group + + + + + SettingsWidget + + Application Settings + + + + General + + + + Security + + + + + SettingsWidgetGeneral + + Remember last databases + + + + Open previous databases on startup + + + + Mark as modified on expanded state changes + + + + Automatically save on exit + + + + Automatically save after every change + + + + Minimize when copying to clipboard + + + + Use group icon on entry creation + + + + Global Auto-Type shortcut + + + + Use entry title to match windows for global auto-type + + + + Language + + + + Show a system tray icon + + + + Hide window to system tray when minimized + + + + + SettingsWidgetSecurity + + Clear clipboard after + + + + sec + + + + Lock databases after inactivity of + + + + Show passwords in cleartext by default + + + + Always ask before performing auto-type + + + + + UnlockDatabaseWidget + + Unlock database + + + + Error + + + + Wrong key. + + + + + WelcomeWidget + + Welcome! + + + + + main + + KeePassX - cross-platform password manager + + + + filename of the password database to open (*.kdbx) + + + + path to a custom config file + + + + password of the database (DANGEROUS!) + + + + key file of the database + + + + diff --git a/share/translations/keepassx_en_plurals.ts b/share/translations/keepassx_en_plurals.ts new file mode 100644 index 0000000..006f6f6 --- /dev/null +++ b/share/translations/keepassx_en_plurals.ts @@ -0,0 +1,41 @@ + + + + + DatabaseWidget + + Do you really want to move %n entry(s) to the recycle bin? + + Do you really want to move %n entry to the recycle bin? + Do you really want to move %n entries to the recycle bin? + + + + + EditEntryWidget + + %n week(s) + + %n week + %n weeks + + + + %n month(s) + + %n month + %n months + + + + + EditWidgetIcons + + Can't delete icon. Still used by %n item(s). + + Can't delete icon. Still used by %n item. + Can't delete icon. Still used by %n items. + + + + diff --git a/share/translations/keepassx_it.ts b/share/translations/keepassx_it.ts new file mode 100644 index 0000000..4f91b75 --- /dev/null +++ b/share/translations/keepassx_it.ts @@ -0,0 +1,1179 @@ + + + AboutDialog + + About KeePassX + A proposito di KeePassX + + + KeePassX is distributed under the term of the GNU General Public License (GPL) version 2 or (at your option) version 3. + KeePassX è distribuito sotto i termini della licenza +GNU General Public License (GPL) versione 2 o, a tua scelta, della versione 3. + + + + AutoType + + Auto-Type - KeePassX + Auto-Type - KeePassX + + + Couldn't find an entry that matches the window title. + Impossibile trovare una voce che corrisponda al titolo della finestra + + + + AutoTypeAssociationsModel + + Window + Finestra + + + Sequence + Sequenza + + + Default sequence + Sequenza predefinita + + + + AutoTypeSelectDialog + + Auto-Type - KeePassX + Auto-Type - KeePassX + + + Select entry to Auto-Type: + Selezionare una voce per Auto-Type: + + + + ChangeMasterKeyWidget + + Password + Password + + + Enter password: + Inserire password: + + + Repeat password: + Ripetere password: + + + Key file + File chiave + + + Browse + Sfogliare + + + Create + Creare + + + Key files + File chiave + + + All files + Tutti i file + + + Create Key File... + Creare file chiave... + + + Error + Errore + + + Unable to create Key File : + Impossibile creare file chiave: + + + Select a key file + Selezionare file chiave + + + Question + Domanda + + + Do you really want to use an empty string as password? + Vuoi veramente usare una stringa vuota come password? + + + Different passwords supplied. + Sono state fornite password differenti. + + + + DatabaseOpenWidget + + Enter master key + Inserire password + + + Key File: + File Chiave: + + + Password: + Password: + + + Browse + Sfogliare + + + Error + Errore + + + Unable to open the database. + Impossibile aprire il database. + + + Can't open key file + Impossibile aprire il file chiave + + + All files + Tutti i file + + + Key files + File chiave + + + Select key file + Selezionare file chiave + + + + DatabaseSettingsWidget + + Database name: + Nome database: + + + Database description: + Descrizione database: + + + Transform rounds: + Round di trasformazione: + + + Default username: + Nome utente predefinito: + + + Use recycle bin: + Utilizzare cestino: + + + MiB + MiB + + + Benchmark + Benchmark + + + Max. history items: + Max. oggetti nella cronologia: + + + Max. history size: + Max. grandezza della cronologia: + + + + DatabaseTabWidget + + Root + Root + + + KeePass 2 Database + Database KeePass 2 + + + All files + Tutti i file + + + Open database + Aprire database + + + Warning + Avviso + + + File not found! + File non trovato! + + + Open KeePass 1 database + Aprire database KeePass 1 + + + KeePass 1 database + Database KeePass 1 + + + All files (*) + Tutti i file (*) + + + Close? + Chiudere? + + + "%1" is in edit mode. +Close anyway? + "%1" è in modalità modifica. +Chiudere comunque? + + + Save changes? + Salvare modifiche? + + + "%1" was modified. +Save changes? + "%1" è stata modificata. +Salvare le modifiche? + + + Error + Errore + + + Writing the database failed. + Scrittura del database fallita. + + + Save database as + Salvare database come + + + New database + Nuovo database + + + locked + bloccato + + + + DatabaseWidget + + Change master key + Cambiare password principale + + + Delete entry? + Eliminare voce? + + + Do you really want to delete the entry "%1" for good? + Vuoi veramente eliminare la voce "%1"? + + + Delete entries? + Eliminare voci? + + + Do you really want to delete %1 entries for good? + Vuoi veramente eliminare %1 voci? + + + Move entries to recycle bin? + Muovere le voci nel cestino? + + + Do you really want to move %n entry(s) to the recycle bin? + Vuoi veramente spostare %n voce(i) nel cestino?Vuoi veramente spostare %n voce(i) nel cestino? + + + Delete group? + Eliminare gruppo? + + + Do you really want to delete the group "%1" for good? + Vuoi veramente eliminare il gruppo "%1"? + + + Current group + Gruppo corrente + + + + EditEntryWidget + + Entry + Voce + + + Advanced + Avanzate + + + Icon + Icona + + + Auto-Type + Auto-Type + + + Properties + Proprietà + + + History + Cronologia + + + Entry history + Cronologia voce + + + Add entry + Aggiungere voce + + + Edit entry + Modificare voce + + + Error + Errore + + + Different passwords supplied. + Sono state immesse password differenti. + + + New attribute + Nuovo attributo + + + Select file + Selezionare file + + + Unable to open file + Impossibile aprire il file + + + Save attachment + Salvare l'allegato + + + Unable to save the attachment: + + Impossibile salvare l'allegato + + + + Tomorrow + Domani + + + %n week(s) + %n settimana(e)%n settimana(e) + + + %n month(s) + %n mese(i)%n mese(i) + + + 1 year + 1 anno + + + + EditEntryWidgetAdvanced + + Additional attributes + Attributi addizionali + + + Add + Aggiungere + + + Edit + Modificare + + + Remove + Rimuovere + + + Attachments + Allegati + + + Save + Salvare + + + + EditEntryWidgetAutoType + + Enable Auto-Type for this entry + Abilitare Auto-Type per questa voce + + + Inherit default Auto-Type sequence from the group + Ereditare la sequenza predefinita di Auto-Type dal gruppo + + + Use custom Auto-Type sequence: + Usare sequenza personalizzata di Auto-Type: + + + + + + + + + - + - + + + Window title: + Titolo finestra: + + + Use default sequence + Usare sequenza predefinita + + + Set custom sequence: + Impostare sequenza personalizzata: + + + + EditEntryWidgetHistory + + Show + Mostrare + + + Restore + Ripristinare + + + Delete + Eliminare + + + Delete all + Eliminare tutti + + + + EditEntryWidgetMain + + Title: + Titolo: + + + Username: + Nome utente: + + + Password: + Password: + + + Repeat: + Ripetere: + + + Gen. + Gen. + + + URL: + URL: + + + Expires + Scade: + + + Presets + Programmare + + + Notes: + Note: + + + + EditGroupWidget + + Group + Gruppo + + + Icon + Icona + + + Properties + Proprietà + + + Add group + Aggiungere gruppo + + + Edit group + Modificare gruppo + + + Enable + Abilitare + + + Disable + Disabilitare + + + Inherit from parent group (%1) + Ereditare dal gruppo genitore (%1) + + + + EditGroupWidgetMain + + Name + Nome + + + Notes + Note + + + Expires + Scade + + + Search + Cercare + + + Auto-type + Auto-Type + + + + EditWidgetIcons + + Use default icon + Usare icona predefinita + + + Use custom icon + Usare icona personalizzata + + + Add custom icon + Aggiungere icona personalizzata + + + Delete custom icon + Rimuovere icona personalizzata + + + Images + Immagini + + + All files + Tutti i file + + + Select Image + Selezionare Immagine + + + Can't delete icon! + Impossibile eliminare icona! + + + Can't delete icon. Still used by %n item(s). + Impossibile eliminare l'icona in quanto è in uso da %n voce(i).Impossibile eliminare l'icona in quanto è in uso da %n voce(i). + + + + EditWidgetProperties + + Created: + Creato: + + + Modified: + Modificato: + + + Accessed: + Accesso: + + + Uuid: + Uuid: + + + + EntryAttributesModel + + Name + Nome + + + + EntryHistoryModel + + Last modified + Ultima modifica + + + Title + Titolo + + + Username + Nome utente + + + URL + URL + + + + EntryModel + + Group + Gruppo + + + Title + Titolo + + + Username + Nome Utente + + + URL + URL + + + + Group + + Recycle Bin + Cestino (Gruppo) + + + + KeePass1OpenWidget + + Import KeePass1 database + Importare database KeePass1 + + + Error + Errore + + + Unable to open the database. + Impossibile aprire il database. + + + + KeePass1Reader + + Unable to read keyfile. + Impossibile leggere il file chiave. + + + Not a KeePass database. + Non è un database KeePass. + + + Unsupported encryption algorithm. + Algoritmo di cifratura non supportato. + + + Unsupported KeePass database version. + Versione database non supportata + + + Root + Root (KeePass1Reader) + + + + KeePass2Reader + + Not a KeePass database. + Non è un database KeePass. + + + Unsupported KeePass database version. + Versione database non supportata + + + Wrong key or database file is corrupt. + Password errata o database corrotto. + + + + MainWindow + + Database + Database + + + Recent databases + Database recenti + + + Help + Aiuto + + + Entries + Voci + + + Copy attribute to clipboard + Copiare attributi negli appunti + + + Groups + Gruppi + + + Extras + Extra + + + View + Visualizzare + + + Quit + Uscire + + + About + A Proposito + + + Open database + Aprire database + + + Save database + Salvare database + + + Close database + Chiudere database + + + New database + Nuovo database + + + Add new entry + Aggiungere nuova voce + + + View/Edit entry + Visualizzare/Modificare voce + + + Delete entry + Eliminare voce + + + Add new group + Aggiungere nuovo gruppo + + + Edit group + Modificare gruppo + + + Delete group + Eliminare gruppo + + + Save database as + Salvare database come + + + Change master key + Cambiare password principale + + + Database settings + Impostazioni database + + + Import KeePass 1 database + Importare database KeePass 1 + + + Clone entry + Clona voce + + + Find + Trovare + + + Username + Nome Utente + + + Copy username to clipboard + Copiare nome utente negli appunti + + + Password + Password + + + Copy password to clipboard + Copiare password negli appunti + + + Settings + Impostazioni + + + Perform Auto-Type + Eseguire Auto-Type + + + Open URL + Aprire URL + + + Lock databases + Bloccare database + + + Title + Titolo + + + URL + URL + + + Notes + Note + + + Show toolbar + Mostrare barra degli strumenti + + + read-only + sola lettura + + + + PasswordGeneratorWidget + + Password: + Password: + + + Length: + Lunghezza: + + + Character Types + Tipi di carattere + + + Upper Case Letters + Lettere maiuscole + + + Lower Case Letters + Lettere minuscole + + + Numbers + Numeri + + + Special Characters + Caratteri speciali + + + Exclude look-alike characters + Escludere caratteri simili + + + Ensure that the password contains characters from every group + Assicurare che la password contenga caratteri di ogni gruppo + + + Accept + Accettare + + + + QCommandLineParser + + Displays version information. + Mostrare informazioni sulla versione. + + + Displays this help. + Mostrare questo aiuto. + + + Unknown option '%1'. + Opzione sconosciuta '%1'. + + + Unknown options: %1. + Opzioni sconosciute '%1'. + + + Missing value after '%1'. + Manca valore dopo '%1'. + + + Unexpected value after '%1'. + Valore inaspettato dopo '%1'. + + + [options] + [opzioni] + + + Usage: %1 + Uso: %1 + + + Options: + Opzioni: + + + Arguments: + Argomenti: + + + + QSaveFile + + Existing file %1 is not writable + Il file esistente %1 non è scrivibile + + + Writing canceled by application + Scrittura cancellata dall'applicazione + + + Partial write. Partition full? + Scrittura parziale. Partizione piena? + + + + QtIOCompressor + + Internal zlib error when compressing: + Errore interno di zlib durante la compressione: + + + Error writing to underlying device: + Errore durante la scrittura nel dispositivo: + + + Error opening underlying device: + Errore durante l'apertura dal dispositivo: + + + Error reading data from underlying device: + Errore durante la lettura dal dispositivo: + + + Internal zlib error when decompressing: + Errore interno di zlib durante la decompressione: + + + + QtIOCompressor::open + + The gzip format not supported in this version of zlib. + Formato gzip non supportato da questa versione di zlib. + + + Internal zlib error: + Errore interno di zlib: + + + + SearchWidget + + Find: + Trovare: + + + Case sensitive + Case sensitive + + + Current group + Gruppo corrente + + + Root group + Gruppo radice + + + + SettingsWidget + + Application Settings + Impostazioni applicazione + + + General + Generale + + + Security + Sicurezza + + + + SettingsWidgetGeneral + + Remember last databases + Ricordare ultimo database + + + Open previous databases on startup + Aprire precedente database all'avvio + + + Mark as modified on expanded state changes + Marcare come modificata quando la voce viene espansa + + + Automatically save on exit + Salvare automaticamente all'uscita + + + Automatically save after every change + Salvare automaticamente dopo ogni modifica + + + Minimize when copying to clipboard + Minimizzare quando si copia negli appunti + + + Use group icon on entry creation + Usare l'icona del gruppo alla creazione di una voce + + + Global Auto-Type shortcut + Scorciatoia Auto-Type globale + + + Use entry title to match windows for global auto-type + Utilizzare il titolo della voce per abbinare la finestra per auto-type globale + + + + SettingsWidgetSecurity + + Clear clipboard after + Pulire appunti dopo + + + sec + sec + + + Lock databases after inactivity of + Bloccare database dopo un'inattività di + + + Show passwords in cleartext by default + Mostrare la password in chiaro in maniera predefinita + + + Always ask before performing auto-type + Chiedere sempre prima di eseguire auto-type + + + + UnlockDatabaseWidget + + Unlock database + Sbloccare database + + + Error + Errore + + + Wrong key. + Password errata. + + + + WelcomeWidget + + Welcome! + Benvenuto/a! + + + + main + + KeePassX - cross-platform password manager + KeePassX - gestore di password cross-platform + + + filename of the password database to open (*.kdbx) + nome del file del database da aprire (*.kdbx) + + + path to a custom config file + percorso ad un file di configurazione personalizzato + + + password of the database (DANGEROUS!) + password del database (PERICOLOSO!) + + + key file of the database + file chiave del database + + + \ No newline at end of file diff --git a/share/translations/keepassx_nl_NL.ts b/share/translations/keepassx_nl_NL.ts new file mode 100644 index 0000000..aa6320e --- /dev/null +++ b/share/translations/keepassx_nl_NL.ts @@ -0,0 +1,1178 @@ + + + AboutDialog + + About KeePassX + Over KeePassX + + + KeePassX is distributed under the term of the GNU General Public License (GPL) version 2 or (at your option) version 3. + KeePassX wordt verspreid onder de bepalingen van de GNU General Public License (GPL) versie 2 of (als u wenst) versie 3. + + + + AutoType + + Auto-Type - KeePassX + Auto-typen - KeePassX + + + Couldn't find an entry that matches the window title. + Kon geen element vinden dat overeenkomt met de venstertitel. + + + + AutoTypeAssociationsModel + + Window + Venster + + + Sequence + Volgorde + + + Default sequence + Standaardvolgorde + + + + AutoTypeSelectDialog + + Auto-Type - KeePassX + Auto-typen - KeePassX + + + Select entry to Auto-Type: + Kies element om automatisch te typen: + + + + ChangeMasterKeyWidget + + Password + Wachtwoord + + + Enter password: + Geef wachtwoord: + + + Repeat password: + Herhaal wachtwoord: + + + Key file + Sleutelbestand + + + Browse + Bladeren + + + Create + Aanmaken + + + Key files + Sleutelbestanden + + + All files + Alle bestanden + + + Create Key File... + Genereer sleutelbestand... + + + Error + Fout + + + Unable to create Key File : + Niet mogelijk om sleutelbestand aan te maken: + + + Select a key file + Kies een sleutelbestand + + + Question + Vraag + + + Do you really want to use an empty string as password? + Weet u zeker dat u een leeg veld als wachtwoord wilt gebruiken? + + + Different passwords supplied. + Verschillende wachtwoorden opgegeven. + + + + DatabaseOpenWidget + + Enter master key + Geef hoofdsleutel + + + Key File: + Sleutelbestand: + + + Password: + Wachtwoord: + + + Browse + Bladeren + + + Error + Fout + + + Unable to open the database. + Niet mogelijk om de database te openen. + + + Can't open key file + Niet mogelijk om het sleutelbestand te openen + + + All files + Alle bestanden + + + Key files + Sleutelbestanden + + + Select key file + Kies sleutelbestand + + + + DatabaseSettingsWidget + + Database name: + Naam van de database: + + + Database description: + Beschrijving van de database: + + + Transform rounds: + Transformatierondes: + + + Default username: + Standaard gebruikersnaam: + + + Use recycle bin: + Gebruik prullenbak: + + + MiB + MiB + + + Benchmark + Test + + + Max. history items: + Max. items in geschiedenis: + + + Max. history size: + Max. grootte geschiedenis: + + + + DatabaseTabWidget + + Root + Alles + + + KeePass 2 Database + KeePass 2 Database + + + All files + Alle bestanden + + + Open database + Open database + + + Warning + Waarschuwing + + + File not found! + Bestand niet gevonden! + + + Open KeePass 1 database + Open KeePass 1 database + + + KeePass 1 database + KeePass 1 database + + + All files (*) + Alle bestanden (*) + + + Close? + Sluiten? + + + "%1" is in edit mode. +Close anyway? + "%1" is in bewerkmodus. +Toch sluiten? + + + Save changes? + Wijzigingen opslaan? + + + "%1" was modified. +Save changes? + "%1" is gewijzigd. +Opslaan? + + + Error + Fout + + + Writing the database failed. + Opslaan van de database is mislukt. + + + Save database as + Database opslaan als + + + New database + Nieuwe database + + + locked + vergrendeld + + + + DatabaseWidget + + Change master key + Wijzig hoofdsleutel + + + Delete entry? + Element verwijderen? + + + Do you really want to delete the entry "%1" for good? + Weet u zeker dat u het element "%1" wilt verwijderen? + + + Delete entries? + Elementen wissen? + + + Do you really want to delete %1 entries for good? + Weet u zeker dat u %1 elementen wilt wissen? + + + Move entries to recycle bin? + Elementen naar de prullenbak verplaatsen? + + + Do you really want to move %n entry(s) to the recycle bin? + Weet u zeker dat u %n element naar de prullenbak wilt verplaatsen?Weet u zeker dat u %n elementen naar de prullenbak wilt verplaatsen? + + + Delete group? + Groep verwijderen? + + + Do you really want to delete the group "%1" for good? + Weet u zeker dat u de groep "%1" wilt verwijderen? + + + Current group + Huidige groep + + + + EditEntryWidget + + Entry + Element + + + Advanced + Geavanceerd + + + Icon + Icoon + + + Auto-Type + Auto-typen - KeePassX + + + Properties + Eigenschappen + + + History + Geschiedenis + + + Entry history + Geschiedenis van element + + + Add entry + Element toevoegen + + + Edit entry + Element wijzigen + + + Error + Fout + + + Different passwords supplied. + Verschillende wachtwoorden opgegeven. + + + New attribute + Nieuwe eigenschap + + + Select file + Kies bestand + + + Unable to open file + Niet mogelijk om bestand te openen + + + Save attachment + Bijlage opslaan + + + Unable to save the attachment: + + Niet mogelijk om de bijlage op te slaan: + + + + Tomorrow + Morgen + + + %n week(s) + %n week%n weken + + + %n month(s) + %n maand%n maanden + + + 1 year + 1 jaar + + + + EditEntryWidgetAdvanced + + Additional attributes + Extra eigenschappen + + + Add + Toevoegen + + + Edit + Wijzigen + + + Remove + Verwijderen + + + Attachments + Bijlagen + + + Save + Opslaan + + + + EditEntryWidgetAutoType + + Enable Auto-Type for this entry + Auto-typen inschakelen voor dit element + + + Inherit default Auto-Type sequence from the group + Erf standaard auto-typevolgorde van de groep + + + Use custom Auto-Type sequence: + Gebruik aangepaste auto-typevolgorde: + + + + + + + + + - + - + + + Window title: + Venstertitel: + + + Use default sequence + Gebruik standaardvolgorde + + + Set custom sequence: + Aangepaste volgorde: + + + + EditEntryWidgetHistory + + Show + Tonen + + + Restore + Herstellen + + + Delete + Verwijderen + + + Delete all + Alles verwijderen + + + + EditEntryWidgetMain + + Title: + Titel: + + + Username: + Gebruikersnaam: + + + Password: + Wachtwoord: + + + Repeat: + Herhalen: + + + Gen. + Gen. + + + URL: + URL: + + + Expires + Verloopt + + + Presets + Ingebouwd + + + Notes: + Opmerkingen: + + + + EditGroupWidget + + Group + Groep + + + Icon + Icoon + + + Properties + Eigenschappen + + + Add group + Groep toevoegen + + + Edit group + Groep wijzigen + + + Enable + Inschakelen + + + Disable + Uitschakelen + + + Inherit from parent group (%1) + Erf van bovenliggende groep (%1) + + + + EditGroupWidgetMain + + Name + Naam + + + Notes + Opmerkingen + + + Expires + Verloopt + + + Search + Zoeken + + + Auto-type + Auto-typen + + + + EditWidgetIcons + + Use default icon + Gebruik standaardicoon + + + Use custom icon + Gebruik aangepast icoon + + + Add custom icon + Voeg icoon toe + + + Delete custom icon + Verwijder icoon + + + Images + Afbeeldingen + + + All files + Alle bestanden + + + Select Image + Kies afbeelding + + + Can't delete icon! + Kan icoon niet verwijderen! + + + Can't delete icon. Still used by %n item(s). + Kan icoon niet verwijderen. Het wordt nog gebruikt door %n element.Kan icoon niet verwijderen. Het wordt nog gebruikt door %n elementen. + + + + EditWidgetProperties + + Created: + Aangemaakt: + + + Modified: + Gewijzigd: + + + Accessed: + Gelezen: + + + Uuid: + Uuid: + + + + EntryAttributesModel + + Name + Naam + + + + EntryHistoryModel + + Last modified + Laatst gewijzigd + + + Title + Titel + + + Username + Gebruikersnaam + + + URL + URL + + + + EntryModel + + Group + Groep + + + Title + Titel + + + Username + Gebruikersnaam + + + URL + URL + + + + Group + + Recycle Bin + Prullenbak + + + + KeePass1OpenWidget + + Import KeePass1 database + Importeer Keepass 1-database + + + Error + Fout + + + Unable to open the database. + Niet mogelijk om de database te openen. + + + + KeePass1Reader + + Unable to read keyfile. + Niet mogelijk om sleutelbestand te lezen + + + Not a KeePass database. + Geen Keepass-database + + + Unsupported encryption algorithm. + Niet-ondersteund encryptie-algoritme + + + Unsupported KeePass database version. + Niet-ondersteunde versie van Keepass-database + + + Root + Alles + + + + KeePass2Reader + + Not a KeePass database. + Geen Keepass-database. + + + Unsupported KeePass database version. + Niet-ondersteunde versie van Keepass-database. + + + Wrong key or database file is corrupt. + Verkeerde sleutel of corrupte database. + + + + MainWindow + + Database + Database + + + Recent databases + Recente databases + + + Help + Help + + + Entries + Elementen + + + Copy attribute to clipboard + Kopieer eigenschap naar klembord + + + Groups + Groepen + + + Extras + Extra's + + + View + Beeld + + + Quit + Afsluiten + + + About + Over + + + Open database + Open database + + + Save database + Sla database op + + + Close database + Sluit database + + + New database + Nieuwe database + + + Add new entry + Voeg element toe + + + View/Edit entry + Bekijk/bewerk element + + + Delete entry + Verwijder element + + + Add new group + Voeg groep toe + + + Edit group + Bewerk groep + + + Delete group + Verwijder groep + + + Save database as + Database opslaan als + + + Change master key + Hoofdsleutel wijzigen + + + Database settings + Database-instellingen + + + Import KeePass 1 database + Importeer Keepass 1-database + + + Clone entry + Element klonen + + + Find + Vind + + + Username + Gebruikersnaam + + + Copy username to clipboard + Kopieer gebruikersnaam naar klembord + + + Password + Wachtwoord + + + Copy password to clipboard + Kopieer wachtwoord naar klembord + + + Settings + Instellingen + + + Perform Auto-Type + Voer auto-typen uit + + + Open URL + Open URL + + + Lock databases + Vergrendel databases + + + Title + Titel + + + URL + URL + + + Notes + Opmerkingen + + + Show toolbar + Werkbalk weergeven + + + read-only + alleen-lezen + + + + PasswordGeneratorWidget + + Password: + Wachtwoord: + + + Length: + Lengte: + + + Character Types + Tekens + + + Upper Case Letters + Hoofdletters + + + Lower Case Letters + Kleine letters + + + Numbers + Cijfers + + + Special Characters + Speciale tekens + + + Exclude look-alike characters + Geen op elkaar lijkende tekens + + + Ensure that the password contains characters from every group + Zorg dat het wachtwoord tekens uit iedere groep bevat + + + Accept + Accepteren + + + + QCommandLineParser + + Displays version information. + Toont versie-informatie. + + + Displays this help. + Toont deze helptekst. + + + Unknown option '%1'. + Onbekende optie '%1'. + + + Unknown options: %1. + Onbekende opties: %1. + + + Missing value after '%1'. + Ontbrekende waarde na '%1'. + + + Unexpected value after '%1'. + Onverwachte waarde na '%1'. + + + [options] + [opties] + + + Usage: %1 + Gebruik: %1 + + + Options: + Opties: + + + Arguments: + Argumenten: + + + + QSaveFile + + Existing file %1 is not writable + Bestaand bestand %1 is niet schrijfbaar + + + Writing canceled by application + Schrijven afgebroken door programma + + + Partial write. Partition full? + Slechts deels geschreven. Is de schijf vol? + + + + QtIOCompressor + + Internal zlib error when compressing: + Interne fout in zlib bij inpakken: + + + Error writing to underlying device: + Fout bij schrijven naar onderliggend apparaat: + + + Error opening underlying device: + Fout bij openen van onderliggend apparaat: + + + Error reading data from underlying device: + Fout bij lezen van gegevens van onderliggend apparaat: + + + Internal zlib error when decompressing: + Interne fout in zlib bij uitpakken: + + + + QtIOCompressor::open + + The gzip format not supported in this version of zlib. + Gzip wordt niet ondersteund in deze versie van zlib. + + + Internal zlib error: + Interne fout in zlib: + + + + SearchWidget + + Find: + Vind: + + + Case sensitive + Hoofdlettergevoelig + + + Current group + Huidige groep + + + Root group + Hoofdgroep + + + + SettingsWidget + + Application Settings + Programma-instellingen + + + General + Algemeen + + + Security + Beveiliging + + + + SettingsWidgetGeneral + + Remember last databases + Onthoud laatste databases + + + Open previous databases on startup + Open vorige databases bij starten + + + Mark as modified on expanded state changes + Markeer database als gewijzigd bij wijzigen van de status + + + Automatically save on exit + Automatisch opslaan bij afsluiten + + + Automatically save after every change + Automatisch opslaan na iedere wijziging + + + Minimize when copying to clipboard + Minimaliseer bij kopieeren naar klembord + + + Use group icon on entry creation + Gebruik icoon van de groep voor nieuwe elementen + + + Global Auto-Type shortcut + Globale sneltoets voor auto-typen + + + Use entry title to match windows for global auto-type + Gebruik naam van element als vensternaam voor auto-typen + + + + SettingsWidgetSecurity + + Clear clipboard after + Leeg klembord na + + + sec + sec + + + Lock databases after inactivity of + Vergrendel databases na inactiviteit van + + + Show passwords in cleartext by default + Laat wachtwoorden standaard zien + + + Always ask before performing auto-type + Altijd vragen alvorens auto-type uit te voeren + + + + UnlockDatabaseWidget + + Unlock database + Database ontgrendelen + + + Error + Fout + + + Wrong key. + Verkeerd wachtwoord + + + + WelcomeWidget + + Welcome! + Welkom! + + + + main + + KeePassX - cross-platform password manager + KeepassX - multi-platform wachtwoordbeheerder + + + filename of the password database to open (*.kdbx) + bestandsnaam van de te openen wachtwoorddatabase (*.kdbx) + + + path to a custom config file + pad naar een configuratiebestand + + + password of the database (DANGEROUS!) + wachtwoord van de database (GEVAARLIJK!) + + + key file of the database + sleutelbestand van de database + + + \ No newline at end of file diff --git a/share/translations/keepassx_sv.ts b/share/translations/keepassx_sv.ts new file mode 100644 index 0000000..2a3ba79 --- /dev/null +++ b/share/translations/keepassx_sv.ts @@ -0,0 +1,1178 @@ + + + AboutDialog + + About KeePassX + Om KeePassX + + + KeePassX is distributed under the term of the GNU General Public License (GPL) version 2 or (at your option) version 3. + Keepassx distribueras enligt villkoren i GNU General Public License (GPL) version 2 eller (om du vill) version 3. + + + + AutoType + + Auto-Type - KeePassX + Auto-skriv - KeePassX + + + Couldn't find an entry that matches the window title. + Kunde inte hitta en post som matchar fönstertiteln. + + + + AutoTypeAssociationsModel + + Window + Fönster + + + Sequence + Sekvens + + + Default sequence + Standard sekvens + + + + AutoTypeSelectDialog + + Auto-Type - KeePassX + Auto-skriv - KeePassX + + + Select entry to Auto-Type: + Välj post att auto-skriva + + + + ChangeMasterKeyWidget + + Password + Lösenord + + + Enter password: + Ange lösenord: + + + Repeat password: + Repetera lösenord: + + + Key file + Nyckel-fil + + + Browse + Bläddra + + + Create + Skapa + + + Key files + Nyckel-filer + + + All files + Alla filer + + + Create Key File... + Skapa nyckel-fil... + + + Error + Fel + + + Unable to create Key File : + Kunde inte skapa nyckel-fil + + + Select a key file + Välj nyckel-fil + + + Question + Fråga + + + Do you really want to use an empty string as password? + Vill du verkligen vill använda en tom sträng som lösenord? + + + Different passwords supplied. + Olika lösenord angivna + + + + DatabaseOpenWidget + + Enter master key + Ange huvud lösenord + + + Key File: + Nyckel-fil: + + + Password: + Lösenord: + + + Browse + Bläddra + + + Error + Fel + + + Unable to open the database. + Kunde inte öppna databas. + + + Can't open key file + Kan inte öppna nyckel-fil + + + All files + Alla filer + + + Key files + Nyckel-filer + + + Select key file + Välj nyckel-fil + + + + DatabaseSettingsWidget + + Database name: + Databasnamn: + + + Database description: + Databasbeskrivning: + + + Transform rounds: + Transformerings varv: + + + Default username: + Standard användarnamn: + + + Use recycle bin: + Använd papperskorg: + + + MiB + MiB + + + Benchmark + Benchmark + + + Max. history items: + Maxantal historik poster: + + + Max. history size: + Maximal historik storlek: + + + + DatabaseTabWidget + + Root + Root + + + KeePass 2 Database + KeePass 2 Databas + + + All files + Alla filer + + + Open database + Öppna databas + + + Warning + Varning + + + File not found! + Filen kunde inte hittas! + + + Open KeePass 1 database + Öppna KeePass 1 databas + + + KeePass 1 database + KeePass 1 databas + + + All files (*) + Alla filer (*) + + + Close? + Stäng? + + + "%1" is in edit mode. +Close anyway? + "%1" är i redigerar-läge. +Stäng ändå? + + + Save changes? + Spara ändringar? + + + "%1" was modified. +Save changes? + "%1" har ändrats. +Spara ändringarna? + + + Error + Fel + + + Writing the database failed. + Kunde inte skriva till databasen. + + + Save database as + Spara databas som + + + New database + Ny databas + + + locked + låst + + + + DatabaseWidget + + Change master key + Ändra huvud lösenord + + + Delete entry? + Ta bort post? + + + Do you really want to delete the entry "%1" for good? + Vill du verkligen ta bort "%1" för gott? + + + Delete entries? + Ta bort poster? + + + Do you really want to delete %1 entries for good? + Vill du verkligen ta bort %1 poser för gott? + + + Move entries to recycle bin? + Lägg poster i papperskorgen? + + + Do you really want to move %n entry(s) to the recycle bin? + Vill du verkligen flytta %n post till papperskorgen?Vill du verkligen flytta %n poster till papperskorgen? + + + Delete group? + Ta bort grupp? + + + Do you really want to delete the group "%1" for good? + Vill du verkligen ta bort gruppen "%1" för gott? + + + Current group + Nuvarande grupp + + + + EditEntryWidget + + Entry + Post + + + Advanced + Avancerat + + + Icon + Ikon + + + Auto-Type + Auto-skriv + + + Properties + Egenskaper + + + History + Historik + + + Entry history + Posthistork + + + Add entry + Lägg till post + + + Edit entry + Ändra post + + + Error + Fel + + + Different passwords supplied. + Olika lösenord angivna + + + New attribute + Nytt attribut + + + Select file + Välj fil + + + Unable to open file + Kunde inte öppna filen. + + + Save attachment + Spara bifogad fil + + + Unable to save the attachment: + + Kunde inte spara bifogad fil: + + + + Tomorrow + Imorgon + + + %n week(s) + %n vecka%n veckor + + + %n month(s) + %n månad%n månader + + + 1 year + 1 år + + + + EditEntryWidgetAdvanced + + Additional attributes + Ytterligare attribut + + + Add + Lägg till + + + Edit + Ändra + + + Remove + Ta bort + + + Attachments + Bilagor + + + Save + Spara + + + + EditEntryWidgetAutoType + + Enable Auto-Type for this entry + Slå på auto-skriv för denna post + + + Inherit default Auto-Type sequence from the group + Ärv standard auto-skriv sekvens för grupp + + + Use custom Auto-Type sequence: + Använd egen auto-skriv sekvens: + + + + + + + + + - + - + + + Window title: + Fönster titel: + + + Use default sequence + Använd standard sekvens + + + Set custom sequence: + Egen sekvens: + + + + EditEntryWidgetHistory + + Show + Visa + + + Restore + Återställ + + + Delete + Ta bort + + + Delete all + Ta bort alla + + + + EditEntryWidgetMain + + Title: + Titel: + + + Username: + Användarnamn: + + + Password: + Lösenord: + + + Repeat: + Repetera: + + + Gen. + Gen. + + + URL: + URL: + + + Expires + Går ut + + + Presets + Förinställningar + + + Notes: + Anteckningar: + + + + EditGroupWidget + + Group + Grupp + + + Icon + Ikon + + + Properties + Egenskaper + + + Add group + Lägg till grupp + + + Edit group + Ändra grupp + + + Enable + Slå på + + + Disable + Stäng av + + + Inherit from parent group (%1) + Ärv från förälder grupp (%1) + + + + EditGroupWidgetMain + + Name + Namn + + + Notes + Anteckningar + + + Expires + Går ut + + + Search + Sök + + + Auto-type + Auto-skriv + + + + EditWidgetIcons + + Use default icon + Använd standard ikon + + + Use custom icon + Använd egen ikon + + + Add custom icon + Lägg till egen ikon + + + Delete custom icon + Ta bort egen ikon + + + Images + Bilder + + + All files + Alla filer + + + Select Image + Välj bild + + + Can't delete icon! + Kan inte ta bort ikon! + + + Can't delete icon. Still used by %n item(s). + Kan inte ta bort ikonen. Den används fortfarande av %n postKan inte ta bort ikonen. Den används fortfarande av %n poster + + + + EditWidgetProperties + + Created: + Skapad: + + + Modified: + Ändrad: + + + Accessed: + Läst: + + + Uuid: + UUID: + + + + EntryAttributesModel + + Name + Namn + + + + EntryHistoryModel + + Last modified + Senast ändrad + + + Title + Titel + + + Username + Användarnamn + + + URL + URL + + + + EntryModel + + Group + Grupp + + + Title + Titel + + + Username + Användarnamn + + + URL + URL + + + + Group + + Recycle Bin + Papperskorg + + + + KeePass1OpenWidget + + Import KeePass1 database + Importera KeePass1 databas + + + Error + Fel + + + Unable to open the database. + Kunde inte öppna databas. + + + + KeePass1Reader + + Unable to read keyfile. + Kunde inte läsa nyckel-filen. + + + Not a KeePass database. + Inte en KeePass databas + + + Unsupported encryption algorithm. + Krypteringsalgoritnmen stöds ej + + + Unsupported KeePass database version. + KeePass databas versionen stöds ej. + + + Root + Root + + + + KeePass2Reader + + Not a KeePass database. + Inte en KeePass databas. + + + Unsupported KeePass database version. + KeePass databas versionen stöds ej. + + + Wrong key or database file is corrupt. + Fel lösenord eller korrupt databas-fil + + + + MainWindow + + Database + Databas + + + Recent databases + Senast använda databser + + + Help + Hjälp + + + Entries + Poster + + + Copy attribute to clipboard + Kopiera attribut + + + Groups + Grupper + + + Extras + Extra + + + View + Vy + + + Quit + Avsluta + + + About + Om + + + Open database + Öppna databas + + + Save database + Spara databas + + + Close database + Stäng databas + + + New database + Ny databas + + + Add new entry + Lägg till ny post + + + View/Edit entry + Visa/ändra post + + + Delete entry + Ta bort post + + + Add new group + Lägg till ny grupp + + + Edit group + Ändra grupp + + + Delete group + Ta bort grupp + + + Save database as + Spara databas som + + + Change master key + Ändra huvud lösenord + + + Database settings + Databasinställningar + + + Import KeePass 1 database + Importera KeePass1 databas + + + Clone entry + Klona post + + + Find + Sök + + + Username + Användarnamn + + + Copy username to clipboard + Kopiera användarnamn + + + Password + Lösenord + + + Copy password to clipboard + Kopiera lösenord + + + Settings + Inställningar + + + Perform Auto-Type + Utför auto-skriv + + + Open URL + Öppna URL + + + Lock databases + Lås databaser + + + Title + Titel + + + URL + URL + + + Notes + Anteckningar + + + Show toolbar + Visa verktygsfält + + + read-only + läs bara + + + + PasswordGeneratorWidget + + Password: + Lösenord: + + + Length: + Längd: + + + Character Types + Teckentyper + + + Upper Case Letters + Versaler + + + Lower Case Letters + Gemener + + + Numbers + Siffror + + + Special Characters + Specialtecken + + + Exclude look-alike characters + Uteslut liknande tecken + + + Ensure that the password contains characters from every group + Säkerställ att lösenordet innehåller tecken från varje grupp + + + Accept + Acceptera + + + + QCommandLineParser + + Displays version information. + Visar versionsinformation. + + + Displays this help. + Visa denna hjälp. + + + Unknown option '%1'. + Okänt alternativ: '%1' + + + Unknown options: %1. + Okända alternativ: '%1' + + + Missing value after '%1'. + Saknar värde efter '%1' + + + Unexpected value after '%1'. + Oväntat värde efter '%1' + + + [options] + [alternativ] + + + Usage: %1 + Användning: %1 + + + Options: + Alternativ: + + + Arguments: + Argument: + + + + QSaveFile + + Existing file %1 is not writable + Den existerande filen %1 är inte skrivbar + + + Writing canceled by application + Skrivning avbruten av applikation + + + Partial write. Partition full? + Delvis skrivet. Är partitionen full? + + + + QtIOCompressor + + Internal zlib error when compressing: + Internt zlib fel vid komprimering: + + + Error writing to underlying device: + Fel vid skrivning till underliggande enhet: + + + Error opening underlying device: + Fel vid öppning av underliggande enhet: + + + Error reading data from underlying device: + Fel vid läsning från underliggande enhet: + + + Internal zlib error when decompressing: + Internt zlib fel vid extrahering: + + + + QtIOCompressor::open + + The gzip format not supported in this version of zlib. + Gzip formatet stöds inte av denna version av zlib. + + + Internal zlib error: + Internt zlib fel: + + + + SearchWidget + + Find: + Sök: + + + Case sensitive + Skiftlägeskänslig + + + Current group + Nuvarande grupp + + + Root group + Root grupp + + + + SettingsWidget + + Application Settings + Applikationsinställningar + + + General + Allmän + + + Security + Säkerhet + + + + SettingsWidgetGeneral + + Remember last databases + Komihåg senaste databasen + + + Open previous databases on startup + Öppna senaste databasen är programmet startar + + + Mark as modified on expanded state changes + Markera som ändrad när utökat läge ändras + + + Automatically save on exit + Spara automatiskt är applikationen anslutas + + + Automatically save after every change + Spara automatiskt efter varje ändring + + + Minimize when copying to clipboard + Minimera vid kopiering + + + Use group icon on entry creation + Använd gruppens ikon för nya poster + + + Global Auto-Type shortcut + Globalt auto-skriv kortkommando + + + Use entry title to match windows for global auto-type + Använda postens titel till matchning med fönster för globalt auto-skriv + + + + SettingsWidgetSecurity + + Clear clipboard after + Rensa urklipp efter + + + sec + sek + + + Lock databases after inactivity of + Lås databaser efter inaktivitet i + + + Show passwords in cleartext by default + Visa lösenord i klartext som standard + + + Always ask before performing auto-type + Fråga alltid innan auto-skriv utförs + + + + UnlockDatabaseWidget + + Unlock database + Lås upp databas + + + Error + Fel + + + Wrong key. + Fel lösenord + + + + WelcomeWidget + + Welcome! + Välkommen! + + + + main + + KeePassX - cross-platform password manager + KeePassX - plattformsoberoende lösenordshanterare + + + filename of the password database to open (*.kdbx) + namn på databas fil att öppna (*.kdbx) + + + path to a custom config file + Sökväg till egen konfigurations-fil + + + password of the database (DANGEROUS!) + lösenord för databasen (FARLIGT!) + + + key file of the database + nyckel-fil för databas + + + \ No newline at end of file diff --git a/share/translations/update.sh b/share/translations/update.sh new file mode 100755 index 0000000..6828dc8 --- /dev/null +++ b/share/translations/update.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +BASEDIR=$(dirname $0) + +cd $BASEDIR/../.. + +lupdate -no-ui-lines -disable-heuristic similartext -locations none -no-obsolete src -ts share/translations/keepassx_en.ts +lupdate -no-ui-lines -disable-heuristic similartext -locations none -pluralonly src -ts share/translations/keepassx_en_plurals.ts diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d57153e..7ffc168 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -35,6 +35,7 @@ set(keepassx_SOURCES core/Entry.cpp core/EntryAttachments.cpp core/EntryAttributes.cpp + core/EntrySearcher.cpp core/FilePath.cpp core/Global.h core/Group.cpp @@ -47,7 +48,9 @@ set(keepassx_SOURCES core/SignalMultiplexer.cpp core/TimeDelta.cpp core/TimeInfo.cpp + core/ToDbExporter.cpp core/Tools.cpp + core/Translator.cpp core/Uuid.cpp core/qcommandlineoption.cpp core/qcommandlineparser.cpp @@ -73,6 +76,7 @@ set(keepassx_SOURCES gui/DatabaseSettingsWidget.cpp gui/DatabaseTabWidget.cpp gui/DatabaseWidget.cpp + gui/DatabaseWidgetStateSync.cpp gui/DialogyWidget.cpp gui/DragTabBar.cpp gui/EditWidget.cpp @@ -154,6 +158,7 @@ set(keepassx_MOC gui/DatabaseSettingsWidget.h gui/DatabaseTabWidget.h gui/DatabaseWidget.h + gui/DatabaseWidgetStateSync.h gui/DialogyWidget.h gui/DragTabBar.h gui/EditWidget.h diff --git a/src/autotype/AutoType.cpp b/src/autotype/AutoType.cpp index 5c28b4d..aac0c0c 100644 --- a/src/autotype/AutoType.cpp +++ b/src/autotype/AutoType.cpp @@ -23,12 +23,14 @@ #include "autotype/AutoTypePlatformPlugin.h" #include "autotype/AutoTypeSelectDialog.h" #include "autotype/WildcardMatcher.h" +#include "core/Config.h" #include "core/Database.h" #include "core/Entry.h" #include "core/FilePath.h" #include "core/Group.h" #include "core/ListDeleter.h" #include "core/Tools.h" +#include "gui/MessageBox.h" AutoType* AutoType::m_instance = Q_NULLPTR; @@ -188,8 +190,12 @@ void AutoType::performGlobalAutoType(const QList& dbList) if (entryList.isEmpty()) { m_inAutoType = false; + QString message = tr("Couldn't find an entry that matches the window title:"); + message.append("\n\n"); + message.append(windowTitle); + MessageBox::information(Q_NULLPTR, tr("Auto-Type - KeePassX"), message); } - else if (entryList.size() == 1) { + else if ((entryList.size() == 1) && !config()->get("security/autotypeask").toBool()) { m_inAutoType = false; performAutoType(entryList.first(), Q_NULLPTR, sequenceHash[entryList.first()]); } @@ -499,6 +505,12 @@ QString AutoType::autoTypeSequence(const Entry* entry, const QString& windowTitl } } + if (!match && config()->get("AutoTypeEntryTitleMatch").toBool() && !entry->title().isEmpty() + && windowTitle.contains(entry->title(), Qt::CaseInsensitive)) { + sequence = entry->defaultAutoTypeSequence(); + match = true; + } + if (!match) { return QString(); } diff --git a/src/autotype/x11/AutoTypeX11.cpp b/src/autotype/x11/AutoTypeX11.cpp index 06a1e32..843fbfa 100644 --- a/src/autotype/x11/AutoTypeX11.cpp +++ b/src/autotype/x11/AutoTypeX11.cpp @@ -209,23 +209,26 @@ QString AutoTypePlatformX11::windowTitle(Window window, bool useBlacklist) unsigned long after; unsigned char* data = Q_NULLPTR; + // the window manager spec says we should read _NET_WM_NAME first, then fall back to WM_NAME + int retVal = XGetWindowProperty(m_dpy, window, m_atomNetWmName, 0, 1000, false, m_atomUtf8String, &type, &format, &nitems, &after, &data); - if (retVal != 0 && data) { + if ((retVal == 0) && data) { title = QString::fromUtf8(reinterpret_cast(data)); } else { XTextProperty textProp; retVal = XGetTextProperty(m_dpy, window, &textProp, m_atomWmName); - if (retVal != 0 && textProp.value) { + if ((retVal != 0) && textProp.value) { char** textList = Q_NULLPTR; int count; if (textProp.encoding == m_atomUtf8String) { title = QString::fromUtf8(reinterpret_cast(textProp.value)); } - else if (XmbTextPropertyToTextList(m_dpy, &textProp, &textList, &count) == 0 && textList && count > 0) { + else if ((XmbTextPropertyToTextList(m_dpy, &textProp, &textList, &count) == 0) + && textList && (count > 0)) { title = QString::fromLocal8Bit(textList[0]); } else if (textProp.encoding == m_atomString) { diff --git a/src/config-keepassx.h.cmake b/src/config-keepassx.h.cmake index 9a3f495..805700a 100644 --- a/src/config-keepassx.h.cmake +++ b/src/config-keepassx.h.cmake @@ -6,6 +6,7 @@ #define KEEPASSX_VERSION "${KEEPASSX_VERSION}" #define KEEPASSX_SOURCE_DIR "${CMAKE_SOURCE_DIR}" +#define KEEPASSX_BINARY_DIR "${CMAKE_BINARY_DIR}" #define KEEPASSX_PLUGIN_DIR "${PLUGIN_INSTALL_DIR}" diff --git a/src/core/Config.cpp b/src/core/Config.cpp index 3cb7634..03b5129 100644 --- a/src/core/Config.cpp +++ b/src/core/Config.cpp @@ -71,7 +71,8 @@ Config::Config(QObject* parent) userPath += "/keepassx/"; #else userPath = QDir::fromNativeSeparators(QDesktopServices::storageLocation(QDesktopServices::DataLocation)); - // storageLocation() appends the application name ("/keepassx/") to the end + // storageLocation() appends the application name ("/keepassx") to the end + userPath += "/"; #endif userPath += "keepassx2.ini"; @@ -94,11 +95,17 @@ void Config::init(const QString& fileName) m_defaults.insert("AutoSaveOnExit", false); m_defaults.insert("ShowToolbar", true); m_defaults.insert("MinimizeOnCopy", false); + m_defaults.insert("UseGroupIconOnEntryCreation", false); + m_defaults.insert("AutoTypeEntryTitleMatch", true); m_defaults.insert("security/clearclipboard", true); m_defaults.insert("security/clearclipboardtimeout", 10); m_defaults.insert("security/lockdatabaseidle", false); m_defaults.insert("security/lockdatabaseidlesec", 10); m_defaults.insert("security/passwordscleartext", false); + m_defaults.insert("security/autotypeask", true); + m_defaults.insert("GUI/Language", "system"); + m_defaults.insert("GUI/ShowTrayIcon", false); + m_defaults.insert("GUI/MinimizeToTray", false); } Config* Config::instance() @@ -110,7 +117,7 @@ Config* Config::instance() return m_instance; } -void Config::createConfigFromFile(QString file) +void Config::createConfigFromFile(const QString& file) { Q_ASSERT(!m_instance); m_instance = new Config(file, qApp); diff --git a/src/core/Config.h b/src/core/Config.h index ee30826..ca0f74c 100644 --- a/src/core/Config.h +++ b/src/core/Config.h @@ -36,7 +36,7 @@ public: void set(const QString& key, const QVariant& value); static Config* instance(); - static void createConfigFromFile(QString file); + static void createConfigFromFile(const QString& file); static void createTempFileInstance(); private: diff --git a/src/core/Database.cpp b/src/core/Database.cpp index 0394051..4c888ea 100644 --- a/src/core/Database.cpp +++ b/src/core/Database.cpp @@ -37,7 +37,7 @@ Database::Database() { m_data.cipher = KeePass2::CIPHER_AES; m_data.compressionAlgo = CompressionGZip; - m_data.transformRounds = 50000; + m_data.transformRounds = 100000; m_data.hasKey = false; setRootGroup(new Group()); diff --git a/src/core/Entry.cpp b/src/core/Entry.cpp index 55f5432..4f97791 100644 --- a/src/core/Entry.cpp +++ b/src/core/Entry.cpp @@ -579,25 +579,6 @@ const Database* Entry::database() const } } -bool Entry::match(const QString& searchTerm, Qt::CaseSensitivity caseSensitivity) -{ - QStringList wordList = searchTerm.split(QRegExp("\\s"), QString::SkipEmptyParts); - Q_FOREACH (const QString& word, wordList) { - if (!wordMatch(word, caseSensitivity)) { - return false; - } - } - return true; -} - -bool Entry::wordMatch(const QString& word, Qt::CaseSensitivity caseSensitivity) -{ - return title().contains(word, caseSensitivity) || - username().contains(word, caseSensitivity) || - url().contains(word, caseSensitivity) || - notes().contains(word, caseSensitivity); -} - QString Entry::resolvePlaceholders(const QString& str) const { QString result = str; diff --git a/src/core/Entry.h b/src/core/Entry.h index c2c2938..ae07ed4 100644 --- a/src/core/Entry.h +++ b/src/core/Entry.h @@ -141,7 +141,6 @@ public: void setGroup(Group* group); void setUpdateTimeinfo(bool value); - bool match(const QString& searchTerm, Qt::CaseSensitivity caseSensitivity); Q_SIGNALS: /** @@ -157,7 +156,6 @@ private Q_SLOTS: void updateModifiedSinceBegin(); private: - bool wordMatch(const QString& word, Qt::CaseSensitivity caseSensitivity); const Database* database() const; template bool set(T& property, const T& value); diff --git a/src/core/EntrySearcher.cpp b/src/core/EntrySearcher.cpp new file mode 100644 index 0000000..82a553e --- /dev/null +++ b/src/core/EntrySearcher.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2014 Florian Geyer + * + * 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 2 or (at your option) + * version 3 of the License. + * + * 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 . + */ + +#include "EntrySearcher.h" + +#include "core/Group.h" + +QList EntrySearcher::search(const QString &searchTerm, const Group* group, Qt::CaseSensitivity caseSensitivity) +{ + if (!group->resolveSearchingEnabled()) { + return QList(); + } + + return searchEntries(searchTerm, group, caseSensitivity); +} + +QList EntrySearcher::searchEntries(const QString& searchTerm, const Group* group, Qt::CaseSensitivity caseSensitivity) +{ + QList searchResult; + + Q_FOREACH (Entry* entry, group->entries()) { + searchResult.append(matchEntry(searchTerm, entry, caseSensitivity)); + } + Q_FOREACH (Group* childGroup, group->children()) { + if (childGroup->searchingEnabled() != Group::Disable) { + searchResult.append(searchEntries(searchTerm, childGroup, caseSensitivity)); + } + } + + return searchResult; +} + +QList EntrySearcher::matchEntry(const QString& searchTerm, Entry* entry, Qt::CaseSensitivity caseSensitivity) +{ + QStringList wordList = searchTerm.split(QRegExp("\\s"), QString::SkipEmptyParts); + Q_FOREACH (const QString& word, wordList) { + if (!wordMatch(word, entry, caseSensitivity)) { + return QList(); + } + } + + return QList() << entry; +} + +bool EntrySearcher::wordMatch(const QString& word, Entry* entry, Qt::CaseSensitivity caseSensitivity) +{ + return entry->title().contains(word, caseSensitivity) || + entry->username().contains(word, caseSensitivity) || + entry->url().contains(word, caseSensitivity) || + entry->notes().contains(word, caseSensitivity); +} diff --git a/src/core/EntrySearcher.h b/src/core/EntrySearcher.h new file mode 100644 index 0000000..246538c --- /dev/null +++ b/src/core/EntrySearcher.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2014 Florian Geyer + * + * 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 2 or (at your option) + * version 3 of the License. + * + * 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 . + */ + +#ifndef KEEPASSX_ENTRYSEARCHER_H +#define KEEPASSX_ENTRYSEARCHER_H + +#include + + +class Group; +class Entry; + +class EntrySearcher +{ +public: + QList search(const QString& searchTerm, const Group* group, Qt::CaseSensitivity caseSensitivity); +private: + QList searchEntries(const QString& searchTerm, const Group* group, Qt::CaseSensitivity caseSensitivity); + QList matchEntry(const QString& searchTerm, Entry* entry, Qt::CaseSensitivity caseSensitivity); + bool wordMatch(const QString &word, Entry *entry, Qt::CaseSensitivity caseSensitivity); +}; + +#endif // KEEPASSX_ENTRYSEARCHER_H diff --git a/src/core/Exporter.h b/src/core/Exporter.h new file mode 100644 index 0000000..dedb1c8 --- /dev/null +++ b/src/core/Exporter.h @@ -0,0 +1,14 @@ +#ifndef KEEPASSX_EXPORTER_H +#define KEEPASSX_EXPORTER_H + +class Database; +class Group; + +class Exporter +{ +public: + virtual Database* exportGroup(Group* group) = 0; + virtual ~Exporter() {} +}; + +#endif // KEEPASSX_EXPORTER_H diff --git a/src/core/Group.cpp b/src/core/Group.cpp index ada9e97..517f8cb 100644 --- a/src/core/Group.cpp +++ b/src/core/Group.cpp @@ -500,22 +500,6 @@ void Group::copyDataFrom(const Group* other) m_lastTopVisibleEntry = other->m_lastTopVisibleEntry; } -Database* Group::exportToDb() -{ - Q_ASSERT(database()); - - Database* db = new Database(); - Group* clonedGroup = clone(Entry::CloneNewUuid | Entry::CloneIncludeHistory); - clonedGroup->setParent(db->rootGroup()); - - QSet customIcons = customIconsRecursive(); - db->metadata()->copyCustomIcons(customIcons, database()->metadata()); - - db->copyAttributesFrom(database()); - - return db; -} - void Group::addEntry(Entry* entry) { Q_ASSERT(entry); @@ -612,37 +596,35 @@ void Group::recCreateDelObjects() } } -QList Group::search(const QString& searchTerm, Qt::CaseSensitivity caseSensitivity, - bool resolveInherit) +bool Group::resolveSearchingEnabled() const { - QList searchResult; - if (includeInSearch(resolveInherit)) { - Q_FOREACH (Entry* entry, m_entries) { - if (entry->match(searchTerm, caseSensitivity)) { - searchResult.append(entry); - } + switch (m_data.searchingEnabled) { + case Inherit: + if (!m_parent) { + return true; } - Q_FOREACH (Group* group, m_children) { - searchResult.append(group->search(searchTerm, caseSensitivity, false)); + else { + return m_parent->resolveSearchingEnabled(); } + case Enable: + return true; + case Disable: + return false; + default: + Q_ASSERT(false); + return false; } - return searchResult; } -bool Group::includeInSearch(bool resolveInherit) +bool Group::resolveAutoTypeEnabled() const { - switch (m_data.searchingEnabled) { + switch (m_data.autoTypeEnabled) { case Inherit: if (!m_parent) { return true; } else { - if (resolveInherit) { - return m_parent->includeInSearch(true); - } - else { - return true; - } + return m_parent->resolveAutoTypeEnabled(); } case Enable: return true; diff --git a/src/core/Group.h b/src/core/Group.h index 558bebc..7391f88 100644 --- a/src/core/Group.h +++ b/src/core/Group.h @@ -65,6 +65,8 @@ public: QString defaultAutoTypeSequence() const; Group::TriState autoTypeEnabled() const; Group::TriState searchingEnabled() const; + bool resolveSearchingEnabled() const; + bool resolveAutoTypeEnabled() const; Entry* lastTopVisibleEntry() const; bool isExpired() const; @@ -109,10 +111,6 @@ public: */ Group* clone(Entry::CloneFlags entryFlags = Entry::CloneNewUuid | Entry::CloneResetTimeInfo) const; void copyDataFrom(const Group* other); - Database* exportToDb(); - - QList search(const QString& searchTerm, Qt::CaseSensitivity caseSensitivity, - bool resolveInherit = true); Q_SIGNALS: void dataChanged(Group* group); @@ -147,7 +145,6 @@ private: void cleanupParent(); void recCreateDelObjects(); void updateTimeinfo(); - bool includeInSearch(bool resolveInherit); QPointer m_db; Uuid m_uuid; diff --git a/src/core/ToDbExporter.cpp b/src/core/ToDbExporter.cpp new file mode 100644 index 0000000..1f76fb7 --- /dev/null +++ b/src/core/ToDbExporter.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2014 Felix Geyer + * Copyright (C) 2014 Florian Geyer + * + * 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 2 or (at your option) + * version 3 of the License. + * + * 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 . + */ + +#include "ToDbExporter.h" +#include "core/Database.h" +#include "core/Group.h" +#include "core/Metadata.h" + +Database* ToDbExporter::exportGroup(Group* group) +{ + Database* oldDb = group->database(); + Q_ASSERT(oldDb); + + Database* db = new Database(); + Group* clonedGroup = group->clone(Entry::CloneNewUuid | Entry::CloneIncludeHistory); + clonedGroup->setParent(db->rootGroup()); + + QSet customIcons = group->customIconsRecursive(); + db->metadata()->copyCustomIcons(customIcons, oldDb->metadata()); + + db->copyAttributesFrom(oldDb); + + return db; +} diff --git a/src/core/ToDbExporter.h b/src/core/ToDbExporter.h new file mode 100644 index 0000000..58c5efe --- /dev/null +++ b/src/core/ToDbExporter.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2014 Felix Geyer + * Copyright (C) 2014 Florian Geyer + * + * 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 2 or (at your option) + * version 3 of the License. + * + * 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 . + */ + +#ifndef KEEPASSX_TODBEXPORTER_H +#define KEEPASSX_TODBEXPORTER_H + +#include "core/Exporter.h" + +class Database; +class Group; + +class ToDbExporter : Exporter +{ +public: + Database* exportGroup(Group* group); +}; + +#endif // KEEPASSX_TODBEXPORTER_H diff --git a/src/core/Translator.cpp b/src/core/Translator.cpp new file mode 100644 index 0000000..bc4d2b6 --- /dev/null +++ b/src/core/Translator.cpp @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2014 Felix Geyer + * + * 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 2 or (at your option) + * version 3 of the License. + * + * 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 . + */ + +#include "Translator.h" + +#include +#include +#include +#include +#include +#include + +#include "config-keepassx.h" +#include "core/Config.h" +#include "core/FilePath.h" + +void Translator::installTranslator() +{ + QString language = config()->get("GUI/Language").toString(); + if (language == "system" || language.isEmpty()) { + language = QLocale::system().name(); + } + + if (!installTranslator(language)) { + // English fallback still needs translations for plurals + if (!installTranslator("en_plurals")) { + qWarning("Couldn't load translations."); + } + } + + installQtTranslator(language); + + availableLanguages(); +} + +QList > Translator::availableLanguages() +{ + QStringList paths; +#ifdef QT_DEBUG + paths.append(QString("%1/share/translations").arg(KEEPASSX_BINARY_DIR)); +#endif + paths.append(filePath()->dataPath("translations")); + + QList > languages; + languages.append(QPair("system", "System default")); + + QRegExp regExp("keepassx_([a-zA-Z_]+)\\.qm", Qt::CaseInsensitive, QRegExp::RegExp2); + Q_FOREACH (const QString& path, paths) { + Q_FOREACH (const QString& filename, QDir(path).entryList()) { + if (regExp.exactMatch(filename)) { + QString langcode = regExp.cap(1); + if (langcode == "en_plurals") { + langcode = "en"; + } + + languages.append(QPair(langcode, + QLocale::languageToString(QLocale(langcode).language()))); + } + } + } + + return languages; +} + +bool Translator::installTranslator(const QString& language) +{ + QStringList paths; +#ifdef QT_DEBUG + paths.append(QString("%1/share/translations").arg(KEEPASSX_BINARY_DIR)); +#endif + paths.append(filePath()->dataPath("translations")); + + Q_FOREACH (const QString& path, paths) { + if (installTranslator(language, path)) { + return true; + } + } + + return false; +} + +bool Translator::installTranslator(const QString& language, const QString& path) +{ + QTranslator* translator = new QTranslator(qApp); + if (translator->load(QString("keepassx_").append(language), path)) { + QCoreApplication::installTranslator(translator); + return true; + } + else { + delete translator; + return false; + } +} + +bool Translator::installQtTranslator(const QString& language) +{ + QTranslator* qtTranslator = new QTranslator(qApp); + if (qtTranslator->load(QString("%1/qt_%2").arg(QLibraryInfo::location(QLibraryInfo::TranslationsPath), language))) { + QCoreApplication::installTranslator(qtTranslator); + return true; + } + else { + delete qtTranslator; + return false; + } +} diff --git a/src/core/Translator.h b/src/core/Translator.h new file mode 100644 index 0000000..4bc4fca --- /dev/null +++ b/src/core/Translator.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2014 Felix Geyer + * + * 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 2 or (at your option) + * version 3 of the License. + * + * 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 . + */ + +#ifndef KEEPASSX_TRANSLATOR_H +#define KEEPASSX_TRANSLATOR_H + +#include +#include + +class Translator +{ +public: + static void installTranslator(); + static QList > availableLanguages(); + +private: + static bool installTranslator(const QString& language); + static bool installTranslator(const QString& language, const QString& path); + static bool installQtTranslator(const QString& language); +}; + +#endif // KEEPASSX_TRANSLATOR_H diff --git a/src/crypto/Crypto.cpp b/src/crypto/Crypto.cpp index 1e28002..13c3c20 100644 --- a/src/crypto/Crypto.cpp +++ b/src/crypto/Crypto.cpp @@ -21,7 +21,12 @@ #include +#include "config-keepassx.h" +#include "crypto/CryptoHash.h" +#include "crypto/SymmetricCipher.h" + bool Crypto::m_initalized(false); +QString Crypto::m_errorStr; #if !defined(GCRYPT_VERSION_NUMBER) || (GCRYPT_VERSION_NUMBER < 0x010600) static int gcry_qt_mutex_init(void** p_sys) @@ -64,11 +69,11 @@ Crypto::Crypto() { } -void Crypto::init() +bool Crypto::init() { if (m_initalized) { qWarning("Crypto::init: already initalized"); - return; + return true; } // libgcrypt >= 1.6 doesn't allow custom thread callbacks anymore. @@ -78,7 +83,19 @@ void Crypto::init() gcry_check_version(0); gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); + if (!checkAlgorithms()) { + return false; + } + + // has to be set before testing Crypto classes m_initalized = true; + + if (!selfTest()) { + m_initalized = false; + return false; + } + + return true; } bool Crypto::initalized() @@ -86,7 +103,89 @@ bool Crypto::initalized() return m_initalized; } -bool Crypto::selfTest() +QString Crypto::errorString() +{ + return m_errorStr; +} + +bool Crypto::backendSelfTest() { return (gcry_control(GCRYCTL_SELFTEST) == 0); } + +bool Crypto::checkAlgorithms() +{ + if (gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_TEST_ALGO, Q_NULLPTR, Q_NULLPTR) != 0) { + m_errorStr = "GCRY_CIPHER_AES256 not found."; + qWarning("Crypto::checkAlgorithms: %s", qPrintable(m_errorStr)); + return false; + } + if (gcry_cipher_algo_info(GCRY_CIPHER_TWOFISH, GCRYCTL_TEST_ALGO, Q_NULLPTR, Q_NULLPTR) != 0) { + m_errorStr = "GCRY_CIPHER_TWOFISH not found."; + qWarning("Crypto::checkAlgorithms: %s", qPrintable(m_errorStr)); + return false; + } +#ifdef GCRYPT_HAS_SALSA20 + if (gcry_cipher_algo_info(GCRY_CIPHER_SALSA20, GCRYCTL_TEST_ALGO, Q_NULLPTR, Q_NULLPTR) != 0) { + m_errorStr = "GCRY_CIPHER_SALSA20 not found."; + qWarning("Crypto::checkAlgorithms: %s", qPrintable(m_errorStr)); + return false; + } +#endif + if (gcry_md_test_algo(GCRY_MD_SHA256) != 0) { + m_errorStr = "GCRY_MD_SHA256 not found."; + qWarning("Crypto::checkAlgorithms: %s", qPrintable(m_errorStr)); + return false; + } + + return true; +} + +bool Crypto::selfTest() +{ + QByteArray sha256Test = CryptoHash::hash("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + CryptoHash::Sha256); + + if (sha256Test != QByteArray::fromHex("248D6A61D20638B8E5C026930C3E6039A33CE45964FF2167F6ECEDD419DB06C1")) { + m_errorStr = "SHA-256 mismatch."; + qWarning("Crypto::selfTest: %s", qPrintable(m_errorStr)); + return false; + } + + QByteArray key = QByteArray::fromHex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"); + QByteArray iv = QByteArray::fromHex("000102030405060708090a0b0c0d0e0f"); + QByteArray plainText = QByteArray::fromHex("6bc1bee22e409f96e93d7e117393172a"); + plainText.append(QByteArray::fromHex("ae2d8a571e03ac9c9eb76fac45af8e51")); + QByteArray cipherText = QByteArray::fromHex("f58c4c04d6e5f1ba779eabfb5f7bfbd6"); + cipherText.append(QByteArray::fromHex("9cfc4e967edb808d679f777bc6702c7d")); + + SymmetricCipher aes256Encrypt(SymmetricCipher::Aes256, SymmetricCipher::Cbc, SymmetricCipher::Encrypt, key, iv); + if (aes256Encrypt.process(plainText) != cipherText) { + m_errorStr = "AES-256 encryption mismatch."; + qWarning("Crypto::selfTest: %s", qPrintable(m_errorStr)); + return false; + } + + SymmetricCipher aes256Descrypt(SymmetricCipher::Aes256, SymmetricCipher::Cbc, SymmetricCipher::Decrypt, key, iv); + if (aes256Descrypt.process(cipherText) != plainText) { + m_errorStr = "AES-256 decryption mismatch."; + qWarning("Crypto::selfTest: %s", qPrintable(m_errorStr)); + return false; + } + + QByteArray salsa20Key = QByteArray::fromHex("F3F4F5F6F7F8F9FAFBFCFDFEFF000102030405060708090A0B0C0D0E0F101112"); + QByteArray salsa20iv = QByteArray::fromHex("0000000000000000"); + QByteArray salsa20Plain = QByteArray::fromHex("00000000000000000000000000000000"); + QByteArray salsa20Cipher = QByteArray::fromHex("B4C0AFA503BE7FC29A62058166D56F8F"); + + SymmetricCipher salsa20Stream(SymmetricCipher::Salsa20, SymmetricCipher::Stream, + SymmetricCipher::Encrypt, salsa20Key, salsa20iv); + + if (salsa20Stream.process(salsa20Plain) != salsa20Cipher) { + m_errorStr = "Salsa20 stream cipher mismatch."; + qWarning("Crypto::selfTest: %s", qPrintable(m_errorStr)); + return false; + } + + return true; +} diff --git a/src/crypto/Crypto.h b/src/crypto/Crypto.h index 63f1177..9926f14 100644 --- a/src/crypto/Crypto.h +++ b/src/crypto/Crypto.h @@ -18,18 +18,25 @@ #ifndef KEEPASSX_CRYPTO_H #define KEEPASSX_CRYPTO_H +#include + #include "core/Global.h" class Crypto { public: - static void init(); + static bool init(); static bool initalized(); - static bool selfTest(); + static bool backendSelfTest(); + static QString errorString(); private: Crypto(); + static bool checkAlgorithms(); + static bool selfTest(); + static bool m_initalized; + static QString m_errorStr; }; #endif // KEEPASSX_CRYPTO_H diff --git a/src/gui/Clipboard.cpp b/src/gui/Clipboard.cpp index eb77d2b..7d8f71f 100644 --- a/src/gui/Clipboard.cpp +++ b/src/gui/Clipboard.cpp @@ -51,6 +51,7 @@ void Clipboard::setText(const QString& text) if (config()->get("security/clearclipboard").toBool()) { int timeout = config()->get("security/clearclipboardtimeout").toInt(); if (timeout > 0) { + m_lastCopied = text; m_timer->start(timeout * 1000); } } @@ -65,8 +66,12 @@ void Clipboard::clearClipboard() return; } - clipboard->clear(QClipboard::Clipboard); - if (clipboard->supportsSelection()) { + if (clipboard->text(QClipboard::Clipboard) == m_lastCopied) { + clipboard->clear(QClipboard::Clipboard); + } + + if (clipboard->supportsSelection() + && (clipboard->text(QClipboard::Selection) == m_lastCopied)) { clipboard->clear(QClipboard::Selection); } @@ -74,6 +79,8 @@ void Clipboard::clearClipboard() QDBusMessage message = QDBusMessage::createMethodCall("org.kde.klipper", "/klipper", "", "clearClipboardHistory"); QDBusConnection::sessionBus().send(message); #endif + + m_lastCopied.clear(); } void Clipboard::cleanup() diff --git a/src/gui/Clipboard.h b/src/gui/Clipboard.h index bc2a19d..8b6ea69 100644 --- a/src/gui/Clipboard.h +++ b/src/gui/Clipboard.h @@ -43,6 +43,7 @@ private: static Clipboard* m_instance; QTimer* m_timer; + QString m_lastCopied; }; inline Clipboard* clipboard() { diff --git a/src/gui/DatabaseOpenWidget.cpp b/src/gui/DatabaseOpenWidget.cpp index 9731925..37bbce7 100644 --- a/src/gui/DatabaseOpenWidget.cpp +++ b/src/gui/DatabaseOpenWidget.cpp @@ -117,8 +117,8 @@ void DatabaseOpenWidget::openDatabase() Q_EMIT editFinished(true); } else { - MessageBox::warning(this, tr("Error"), tr("Unable to open the database.\n%1") - .arg(reader.errorString())); + MessageBox::warning(this, tr("Error"), tr("Unable to open the database.").append("\n") + .append(reader.errorString())); m_ui->editPassword->clear(); } } @@ -138,7 +138,7 @@ CompositeKey DatabaseOpenWidget::databaseKey() QString keyFilename = m_ui->comboKeyFile->currentText(); QString errorMsg; if (!key.load(keyFilename, &errorMsg)) { - MessageBox::warning(this, tr("Error"), tr("Can't open key file:\n%1").arg(errorMsg)); + MessageBox::warning(this, tr("Error"), tr("Can't open key file").append(":\n").append(errorMsg)); return CompositeKey(); } masterKey.addKey(key); diff --git a/src/gui/DatabaseTabWidget.cpp b/src/gui/DatabaseTabWidget.cpp index 8c2ba06..7f99846 100644 --- a/src/gui/DatabaseTabWidget.cpp +++ b/src/gui/DatabaseTabWidget.cpp @@ -27,6 +27,7 @@ #include "core/Metadata.h" #include "core/qsavefile.h" #include "gui/DatabaseWidget.h" +#include "gui/DatabaseWidgetStateSync.h" #include "gui/DragTabBar.h" #include "gui/FileDialog.h" #include "gui/MessageBox.h" @@ -46,12 +47,15 @@ const int DatabaseTabWidget::LastDatabasesCount = 5; DatabaseTabWidget::DatabaseTabWidget(QWidget* parent) : QTabWidget(parent) + , m_dbWidgetSateSync(new DatabaseWidgetStateSync(this)) { DragTabBar* tabBar = new DragTabBar(this); tabBar->setDrawBase(false); setTabBar(tabBar); connect(this, SIGNAL(tabCloseRequested(int)), SLOT(closeDatabase(int))); + connect(this, SIGNAL(currentChanged(int)), SLOT(emitActivateDatabaseChanged())); + connect(this, SIGNAL(activateDatabaseChanged(DatabaseWidget*)), m_dbWidgetSateSync, SLOT(setActive(DatabaseWidget*))); connect(autoType(), SIGNAL(globalShortcutTriggered()), SLOT(performGlobalAutoType())); } @@ -189,7 +193,7 @@ bool DatabaseTabWidget::closeDatabase(Database* db) if (dbName.right(1) == "*") { dbName.chop(1); } - if (dbStruct.dbWidget->currentMode() == DatabaseWidget::EditMode && db->hasKey()) { + if (dbStruct.dbWidget->isInEditMode() && db->hasKey()) { QMessageBox::StandardButton result = MessageBox::question( this, tr("Close?"), @@ -503,7 +507,7 @@ DatabaseWidget* DatabaseTabWidget::currentDatabaseWidget() } } -bool DatabaseTabWidget::hasLockableDatabases() +bool DatabaseTabWidget::hasLockableDatabases() const { QHashIterator i(m_dbList); while (i.hasNext()) { @@ -584,6 +588,11 @@ void DatabaseTabWidget::changeDatabase(Database* newDb) connectDatabase(newDb, oldDb); } +void DatabaseTabWidget::emitActivateDatabaseChanged() +{ + Q_EMIT activateDatabaseChanged(currentDatabaseWidget()); +} + void DatabaseTabWidget::connectDatabase(Database* newDb, Database* oldDb) { if (oldDb) { diff --git a/src/gui/DatabaseTabWidget.h b/src/gui/DatabaseTabWidget.h index 9261a06..25d34f3 100644 --- a/src/gui/DatabaseTabWidget.h +++ b/src/gui/DatabaseTabWidget.h @@ -25,6 +25,7 @@ #include "gui/DatabaseWidget.h" class DatabaseWidget; +class DatabaseWidgetStateSync; class DatabaseOpenWidget; class QFile; @@ -53,7 +54,7 @@ public: void openDatabase(const QString& fileName, const QString& pw = QString(), const QString& keyFile = QString()); DatabaseWidget* currentDatabaseWidget(); - bool hasLockableDatabases(); + bool hasLockableDatabases() const; static const int LastDatabasesCount; @@ -75,6 +76,7 @@ public Q_SLOTS: Q_SIGNALS: void tabNameChanged(); void databaseWithFileClosed(QString filePath); + void activateDatabaseChanged(DatabaseWidget* dbWidget); private Q_SLOTS: void updateTabName(Database* db); @@ -83,6 +85,7 @@ private Q_SLOTS: void modified(); void toggleTabbar(); void changeDatabase(Database* newDb); + void emitActivateDatabaseChanged(); private: void saveDatabase(Database* db); @@ -99,6 +102,7 @@ private: KeePass2Writer m_writer; QHash m_dbList; + DatabaseWidgetStateSync* m_dbWidgetSateSync; }; #endif // KEEPASSX_DATABASETABWIDGET_H diff --git a/src/gui/DatabaseWidget.cpp b/src/gui/DatabaseWidget.cpp index 56ab8b6..cc9c5fd 100644 --- a/src/gui/DatabaseWidget.cpp +++ b/src/gui/DatabaseWidget.cpp @@ -28,7 +28,9 @@ #include "autotype/AutoType.h" #include "core/Config.h" +#include "core/EntrySearcher.h" #include "core/FilePath.h" +#include "core/Group.h" #include "core/Metadata.h" #include "core/Tools.h" #include "gui/ChangeMasterKeyWidget.h" @@ -59,12 +61,13 @@ DatabaseWidget::DatabaseWidget(Database* db, QWidget* parent) m_mainWidget = new QWidget(this); QLayout* layout = new QHBoxLayout(m_mainWidget); - QSplitter* splitter = new QSplitter(m_mainWidget); + m_splitter = new QSplitter(m_mainWidget); + m_splitter->setChildrenCollapsible(false); - QWidget* rightHandSideWidget = new QWidget(splitter); + QWidget* rightHandSideWidget = new QWidget(m_splitter); m_searchWidget->setParent(rightHandSideWidget); - m_groupView = new GroupView(db, splitter); + m_groupView = new GroupView(db, m_splitter); m_groupView->setObjectName("groupView"); m_groupView->setContextMenuPolicy(Qt::CustomContextMenu); connect(m_groupView, SIGNAL(customContextMenuRequested(QPoint)), @@ -77,14 +80,6 @@ DatabaseWidget::DatabaseWidget(Database* db, QWidget* parent) connect(m_entryView, SIGNAL(customContextMenuRequested(QPoint)), SLOT(emitEntryContextMenuRequested(QPoint))); - QSizePolicy policy; - policy = m_groupView->sizePolicy(); - policy.setHorizontalStretch(30); - m_groupView->setSizePolicy(policy); - policy = rightHandSideWidget->sizePolicy(); - policy.setHorizontalStretch(70); - rightHandSideWidget->setSizePolicy(policy); - QAction* closeAction = new QAction(m_searchWidget); QIcon closeIcon = filePath()->icon("actions", "dialog-close"); closeAction->setIcon(closeIcon); @@ -100,10 +95,17 @@ DatabaseWidget::DatabaseWidget(Database* db, QWidget* parent) rightHandSideWidget->setLayout(vLayout); - splitter->addWidget(m_groupView); - splitter->addWidget(rightHandSideWidget); + setTabOrder(m_searchUi->searchRootRadioButton, m_entryView); + setTabOrder(m_entryView, m_groupView); + setTabOrder(m_groupView, m_searchWidget); + + m_splitter->addWidget(m_groupView); + m_splitter->addWidget(rightHandSideWidget); - layout->addWidget(splitter); + m_splitter->setStretchFactor(0, 30); + m_splitter->setStretchFactor(1, 70); + + layout->addWidget(m_splitter); m_mainWidget->setLayout(layout); m_editEntryWidget = new EditEntryWidget(); @@ -135,6 +137,8 @@ DatabaseWidget::DatabaseWidget(Database* db, QWidget* parent) addWidget(m_keepass1OpenWidget); addWidget(m_unlockDatabaseWidget); + connect(m_splitter, SIGNAL(splitterMoved(int,int)), SIGNAL(splitterSizesChanged())); + connect(m_entryView->header(), SIGNAL(sectionResized(int,int,int)), SIGNAL(entryColumnSizesChanged())); connect(m_groupView, SIGNAL(groupChanged(Group*)), this, SLOT(clearLastGroup(Group*))); connect(m_groupView, SIGNAL(groupChanged(Group*)), SIGNAL(groupChanged())); connect(m_groupView, SIGNAL(groupChanged(Group*)), m_entryView, SLOT(setGroup(Group*))); @@ -166,7 +170,7 @@ DatabaseWidget::~DatabaseWidget() { } -DatabaseWidget::Mode DatabaseWidget::currentMode() +DatabaseWidget::Mode DatabaseWidget::currentMode() const { if (currentWidget() == Q_NULLPTR) { return DatabaseWidget::None; @@ -182,19 +186,54 @@ DatabaseWidget::Mode DatabaseWidget::currentMode() } } -void DatabaseWidget::emitCurrentModeChanged() +bool DatabaseWidget::isInEditMode() const { - Q_EMIT currentModeChanged(currentMode()); + if (currentMode() == DatabaseWidget::LockedMode) { + return m_widgetBeforeLock != Q_NULLPTR + && m_widgetBeforeLock != m_mainWidget + && m_widgetBeforeLock != m_unlockDatabaseWidget; + } + else { + return currentMode() == DatabaseWidget::EditMode; + } } -GroupView* DatabaseWidget::groupView() +QList DatabaseWidget::splitterSizes() const { - return m_groupView; + return m_splitter->sizes(); } -EntryView* DatabaseWidget::entryView() +void DatabaseWidget::setSplitterSizes(const QList& sizes) { - return m_entryView; + m_splitter->setSizes(sizes); +} + +QList DatabaseWidget::entryHeaderViewSizes() const +{ + QList sizes; + + for (int i = 0; i < m_entryView->header()->count(); i++) { + sizes.append(m_entryView->header()->sectionSize(i)); + } + + return sizes; +} + +void DatabaseWidget::setEntryViewHeaderSizes(const QList& sizes) +{ + if (sizes.size() != m_entryView->header()->count()) { + Q_ASSERT(false); + return; + } + + for (int i = 0; i < sizes.size(); i++) { + m_entryView->header()->resizeSection(i, sizes[i]); + } +} + +void DatabaseWidget::emitCurrentModeChanged() +{ + Q_EMIT currentModeChanged(currentMode()); } Database* DatabaseWidget::database() @@ -213,9 +252,28 @@ void DatabaseWidget::createEntry() m_newEntry->setUuid(Uuid::random()); m_newEntry->setUsername(m_db->metadata()->defaultUserName()); m_newParent = m_groupView->currentGroup(); + setIconFromParent(); switchToEntryEdit(m_newEntry, true); } +void DatabaseWidget::setIconFromParent() +{ + if (!config()->get("UseGroupIconOnEntryCreation").toBool()) { + return; + } + + if (m_newParent->iconNumber() == Group::DefaultIconNumber && m_newParent->iconUuid().isNull()) { + return; + } + + if (m_newParent->iconUuid().isNull()) { + m_newEntry->setIcon(m_newParent->iconNumber()); + } + else { + m_newEntry->setIcon(m_newParent->iconUuid()); + } +} + void DatabaseWidget::cloneEntry() { Entry* currentEntry = m_entryView->currentEntry(); @@ -274,8 +332,7 @@ void DatabaseWidget::deleteEntries() if (selected.size() > 1) { QMessageBox::StandardButton result = MessageBox::question( this, tr("Move entries to recycle bin?"), - tr("Do you really want to move %1 entries to the recycle bin?") - .arg(selected.size()), + tr("Do you really want to move %n entry(s) to the recycle bin?", 0, selected.size()), QMessageBox::Yes | QMessageBox::No); if (result == QMessageBox::No) { return; @@ -407,7 +464,7 @@ void DatabaseWidget::createGroup() void DatabaseWidget::deleteGroup() { Group* currentGroup = m_groupView->currentGroup(); - if (!currentGroup || !canDeleteCurrentGoup()) { + if (!currentGroup || !canDeleteCurrentGroup()) { Q_ASSERT(false); return; } @@ -575,7 +632,7 @@ void DatabaseWidget::unlockDatabase(bool accepted) Q_ASSERT(accepted); Q_UNUSED(accepted); - setCurrentWidget(widgetBeforeLock); + setCurrentWidget(m_widgetBeforeLock); Q_EMIT unlockedDatabase(); } @@ -647,8 +704,16 @@ void DatabaseWidget::switchToImportKeepass1(const QString& fileName) void DatabaseWidget::toggleSearch() { - if (m_entryView->inEntryListMode()) { - closeSearch(); + if (isInSearchMode()) { + if (m_searchUi->searchEdit->hasFocus()) { + closeSearch(); + } + else { + m_searchUi->searchEdit->selectAll(); + m_searchUi->searchEdit->setFocus(); + // make sure the search action is checked again + emitCurrentModeChanged(); + } } else { showSearch(); @@ -658,11 +723,19 @@ void DatabaseWidget::toggleSearch() void DatabaseWidget::closeSearch() { Q_ASSERT(m_lastGroup); + + Q_EMIT listModeAboutToActivate(); + m_groupView->setCurrentGroup(m_lastGroup); + m_searchTimer->stop(); + + Q_EMIT listModeActivated(); } void DatabaseWidget::showSearch() { + Q_EMIT searchModeAboutToActivate(); + m_searchUi->searchEdit->blockSignals(true); m_searchUi->searchEdit->clear(); m_searchUi->searchEdit->blockSignals(false); @@ -696,6 +769,8 @@ void DatabaseWidget::showSearch() m_searchWidget->show(); search(); m_searchUi->searchEdit->setFocus(); + + Q_EMIT searchModeActivated(); } void DatabaseWidget::search() @@ -721,8 +796,8 @@ void DatabaseWidget::search() else { sensitivity = Qt::CaseInsensitive; } - QList searchResult = searchGroup->search(m_searchUi->searchEdit->text(), sensitivity); + QList searchResult = EntrySearcher().search(m_searchUi->searchEdit->text(), searchGroup, sensitivity); m_entryView->setEntryList(searchResult); } @@ -753,19 +828,19 @@ void DatabaseWidget::emitEntryContextMenuRequested(const QPoint& pos) Q_EMIT entryContextMenuRequested(m_entryView->viewport()->mapToGlobal(pos)); } -bool DatabaseWidget::dbHasKey() +bool DatabaseWidget::dbHasKey() const { return m_db->hasKey(); } -bool DatabaseWidget::canDeleteCurrentGoup() +bool DatabaseWidget::canDeleteCurrentGroup() const { bool isRootGroup = m_db->rootGroup() == m_groupView->currentGroup(); bool isRecycleBin = m_db->metadata()->recycleBin() == m_groupView->currentGroup(); return !isRootGroup && !isRecycleBin; } -bool DatabaseWidget::isInSearchMode() +bool DatabaseWidget::isInSearchMode() const { return m_entryView->inEntryListMode(); } @@ -782,7 +857,7 @@ void DatabaseWidget::lock() { Q_ASSERT(currentMode() != DatabaseWidget::LockedMode); - widgetBeforeLock = currentWidget(); + m_widgetBeforeLock = currentWidget(); m_unlockDatabaseWidget->load(m_filename, m_db); setCurrentWidget(m_unlockDatabaseWidget); } @@ -791,3 +866,23 @@ void DatabaseWidget::updateFilename(const QString& fileName) { m_filename = fileName; } + +int DatabaseWidget::numberOfSelectedEntries() const +{ + return m_entryView->numberOfSelectedEntries(); +} + +QStringList DatabaseWidget::customEntryAttributes() const +{ + Entry* entry = m_entryView->currentEntry(); + if (!entry) { + return QStringList(); + } + + return entry->attributes()->customKeys(); +} + +bool DatabaseWidget::isGroupSelected() const +{ + return m_groupView->currentGroup() != Q_NULLPTR; +} diff --git a/src/gui/DatabaseWidget.h b/src/gui/DatabaseWidget.h index 240fe28..cbab175 100644 --- a/src/gui/DatabaseWidget.h +++ b/src/gui/DatabaseWidget.h @@ -38,6 +38,7 @@ class GroupView; class KeePass1OpenWidget; class QFile; class QMenu; +class QSplitter; class UnlockDatabaseWidget; namespace Ui { @@ -59,18 +60,24 @@ public: explicit DatabaseWidget(Database* db, QWidget* parent = Q_NULLPTR); ~DatabaseWidget(); - GroupView* groupView(); - EntryView* entryView(); Database* database(); - bool dbHasKey(); - bool canDeleteCurrentGoup(); - bool isInSearchMode(); + bool dbHasKey() const; + bool canDeleteCurrentGroup() const; + bool isInSearchMode() const; int addWidget(QWidget* w); void setCurrentIndex(int index); void setCurrentWidget(QWidget* widget); - DatabaseWidget::Mode currentMode(); + DatabaseWidget::Mode currentMode() const; void lock(); void updateFilename(const QString& filename); + int numberOfSelectedEntries() const; + QStringList customEntryAttributes() const; + bool isGroupSelected() const; + bool isInEditMode() const; + QList splitterSizes() const; + void setSplitterSizes(const QList& sizes); + QList entryHeaderViewSizes() const; + void setEntryViewHeaderSizes(const QList& sizes); Q_SIGNALS: void closeRequest(); @@ -81,6 +88,12 @@ Q_SIGNALS: void groupContextMenuRequested(const QPoint& globalPos); void entryContextMenuRequested(const QPoint& globalPos); void unlockedDatabase(); + void listModeAboutToActivate(); + void listModeActivated(); + void searchModeAboutToActivate(); + void searchModeActivated(); + void splitterSizesChanged(); + void entryColumnSizesChanged(); public Q_SLOTS: void createEntry(); @@ -105,8 +118,6 @@ public Q_SLOTS: void switchToOpenDatabase(const QString& fileName, const QString& password, const QString& keyFile); void switchToImportKeepass1(const QString& fileName); void toggleSearch(); - void emitGroupContextMenuRequested(const QPoint& pos); - void emitEntryContextMenuRequested(const QPoint& pos); private Q_SLOTS: void entryActivationSignalReceived(Entry* entry, EntryModel::ModelColumn column); @@ -116,6 +127,8 @@ private Q_SLOTS: void switchToEntryEdit(Entry* entry); void switchToEntryEdit(Entry* entry, bool create); void switchToGroupEdit(Group* entry, bool create); + void emitGroupContextMenuRequested(const QPoint& pos); + void emitEntryContextMenuRequested(const QPoint& pos); void updateMasterKey(bool accepted); void openDatabase(bool accepted); void unlockDatabase(bool accepted); @@ -129,6 +142,7 @@ private Q_SLOTS: private: void setClipboardTextAndMinimize(const QString& text); + void setIconFromParent(); Database* m_db; const QScopedPointer m_searchUi; @@ -142,6 +156,7 @@ private: DatabaseOpenWidget* m_databaseOpenWidget; KeePass1OpenWidget* m_keepass1OpenWidget; UnlockDatabaseWidget* m_unlockDatabaseWidget; + QSplitter* m_splitter; GroupView* m_groupView; EntryView* m_entryView; Group* m_newGroup; @@ -149,7 +164,7 @@ private: Group* m_newParent; Group* m_lastGroup; QTimer* m_searchTimer; - QWidget* widgetBeforeLock; + QWidget* m_widgetBeforeLock; QString m_filename; }; diff --git a/src/gui/DatabaseWidgetStateSync.cpp b/src/gui/DatabaseWidgetStateSync.cpp new file mode 100644 index 0000000..66b8492 --- /dev/null +++ b/src/gui/DatabaseWidgetStateSync.cpp @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2014 Felix Geyer + * Copyright (C) 2014 Florian Geyer + * + * 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 2 or (at your option) + * version 3 of the License. + * + * 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 . + */ + +#include "DatabaseWidgetStateSync.h" + +#include "core/Config.h" + +DatabaseWidgetStateSync::DatabaseWidgetStateSync(QObject* parent) + : QObject(parent) + , m_activeDbWidget(Q_NULLPTR) + , m_blockUpdates(false) +{ + m_splitterSizes = variantToIntList(config()->get("GUI/SplitterState")); + m_columnSizesList = variantToIntList(config()->get("GUI/EntryListColumnSizes")); + m_columnSizesSearch = variantToIntList(config()->get("GUI/EntrySearchColumnSizes")); +} + +DatabaseWidgetStateSync::~DatabaseWidgetStateSync() +{ + config()->set("GUI/SplitterState", intListToVariant(m_splitterSizes)); + config()->set("GUI/EntryListColumnSizes", intListToVariant(m_columnSizesList)); + config()->set("GUI/EntrySearchColumnSizes", intListToVariant(m_columnSizesSearch)); +} + +void DatabaseWidgetStateSync::setActive(DatabaseWidget* dbWidget) +{ + if (m_activeDbWidget) { + disconnect(m_activeDbWidget, 0, this, 0); + } + + m_activeDbWidget = dbWidget; + + if (m_activeDbWidget) { + m_blockUpdates = true; + + if (!m_splitterSizes.isEmpty()) { + m_activeDbWidget->setSplitterSizes(m_splitterSizes); + } + + if (m_activeDbWidget->isGroupSelected()) { + restoreListView(); + } + else { + restoreSearchView(); + } + + m_blockUpdates = false; + + connect(m_activeDbWidget, SIGNAL(splitterSizesChanged()), + SLOT(updateSplitterSizes())); + connect(m_activeDbWidget, SIGNAL(entryColumnSizesChanged()), + SLOT(updateColumnSizes())); + connect(m_activeDbWidget, SIGNAL(listModeActivated()), + SLOT(restoreListView())); + connect(m_activeDbWidget, SIGNAL(searchModeActivated()), + SLOT(restoreSearchView())); + connect(m_activeDbWidget, SIGNAL(listModeAboutToActivate()), + SLOT(blockUpdates())); + connect(m_activeDbWidget, SIGNAL(searchModeAboutToActivate()), + SLOT(blockUpdates())); + } +} + +void DatabaseWidgetStateSync::restoreListView() +{ + if (!m_columnSizesList.isEmpty()) { + m_activeDbWidget->setEntryViewHeaderSizes(m_columnSizesList); + } + + m_blockUpdates = false; +} + +void DatabaseWidgetStateSync::restoreSearchView() +{ + if (!m_columnSizesSearch.isEmpty()) { + m_activeDbWidget->setEntryViewHeaderSizes(m_columnSizesSearch); + } + + m_blockUpdates = false; +} + +void DatabaseWidgetStateSync::blockUpdates() +{ + m_blockUpdates = true; +} + +void DatabaseWidgetStateSync::updateSplitterSizes() +{ + if (m_blockUpdates) { + return; + } + + m_splitterSizes = m_activeDbWidget->splitterSizes(); +} + +void DatabaseWidgetStateSync::updateColumnSizes() +{ + if (m_blockUpdates) { + return; + } + + if (m_activeDbWidget->isGroupSelected()) { + m_columnSizesList = m_activeDbWidget->entryHeaderViewSizes(); + } + else { + m_columnSizesSearch = m_activeDbWidget->entryHeaderViewSizes(); + } +} + +QList DatabaseWidgetStateSync::variantToIntList(const QVariant& variant) +{ + QVariantList list = variant.toList(); + QList result; + + Q_FOREACH (const QVariant& var, list) { + bool ok; + int size = var.toInt(&ok); + if (ok) { + result.append(size); + } + else { + result.clear(); + break; + } + } + + return result; +} + +QVariant DatabaseWidgetStateSync::intListToVariant(const QList& list) +{ + QVariantList result; + + Q_FOREACH (int value, list) { + result.append(value); + } + + return result; +} diff --git a/src/gui/DatabaseWidgetStateSync.h b/src/gui/DatabaseWidgetStateSync.h new file mode 100644 index 0000000..f6a87cd --- /dev/null +++ b/src/gui/DatabaseWidgetStateSync.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2014 Felix Geyer + * Copyright (C) 2014 Florian Geyer + * + * 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 2 or (at your option) + * version 3 of the License. + * + * 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 . + */ + +#ifndef KEEPASSX_HEADERVIEWSYNC_H +#define KEEPASSX_HEADERVIEWSYNC_H + +#include "gui/DatabaseWidget.h" + +class DatabaseWidgetStateSync : public QObject +{ + Q_OBJECT + +public: + explicit DatabaseWidgetStateSync(QObject* parent = Q_NULLPTR); + ~DatabaseWidgetStateSync(); + +public Q_SLOTS: + void setActive(DatabaseWidget* dbWidget); + void restoreListView(); + void restoreSearchView(); + +private Q_SLOTS: + void blockUpdates(); + void updateSplitterSizes(); + void updateColumnSizes(); + +private: + static QList variantToIntList(const QVariant& variant); + static QVariant intListToVariant(const QList& list); + + DatabaseWidget* m_activeDbWidget; + + bool m_blockUpdates; + QList m_splitterSizes; + QList m_columnSizesList; + QList m_columnSizesSearch; +}; + +#endif // KEEPASSX_HEADERVIEWSYNC_H diff --git a/src/gui/EditWidgetIcons.cpp b/src/gui/EditWidgetIcons.cpp index 26314d3..9e85745 100644 --- a/src/gui/EditWidgetIcons.cpp +++ b/src/gui/EditWidgetIcons.cpp @@ -194,8 +194,7 @@ void EditWidgetIcons::removeCustomIcon() } else { MessageBox::information(this, tr("Can't delete icon!"), - tr("Can't delete icon. Still used by %1 items.") - .arg(iconUsedCount)); + tr("Can't delete icon. Still used by %n item(s).", 0, iconUsedCount)); } } } diff --git a/src/gui/KeePass1OpenWidget.cpp b/src/gui/KeePass1OpenWidget.cpp index 5f23d80..96ddf13 100644 --- a/src/gui/KeePass1OpenWidget.cpp +++ b/src/gui/KeePass1OpenWidget.cpp @@ -64,8 +64,8 @@ void KeePass1OpenWidget::openDatabase() Q_EMIT editFinished(true); } else { - MessageBox::warning(this, tr("Error"), tr("Unable to open the database.\n%1") - .arg(reader.errorString())); + MessageBox::warning(this, tr("Error"), tr("Unable to open the database.").append("\n") + .append(reader.errorString())); m_ui->editPassword->clear(); } } diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index 36fb656..dd77989 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -23,24 +23,23 @@ #include "autotype/AutoType.h" #include "core/Config.h" -#include "core/Database.h" -#include "core/Entry.h" #include "core/FilePath.h" #include "core/InactivityTimer.h" #include "core/Metadata.h" #include "gui/AboutDialog.h" #include "gui/DatabaseWidget.h" -#include "gui/entry/EntryView.h" -#include "gui/group/GroupView.h" const QString MainWindow::BaseWindowTitle = "KeePassX"; MainWindow::MainWindow() : m_ui(new Ui::MainWindow()) + , m_trayIcon(Q_NULLPTR) { m_ui->setupUi(this); - restoreGeometry(config()->get("window/Geometry").toByteArray()); + m_countDefaultAttributes = m_ui->menuEntryCopyAttribute->actions().size(); + + restoreGeometry(config()->get("GUI/MainWindowGeometry").toByteArray()); setWindowIcon(filePath()->applicationIcon()); QAction* toggleViewAction = m_ui->toolBar->toggleViewAction(); @@ -203,6 +202,8 @@ MainWindow::MainWindow() m_actionMultiplexer.connect(m_ui->actionSearch, SIGNAL(triggered()), SLOT(toggleSearch())); + + updateTrayIcon(); } MainWindow::~MainWindow() @@ -229,17 +230,16 @@ void MainWindow::updateCopyAttributesMenu() return; } - Entry* entry = dbWidget->entryView()->currentEntry(); - if (!entry || !dbWidget->entryView()->isSingleEntrySelected()) { + if (dbWidget->numberOfSelectedEntries() != 1) { return; } QList actions = m_ui->menuEntryCopyAttribute->actions(); - for (int i = EntryAttributes::DefaultAttributes.size() + 1; i < actions.size(); i++) { + for (int i = m_countDefaultAttributes; i < actions.size(); i++) { delete actions[i]; } - Q_FOREACH (const QString& key, entry->attributes()->customKeys()) { + Q_FOREACH (const QString& key, dbWidget->customEntryAttributes()) { QAction* action = m_ui->menuEntryCopyAttribute->addAction(key); m_copyAdditionalAttributeActions->addAction(action); } @@ -276,9 +276,9 @@ void MainWindow::setMenuActionState(DatabaseWidget::Mode mode) switch (mode) { case DatabaseWidget::ViewMode: { bool inSearch = dbWidget->isInSearchMode(); - bool singleEntrySelected = dbWidget->entryView()->isSingleEntrySelected(); - bool entriesSelected = !dbWidget->entryView()->selectionModel()->selectedRows().isEmpty(); - bool groupSelected = dbWidget->groupView()->currentGroup(); + bool singleEntrySelected = dbWidget->numberOfSelectedEntries() == 1; + bool entriesSelected = dbWidget->numberOfSelectedEntries() > 0; + bool groupSelected = dbWidget->isGroupSelected(); m_ui->actionEntryNew->setEnabled(!inSearch); m_ui->actionEntryClone->setEnabled(singleEntrySelected && !inSearch); @@ -294,7 +294,7 @@ void MainWindow::setMenuActionState(DatabaseWidget::Mode mode) m_ui->actionEntryOpenUrl->setEnabled(singleEntrySelected); m_ui->actionGroupNew->setEnabled(groupSelected); m_ui->actionGroupEdit->setEnabled(groupSelected); - m_ui->actionGroupDelete->setEnabled(groupSelected && dbWidget->canDeleteCurrentGoup()); + m_ui->actionGroupDelete->setEnabled(groupSelected && dbWidget->canDeleteCurrentGroup()); m_ui->actionSearch->setEnabled(true); // TODO: get checked state from db widget m_ui->actionSearch->setChecked(inSearch); @@ -313,6 +313,11 @@ void MainWindow::setMenuActionState(DatabaseWidget::Mode mode) Q_FOREACH (QAction* action, m_ui->menuGroups->actions()) { action->setEnabled(false); } + m_ui->actionEntryCopyTitle->setEnabled(false); + m_ui->actionEntryCopyUsername->setEnabled(false); + m_ui->actionEntryCopyPassword->setEnabled(false); + m_ui->actionEntryCopyURL->setEnabled(false); + m_ui->actionEntryCopyNotes->setEnabled(false); m_ui->menuEntryCopyAttribute->setEnabled(false); m_ui->actionSearch->setEnabled(false); @@ -335,6 +340,11 @@ void MainWindow::setMenuActionState(DatabaseWidget::Mode mode) Q_FOREACH (QAction* action, m_ui->menuGroups->actions()) { action->setEnabled(false); } + m_ui->actionEntryCopyTitle->setEnabled(false); + m_ui->actionEntryCopyUsername->setEnabled(false); + m_ui->actionEntryCopyPassword->setEnabled(false); + m_ui->actionEntryCopyURL->setEnabled(false); + m_ui->actionEntryCopyNotes->setEnabled(false); m_ui->menuEntryCopyAttribute->setEnabled(false); m_ui->actionSearch->setEnabled(false); @@ -422,15 +432,29 @@ void MainWindow::closeEvent(QCloseEvent* event) saveWindowInformation(); event->accept(); + QApplication::quit(); } else { event->ignore(); } } +void MainWindow::changeEvent(QEvent *event) +{ + if ((event->type() == QEvent::WindowStateChange) && isMinimized() + && isTrayIconEnabled() && config()->get("GUI/MinimizeToTray").toBool()) + { + event->ignore(); + hide(); + } + else { + QMainWindow::changeEvent(event); + } +} + void MainWindow::saveWindowInformation() { - config()->set("window/Geometry", saveGeometry()); + config()->set("GUI/MainWindowGeometry", saveGeometry()); } bool MainWindow::saveLastDatabases() @@ -460,6 +484,35 @@ bool MainWindow::saveLastDatabases() return accept; } +void MainWindow::updateTrayIcon() +{ + if (isTrayIconEnabled()) { + if (!m_trayIcon) { + m_trayIcon = new QSystemTrayIcon(filePath()->applicationIcon(), this); + + QMenu* menu = new QMenu(this); + + QAction* actionToggle = new QAction(tr("Toggle window"), menu); + menu->addAction(actionToggle); + + menu->addAction(m_ui->actionQuit); + + connect(m_trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), + SLOT(trayIconTriggered(QSystemTrayIcon::ActivationReason))); + connect(actionToggle, SIGNAL(triggered()), SLOT(toggleWindow())); + + m_trayIcon->setContextMenu(menu); + m_trayIcon->show(); + } + } + else { + if (m_trayIcon) { + delete m_trayIcon; + m_trayIcon = Q_NULLPTR; + } + } +} + void MainWindow::showEntryContextMenu(const QPoint& globalPos) { m_ui->menuEntries->popup(globalPos); @@ -504,4 +557,31 @@ void MainWindow::applySettingsChanges() else { m_inactivityTimer->deactivate(); } + + updateTrayIcon(); +} + +void MainWindow::trayIconTriggered(QSystemTrayIcon::ActivationReason reason) +{ + if (reason == QSystemTrayIcon::Trigger) { + toggleWindow(); + } +} + +void MainWindow::toggleWindow() +{ + if (QApplication::activeWindow() == this) { + hide(); + } + else { + show(); + raise(); + activateWindow(); + } +} + +bool MainWindow::isTrayIconEnabled() const +{ + return config()->get("GUI/ShowTrayIcon").toBool() + && QSystemTrayIcon::isSystemTrayAvailable(); } diff --git a/src/gui/MainWindow.h b/src/gui/MainWindow.h index 706fd2d..b966703 100644 --- a/src/gui/MainWindow.h +++ b/src/gui/MainWindow.h @@ -20,6 +20,7 @@ #include #include +#include #include "core/SignalMultiplexer.h" #include "gui/DatabaseWidget.h" @@ -44,6 +45,7 @@ public Q_SLOTS: protected: void closeEvent(QCloseEvent* event) Q_DECL_OVERRIDE; + void changeEvent(QEvent* event) Q_DECL_OVERRIDE; private Q_SLOTS: void setMenuActionState(DatabaseWidget::Mode mode = DatabaseWidget::None); @@ -61,6 +63,8 @@ private Q_SLOTS: void saveToolbarState(bool value); void rememberOpenDatabases(const QString& filePath); void applySettingsChanges(); + void trayIconTriggered(QSystemTrayIcon::ActivationReason reason); + void toggleWindow(); private: static void setShortcut(QAction* action, QKeySequence::StandardKey standard, int fallback = 0); @@ -69,6 +73,8 @@ private: void saveWindowInformation(); bool saveLastDatabases(); + void updateTrayIcon(); + bool isTrayIconEnabled() const; const QScopedPointer m_ui; SignalMultiplexer m_actionMultiplexer; @@ -77,6 +83,8 @@ private: QActionGroup* m_copyAdditionalAttributeActions; QStringList m_openDatabases; InactivityTimer* m_inactivityTimer; + int m_countDefaultAttributes; + QSystemTrayIcon* m_trayIcon; Q_DISABLE_COPY(MainWindow) }; diff --git a/src/gui/PasswordComboBox.cpp b/src/gui/PasswordComboBox.cpp index af8e994..f11311a 100644 --- a/src/gui/PasswordComboBox.cpp +++ b/src/gui/PasswordComboBox.cpp @@ -45,7 +45,13 @@ void PasswordComboBox::setEcho(bool echo) // add fake item to show visual indication that a popup is available addItem(""); - setStyleSheet("QComboBox { font-family: monospace; }"); +#ifdef Q_OS_MAC + // Qt on Mac OS doesn't seem to know the generic monospace family (tested with 4.8.6) + setStyleSheet("QComboBox { font-family: monospace,Menlo,Monaco; }"); +#else + setStyleSheet("QComboBox { font-family: monospace,Courier; }"); +#endif + } else { // clear items so the combobox indicates that no popup menu is available diff --git a/src/gui/PasswordEdit.cpp b/src/gui/PasswordEdit.cpp index 8532696..b68eef6 100644 --- a/src/gui/PasswordEdit.cpp +++ b/src/gui/PasswordEdit.cpp @@ -56,7 +56,12 @@ void PasswordEdit::updateStylesheet() QString stylesheet("QLineEdit { "); if (echoMode() == QLineEdit::Normal) { +#ifdef Q_OS_MAC + // Qt on Mac OS doesn't seem to know the generic monospace family (tested with 4.8.6) + stylesheet.append("font-family: monospace,Menlo,Monaco; "); +#else stylesheet.append("font-family: monospace; "); +#endif } if (m_basePasswordEdit && !passwordsEqual()) { diff --git a/src/gui/PasswordGeneratorWidget.ui b/src/gui/PasswordGeneratorWidget.ui index 342f191..5c75ef9 100644 --- a/src/gui/PasswordGeneratorWidget.ui +++ b/src/gui/PasswordGeneratorWidget.ui @@ -100,7 +100,7 @@ Upper Case Letters - A-Z + A-Z true @@ -116,7 +116,7 @@ Lower Case Letters - a-z + a-z true @@ -132,7 +132,7 @@ Numbers - 0-9 + 0-9 true @@ -148,7 +148,7 @@ Special Characters - /*_& ... + /*_& ... true diff --git a/src/gui/SearchWidget.ui b/src/gui/SearchWidget.ui index c3d59b8..ce4845d 100644 --- a/src/gui/SearchWidget.ui +++ b/src/gui/SearchWidget.ui @@ -11,7 +11,16 @@ - + + 0 + + + 0 + + + 0 + + 0 @@ -21,6 +30,9 @@ + + Qt::ClickFocus + true @@ -38,7 +50,16 @@ - + + 0 + + + 0 + + + 0 + + 0 diff --git a/src/gui/SettingsWidget.cpp b/src/gui/SettingsWidget.cpp index d8516c6..a7863ea 100644 --- a/src/gui/SettingsWidget.cpp +++ b/src/gui/SettingsWidget.cpp @@ -21,6 +21,7 @@ #include "autotype/AutoType.h" #include "core/Config.h" +#include "core/Translator.h" SettingsWidget::SettingsWidget(QWidget* parent) : EditWidget(parent) @@ -46,6 +47,8 @@ SettingsWidget::SettingsWidget(QWidget* parent) connect(m_generalUi->autoSaveAfterEveryChangeCheckBox, SIGNAL(toggled(bool)), this, SLOT(enableAutoSaveOnExit(bool))); + connect(m_generalUi->systrayShowCheckBox, SIGNAL(toggled(bool)), + m_generalUi->systrayMinimizeToTrayCheckBox, SLOT(setEnabled(bool))); connect(m_secUi->clearClipboardCheckBox, SIGNAL(toggled(bool)), m_secUi->clearClipboardSpinBox, SLOT(setEnabled(bool))); @@ -66,6 +69,21 @@ void SettingsWidget::loadSettings() m_generalUi->autoSaveAfterEveryChangeCheckBox->setChecked(config()->get("AutoSaveAfterEveryChange").toBool()); m_generalUi->autoSaveOnExitCheckBox->setChecked(config()->get("AutoSaveOnExit").toBool()); m_generalUi->minimizeOnCopyCheckBox->setChecked(config()->get("MinimizeOnCopy").toBool()); + m_generalUi->useGroupIconOnEntryCreationCheckBox->setChecked(config()->get("UseGroupIconOnEntryCreation").toBool()); + m_generalUi->autoTypeEntryTitleMatchCheckBox->setChecked(config()->get("AutoTypeEntryTitleMatch").toBool()); + + m_generalUi->languageComboBox->clear(); + QList > languages = Translator::availableLanguages(); + for (int i = 0; i < languages.size(); i++) { + m_generalUi->languageComboBox->addItem(languages[i].second, languages[i].first); + } + int defaultIndex = m_generalUi->languageComboBox->findData(config()->get("GUI/Language")); + if (defaultIndex > 0) { + m_generalUi->languageComboBox->setCurrentIndex(defaultIndex); + } + + m_generalUi->systrayShowCheckBox->setChecked(config()->get("GUI/ShowTrayIcon").toBool()); + m_generalUi->systrayMinimizeToTrayCheckBox->setChecked(config()->get("GUI/MinimizeToTray").toBool()); if (autoType()->isAvailable()) { m_globalAutoTypeKey = static_cast(config()->get("GlobalAutoTypeKey").toInt()); @@ -83,6 +101,8 @@ void SettingsWidget::loadSettings() m_secUi->passwordCleartextCheckBox->setChecked(config()->get("security/passwordscleartext").toBool()); + m_secUi->autoTypeAskCheckBox->setChecked(config()->get("security/autotypeask").toBool()); + setCurrentRow(0); } @@ -97,6 +117,16 @@ void SettingsWidget::saveSettings() m_generalUi->autoSaveAfterEveryChangeCheckBox->isChecked()); config()->set("AutoSaveOnExit", m_generalUi->autoSaveOnExitCheckBox->isChecked()); config()->set("MinimizeOnCopy", m_generalUi->minimizeOnCopyCheckBox->isChecked()); + config()->set("UseGroupIconOnEntryCreation", + m_generalUi->useGroupIconOnEntryCreationCheckBox->isChecked()); + config()->set("AutoTypeEntryTitleMatch", + m_generalUi->autoTypeEntryTitleMatchCheckBox->isChecked()); + int currentLangIndex = m_generalUi->languageComboBox->currentIndex(); + config()->set("GUI/Language", m_generalUi->languageComboBox->itemData(currentLangIndex).toString()); + + config()->set("GUI/ShowTrayIcon", m_generalUi->systrayShowCheckBox->isChecked()); + config()->set("GUI/MinimizeToTray", m_generalUi->systrayMinimizeToTrayCheckBox->isChecked()); + if (autoType()->isAvailable()) { config()->set("GlobalAutoTypeKey", m_generalUi->autoTypeShortcutWidget->key()); config()->set("GlobalAutoTypeModifiers", @@ -110,6 +140,8 @@ void SettingsWidget::saveSettings() config()->set("security/passwordscleartext", m_secUi->passwordCleartextCheckBox->isChecked()); + config()->set("security/autotypeask", m_secUi->autoTypeAskCheckBox->isChecked()); + Q_EMIT editFinished(true); } diff --git a/src/gui/SettingsWidgetGeneral.ui b/src/gui/SettingsWidgetGeneral.ui index b723d18..cbad7e5 100644 --- a/src/gui/SettingsWidgetGeneral.ui +++ b/src/gui/SettingsWidgetGeneral.ui @@ -7,10 +7,13 @@ 0 0 456 - 185 + 340 + + QFormLayout::AllNonFixedFieldsGrow + @@ -21,6 +24,13 @@ + + + + Open previous databases on startup + + + @@ -31,6 +41,13 @@ + + + + Automatically save on exit + + + @@ -38,34 +55,61 @@ - - + + - Automatically save on exit + Minimize when copying to clipboard + + + Use group icon on entry creation + + + + Global Auto-Type shortcut - + - - + + - Open previous databases on startup + Use entry title to match windows for global auto-type - - + + - Minimize when copying to clipboard + Language + + + + + + + + + + Show a system tray icon + + + + + + + false + + + Hide window to system tray when minimized diff --git a/src/gui/SettingsWidgetSecurity.ui b/src/gui/SettingsWidgetSecurity.ui index c2a6ccc..b52e862 100644 --- a/src/gui/SettingsWidgetSecurity.ui +++ b/src/gui/SettingsWidgetSecurity.ui @@ -64,6 +64,13 @@ + + + + Always ask before performing auto-type + + + diff --git a/src/gui/entry/EditEntryWidget.cpp b/src/gui/entry/EditEntryWidget.cpp index 4a67433..465f5d4 100644 --- a/src/gui/entry/EditEntryWidget.cpp +++ b/src/gui/entry/EditEntryWidget.cpp @@ -590,14 +590,14 @@ void EditEntryWidget::insertAttachment() QFile file(filename); if (!file.open(QIODevice::ReadOnly)) { MessageBox::warning(this, tr("Error"), - tr("Unable to open file:\n").append(file.errorString())); + tr("Unable to open file").append(":\n").append(file.errorString())); return; } QByteArray data; if (!Tools::readAllFromDevice(&file, data)) { MessageBox::warning(this, tr("Error"), - tr("Unable to open file:\n").append(file.errorString())); + tr("Unable to open file").append(":\n").append(file.errorString())); return; } @@ -783,13 +783,13 @@ QMenu* EditEntryWidget::createPresetsMenu() QMenu* expirePresetsMenu = new QMenu(this); expirePresetsMenu->addAction(tr("Tomorrow"))->setData(QVariant::fromValue(TimeDelta::fromDays(1))); expirePresetsMenu->addSeparator(); - expirePresetsMenu->addAction(tr("1 week"))->setData(QVariant::fromValue(TimeDelta::fromDays(7))); - expirePresetsMenu->addAction(tr("2 weeks"))->setData(QVariant::fromValue(TimeDelta::fromDays(14))); - expirePresetsMenu->addAction(tr("3 weeks"))->setData(QVariant::fromValue(TimeDelta::fromDays(21))); + expirePresetsMenu->addAction(tr("%n week(s)", 0, 1))->setData(QVariant::fromValue(TimeDelta::fromDays(7))); + expirePresetsMenu->addAction(tr("%n week(s)", 0, 2))->setData(QVariant::fromValue(TimeDelta::fromDays(14))); + expirePresetsMenu->addAction(tr("%n week(s)", 0, 3))->setData(QVariant::fromValue(TimeDelta::fromDays(21))); expirePresetsMenu->addSeparator(); - expirePresetsMenu->addAction(tr("1 month"))->setData(QVariant::fromValue(TimeDelta::fromMonths(1))); - expirePresetsMenu->addAction(tr("3 months"))->setData(QVariant::fromValue(TimeDelta::fromMonths(3))); - expirePresetsMenu->addAction(tr("6 months"))->setData(QVariant::fromValue(TimeDelta::fromMonths(6))); + expirePresetsMenu->addAction(tr("%n month(s)", 0, 1))->setData(QVariant::fromValue(TimeDelta::fromMonths(1))); + expirePresetsMenu->addAction(tr("%n month(s)", 0, 3))->setData(QVariant::fromValue(TimeDelta::fromMonths(3))); + expirePresetsMenu->addAction(tr("%n month(s)", 0, 6))->setData(QVariant::fromValue(TimeDelta::fromMonths(6))); expirePresetsMenu->addSeparator(); expirePresetsMenu->addAction(tr("1 year"))->setData(QVariant::fromValue(TimeDelta::fromYears(1))); return expirePresetsMenu; diff --git a/src/gui/entry/EntryView.cpp b/src/gui/entry/EntryView.cpp index f71f80b..cd2c6fb 100644 --- a/src/gui/entry/EntryView.cpp +++ b/src/gui/entry/EntryView.cpp @@ -17,6 +17,7 @@ #include "EntryView.h" +#include #include #include "gui/SortFilterHideProxyModel.h" @@ -40,6 +41,7 @@ EntryView::EntryView(QWidget* parent) setDragEnabled(true); setSortingEnabled(true); setSelectionMode(QAbstractItemView::ExtendedSelection); + header()->setDefaultSectionSize(150); // QAbstractItemView::startDrag() uses this property as the default drag action setDefaultDropAction(Qt::MoveAction); @@ -62,13 +64,24 @@ void EntryView::keyPressEvent(QKeyEvent* event) void EntryView::setGroup(Group* group) { m_model->setGroup(group); - Q_EMIT entrySelectionChanged(); + setFirstEntryActive(); } void EntryView::setEntryList(const QList& entries) { m_model->setEntryList(entries); - Q_EMIT entrySelectionChanged(); + setFirstEntryActive(); +} + +void EntryView::setFirstEntryActive() +{ + if(m_model->rowCount() > 0) { + QModelIndex index = m_sortModel->mapToSource(m_sortModel->index(0, 0)); + setCurrentEntry(m_model->entryFromIndex(index)); + } + else { + Q_EMIT entrySelectionChanged(); + } } bool EntryView::inEntryListMode() @@ -100,9 +113,9 @@ Entry* EntryView::currentEntry() } } -bool EntryView::isSingleEntrySelected() +int EntryView::numberOfSelectedEntries() { - return (selectionModel()->selectedRows().size() == 1); + return selectionModel()->selectedRows().size(); } void EntryView::setCurrentEntry(Entry* entry) diff --git a/src/gui/entry/EntryView.h b/src/gui/entry/EntryView.h index b5f056a..c11d041 100644 --- a/src/gui/entry/EntryView.h +++ b/src/gui/entry/EntryView.h @@ -37,11 +37,12 @@ public: explicit EntryView(QWidget* parent = Q_NULLPTR); void setModel(QAbstractItemModel* model) Q_DECL_OVERRIDE; Entry* currentEntry(); - bool isSingleEntrySelected(); void setCurrentEntry(Entry* entry); Entry* entryFromIndex(const QModelIndex& index); void setEntryList(const QList& entries); bool inEntryListMode(); + int numberOfSelectedEntries(); + void setFirstEntryActive(); public Q_SLOTS: void setGroup(Group* group); diff --git a/src/gui/group/EditGroupWidget.cpp b/src/gui/group/EditGroupWidget.cpp index c24afb9..b26fe4c 100644 --- a/src/gui/group/EditGroupWidget.cpp +++ b/src/gui/group/EditGroupWidget.cpp @@ -37,9 +37,6 @@ EditGroupWidget::EditGroupWidget(QWidget* parent) add(tr("Icon"), m_editGroupWidgetIcons); add(tr("Properties"), m_editWidgetProperties); - addTriStateItems(m_mainUi->searchComboBox); - addTriStateItems(m_mainUi->autotypeComboBox); - connect(m_mainUi->expireCheck, SIGNAL(toggled(bool)), m_mainUi->expireDatePicker, SLOT(setEnabled(bool))); connect(this, SIGNAL(accepted()), SLOT(save())); @@ -62,6 +59,15 @@ void EditGroupWidget::loadGroup(Group* group, bool create, Database* database) setHeadline(tr("Edit group")); } + if (m_group->parentGroup()) { + addTriStateItems(m_mainUi->searchComboBox, m_group->parentGroup()->resolveSearchingEnabled()); + addTriStateItems(m_mainUi->autotypeComboBox, m_group->parentGroup()->resolveAutoTypeEnabled()); + } + else { + addTriStateItems(m_mainUi->searchComboBox, true); + addTriStateItems(m_mainUi->autotypeComboBox, true); + } + m_mainUi->editName->setText(m_group->name()); m_mainUi->editNotes->setPlainText(m_group->notes()); m_mainUi->expireCheck->setChecked(group->timeInfo().expires()); @@ -120,9 +126,18 @@ void EditGroupWidget::cancel() Q_EMIT editFinished(false); } -void EditGroupWidget::addTriStateItems(QComboBox* comboBox) +void EditGroupWidget::addTriStateItems(QComboBox* comboBox, bool inheritDefault) { - comboBox->addItem(tr("Inherit")); + QString inheritDefaultString; + if (inheritDefault) { + inheritDefaultString = tr("Enable"); + } + else { + inheritDefaultString = tr("Disable"); + } + + comboBox->clear(); + comboBox->addItem(tr("Inherit from parent group (%1)").arg(inheritDefaultString)); comboBox->addItem(tr("Enable")); comboBox->addItem(tr("Disable")); } diff --git a/src/gui/group/EditGroupWidget.h b/src/gui/group/EditGroupWidget.h index de075be..971b6de 100644 --- a/src/gui/group/EditGroupWidget.h +++ b/src/gui/group/EditGroupWidget.h @@ -50,7 +50,7 @@ private Q_SLOTS: void cancel(); private: - void addTriStateItems(QComboBox* comboBox); + void addTriStateItems(QComboBox* comboBox, bool inheritValue); int indexFromTriState(Group::TriState triState); Group::TriState triStateFromIndex(int index); diff --git a/src/gui/group/EditGroupWidgetMain.ui b/src/gui/group/EditGroupWidgetMain.ui index c528c18..fdbf054 100644 --- a/src/gui/group/EditGroupWidgetMain.ui +++ b/src/gui/group/EditGroupWidgetMain.ui @@ -66,7 +66,7 @@ - Autotype + Auto-type diff --git a/src/main.cpp b/src/main.cpp index abe7ceb..2bdef5b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -21,9 +21,11 @@ #include "core/Config.h" #include "core/qcommandlineparser.h" #include "core/Tools.h" +#include "core/Translator.h" #include "crypto/Crypto.h" #include "gui/Application.h" #include "gui/MainWindow.h" +#include "gui/MessageBox.h" int main(int argc, char** argv) { @@ -37,7 +39,16 @@ int main(int argc, char** argv) // don't set organizationName as that changes the return value of // QDesktopServices::storageLocation(QDesktopServices::DataLocation) - Crypto::init(); + QApplication::setQuitOnLastWindowClosed(false); + + if (!Crypto::init()) { + QString error = QCoreApplication::translate("Main", + "Fatal error while testing the cryptographic functions."); + error.append("\n"); + error.append(Crypto::errorString()); + MessageBox::critical(Q_NULLPTR, QCoreApplication::translate("Main", "KeePassX - Error"), error); + return 1; + } QCommandLineParser parser; parser.setApplicationDescription(QCoreApplication::translate("main", "KeePassX - cross-platform password manager")); @@ -66,6 +77,8 @@ int main(int argc, char** argv) Config::createConfigFromFile(parser.value(configOption)); } + Translator::installTranslator(); + #ifdef Q_OS_MAC // Don't show menu icons on OSX QApplication::setAttribute(Qt::AA_DontShowIconsInMenus); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8df0050..c094f82 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -13,7 +13,6 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}) include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}/src) add_definitions(-DQT_TEST_LIB) @@ -165,6 +164,12 @@ add_unit_test(NAME testqcommandlineparser SOURCES TestQCommandLineParser.cpp MOC add_unit_test(NAME testrandom SOURCES TestRandom.cpp MOCS TestRandom.h LIBS ${TEST_LIBRARIES}) +add_unit_test(NAME testentrysearcher SOURCES TestEntrySearcher.cpp MOCS TestEntrySearcher.h + LIBS ${TEST_LIBRARIES}) + +add_unit_test(NAME testexporter SOURCES TestExporter.cpp MOCS TestExporter.h + LIBS ${TEST_LIBRARIES}) + if(WITH_GUI_TESTS) add_subdirectory(gui) endif(WITH_GUI_TESTS) diff --git a/tests/TestAutoType.cpp b/tests/TestAutoType.cpp index 2fb5335..818f57c 100644 --- a/tests/TestAutoType.cpp +++ b/tests/TestAutoType.cpp @@ -21,6 +21,7 @@ #include #include "tests.h" +#include "core/Config.h" #include "core/FilePath.h" #include "core/Entry.h" #include "core/Group.h" @@ -28,12 +29,17 @@ #include "autotype/AutoType.h" #include "autotype/AutoTypePlatformPlugin.h" #include "autotype/test/AutoTypeTestInterface.h" +#include "gui/MessageBox.h" + +QTEST_GUILESS_MAIN(TestAutoType) void TestAutoType::initTestCase() { - Crypto::init(); - + QVERIFY(Crypto::init()); + Config::createTempFileInstance(); AutoType::createTestInstance(); + config()->set("AutoTypeEntryTitleMatch", false); + config()->set("security/autotypeask", false); QPluginLoader loader(filePath()->pluginPath("keepassx-autotype-test")); loader.setLoadHints(QLibrary::ResolveAllSymbolsHint); @@ -53,12 +59,24 @@ void TestAutoType::init() m_test->clearActions(); m_db = new Database(); + m_dbList.clear(); + m_dbList.append(m_db); m_group = new Group(); m_db->setRootGroup(m_group); - m_entry = new Entry(); - m_entry->setGroup(m_group); - m_entry->setUsername("myuser"); - m_entry->setPassword("mypass"); + + m_entry1 = new Entry(); + m_entry1->setGroup(m_group); + m_entry1->setUsername("myuser"); + m_entry1->setPassword("mypass"); + AutoTypeAssociations::Association association; + association.window = "custom window"; + association.sequence = "{username}association{password}"; + m_entry1->autoTypeAssociations()->add(association); + + m_entry2 = new Entry(); + m_entry2->setGroup(m_group); + m_entry2->setPassword("myuser"); + m_entry2->setTitle("entry title"); } void TestAutoType::cleanup() @@ -76,7 +94,7 @@ void TestAutoType::testInternal() void TestAutoType::testAutoTypeWithoutSequence() { - m_autoType->performAutoType(m_entry, Q_NULLPTR); + m_autoType->performAutoType(m_entry1, Q_NULLPTR); QCOMPARE(m_test->actionCount(), 14); QCOMPARE(m_test->actionChars(), @@ -87,41 +105,54 @@ void TestAutoType::testAutoTypeWithoutSequence() void TestAutoType::testAutoTypeWithSequence() { - m_autoType->performAutoType(m_entry, Q_NULLPTR, "{Username}abc{PaSsWoRd}"); + m_autoType->performAutoType(m_entry1, Q_NULLPTR, "{Username}abc{PaSsWoRd}"); QCOMPARE(m_test->actionCount(), 15); QCOMPARE(m_test->actionChars(), QString("%1abc%2") - .arg(m_entry->username()) - .arg(m_entry->password())); + .arg(m_entry1->username()) + .arg(m_entry1->password())); } void TestAutoType::testGlobalAutoTypeWithNoMatch() { - QList dbList; - dbList.append(m_db); - - m_autoType->performGlobalAutoType(dbList); + m_test->setActiveWindowTitle("nomatch"); + MessageBox::setNextAnswer(QMessageBox::Ok); + m_autoType->performGlobalAutoType(m_dbList); QCOMPARE(m_test->actionChars(), QString()); } void TestAutoType::testGlobalAutoTypeWithOneMatch() { - QList dbList; - dbList.append(m_db); - AutoTypeAssociations::Association association; - association.window = "custom window"; - association.sequence = "{username}association{password}"; - m_entry->autoTypeAssociations()->add(association); - m_test->setActiveWindowTitle("custom window"); - m_autoType->performGlobalAutoType(dbList); + m_autoType->performGlobalAutoType(m_dbList); QCOMPARE(m_test->actionChars(), QString("%1association%2") - .arg(m_entry->username()) - .arg(m_entry->password())); + .arg(m_entry1->username()) + .arg(m_entry1->password())); } -QTEST_GUILESS_MAIN(TestAutoType) +void TestAutoType::testGlobalAutoTypeTitleMatch() +{ + config()->set("AutoTypeEntryTitleMatch", true); + + m_test->setActiveWindowTitle("An Entry Title!"); + m_autoType->performGlobalAutoType(m_dbList); + + QCOMPARE(m_test->actionChars(), + QString("%1%2").arg(m_entry2->password(), m_test->keyToString(Qt::Key_Enter))); +} + +void TestAutoType::testGlobalAutoTypeTitleMatchDisabled() +{ + config()->set("AutoTypeEntryTitleMatch", false); + + m_test->setActiveWindowTitle("An Entry Title!"); + MessageBox::setNextAnswer(QMessageBox::Ok); + m_autoType->performGlobalAutoType(m_dbList); + + QCOMPARE(m_test->actionChars(), QString()); + +} diff --git a/tests/TestAutoType.h b/tests/TestAutoType.h index fba7fde..d46a559 100644 --- a/tests/TestAutoType.h +++ b/tests/TestAutoType.h @@ -41,14 +41,18 @@ private Q_SLOTS: void testAutoTypeWithSequence(); void testGlobalAutoTypeWithNoMatch(); void testGlobalAutoTypeWithOneMatch(); + void testGlobalAutoTypeTitleMatch(); + void testGlobalAutoTypeTitleMatchDisabled(); private: AutoTypePlatformInterface* m_platform; AutoTypeTestInterface* m_test; AutoType* m_autoType; Database* m_db; + QList m_dbList; Group* m_group; - Entry* m_entry; + Entry* m_entry1; + Entry* m_entry2; }; #endif // KEEPASSX_TESTAUTOTYPE_H diff --git a/tests/TestCryptoHash.cpp b/tests/TestCryptoHash.cpp index 4f258a1..eb26ca8 100644 --- a/tests/TestCryptoHash.cpp +++ b/tests/TestCryptoHash.cpp @@ -23,15 +23,17 @@ #include "crypto/Crypto.h" #include "crypto/CryptoHash.h" +QTEST_GUILESS_MAIN(TestCryptoHash) + void TestCryptoHash::initTestCase() { - Crypto::init(); + QVERIFY(Crypto::init()); } void TestCryptoHash::test() { // TODO: move somewhere else - QVERIFY(Crypto::selfTest()); + QVERIFY(Crypto::backendSelfTest()); CryptoHash cryptoHash1(CryptoHash::Sha256); QCOMPARE(cryptoHash1.result(), @@ -47,5 +49,3 @@ void TestCryptoHash::test() QCOMPARE(cryptoHash3.result(), QByteArray::fromHex("0b56e5f65263e747af4a833bd7dd7ad26a64d7a4de7c68e52364893dca0766b4")); } - -QTEST_GUILESS_MAIN(TestCryptoHash) diff --git a/tests/TestDeletedObjects.cpp b/tests/TestDeletedObjects.cpp index 914096c..277dbcb 100644 --- a/tests/TestDeletedObjects.cpp +++ b/tests/TestDeletedObjects.cpp @@ -26,9 +26,11 @@ #include "format/KeePass2XmlReader.h" #include "config-keepassx-tests.h" +QTEST_GUILESS_MAIN(TestDeletedObjects) + void TestDeletedObjects::initTestCase() { - Crypto::init(); + QVERIFY(Crypto::init()); } void TestDeletedObjects::createAndDelete(Database* db, int delObjectsSize) @@ -158,5 +160,3 @@ void TestDeletedObjects::testDatabaseChange() delete db; delete db2; } - -QTEST_GUILESS_MAIN(TestDeletedObjects) diff --git a/tests/TestEntry.cpp b/tests/TestEntry.cpp index 15f398f..477e83b 100644 --- a/tests/TestEntry.cpp +++ b/tests/TestEntry.cpp @@ -23,9 +23,11 @@ #include "core/Entry.h" #include "crypto/Crypto.h" +QTEST_GUILESS_MAIN(TestEntry) + void TestEntry::initTestCase() { - Crypto::init(); + QVERIFY(Crypto::init()); } void TestEntry::testHistoryItemDeletion() @@ -121,5 +123,3 @@ void TestEntry::testClone() QCOMPARE(entryCloneHistory->historyItems().first()->title(), QString("Original Title")); QCOMPARE(entryCloneHistory->timeInfo().creationTime(), entryOrg->timeInfo().creationTime()); } - -QTEST_GUILESS_MAIN(TestEntry) diff --git a/tests/TestEntryModel.cpp b/tests/TestEntryModel.cpp index fab63db..7ba886b 100644 --- a/tests/TestEntryModel.cpp +++ b/tests/TestEntryModel.cpp @@ -33,10 +33,12 @@ #include "gui/entry/EntryAttachmentsModel.h" #include "gui/entry/EntryAttributesModel.h" +QTEST_GUILESS_MAIN(TestEntryModel) + void TestEntryModel::initTestCase() { qRegisterMetaType("QModelIndex"); - Crypto::init(); + QVERIFY(Crypto::init()); } void TestEntryModel::test() @@ -341,5 +343,3 @@ void TestEntryModel::testDatabaseDelete() delete modelTest; delete model; } - -QTEST_GUILESS_MAIN(TestEntryModel) diff --git a/tests/TestEntrySearcher.cpp b/tests/TestEntrySearcher.cpp new file mode 100644 index 0000000..9f7ca13 --- /dev/null +++ b/tests/TestEntrySearcher.cpp @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2014 Florian Geyer + * + * 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 2 or (at your option) + * version 3 of the License. + * + * 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 . + */ + +#include "TestEntrySearcher.h" + +#include + +#include "tests.h" + +QTEST_GUILESS_MAIN(TestEntrySearcher) + +void TestEntrySearcher::initTestCase() +{ + m_groupRoot = new Group(); +} + +void TestEntrySearcher::cleanupTestCase() +{ + delete m_groupRoot; +} + +void TestEntrySearcher::testSearch() +{ + Group* group1 = new Group(); + Group* group2 = new Group(); + Group* group3 = new Group(); + + group1->setParent(m_groupRoot); + group2->setParent(m_groupRoot); + group3->setParent(m_groupRoot); + + Group* group11 = new Group(); + + group11->setParent(group1); + + Group* group21 = new Group(); + Group* group211 = new Group(); + Group* group2111 = new Group(); + + group21->setParent(group2); + group211->setParent(group21); + group2111->setParent(group211); + + group1->setSearchingEnabled(Group::Disable); + group11->setSearchingEnabled(Group::Enable); + + Entry* eRoot = new Entry(); + eRoot->setNotes("test search term test"); + eRoot->setGroup(m_groupRoot); + + Entry* eRoot2 = new Entry(); + eRoot2->setNotes("test term test"); + eRoot2->setGroup(m_groupRoot); + + Entry* e1 = new Entry(); + e1->setNotes("test search term test"); + e1->setGroup(group1); + + Entry* e11 = new Entry(); + e11->setNotes("test search term test"); + e11->setGroup(group11); + + Entry* e2111 = new Entry(); + e2111->setNotes("test search term test"); + e2111->setGroup(group2111); + + Entry* e2111b = new Entry(); + e2111b->setNotes("test search test"); + e2111b->setGroup(group2111); + + Entry* e3 = new Entry(); + e3->setNotes("test search term test"); + e3->setGroup(group3); + + Entry* e3b = new Entry(); + e3b->setNotes("test search test"); + e3b->setGroup(group3); + + m_searchResult = m_entrySearcher.search("search term", m_groupRoot, Qt::CaseInsensitive); + QCOMPARE(m_searchResult.count(), 3); + + m_searchResult = m_entrySearcher.search("search term", group211, Qt::CaseInsensitive); + QCOMPARE(m_searchResult.count(), 1); + + m_searchResult = m_entrySearcher.search("search term", group11, Qt::CaseInsensitive); + QCOMPARE(m_searchResult.count(), 1); + + m_searchResult = m_entrySearcher.search("search term", group1, Qt::CaseInsensitive); + QCOMPARE(m_searchResult.count(), 0); +} + +void TestEntrySearcher::testAndConcatenationInSearch() +{ + Entry* entry = new Entry(); + entry->setNotes("abc def ghi"); + entry->setTitle("jkl"); + entry->setGroup(m_groupRoot); + + m_searchResult = m_entrySearcher.search("", m_groupRoot, Qt::CaseInsensitive); + QCOMPARE(m_searchResult.count(), 1); + + m_searchResult = m_entrySearcher.search("def", m_groupRoot, Qt::CaseInsensitive); + QCOMPARE(m_searchResult.count(), 1); + + m_searchResult = m_entrySearcher.search(" abc ghi ", m_groupRoot, Qt::CaseInsensitive); + QCOMPARE(m_searchResult.count(), 1); + + m_searchResult = m_entrySearcher.search("ghi ef", m_groupRoot, Qt::CaseInsensitive); + QCOMPARE(m_searchResult.count(), 1); + + m_searchResult = m_entrySearcher.search("abc ef xyz", m_groupRoot, Qt::CaseInsensitive); + QCOMPARE(m_searchResult.count(), 0); + + m_searchResult = m_entrySearcher.search("abc kl", m_groupRoot, Qt::CaseInsensitive); + QCOMPARE(m_searchResult.count(), 1); +} + +void TestEntrySearcher::testAllAttributesAreSearched() +{ + Entry* entry = new Entry(); + entry->setGroup(m_groupRoot); + + entry->setTitle("testTitle"); + entry->setUsername("testUsername"); + entry->setUrl("testUrl"); + entry->setNotes("testNote"); + + m_searchResult = m_entrySearcher.search("testTitle testUsername testUrl testNote", m_groupRoot, Qt::CaseInsensitive); + QCOMPARE(m_searchResult.count(), 1); +} diff --git a/tests/TestEntrySearcher.h b/tests/TestEntrySearcher.h new file mode 100644 index 0000000..7c45451 --- /dev/null +++ b/tests/TestEntrySearcher.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2014 Florian Geyer + * + * 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 2 or (at your option) + * version 3 of the License. + * + * 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 . + */ + + +#ifndef KEEPASSX_TESTENTRYSEARCHER_H +#define KEEPASSX_TESTENTRYSEARCHER_H + +#include + +#include "core/EntrySearcher.h" +#include "core/Group.h" + +class TestEntrySearcher : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + + void testAndConcatenationInSearch(); + void testSearch(); + void testAllAttributesAreSearched(); + +private: + Group* m_groupRoot; + EntrySearcher m_entrySearcher; + QList m_searchResult; +}; + +#endif // KEEPASSX_TESTENTRYSEARCHER_H diff --git a/tests/TestExporter.cpp b/tests/TestExporter.cpp new file mode 100644 index 0000000..d703e02 --- /dev/null +++ b/tests/TestExporter.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2014 Felix Geyer + * Copyright (C) 2014 Florian Geyer + * + * 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 2 or (at your option) + * version 3 of the License. + * + * 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 . + */ + +#include "TestExporter.h" + +#include + +#include "tests.h" +#include "core/ToDbExporter.h" +#include "core/Group.h" +#include "core/Metadata.h" +#include "crypto/Crypto.h" + +QTEST_GUILESS_MAIN(TestExporter) + +void TestExporter::initTestCase() +{ + QVERIFY(Crypto::init()); +} + +void TestExporter::testToDbExporter() +{ + QImage iconImage(1, 1, QImage::Format_RGB32); + iconImage.setPixel(0, 0, qRgb(1, 2, 3)); + Uuid iconUuid = Uuid::random(); + + QImage iconUnusedImage(1, 1, QImage::Format_RGB32); + iconUnusedImage.setPixel(0, 0, qRgb(1, 2, 3)); + Uuid iconUnusedUuid = Uuid::random(); + + Database* dbOrg = new Database(); + Group* groupOrg = new Group(); + groupOrg->setParent(dbOrg->rootGroup()); + groupOrg->setName("GTEST"); + Entry* entryOrg = new Entry(); + entryOrg->setGroup(groupOrg); + entryOrg->setTitle("ETEST"); + dbOrg->metadata()->addCustomIcon(iconUuid, iconImage); + dbOrg->metadata()->addCustomIcon(iconUnusedUuid, iconUnusedImage); + entryOrg->setIcon(iconUuid); + entryOrg->beginUpdate(); + entryOrg->setIcon(Entry::DefaultIconNumber); + entryOrg->endUpdate(); + + Database* dbExp = ToDbExporter().exportGroup(groupOrg); + + QCOMPARE(dbExp->rootGroup()->children().size(), 1); + Group* groupExp = dbExp->rootGroup()->children().first(); + QVERIFY(groupExp != groupOrg); + QCOMPARE(groupExp->name(), groupOrg->name()); + QCOMPARE(groupExp->entries().size(), 1); + + Entry* entryExp = groupExp->entries().first(); + QCOMPARE(entryExp->title(), entryOrg->title()); + QCOMPARE(dbExp->metadata()->customIcons().size(), 1); + QVERIFY(dbExp->metadata()->containsCustomIcon(iconUuid)); + QCOMPARE(entryExp->iconNumber(), entryOrg->iconNumber()); + + QCOMPARE(entryExp->historyItems().size(), 1); + QCOMPARE(entryExp->historyItems().first()->iconUuid(), iconUuid); + + delete dbOrg; + delete dbExp; +} + + + diff --git a/tests/TestExporter.h b/tests/TestExporter.h new file mode 100644 index 0000000..15f9a7c --- /dev/null +++ b/tests/TestExporter.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2014 Felix Geyer + * Copyright (C) 2014 Florian Geyer + * + * 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 2 or (at your option) + * version 3 of the License. + * + * 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 . + */ + +#ifndef KEEPASSX_TESTEXPORTER_H +#define KEEPASSX_TESTEXPORTER_H + +#include + +class TestExporter : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + void testToDbExporter(); +}; + +#endif // KEEPASSX_TESTEXPORTER_H diff --git a/tests/TestGroup.cpp b/tests/TestGroup.cpp index 86b55b7..507cf15 100644 --- a/tests/TestGroup.cpp +++ b/tests/TestGroup.cpp @@ -27,11 +27,13 @@ #include "core/Metadata.h" #include "crypto/Crypto.h" +QTEST_GUILESS_MAIN(TestGroup) + void TestGroup::initTestCase() { qRegisterMetaType("Entry*"); qRegisterMetaType("Group*"); - Crypto::init(); + QVERIFY(Crypto::init()); } void TestGroup::testParenting() @@ -334,102 +336,6 @@ void TestGroup::testCopyCustomIcon() delete dbTarget; } -void TestGroup::testSearch() -{ - Group* groupRoot = new Group(); - Group* group1 = new Group(); - Group* group2 = new Group(); - Group* group3 = new Group(); - - group1->setParent(groupRoot); - group2->setParent(groupRoot); - group3->setParent(groupRoot); - - Group* group11 = new Group(); - - group11->setParent(group1); - - Group* group21 = new Group(); - Group* group211 = new Group(); - Group* group2111 = new Group(); - - group21->setParent(group2); - group211->setParent(group21); - group2111->setParent(group211); - - group1->setSearchingEnabled(Group::Disable); - group11->setSearchingEnabled(Group::Enable); - - Entry* eRoot = new Entry(); - eRoot->setNotes("test search term test"); - eRoot->setGroup(groupRoot); - - Entry* eRoot2 = new Entry(); - eRoot2->setNotes("test term test"); - eRoot2->setGroup(groupRoot); - - Entry* e1 = new Entry(); - e1->setNotes("test search term test"); - e1->setGroup(group1); - - Entry* e2111 = new Entry(); - e2111->setNotes("test search term test"); - e2111->setGroup(group2111); - - Entry* e2111b = new Entry(); - e2111b->setNotes("test search test"); - e2111b->setGroup(group2111); - - Entry* e3 = new Entry(); - e3->setNotes("test search term test"); - e3->setGroup(group3); - - Entry* e3b = new Entry(); - e3b->setNotes("test search test"); - e3b->setGroup(group3); - - QList searchResult; - - searchResult = groupRoot->search("search term", Qt::CaseInsensitive); - QCOMPARE(searchResult.count(), 3); - - searchResult = group211->search("search term", Qt::CaseInsensitive); - QCOMPARE(searchResult.count(), 1); - - delete groupRoot; -} - -void TestGroup::testAndConcatenationInSearch() -{ - Group* group = new Group(); - Entry* entry = new Entry(); - entry->setNotes("abc def ghi"); - entry->setTitle("jkl"); - entry->setGroup(group); - - QList searchResult; - - searchResult = group->search("", Qt::CaseInsensitive); - QCOMPARE(searchResult.count(), 1); - - searchResult = group->search("def", Qt::CaseInsensitive); - QCOMPARE(searchResult.count(), 1); - - searchResult = group->search(" abc ghi ", Qt::CaseInsensitive); - QCOMPARE(searchResult.count(), 1); - - searchResult = group->search("ghi ef", Qt::CaseInsensitive); - QCOMPARE(searchResult.count(), 1); - - searchResult = group->search("abc ef xyz", Qt::CaseInsensitive); - QCOMPARE(searchResult.count(), 0); - - searchResult = group->search("abc kl", Qt::CaseInsensitive); - QCOMPARE(searchResult.count(), 1); - - delete group; -} - void TestGroup::testClone() { Database* db = new Database(); @@ -536,49 +442,3 @@ void TestGroup::testCopyCustomIcons() QCOMPARE(metaTarget->customIcon(group1Icon).pixel(0, 0), qRgb(1, 2, 3)); QCOMPARE(metaTarget->customIcon(group2Icon).pixel(0, 0), qRgb(4, 5, 6)); } - -void TestGroup::testExportToDb() -{ - QImage iconImage(1, 1, QImage::Format_RGB32); - iconImage.setPixel(0, 0, qRgb(1, 2, 3)); - Uuid iconUuid = Uuid::random(); - - QImage iconUnusedImage(1, 1, QImage::Format_RGB32); - iconUnusedImage.setPixel(0, 0, qRgb(1, 2, 3)); - Uuid iconUnusedUuid = Uuid::random(); - - Database* dbOrg = new Database(); - Group* groupOrg = new Group(); - groupOrg->setParent(dbOrg->rootGroup()); - groupOrg->setName("GTEST"); - Entry* entryOrg = new Entry(); - entryOrg->setGroup(groupOrg); - entryOrg->setTitle("ETEST"); - dbOrg->metadata()->addCustomIcon(iconUuid, iconImage); - dbOrg->metadata()->addCustomIcon(iconUnusedUuid, iconUnusedImage); - entryOrg->setIcon(iconUuid); - entryOrg->beginUpdate(); - entryOrg->setIcon(Entry::DefaultIconNumber); - entryOrg->endUpdate(); - - Database* dbExp = groupOrg->exportToDb(); - QCOMPARE(dbExp->rootGroup()->children().size(), 1); - Group* groupExp = dbExp->rootGroup()->children().first(); - QVERIFY(groupExp != groupOrg); - QCOMPARE(groupExp->name(), groupOrg->name()); - QCOMPARE(groupExp->entries().size(), 1); - - Entry* entryExp = groupExp->entries().first(); - QCOMPARE(entryExp->title(), entryOrg->title()); - QCOMPARE(dbExp->metadata()->customIcons().size(), 1); - QVERIFY(dbExp->metadata()->containsCustomIcon(iconUuid)); - QCOMPARE(entryExp->iconNumber(), entryOrg->iconNumber()); - - QCOMPARE(entryExp->historyItems().size(), 1); - QCOMPARE(entryExp->historyItems().first()->iconUuid(), iconUuid); - - delete dbOrg; - delete dbExp; -} - -QTEST_GUILESS_MAIN(TestGroup) diff --git a/tests/TestGroup.h b/tests/TestGroup.h index 895c2cc..c612a3a 100644 --- a/tests/TestGroup.h +++ b/tests/TestGroup.h @@ -31,11 +31,8 @@ private Q_SLOTS: void testEntries(); void testDeleteSignals(); void testCopyCustomIcon(); - void testSearch(); - void testAndConcatenationInSearch(); void testClone(); void testCopyCustomIcons(); - void testExportToDb(); }; #endif // KEEPASSX_TESTGROUP_H diff --git a/tests/TestGroupModel.cpp b/tests/TestGroupModel.cpp index a16386c..32a4b8e 100644 --- a/tests/TestGroupModel.cpp +++ b/tests/TestGroupModel.cpp @@ -27,10 +27,12 @@ #include "crypto/Crypto.h" #include "gui/group/GroupModel.h" +QTEST_GUILESS_MAIN(TestGroupModel) + void TestGroupModel::initTestCase() { qRegisterMetaType("QModelIndex"); - Crypto::init(); + QVERIFY(Crypto::init()); } void TestGroupModel::test() @@ -149,5 +151,3 @@ void TestGroupModel::test() delete modelTest; delete model; } - -QTEST_GUILESS_MAIN(TestGroupModel) diff --git a/tests/TestHashedBlockStream.cpp b/tests/TestHashedBlockStream.cpp index ab7d386..09179fe 100644 --- a/tests/TestHashedBlockStream.cpp +++ b/tests/TestHashedBlockStream.cpp @@ -24,9 +24,11 @@ #include "crypto/Crypto.h" #include "streams/HashedBlockStream.h" +QTEST_GUILESS_MAIN(TestHashedBlockStream) + void TestHashedBlockStream::initTestCase() { - Crypto::init(); + QVERIFY(Crypto::init()); } void TestHashedBlockStream::testWriteRead() @@ -69,5 +71,3 @@ void TestHashedBlockStream::testWriteRead() buffer.reset(); buffer.buffer().clear(); } - -QTEST_GUILESS_MAIN(TestHashedBlockStream) diff --git a/tests/TestKeePass1Reader.cpp b/tests/TestKeePass1Reader.cpp index 3ec4e78..249a365 100644 --- a/tests/TestKeePass1Reader.cpp +++ b/tests/TestKeePass1Reader.cpp @@ -33,9 +33,11 @@ #include "keys/FileKey.h" #include "keys/PasswordKey.h" +QTEST_GUILESS_MAIN(TestKeePass1Reader) + void TestKeePass1Reader::initTestCase() { - Crypto::init(); + QVERIFY(Crypto::init()); QString filename = QString(KEEPASSX_TEST_DATA_DIR).append("/basic.kdb"); @@ -292,5 +294,3 @@ void TestKeePass1Reader::reopenDatabase(Database* db, const QString& password, c QVERIFY(!reader.hasError()); delete newDb; } - -QTEST_GUILESS_MAIN(TestKeePass1Reader) diff --git a/tests/TestKeePass2RandomStream.cpp b/tests/TestKeePass2RandomStream.cpp index 74a1540..7963e9a 100644 --- a/tests/TestKeePass2RandomStream.cpp +++ b/tests/TestKeePass2RandomStream.cpp @@ -26,9 +26,11 @@ #include "format/KeePass2.h" #include "format/KeePass2RandomStream.h" +QTEST_GUILESS_MAIN(TestKeePass2RandomStream) + void TestKeePass2RandomStream::initTestCase() { - Crypto::init(); + QVERIFY(Crypto::init()); } void TestKeePass2RandomStream::test() @@ -77,5 +79,3 @@ void TestKeePass2RandomStream::test() QCOMPARE(cipherData, cipherDataEncrypt); QCOMPARE(randomStreamData, cipherData); } - -QTEST_GUILESS_MAIN(TestKeePass2RandomStream) diff --git a/tests/TestKeePass2Reader.cpp b/tests/TestKeePass2Reader.cpp index 6b1ee1e..d6cb70c 100644 --- a/tests/TestKeePass2Reader.cpp +++ b/tests/TestKeePass2Reader.cpp @@ -28,9 +28,11 @@ #include "format/KeePass2Reader.h" #include "keys/PasswordKey.h" +QTEST_GUILESS_MAIN(TestKeePass2Reader) + void TestKeePass2Reader::initTestCase() { - Crypto::init(); + QVERIFY(Crypto::init()); } void TestKeePass2Reader::testNonAscii() @@ -154,5 +156,3 @@ void TestKeePass2Reader::testFormat300() delete db; } - -QTEST_GUILESS_MAIN(TestKeePass2Reader) diff --git a/tests/TestKeePass2Writer.cpp b/tests/TestKeePass2Writer.cpp index bbc4992..cf4ab1c 100644 --- a/tests/TestKeePass2Writer.cpp +++ b/tests/TestKeePass2Writer.cpp @@ -29,9 +29,11 @@ #include "format/KeePass2Writer.h" #include "keys/PasswordKey.h" +QTEST_GUILESS_MAIN(TestKeePass2Writer) + void TestKeePass2Writer::initTestCase() { - Crypto::init(); + QVERIFY(Crypto::init()); CompositeKey key; key.addKey(PasswordKey("test")); @@ -104,5 +106,3 @@ void TestKeePass2Writer::cleanupTestCase() delete m_dbOrg; delete m_dbTest; } - -QTEST_GUILESS_MAIN(TestKeePass2Writer) diff --git a/tests/TestKeePass2XmlReader.cpp b/tests/TestKeePass2XmlReader.cpp index ca57db9..8e87d67 100644 --- a/tests/TestKeePass2XmlReader.cpp +++ b/tests/TestKeePass2XmlReader.cpp @@ -28,6 +28,8 @@ #include "format/KeePass2XmlReader.h" #include "config-keepassx-tests.h" +QTEST_GUILESS_MAIN(TestKeePass2XmlReader) + namespace QTest { template<> char* toString(const Uuid& uuid) @@ -66,7 +68,7 @@ QDateTime TestKeePass2XmlReader::genDT(int year, int month, int day, int hour, i void TestKeePass2XmlReader::initTestCase() { - Crypto::init(); + QVERIFY(Crypto::init()); KeePass2XmlReader reader; QString xmlFile = QString(KEEPASSX_TEST_DATA_DIR).append("/NewDatabase.xml"); @@ -378,5 +380,3 @@ void TestKeePass2XmlReader::cleanupTestCase() { delete m_db; } - -QTEST_GUILESS_MAIN(TestKeePass2XmlReader) diff --git a/tests/TestKeys.cpp b/tests/TestKeys.cpp index ec9a35b..d6758d6 100644 --- a/tests/TestKeys.cpp +++ b/tests/TestKeys.cpp @@ -31,9 +31,11 @@ #include "keys/FileKey.h" #include "keys/PasswordKey.h" +QTEST_GUILESS_MAIN(TestKeys) + void TestKeys::initTestCase() { - Crypto::init(); + QVERIFY(Crypto::init()); } void TestKeys::testComposite() @@ -184,5 +186,3 @@ void TestKeys::benchmarkTransformKey() compositeKey.transform(seed, 1e6); } } - -QTEST_GUILESS_MAIN(TestKeys) diff --git a/tests/TestModified.cpp b/tests/TestModified.cpp index 864ea1c..e275e83 100644 --- a/tests/TestModified.cpp +++ b/tests/TestModified.cpp @@ -27,9 +27,11 @@ #include "core/Tools.h" #include "crypto/Crypto.h" +QTEST_GUILESS_MAIN(TestModified) + void TestModified::initTestCase() { - Crypto::init(); + QVERIFY(Crypto::init()); } void TestModified::testSignals() @@ -466,5 +468,3 @@ void TestModified::testHistoryItem() delete db; } - -QTEST_GUILESS_MAIN(TestModified) diff --git a/tests/TestQCommandLineParser.cpp b/tests/TestQCommandLineParser.cpp index d487862..4e2c635 100644 --- a/tests/TestQCommandLineParser.cpp +++ b/tests/TestQCommandLineParser.cpp @@ -46,6 +46,8 @@ #include "tests.h" #include "core/qcommandlineparser.h" +QTEST_GUILESS_MAIN(TestQCommandLineParser) + Q_DECLARE_METATYPE(char**) static char *empty_argv[] = { 0 }; @@ -412,5 +414,3 @@ void TestQCommandLineParser::testSingleDashWordOptionModes() QCOMPARE(parser.value(parser.optionNames().at(i)), expectedOptionValues.at(i)); QCOMPARE(parser.unknownOptionNames(), QStringList()); } - -QTEST_GUILESS_MAIN(TestQCommandLineParser) diff --git a/tests/TestQSaveFile.cpp b/tests/TestQSaveFile.cpp index bccee0e..443db52 100644 --- a/tests/TestQSaveFile.cpp +++ b/tests/TestQSaveFile.cpp @@ -29,6 +29,8 @@ #include "tests.h" #include "core/qsavefile.h" +QTEST_GUILESS_MAIN(TestQSaveFile) + class DirCleanup { public: @@ -154,6 +156,9 @@ void TestQSaveFile::transactionalWriteCanceled() void TestQSaveFile::transactionalWriteErrorRenaming() { #ifndef Q_OS_WIN + if (::geteuid() == 0) { + QSKIP("not valid running this test as root", SkipAll); + } const QString dir = tmpDir(); QVERIFY(!dir.isEmpty()); const QString targetFile = dir + QString::fromLatin1("/outfile"); @@ -197,5 +202,3 @@ QString TestQSaveFile::tmpDir() return dirName; } - -QTEST_GUILESS_MAIN(TestQSaveFile) diff --git a/tests/TestRandom.cpp b/tests/TestRandom.cpp index 8ac570e..40ab702 100644 --- a/tests/TestRandom.cpp +++ b/tests/TestRandom.cpp @@ -22,6 +22,8 @@ #include +QTEST_GUILESS_MAIN(TestRandom) + void TestRandom::initTestCase() { m_backend = new RandomBackendTest(); @@ -93,5 +95,3 @@ void RandomBackendTest::setNextBytes(const QByteArray& nextBytes) m_nextBytes = nextBytes; m_bytesIndex = 0; } - -QTEST_GUILESS_MAIN(TestRandom) diff --git a/tests/TestSymmetricCipher.cpp b/tests/TestSymmetricCipher.cpp index b47a005..6d4e94f 100644 --- a/tests/TestSymmetricCipher.cpp +++ b/tests/TestSymmetricCipher.cpp @@ -25,9 +25,11 @@ #include "crypto/SymmetricCipher.h" #include "streams/SymmetricCipherStream.h" +QTEST_GUILESS_MAIN(TestSymmetricCipher) + void TestSymmetricCipher::initTestCase() { - Crypto::init(); + QVERIFY(Crypto::init()); } void TestSymmetricCipher::testAes256CbcEncryption() @@ -192,5 +194,3 @@ void TestSymmetricCipher::testPadding() QByteArray decrypted = streamDec.readAll(); QCOMPARE(decrypted, plainText); } - -QTEST_GUILESS_MAIN(TestSymmetricCipher) diff --git a/tests/TestWildcardMatcher.cpp b/tests/TestWildcardMatcher.cpp index e06125b..dc9991d 100644 --- a/tests/TestWildcardMatcher.cpp +++ b/tests/TestWildcardMatcher.cpp @@ -22,6 +22,8 @@ #include "tests.h" #include "autotype/WildcardMatcher.h" +QTEST_GUILESS_MAIN(TestWildcardMatcher) + const QString TestWildcardMatcher::DefaultText = QString("some text"); const QString TestWildcardMatcher::AlternativeText = QString("some other text"); @@ -82,5 +84,3 @@ void TestWildcardMatcher::verifyNoMatch(QString pattern) bool matchResult = m_matcher->match(pattern); QVERIFY(!matchResult); } - -QTEST_GUILESS_MAIN(TestWildcardMatcher) diff --git a/tests/gui/TestGui.cpp b/tests/gui/TestGui.cpp index a4d04c5..326c349 100644 --- a/tests/gui/TestGui.cpp +++ b/tests/gui/TestGui.cpp @@ -51,7 +51,7 @@ void TestGui::initTestCase() { - Crypto::init(); + QVERIFY(Crypto::init()); Config::createTempFileInstance(); m_mainWindow = new MainWindow(); m_tabWidget = m_mainWindow->findChild("tabWidget"); @@ -83,7 +83,7 @@ void TestGui::testTabs() void TestGui::testEditEntry() { - EntryView* entryView = m_dbWidget->entryView(); + EntryView* entryView = m_dbWidget->findChild("entryView"); QModelIndex item = entryView->model()->index(0, 1); QRect itemRect = entryView->visualRect(item); QTest::mouseClick(entryView->viewport(), Qt::LeftButton, Qt::NoModifier, itemRect.center()); @@ -237,8 +237,8 @@ void TestGui::testSearch() void TestGui::testDeleteEntry() { - GroupView* groupView = m_dbWidget->groupView(); - EntryView* entryView = m_dbWidget->entryView(); + GroupView* groupView = m_dbWidget->findChild("groupView"); + EntryView* entryView = m_dbWidget->findChild("entryView"); QToolBar* toolBar = m_mainWindow->findChild("toolBar"); QAction* entryDeleteAction = m_mainWindow->findChild("actionEntryDelete"); QWidget* entryDeleteWidget = toolBar->widgetForAction(entryDeleteAction); @@ -274,7 +274,7 @@ void TestGui::testDeleteEntry() void TestGui::testCloneEntry() { - EntryView* entryView = m_dbWidget->entryView(); + EntryView* entryView = m_dbWidget->findChild("entryView"); QCOMPARE(entryView->model()->rowCount(), 1); @@ -292,8 +292,8 @@ void TestGui::testCloneEntry() void TestGui::testDragAndDropEntry() { - EntryView* entryView = m_dbWidget->entryView(); - GroupView* groupView = m_dbWidget->groupView(); + EntryView* entryView = m_dbWidget->findChild("entryView"); + GroupView* groupView = m_dbWidget->findChild("groupView"); QAbstractItemModel* groupModel = groupView->model(); QModelIndex sourceIndex = entryView->model()->index(0, 1); @@ -314,7 +314,7 @@ void TestGui::testDragAndDropEntry() void TestGui::testDragAndDropGroup() { - QAbstractItemModel* groupModel = m_dbWidget->groupView()->model(); + QAbstractItemModel* groupModel = m_dbWidget->findChild("groupView")->model(); QModelIndex rootIndex = groupModel->index(0, 0); dragAndDropGroup(groupModel->index(0, 0, rootIndex), @@ -453,7 +453,7 @@ void TestGui::dragAndDropGroup(const QModelIndex& sourceIndex, const QModelIndex QVERIFY(sourceIndex.isValid()); QVERIFY(targetIndex.isValid()); - GroupModel* groupModel = qobject_cast(m_dbWidget->groupView()->model()); + GroupModel* groupModel = qobject_cast(m_dbWidget->findChild("groupView")->model()); QMimeData mimeData; QByteArray encoded; diff --git a/tests/gui/TestGuiPixmaps.cpp b/tests/gui/TestGuiPixmaps.cpp index 401f68b..87e3f24 100644 --- a/tests/gui/TestGuiPixmaps.cpp +++ b/tests/gui/TestGuiPixmaps.cpp @@ -29,7 +29,7 @@ void TestGuiPixmaps::initTestCase() { - Crypto::init(); + QVERIFY(Crypto::init()); } void TestGuiPixmaps::testDatabaseIcons() diff --git a/utils/kdbx-extract.cpp b/utils/kdbx-extract.cpp index beee71d..f5d2a19 100644 --- a/utils/kdbx-extract.cpp +++ b/utils/kdbx-extract.cpp @@ -38,7 +38,9 @@ int main(int argc, char **argv) return 1; } - Crypto::init(); + if (!Crypto::init()) { + qFatal("Fatal error while testing the cryptographic functions:\n%s", qPrintable(Crypto::errorString())); + } CompositeKey key; if (QFile::exists(app.arguments().at(1))) {