diff options
-rw-r--r-- | KeePassX.spec | 25 | ||||
-rw-r--r-- | git.patch | 9977 |
2 files changed, 9996 insertions, 6 deletions
diff --git a/KeePassX.spec b/KeePassX.spec index 82645bc..6d7249b 100644 --- a/KeePassX.spec +++ b/KeePassX.spec @@ -12,15 +12,21 @@ Group: X11/Applications #Source0: http://downloads.sourceforge.net/keepassx/keepassx-%{version}.tar.gz Source0: http://www.keepassx.org/dev/attachments/download/69/keepassx-%{version}-%{pre}.tar.gz # Source0-md5: 7c1c3a42aff63abd8db3bc8df6c963f6 +Patch0: git.patch URL: http://keepassx.sourceforge.net/ -BuildRequires: ImageMagick -BuildRequires: Qt3Support-devel >= 4.0 -BuildRequires: QtGui-devel >= 4.0 -BuildRequires: QtXml-devel >= 4.0 -BuildRequires: qt4-build >= 4.3.3-3 -BuildRequires: qt4-qmake >= 4.3.3-3 +BuildRequires: QtCore-devel >= 4.6.0 +BuildRequires: QtDBus-devel >= 4.6.0 +BuildRequires: QtGui-devel >= 4.6.0 +BuildRequires: QtXml-devel >= 4.6.0 +BuildRequires: libgcrypt-devel >= 1.6 +BuildRequires: qt4-build >= 4.6.0 +BuildRequires: qt4-linguist >= 4.6.0 +BuildRequires: qt4-qmake >= 4.6.0 BuildRequires: rpmbuild(macros) >= 1.230 +BuildRequires: xorg-lib-libX11-devel +BuildRequires: xorg-lib-libXext-devel BuildRequires: xorg-lib-libXtst-devel +BuildRequires: zlib-devel Requires: desktop-file-utils Requires: hicolor-icon-theme Requires: shared-mime-info @@ -47,6 +53,7 @@ szyfrowania jakie są do tej pory znane (AES i TwoFish). %prep %setup -q -n keepassx-%{version}-%{pre} +%patch0 -p1 %build install -d build @@ -81,6 +88,12 @@ rm -rf $RPM_BUILD_ROOT %{_desktopdir}/keepassx.desktop %dir %{_datadir}/keepassx %{_datadir}/keepassx/icons +%dir %{_datadir}/keepassx/translations +%lang(de) %{_datadir}/keepassx/translations/keepassx_de.qm +%{_datadir}/keepassx/translations/keepassx_en_plurals.qm +%lang(it) %{_datadir}/keepassx/translations/keepassx_it.qm +%lang(nl) %{_datadir}/keepassx/translations/keepassx_nl_NL.qm +%lang(sv) %{_datadir}/keepassx/translations/keepassx_sv.qm %dir %{_libdir}/keepassx %attr(755,root,root) %{_libdir}/keepassx/libkeepassx-autotype-x11.so %{_iconsdir}/hicolor/*x*/apps/keepassx.png diff --git a/git.patch b/git.patch new file mode 100644 index 0000000..dfdace3 --- /dev/null +++ b/git.patch @@ -0,0 +1,9977 @@ +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_<lang>.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 <http://www.gnu.org/licenses/>. + ++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 <debfx@fobos.de> ++# ++# 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 <http://www.gnu.org/licenses/>. ++ ++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 @@ ++<?xml version="1.0" ?><!DOCTYPE TS><TS language="de" version="2.0"> ++<context> ++ <name>AboutDialog</name> ++ <message> ++ <source>About KeePassX</source> ++ <translation>Über KeePassX</translation> ++ </message> ++ <message> ++ <source>KeePassX is distributed under the term of the GNU General Public License (GPL) version 2 or (at your option) version 3.</source> ++ <translation>KeePassX ist unter der GNU General Public License (GPL) version 2 (version 3) veröffentlicht.</translation> ++ </message> ++</context> ++<context> ++ <name>AutoType</name> ++ <message> ++ <source>Auto-Type - KeePassX</source> ++ <translation>Auto-Type - KeePassX</translation> ++ </message> ++ <message> ++ <source>Couldn't find an entry that matches the window title.</source> ++ <translation>Konnte dem Fenstertitel keinen passenden Eintrag zuordnen.</translation> ++ </message> ++</context> ++<context> ++ <name>AutoTypeAssociationsModel</name> ++ <message> ++ <source>Window</source> ++ <translation>Fenster</translation> ++ </message> ++ <message> ++ <source>Sequence</source> ++ <translation>Reihenfolge</translation> ++ </message> ++ <message> ++ <source>Default sequence</source> ++ <translation>Standardreihenfolge</translation> ++ </message> ++</context> ++<context> ++ <name>AutoTypeSelectDialog</name> ++ <message> ++ <source>Auto-Type - KeePassX</source> ++ <translation>Auto-Type - KeePassX</translation> ++ </message> ++ <message> ++ <source>Select entry to Auto-Type:</source> ++ <translation>Wählen Sie einen Eintrag für Auto-Type:</translation> ++ </message> ++</context> ++<context> ++ <name>ChangeMasterKeyWidget</name> ++ <message> ++ <source>Password</source> ++ <translation>Passwort</translation> ++ </message> ++ <message> ++ <source>Enter password:</source> ++ <translation>Passwort eingeben:</translation> ++ </message> ++ <message> ++ <source>Repeat password:</source> ++ <translation>Passwort wiederholen:</translation> ++ </message> ++ <message> ++ <source>Key file</source> ++ <translation>Schlüsseldatei</translation> ++ </message> ++ <message> ++ <source>Browse</source> ++ <translation>Durchsuchen</translation> ++ </message> ++ <message> ++ <source>Create</source> ++ <translation>Erstellen</translation> ++ </message> ++ <message> ++ <source>Key files</source> ++ <translation>Schlüsseldateien</translation> ++ </message> ++ <message> ++ <source>All files</source> ++ <translation>Alle Dateien</translation> ++ </message> ++ <message> ++ <source>Create Key File...</source> ++ <translation>Erzeuge eine Schlüsseldatei...</translation> ++ </message> ++ <message> ++ <source>Error</source> ++ <translation>Fehler</translation> ++ </message> ++ <message> ++ <source>Unable to create Key File : </source> ++ <translation>Erzeugen der Schlüsseldatei nicht möglich:</translation> ++ </message> ++ <message> ++ <source>Select a key file</source> ++ <translation>Schlüsseldatei auswählen</translation> ++ </message> ++ <message> ++ <source>Question</source> ++ <translation>Frage</translation> ++ </message> ++ <message> ++ <source>Do you really want to use an empty string as password?</source> ++ <translation>Wollen Sie wirklich eine leere Zeichenkette als Passwort verwenden?</translation> ++ </message> ++ <message> ++ <source>Different passwords supplied.</source> ++ <translation>Unterschiedliche Passwörter eingegeben.</translation> ++ </message> ++</context> ++<context> ++ <name>DatabaseOpenWidget</name> ++ <message> ++ <source>Enter master key</source> ++ <translation>Hauptschlüssel eingeben</translation> ++ </message> ++ <message> ++ <source>Key File:</source> ++ <translation>Schlüsseldatei:</translation> ++ </message> ++ <message> ++ <source>Password:</source> ++ <translation>Passwort:</translation> ++ </message> ++ <message> ++ <source>Browse</source> ++ <translation>Durchsuchen</translation> ++ </message> ++ <message> ++ <source>Error</source> ++ <translation>Fehler</translation> ++ </message> ++ <message> ++ <source>Unable to open the database.</source> ++ <translation>Öffnen der Datenbank nicht möglich.</translation> ++ </message> ++ <message> ++ <source>Can't open key file</source> ++ <translation>Schlüsseldatein kann nicht geöffnet werden</translation> ++ </message> ++ <message> ++ <source>All files</source> ++ <translation>Alle Dateien</translation> ++ </message> ++ <message> ++ <source>Key files</source> ++ <translation>Schlüsseldateien</translation> ++ </message> ++ <message> ++ <source>Select key file</source> ++ <translation>Schlüsseldatei auswählen</translation> ++ </message> ++</context> ++<context> ++ <name>DatabaseSettingsWidget</name> ++ <message> ++ <source>Database name:</source> ++ <translation>Datenbankname:</translation> ++ </message> ++ <message> ++ <source>Database description:</source> ++ <translation>Datenbankbeschreibung:</translation> ++ </message> ++ <message> ++ <source>Transform rounds:</source> ++ <translation>Verschlüsselungsdurchläufe:</translation> ++ </message> ++ <message> ++ <source>Default username:</source> ++ <translation>Standardbenutzername:</translation> ++ </message> ++ <message> ++ <source>Use recycle bin:</source> ++ <translation>Verwende Papierkorb:</translation> ++ </message> ++ <message> ++ <source> MiB</source> ++ <translation> MiB</translation> ++ </message> ++ <message> ++ <source>Benchmark</source> ++ <translation>Benchmark</translation> ++ </message> ++ <message> ++ <source>Max. history items:</source> ++ <translation>Max Einträge im Verlauf:</translation> ++ </message> ++ <message> ++ <source>Max. history size:</source> ++ <translation>Max. Verlaufsgröße:</translation> ++ </message> ++</context> ++<context> ++ <name>DatabaseTabWidget</name> ++ <message> ++ <source>Root</source> ++ <translation>Root</translation> ++ </message> ++ <message> ++ <source>KeePass 2 Database</source> ++ <translation>KeePass 2 Datenbank</translation> ++ </message> ++ <message> ++ <source>All files</source> ++ <translation>Alle Dateien</translation> ++ </message> ++ <message> ++ <source>Open database</source> ++ <translation>Datenbank öffnen</translation> ++ </message> ++ <message> ++ <source>Warning</source> ++ <translation>Warnung</translation> ++ </message> ++ <message> ++ <source>File not found!</source> ++ <translation>Datei nicht gefunden!</translation> ++ </message> ++ <message> ++ <source>Open KeePass 1 database</source> ++ <translation>KeePass 1 Datenbank öffnen</translation> ++ </message> ++ <message> ++ <source>KeePass 1 database</source> ++ <translation>KeePass 1 Datenbank</translation> ++ </message> ++ <message> ++ <source>All files (*)</source> ++ <translation>Alle Dateien (*)</translation> ++ </message> ++ <message> ++ <source>Close?</source> ++ <translation>Schließen?</translation> ++ </message> ++ <message> ++ <source>"%1" is in edit mode. ++Close anyway?</source> ++ <translation>"%1" wird bearbeitet. ++Trotzdem schließen?</translation> ++ </message> ++ <message> ++ <source>Save changes?</source> ++ <translation>Änderungen speichern?</translation> ++ </message> ++ <message> ++ <source>"%1" was modified. ++Save changes?</source> ++ <translation>"%1" wurde geändert. ++Änderungen speichern?</translation> ++ </message> ++ <message> ++ <source>Error</source> ++ <translation>Fehler</translation> ++ </message> ++ <message> ++ <source>Writing the database failed.</source> ++ <translation>Schreiben der Datenbank fehlgeschlagen.</translation> ++ </message> ++ <message> ++ <source>Save database as</source> ++ <translation>Datenbank speichern unter</translation> ++ </message> ++ <message> ++ <source>New database</source> ++ <translation>Neue Datenbank</translation> ++ </message> ++ <message> ++ <source>locked</source> ++ <translation>gesperrt</translation> ++ </message> ++</context> ++<context> ++ <name>DatabaseWidget</name> ++ <message> ++ <source>Change master key</source> ++ <translation>Hauptschlüssel ändern</translation> ++ </message> ++ <message> ++ <source>Delete entry?</source> ++ <translation>Eintrag löschen?</translation> ++ </message> ++ <message> ++ <source>Do you really want to delete the entry "%1" for good?</source> ++ <translation>Wollen Sie den Eintrag "%1" wirklich löschen?</translation> ++ </message> ++ <message> ++ <source>Delete entries?</source> ++ <translation>Einträge löschen?</translation> ++ </message> ++ <message> ++ <source>Do you really want to delete %1 entries for good?</source> ++ <translation>Wollen Sie die Einträge "%1" wirklich löschen?</translation> ++ </message> ++ <message> ++ <source>Move entries to recycle bin?</source> ++ <translation>Einträge in den Papierkorb verschieben?</translation> ++ </message> ++ <message numerus="yes"> ++ <source>Do you really want to move %n entry(s) to the recycle bin?</source> ++ <translation><numerusform>Wollen Sie wirklich %n Eintrag in den Papierkorb verschieben?</numerusform><numerusform>Wollen Sie wirklich %n Einträge in den Papierkorb verschieben?</numerusform></translation> ++ </message> ++ <message> ++ <source>Delete group?</source> ++ <translation>Gruppe löschen?</translation> ++ </message> ++ <message> ++ <source>Do you really want to delete the group "%1" for good?</source> ++ <translation>Wollen Sie die Gruppe "%1" wirklich löschen?</translation> ++ </message> ++ <message> ++ <source>Current group</source> ++ <translation>Aktuelle Gruppe</translation> ++ </message> ++</context> ++<context> ++ <name>EditEntryWidget</name> ++ <message> ++ <source>Entry</source> ++ <translation>Eintrag</translation> ++ </message> ++ <message> ++ <source>Advanced</source> ++ <translation>Fortgeschritten</translation> ++ </message> ++ <message> ++ <source>Icon</source> ++ <translation>Symbol</translation> ++ </message> ++ <message> ++ <source>Auto-Type</source> ++ <translation>Auto-Type</translation> ++ </message> ++ <message> ++ <source>Properties</source> ++ <translation>Eigenschaften</translation> ++ </message> ++ <message> ++ <source>History</source> ++ <translation>Verlauf</translation> ++ </message> ++ <message> ++ <source>Entry history</source> ++ <translation>Eintragsverlauf</translation> ++ </message> ++ <message> ++ <source>Add entry</source> ++ <translation>Eintrag hinzufügen</translation> ++ </message> ++ <message> ++ <source>Edit entry</source> ++ <translation>Eintrag bearbeiten</translation> ++ </message> ++ <message> ++ <source>Error</source> ++ <translation>Fehler</translation> ++ </message> ++ <message> ++ <source>Different passwords supplied.</source> ++ <translation>Unterschiedliche Passwörter eingegeben.</translation> ++ </message> ++ <message> ++ <source>New attribute</source> ++ <translation>Neue Eigenschaft</translation> ++ </message> ++ <message> ++ <source>Select file</source> ++ <translation>Datei wählen</translation> ++ </message> ++ <message> ++ <source>Unable to open file</source> ++ <translation>Öffnen der Datei nicht möglich</translation> ++ </message> ++ <message> ++ <source>Save attachment</source> ++ <translation>Anhang speichern</translation> ++ </message> ++ <message> ++ <source>Unable to save the attachment: ++</source> ++ <translation>Speichern des Anhangs nicht möglich:</translation> ++ </message> ++ <message> ++ <source>Tomorrow</source> ++ <translation>Morgen</translation> ++ </message> ++ <message numerus="yes"> ++ <source>%n week(s)</source> ++ <translation><numerusform>%n Woche</numerusform><numerusform>%n Wochen</numerusform></translation> ++ </message> ++ <message numerus="yes"> ++ <source>%n month(s)</source> ++ <translation><numerusform>%n Monat</numerusform><numerusform>%n Monaten</numerusform></translation> ++ </message> ++ <message> ++ <source>1 year</source> ++ <translation>1 Jahr</translation> ++ </message> ++</context> ++<context> ++ <name>EditEntryWidgetAdvanced</name> ++ <message> ++ <source>Additional attributes</source> ++ <translation>Zusätzliche Eigenschaften</translation> ++ </message> ++ <message> ++ <source>Add</source> ++ <translation>Hinzufügen</translation> ++ </message> ++ <message> ++ <source>Edit</source> ++ <translation>Bearbeiten</translation> ++ </message> ++ <message> ++ <source>Remove</source> ++ <translation>Entfernen</translation> ++ </message> ++ <message> ++ <source>Attachments</source> ++ <translation>Anhänge</translation> ++ </message> ++ <message> ++ <source>Save</source> ++ <translation>Speichern</translation> ++ </message> ++</context> ++<context> ++ <name>EditEntryWidgetAutoType</name> ++ <message> ++ <source>Enable Auto-Type for this entry</source> ++ <translation>Auto-Type für diesen Eintrag aktivieren</translation> ++ </message> ++ <message> ++ <source>Inherit default Auto-Type sequence from the group</source> ++ <translation>Standard-Auto-Type-Sequenz von der Gruppe erben</translation> ++ </message> ++ <message> ++ <source>Use custom Auto-Type sequence:</source> ++ <translation>Benutzerdefinierte Auto-Type-Sequenz benutzen:</translation> ++ </message> ++ <message> ++ <source>+</source> ++ <translation>+</translation> ++ </message> ++ <message> ++ <source>-</source> ++ <translation>-</translation> ++ </message> ++ <message> ++ <source>Window title:</source> ++ <translation>Fenstertitel:</translation> ++ </message> ++ <message> ++ <source>Use default sequence</source> ++ <translation>Standardsequenz benutzen</translation> ++ </message> ++ <message> ++ <source>Set custom sequence:</source> ++ <translation>Benutzerdefinierte Sequenz verwenden:</translation> ++ </message> ++</context> ++<context> ++ <name>EditEntryWidgetHistory</name> ++ <message> ++ <source>Show</source> ++ <translation>Anzeigen</translation> ++ </message> ++ <message> ++ <source>Restore</source> ++ <translation>Wiederherstellen</translation> ++ </message> ++ <message> ++ <source>Delete</source> ++ <translation>Löschen</translation> ++ </message> ++ <message> ++ <source>Delete all</source> ++ <translation>Alle löschen</translation> ++ </message> ++</context> ++<context> ++ <name>EditEntryWidgetMain</name> ++ <message> ++ <source>Title:</source> ++ <translation>Titel:</translation> ++ </message> ++ <message> ++ <source>Username:</source> ++ <translation>Benutzername:</translation> ++ </message> ++ <message> ++ <source>Password:</source> ++ <translation>Passwort:</translation> ++ </message> ++ <message> ++ <source>Repeat:</source> ++ <translation>Wiederholen:</translation> ++ </message> ++ <message> ++ <source>Gen.</source> ++ <translation>Gen.</translation> ++ </message> ++ <message> ++ <source>URL:</source> ++ <translation>URL:</translation> ++ </message> ++ <message> ++ <source>Expires</source> ++ <translation>Erlischt</translation> ++ </message> ++ <message> ++ <source>Presets</source> ++ <translation>Vorgaben</translation> ++ </message> ++ <message> ++ <source>Notes:</source> ++ <translation>Notizen:</translation> ++ </message> ++</context> ++<context> ++ <name>EditGroupWidget</name> ++ <message> ++ <source>Group</source> ++ <translation>Gruppe</translation> ++ </message> ++ <message> ++ <source>Icon</source> ++ <translation>Symbol</translation> ++ </message> ++ <message> ++ <source>Properties</source> ++ <translation>Eigenschaften</translation> ++ </message> ++ <message> ++ <source>Add group</source> ++ <translation>Gruppe hinzufügen</translation> ++ </message> ++ <message> ++ <source>Edit group</source> ++ <translation>Gruppe bearbeiten</translation> ++ </message> ++ <message> ++ <source>Enable</source> ++ <translation>Aktivieren</translation> ++ </message> ++ <message> ++ <source>Disable</source> ++ <translation>Deaktivieren</translation> ++ </message> ++ <message> ++ <source>Inherit from parent group (%1)</source> ++ <translation>Von der übergeordneten Gruppe (%1) erben</translation> ++ </message> ++</context> ++<context> ++ <name>EditGroupWidgetMain</name> ++ <message> ++ <source>Name</source> ++ <translation>Name</translation> ++ </message> ++ <message> ++ <source>Notes</source> ++ <translation>Notizen</translation> ++ </message> ++ <message> ++ <source>Expires</source> ++ <translation>Erlischt</translation> ++ </message> ++ <message> ++ <source>Search</source> ++ <translation>Suche</translation> ++ </message> ++ <message> ++ <source>Auto-type</source> ++ <translation>Auto-type</translation> ++ </message> ++</context> ++<context> ++ <name>EditWidgetIcons</name> ++ <message> ++ <source>Use default icon</source> ++ <translation>Standardsymbol verwenden</translation> ++ </message> ++ <message> ++ <source>Use custom icon</source> ++ <translation>Benutzerdefiniertes Symbol verwenden</translation> ++ </message> ++ <message> ++ <source>Add custom icon</source> ++ <translation>Benutzerdefiniertes Symbol hinzufügen</translation> ++ </message> ++ <message> ++ <source>Delete custom icon</source> ++ <translation>Benutzerdefiniertes Symbol löschen</translation> ++ </message> ++ <message> ++ <source>Images</source> ++ <translation>Bilder</translation> ++ </message> ++ <message> ++ <source>All files</source> ++ <translation>Alle Dateien</translation> ++ </message> ++ <message> ++ <source>Select Image</source> ++ <translation>Bild auswählen</translation> ++ </message> ++ <message> ++ <source>Can't delete icon!</source> ++ <translation>Symbol kann nicht gelöscht werden!</translation> ++ </message> ++ <message numerus="yes"> ++ <source>Can't delete icon. Still used by %n item(s).</source> ++ <translation><numerusform>Symbol kann nicht gelöscht werden. Es wird von %n Eintrag verwendet.</numerusform><numerusform>Symbol kann nicht gelöscht werden. Es wird von %n Einträgen verwendet.</numerusform></translation> ++ </message> ++</context> ++<context> ++ <name>EditWidgetProperties</name> ++ <message> ++ <source>Created:</source> ++ <translation>Erstellt:</translation> ++ </message> ++ <message> ++ <source>Modified:</source> ++ <translation>Bearbeitet:</translation> ++ </message> ++ <message> ++ <source>Accessed:</source> ++ <translation>Zugegriffen:</translation> ++ </message> ++ <message> ++ <source>Uuid:</source> ++ <translation>Uuid:</translation> ++ </message> ++</context> ++<context> ++ <name>EntryAttributesModel</name> ++ <message> ++ <source>Name</source> ++ <translation>Name</translation> ++ </message> ++</context> ++<context> ++ <name>EntryHistoryModel</name> ++ <message> ++ <source>Last modified</source> ++ <translation>Zuletzt geändert</translation> ++ </message> ++ <message> ++ <source>Title</source> ++ <translation>Titel</translation> ++ </message> ++ <message> ++ <source>Username</source> ++ <translation>Benutzername</translation> ++ </message> ++ <message> ++ <source>URL</source> ++ <translation>URL</translation> ++ </message> ++</context> ++<context> ++ <name>EntryModel</name> ++ <message> ++ <source>Group</source> ++ <translation>Gruppe</translation> ++ </message> ++ <message> ++ <source>Title</source> ++ <translation>Titel</translation> ++ </message> ++ <message> ++ <source>Username</source> ++ <translation>Benutzername</translation> ++ </message> ++ <message> ++ <source>URL</source> ++ <translation>URL</translation> ++ </message> ++</context> ++<context> ++ <name>Group</name> ++ <message> ++ <source>Recycle Bin</source> ++ <translation>Papierkorb</translation> ++ </message> ++</context> ++<context> ++ <name>KeePass1OpenWidget</name> ++ <message> ++ <source>Import KeePass1 database</source> ++ <translation>KeePass 1 Datenbank importieren</translation> ++ </message> ++ <message> ++ <source>Error</source> ++ <translation>Fehler</translation> ++ </message> ++ <message> ++ <source>Unable to open the database.</source> ++ <translation>Öffnen der Datenbank nicht möglich.</translation> ++ </message> ++</context> ++<context> ++ <name>KeePass1Reader</name> ++ <message> ++ <source>Unable to read keyfile.</source> ++ <translation>Lesen der Schlüsseldatei nicht möglich.</translation> ++ </message> ++ <message> ++ <source>Not a KeePass database.</source> ++ <translation>Keine KeePass-Datenbank.</translation> ++ </message> ++ <message> ++ <source>Unsupported encryption algorithm.</source> ++ <translation>Nicht unterstützter Verschlüsselungsalgorithmus.</translation> ++ </message> ++ <message> ++ <source>Unsupported KeePass database version.</source> ++ <translation>Nicht unterstützte KeePass-Datenbankversion.</translation> ++ </message> ++ <message> ++ <source>Root</source> ++ <translation>Root</translation> ++ </message> ++</context> ++<context> ++ <name>KeePass2Reader</name> ++ <message> ++ <source>Not a KeePass database.</source> ++ <translation>Keine KeePass-Datenbank.</translation> ++ </message> ++ <message> ++ <source>Unsupported KeePass database version.</source> ++ <translation>Nicht unterstützte KeePass-Datenbankversion.</translation> ++ </message> ++ <message> ++ <source>Wrong key or database file is corrupt.</source> ++ <translation>Falscher Schlüssel oder die Datei ist beschädigt.</translation> ++ </message> ++</context> ++<context> ++ <name>MainWindow</name> ++ <message> ++ <source>Database</source> ++ <translation>Datenbank</translation> ++ </message> ++ <message> ++ <source>Recent databases</source> ++ <translation>Aktuelle Datenbanken</translation> ++ </message> ++ <message> ++ <source>Help</source> ++ <translation>Hilfe</translation> ++ </message> ++ <message> ++ <source>Entries</source> ++ <translation>Einträge</translation> ++ </message> ++ <message> ++ <source>Copy attribute to clipboard</source> ++ <translation>Eingenschaft in die Zwischenablage kopieren</translation> ++ </message> ++ <message> ++ <source>Groups</source> ++ <translation>Gruppen</translation> ++ </message> ++ <message> ++ <source>Extras</source> ++ <translation>Extras</translation> ++ </message> ++ <message> ++ <source>View</source> ++ <translation>Ansicht</translation> ++ </message> ++ <message> ++ <source>Quit</source> ++ <translation>Beenden</translation> ++ </message> ++ <message> ++ <source>About</source> ++ <translation>Über</translation> ++ </message> ++ <message> ++ <source>Open database</source> ++ <translation>Datenbank öffnen</translation> ++ </message> ++ <message> ++ <source>Save database</source> ++ <translation>Datenbank speichern</translation> ++ </message> ++ <message> ++ <source>Close database</source> ++ <translation>Datenbank schließen</translation> ++ </message> ++ <message> ++ <source>New database</source> ++ <translation>Neue Datenbank</translation> ++ </message> ++ <message> ++ <source>Add new entry</source> ++ <translation>Neuen Eintrag hinzufügen</translation> ++ </message> ++ <message> ++ <source>View/Edit entry</source> ++ <translation>Eintrag anzeigen/bearbeiten</translation> ++ </message> ++ <message> ++ <source>Delete entry</source> ++ <translation>Eintrag löschen</translation> ++ </message> ++ <message> ++ <source>Add new group</source> ++ <translation>Neue Gruppe hinzufügen</translation> ++ </message> ++ <message> ++ <source>Edit group</source> ++ <translation>Gruppe bearbeiten</translation> ++ </message> ++ <message> ++ <source>Delete group</source> ++ <translation>Gruppe löschen</translation> ++ </message> ++ <message> ++ <source>Save database as</source> ++ <translation>Datenbank speichern als</translation> ++ </message> ++ <message> ++ <source>Change master key</source> ++ <translation>Hauptschlüssel ändern</translation> ++ </message> ++ <message> ++ <source>Database settings</source> ++ <translation>Datenbankeinstellungen</translation> ++ </message> ++ <message> ++ <source>Import KeePass 1 database</source> ++ <translation>KeePass 1 Datenbank importieren</translation> ++ </message> ++ <message> ++ <source>Clone entry</source> ++ <translation>Eintrag klonen</translation> ++ </message> ++ <message> ++ <source>Find</source> ++ <translation>Suchen</translation> ++ </message> ++ <message> ++ <source>Username</source> ++ <translation>Benutzername</translation> ++ </message> ++ <message> ++ <source>Copy username to clipboard</source> ++ <translation>Benutzername in die Zwischenablage kopieren</translation> ++ </message> ++ <message> ++ <source>Password</source> ++ <translation>Passwort</translation> ++ </message> ++ <message> ++ <source>Copy password to clipboard</source> ++ <translation>Passwort in die Zwischenablage kopieren</translation> ++ </message> ++ <message> ++ <source>Settings</source> ++ <translation>Einstellungen</translation> ++ </message> ++ <message> ++ <source>Perform Auto-Type</source> ++ <translation>Auto-Type ausführen</translation> ++ </message> ++ <message> ++ <source>Open URL</source> ++ <translation>URL öffnen</translation> ++ </message> ++ <message> ++ <source>Lock databases</source> ++ <translation>Datenbank sperren</translation> ++ </message> ++ <message> ++ <source>Title</source> ++ <translation>Titel</translation> ++ </message> ++ <message> ++ <source>URL</source> ++ <translation>URL</translation> ++ </message> ++ <message> ++ <source>Notes</source> ++ <translation>Notizen</translation> ++ </message> ++ <message> ++ <source>Show toolbar</source> ++ <translation>Symbolleiste anzeigen</translation> ++ </message> ++ <message> ++ <source>read-only</source> ++ <translation>Nur Lesezugriff</translation> ++ </message> ++</context> ++<context> ++ <name>PasswordGeneratorWidget</name> ++ <message> ++ <source>Password:</source> ++ <translation>Passwort:</translation> ++ </message> ++ <message> ++ <source>Length:</source> ++ <translation>Länge:</translation> ++ </message> ++ <message> ++ <source>Character Types</source> ++ <translation>Zeichenarten</translation> ++ </message> ++ <message> ++ <source>Upper Case Letters</source> ++ <translation>Großbuchstaben</translation> ++ </message> ++ <message> ++ <source>Lower Case Letters</source> ++ <translation>Kleinbuchstaben</translation> ++ </message> ++ <message> ++ <source>Numbers</source> ++ <translation>Zahlen</translation> ++ </message> ++ <message> ++ <source>Special Characters</source> ++ <translation>Sonderzeichen</translation> ++ </message> ++ <message> ++ <source>Exclude look-alike characters</source> ++ <translation>Gleich aussehende Zeichen ausschließen</translation> ++ </message> ++ <message> ++ <source>Ensure that the password contains characters from every group</source> ++ <translation>Sicher stellen, dass das Passwort Zeichen aller Gruppen enthält</translation> ++ </message> ++ <message> ++ <source>Accept</source> ++ <translation>Akzeptieren</translation> ++ </message> ++</context> ++<context> ++ <name>QCommandLineParser</name> ++ <message> ++ <source>Displays version information.</source> ++ <translation>Versionsinformationen anzeigen.</translation> ++ </message> ++ <message> ++ <source>Displays this help.</source> ++ <translation>Zeigt diese Hilfe an.</translation> ++ </message> ++ <message> ++ <source>Unknown option '%1'.</source> ++ <translation>Unbekannte Option '%1'.</translation> ++ </message> ++ <message> ++ <source>Unknown options: %1.</source> ++ <translation>Unbekannte Optionen: '%1'.</translation> ++ </message> ++ <message> ++ <source>Missing value after '%1'.</source> ++ <translation>Fehlender Wert nach '%1'.</translation> ++ </message> ++ <message> ++ <source>Unexpected value after '%1'.</source> ++ <translation>Unerwarteter Wert nach '%1'.</translation> ++ </message> ++ <message> ++ <source>[options]</source> ++ <translation>[Optionen]</translation> ++ </message> ++ <message> ++ <source>Usage: %1</source> ++ <translation>Verwendung: %1</translation> ++ </message> ++ <message> ++ <source>Options:</source> ++ <translation>Optionen:</translation> ++ </message> ++ <message> ++ <source>Arguments:</source> ++ <translation>Argumente:</translation> ++ </message> ++</context> ++<context> ++ <name>QSaveFile</name> ++ <message> ++ <source>Existing file %1 is not writable</source> ++ <translation>Bestehende Datei(en) %1 ist nicht schreibbar</translation> ++ </message> ++ <message> ++ <source>Writing canceled by application</source> ++ <translation>Schreiben von der Applikation abgebrochen</translation> ++ </message> ++ <message> ++ <source>Partial write. Partition full?</source> ++ <translation>Unvollständiger Schreibvorgang. Partition voll?</translation> ++ </message> ++</context> ++<context> ++ <name>QtIOCompressor</name> ++ <message> ++ <source>Internal zlib error when compressing: </source> ++ <translation>Interner Fehler in zlib beim komprimieren:</translation> ++ </message> ++ <message> ++ <source>Error writing to underlying device: </source> ++ <translation>Fehler beim Schreiben auf das zugrunde liegende Gerät: </translation> ++ </message> ++ <message> ++ <source>Error opening underlying device: </source> ++ <translation>Fehler beim Öffnen des zugrunde liegenden Gerätes: </translation> ++ </message> ++ <message> ++ <source>Error reading data from underlying device: </source> ++ <translation>Fehler beim Lesen von Daten auf dem zugrunde liegenden Gerät: </translation> ++ </message> ++ <message> ++ <source>Internal zlib error when decompressing: </source> ++ <translation>Interner Fehler in zlib beim dekomprimieren:</translation> ++ </message> ++</context> ++<context> ++ <name>QtIOCompressor::open</name> ++ <message> ++ <source>The gzip format not supported in this version of zlib.</source> ++ <translation>Das gzip-Format wird von dieser zlib Version nicht unterstützt.</translation> ++ </message> ++ <message> ++ <source>Internal zlib error: </source> ++ <translation>Interner Fehler in zlib:</translation> ++ </message> ++</context> ++<context> ++ <name>SearchWidget</name> ++ <message> ++ <source>Find:</source> ++ <translation>Suchen nach:</translation> ++ </message> ++ <message> ++ <source>Case sensitive</source> ++ <translation>Groß-/Kleinschreibung unterscheiden</translation> ++ </message> ++ <message> ++ <source>Current group</source> ++ <translation>Aktuelle Gruppe</translation> ++ </message> ++ <message> ++ <source>Root group</source> ++ <translation>Root-Gruppe</translation> ++ </message> ++</context> ++<context> ++ <name>SettingsWidget</name> ++ <message> ++ <source>Application Settings</source> ++ <translation>Anwendungseinstellungen</translation> ++ </message> ++ <message> ++ <source>General</source> ++ <translation>Allgemein</translation> ++ </message> ++ <message> ++ <source>Security</source> ++ <translation>Sicherheit</translation> ++ </message> ++</context> ++<context> ++ <name>SettingsWidgetGeneral</name> ++ <message> ++ <source>Remember last databases</source> ++ <translation>Letzte Datenbank merken</translation> ++ </message> ++ <message> ++ <source>Open previous databases on startup</source> ++ <translation>Letzte Datenbank beim Starten öffnen</translation> ++ </message> ++ <message> ++ <source>Mark as modified on expanded state changes</source> ++ <translation>Als erweiterte Zustandsänderungen makieren</translation> ++ </message> ++ <message> ++ <source>Automatically save on exit</source> ++ <translation>Automatisch speichern beim Schließen</translation> ++ </message> ++ <message> ++ <source>Automatically save after every change</source> ++ <translation>Automatisch nach jeder Änderung speichern</translation> ++ </message> ++ <message> ++ <source>Minimize when copying to clipboard</source> ++ <translation>Minimieren beim Kopieren in die Zwischenablage</translation> ++ </message> ++ <message> ++ <source>Use group icon on entry creation</source> ++ <translation>Gruppensymbol für das Erstellen neuer Einträge verwenden</translation> ++ </message> ++ <message> ++ <source>Global Auto-Type shortcut</source> ++ <translation>Globale Tastenkombination für Auto-Type</translation> ++ </message> ++ <message> ++ <source>Use entry title to match windows for global auto-type</source> ++ <translation>Verwende den Eintragstitel für entsprechende Fenster für den globale Auto-Typ</translation> ++ </message> ++</context> ++<context> ++ <name>SettingsWidgetSecurity</name> ++ <message> ++ <source>Clear clipboard after</source> ++ <translation>Zwischenablage leeren nach</translation> ++ </message> ++ <message> ++ <source> sec</source> ++ <translation> sek</translation> ++ </message> ++ <message> ++ <source>Lock databases after inactivity of</source> ++ <translation>Datenbank sperren nach einer Inaktivität von</translation> ++ </message> ++ <message> ++ <source>Show passwords in cleartext by default</source> ++ <translation>Passwort standartmäßig in Klartext anzeigen</translation> ++ </message> ++ <message> ++ <source>Always ask before performing auto-type</source> ++ <translation>Immer vor einem Auto-type fragen</translation> ++ </message> ++</context> ++<context> ++ <name>UnlockDatabaseWidget</name> ++ <message> ++ <source>Unlock database</source> ++ <translation>Datenbank entsperren</translation> ++ </message> ++ <message> ++ <source>Error</source> ++ <translation>Fehler</translation> ++ </message> ++ <message> ++ <source>Wrong key.</source> ++ <translation>Falscher Schlüssel.</translation> ++ </message> ++</context> ++<context> ++ <name>WelcomeWidget</name> ++ <message> ++ <source>Welcome!</source> ++ <translation>Willkommen!</translation> ++ </message> ++</context> ++<context> ++ <name>main</name> ++ <message> ++ <source>KeePassX - cross-platform password manager</source> ++ <translation>KeePassX - plattformübergreifender Passwortmanager</translation> ++ </message> ++ <message> ++ <source>filename of the password database to open (*.kdbx)</source> ++ <translation>Dateiname für die zu öffnende Passwortdatenbank (*.kdbx)</translation> ++ </message> ++ <message> ++ <source>path to a custom config file</source> ++ <translation>Pfad zu einer benutzerdefinierten Konfigurationsdatei</translation> ++ </message> ++ <message> ++ <source>password of the database (DANGEROUS!)</source> ++ <translation>Passwort der Datenbank (GEFÄHRLICH!)</translation> ++ </message> ++ <message> ++ <source>key file of the database</source> ++ <translation>Schlüsseldatei der Datenbank</translation> ++ </message> ++</context> ++</TS> +\ 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 @@ ++<?xml version="1.0" encoding="utf-8"?> ++<!DOCTYPE TS> ++<TS version="2.0" language="en_US"> ++<context> ++ <name>AboutDialog</name> ++ <message> ++ <source>About KeePassX</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>KeePassX is distributed under the term of the GNU General Public License (GPL) version 2 or (at your option) version 3.</source> ++ <translation type="unfinished"></translation> ++ </message> ++</context> ++<context> ++ <name>AutoType</name> ++ <message> ++ <source>Auto-Type - KeePassX</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Couldn't find an entry that matches the window title:</source> ++ <translation type="unfinished"></translation> ++ </message> ++</context> ++<context> ++ <name>AutoTypeAssociationsModel</name> ++ <message> ++ <source>Window</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Sequence</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Default sequence</source> ++ <translation type="unfinished"></translation> ++ </message> ++</context> ++<context> ++ <name>AutoTypeSelectDialog</name> ++ <message> ++ <source>Auto-Type - KeePassX</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Select entry to Auto-Type:</source> ++ <translation type="unfinished"></translation> ++ </message> ++</context> ++<context> ++ <name>ChangeMasterKeyWidget</name> ++ <message> ++ <source>Password</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Enter password:</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Repeat password:</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Key file</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Browse</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Create</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Key files</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>All files</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Create Key File...</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Error</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Unable to create Key File : </source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Select a key file</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Question</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Do you really want to use an empty string as password?</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Different passwords supplied.</source> ++ <translation type="unfinished"></translation> ++ </message> ++</context> ++<context> ++ <name>DatabaseOpenWidget</name> ++ <message> ++ <source>Enter master key</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Key File:</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Password:</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Browse</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Error</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Unable to open the database.</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Can't open key file</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>All files</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Key files</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Select key file</source> ++ <translation type="unfinished"></translation> ++ </message> ++</context> ++<context> ++ <name>DatabaseSettingsWidget</name> ++ <message> ++ <source>Database name:</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Database description:</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Transform rounds:</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Default username:</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Use recycle bin:</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source> MiB</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Benchmark</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Max. history items:</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Max. history size:</source> ++ <translation type="unfinished"></translation> ++ </message> ++</context> ++<context> ++ <name>DatabaseTabWidget</name> ++ <message> ++ <source>Root</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>KeePass 2 Database</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>All files</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Open database</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Warning</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>File not found!</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Open KeePass 1 database</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>KeePass 1 database</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>All files (*)</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Close?</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>"%1" is in edit mode. ++Close anyway?</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Save changes?</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>"%1" was modified. ++Save changes?</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Error</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Writing the database failed.</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Save database as</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>New database</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>locked</source> ++ <translation type="unfinished"></translation> ++ </message> ++</context> ++<context> ++ <name>DatabaseWidget</name> ++ <message> ++ <source>Change master key</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Delete entry?</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Do you really want to delete the entry "%1" for good?</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Delete entries?</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Do you really want to delete %1 entries for good?</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Move entries to recycle bin?</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message numerus="yes"> ++ <source>Do you really want to move %n entry(s) to the recycle bin?</source> ++ <translation type="unfinished"> ++ <numerusform></numerusform> ++ <numerusform></numerusform> ++ </translation> ++ </message> ++ <message> ++ <source>Delete group?</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Do you really want to delete the group "%1" for good?</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Current group</source> ++ <translation type="unfinished"></translation> ++ </message> ++</context> ++<context> ++ <name>EditEntryWidget</name> ++ <message> ++ <source>Entry</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Advanced</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Icon</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Auto-Type</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Properties</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>History</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Entry history</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Add entry</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Edit entry</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Error</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Different passwords supplied.</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>New attribute</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Select file</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Unable to open file</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Save attachment</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Unable to save the attachment: ++</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Tomorrow</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message numerus="yes"> ++ <source>%n week(s)</source> ++ <translation type="unfinished"> ++ <numerusform></numerusform> ++ <numerusform></numerusform> ++ </translation> ++ </message> ++ <message numerus="yes"> ++ <source>%n month(s)</source> ++ <translation type="unfinished"> ++ <numerusform></numerusform> ++ <numerusform></numerusform> ++ </translation> ++ </message> ++ <message> ++ <source>1 year</source> ++ <translation type="unfinished"></translation> ++ </message> ++</context> ++<context> ++ <name>EditEntryWidgetAdvanced</name> ++ <message> ++ <source>Additional attributes</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Add</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Edit</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Remove</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Attachments</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Save</source> ++ <translation type="unfinished"></translation> ++ </message> ++</context> ++<context> ++ <name>EditEntryWidgetAutoType</name> ++ <message> ++ <source>Enable Auto-Type for this entry</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Inherit default Auto-Type sequence from the group</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Use custom Auto-Type sequence:</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>+</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>-</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Window title:</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Use default sequence</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Set custom sequence:</source> ++ <translation type="unfinished"></translation> ++ </message> ++</context> ++<context> ++ <name>EditEntryWidgetHistory</name> ++ <message> ++ <source>Show</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Restore</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Delete</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Delete all</source> ++ <translation type="unfinished"></translation> ++ </message> ++</context> ++<context> ++ <name>EditEntryWidgetMain</name> ++ <message> ++ <source>Title:</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Username:</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Password:</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Repeat:</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Gen.</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>URL:</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Expires</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Presets</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Notes:</source> ++ <translation type="unfinished"></translation> ++ </message> ++</context> ++<context> ++ <name>EditGroupWidget</name> ++ <message> ++ <source>Group</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Icon</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Properties</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Add group</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Edit group</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Enable</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Disable</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Inherit from parent group (%1)</source> ++ <translation type="unfinished"></translation> ++ </message> ++</context> ++<context> ++ <name>EditGroupWidgetMain</name> ++ <message> ++ <source>Name</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Notes</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Expires</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Search</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Auto-type</source> ++ <translation type="unfinished"></translation> ++ </message> ++</context> ++<context> ++ <name>EditWidgetIcons</name> ++ <message> ++ <source>Use default icon</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Use custom icon</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Add custom icon</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Delete custom icon</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Images</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>All files</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Select Image</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Can't delete icon!</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message numerus="yes"> ++ <source>Can't delete icon. Still used by %n item(s).</source> ++ <translation type="unfinished"> ++ <numerusform></numerusform> ++ <numerusform></numerusform> ++ </translation> ++ </message> ++</context> ++<context> ++ <name>EditWidgetProperties</name> ++ <message> ++ <source>Created:</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Modified:</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Accessed:</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Uuid:</source> ++ <translation type="unfinished"></translation> ++ </message> ++</context> ++<context> ++ <name>EntryAttributesModel</name> ++ <message> ++ <source>Name</source> ++ <translation type="unfinished"></translation> ++ </message> ++</context> ++<context> ++ <name>EntryHistoryModel</name> ++ <message> ++ <source>Last modified</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Title</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Username</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>URL</source> ++ <translation type="unfinished"></translation> ++ </message> ++</context> ++<context> ++ <name>EntryModel</name> ++ <message> ++ <source>Group</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Title</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Username</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>URL</source> ++ <translation type="unfinished"></translation> ++ </message> ++</context> ++<context> ++ <name>Group</name> ++ <message> ++ <source>Recycle Bin</source> ++ <translation type="unfinished"></translation> ++ </message> ++</context> ++<context> ++ <name>KeePass1OpenWidget</name> ++ <message> ++ <source>Import KeePass1 database</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Error</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Unable to open the database.</source> ++ <translation type="unfinished"></translation> ++ </message> ++</context> ++<context> ++ <name>KeePass1Reader</name> ++ <message> ++ <source>Unable to read keyfile.</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Not a KeePass database.</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Unsupported encryption algorithm.</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Unsupported KeePass database version.</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Root</source> ++ <translation type="unfinished"></translation> ++ </message> ++</context> ++<context> ++ <name>KeePass2Reader</name> ++ <message> ++ <source>Not a KeePass database.</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Unsupported KeePass database version.</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Wrong key or database file is corrupt.</source> ++ <translation type="unfinished"></translation> ++ </message> ++</context> ++<context> ++ <name>Main</name> ++ <message> ++ <source>Fatal error while testing the cryptographic functions.</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>KeePassX - Error</source> ++ <translation type="unfinished"></translation> ++ </message> ++</context> ++<context> ++ <name>MainWindow</name> ++ <message> ++ <source>Database</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Recent databases</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Help</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Entries</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Copy attribute to clipboard</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Groups</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Extras</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>View</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Quit</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>About</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Open database</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Save database</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Close database</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>New database</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Add new entry</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>View/Edit entry</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Delete entry</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Add new group</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Edit group</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Delete group</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Save database as</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Change master key</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Database settings</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Import KeePass 1 database</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Clone entry</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Find</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Username</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Copy username to clipboard</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Password</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Copy password to clipboard</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Settings</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Perform Auto-Type</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Open URL</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Lock databases</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Title</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>URL</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Notes</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Show toolbar</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>read-only</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Toggle window</source> ++ <translation type="unfinished"></translation> ++ </message> ++</context> ++<context> ++ <name>PasswordGeneratorWidget</name> ++ <message> ++ <source>Password:</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Length:</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Character Types</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Upper Case Letters</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Lower Case Letters</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Numbers</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Special Characters</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Exclude look-alike characters</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Ensure that the password contains characters from every group</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Accept</source> ++ <translation type="unfinished"></translation> ++ </message> ++</context> ++<context> ++ <name>QCommandLineParser</name> ++ <message> ++ <source>Displays version information.</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Displays this help.</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Unknown option '%1'.</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Unknown options: %1.</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Missing value after '%1'.</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Unexpected value after '%1'.</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>[options]</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Usage: %1</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Options:</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Arguments:</source> ++ <translation type="unfinished"></translation> ++ </message> ++</context> ++<context> ++ <name>QSaveFile</name> ++ <message> ++ <source>Existing file %1 is not writable</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Writing canceled by application</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Partial write. Partition full?</source> ++ <translation type="unfinished"></translation> ++ </message> ++</context> ++<context> ++ <name>QtIOCompressor</name> ++ <message> ++ <source>Internal zlib error when compressing: </source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Error writing to underlying device: </source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Error opening underlying device: </source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Error reading data from underlying device: </source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Internal zlib error when decompressing: </source> ++ <translation type="unfinished"></translation> ++ </message> ++</context> ++<context> ++ <name>QtIOCompressor::open</name> ++ <message> ++ <source>The gzip format not supported in this version of zlib.</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Internal zlib error: </source> ++ <translation type="unfinished"></translation> ++ </message> ++</context> ++<context> ++ <name>SearchWidget</name> ++ <message> ++ <source>Find:</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Case sensitive</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Current group</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Root group</source> ++ <translation type="unfinished"></translation> ++ </message> ++</context> ++<context> ++ <name>SettingsWidget</name> ++ <message> ++ <source>Application Settings</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>General</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Security</source> ++ <translation type="unfinished"></translation> ++ </message> ++</context> ++<context> ++ <name>SettingsWidgetGeneral</name> ++ <message> ++ <source>Remember last databases</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Open previous databases on startup</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Mark as modified on expanded state changes</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Automatically save on exit</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Automatically save after every change</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Minimize when copying to clipboard</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Use group icon on entry creation</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Global Auto-Type shortcut</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Use entry title to match windows for global auto-type</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Language</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Show a system tray icon</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Hide window to system tray when minimized</source> ++ <translation type="unfinished"></translation> ++ </message> ++</context> ++<context> ++ <name>SettingsWidgetSecurity</name> ++ <message> ++ <source>Clear clipboard after</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source> sec</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Lock databases after inactivity of</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Show passwords in cleartext by default</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Always ask before performing auto-type</source> ++ <translation type="unfinished"></translation> ++ </message> ++</context> ++<context> ++ <name>UnlockDatabaseWidget</name> ++ <message> ++ <source>Unlock database</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Error</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>Wrong key.</source> ++ <translation type="unfinished"></translation> ++ </message> ++</context> ++<context> ++ <name>WelcomeWidget</name> ++ <message> ++ <source>Welcome!</source> ++ <translation type="unfinished"></translation> ++ </message> ++</context> ++<context> ++ <name>main</name> ++ <message> ++ <source>KeePassX - cross-platform password manager</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>filename of the password database to open (*.kdbx)</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>path to a custom config file</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>password of the database (DANGEROUS!)</source> ++ <translation type="unfinished"></translation> ++ </message> ++ <message> ++ <source>key file of the database</source> ++ <translation type="unfinished"></translation> ++ </message> ++</context> ++</TS> +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 @@ ++<?xml version="1.0" encoding="utf-8"?> ++<!DOCTYPE TS> ++<TS version="2.0" language="en_US"> ++<context> ++ <name>DatabaseWidget</name> ++ <message numerus="yes"> ++ <source>Do you really want to move %n entry(s) to the recycle bin?</source> ++ <translation> ++ <numerusform>Do you really want to move %n entry to the recycle bin?</numerusform> ++ <numerusform>Do you really want to move %n entries to the recycle bin?</numerusform> ++ </translation> ++ </message> ++</context> ++<context> ++ <name>EditEntryWidget</name> ++ <message numerus="yes"> ++ <source>%n week(s)</source> ++ <translation> ++ <numerusform>%n week</numerusform> ++ <numerusform>%n weeks</numerusform> ++ </translation> ++ </message> ++ <message numerus="yes"> ++ <source>%n month(s)</source> ++ <translation> ++ <numerusform>%n month</numerusform> ++ <numerusform>%n months</numerusform> ++ </translation> ++ </message> ++</context> ++<context> ++ <name>EditWidgetIcons</name> ++ <message numerus="yes"> ++ <source>Can't delete icon. Still used by %n item(s).</source> ++ <translation> ++ <numerusform>Can't delete icon. Still used by %n item.</numerusform> ++ <numerusform>Can't delete icon. Still used by %n items.</numerusform> ++ </translation> ++ </message> ++</context> ++</TS> +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 @@ ++<?xml version="1.0" ?><!DOCTYPE TS><TS language="it" version="2.0"> ++<context> ++ <name>AboutDialog</name> ++ <message> ++ <source>About KeePassX</source> ++ <translation>A proposito di KeePassX</translation> ++ </message> ++ <message> ++ <source>KeePassX is distributed under the term of the GNU General Public License (GPL) version 2 or (at your option) version 3.</source> ++ <translation>KeePassX è distribuito sotto i termini della licenza ++GNU General Public License (GPL) versione 2 o, a tua scelta, della versione 3.</translation> ++ </message> ++</context> ++<context> ++ <name>AutoType</name> ++ <message> ++ <source>Auto-Type - KeePassX</source> ++ <translation>Auto-Type - KeePassX</translation> ++ </message> ++ <message> ++ <source>Couldn't find an entry that matches the window title.</source> ++ <translation>Impossibile trovare una voce che corrisponda al titolo della finestra</translation> ++ </message> ++</context> ++<context> ++ <name>AutoTypeAssociationsModel</name> ++ <message> ++ <source>Window</source> ++ <translation>Finestra</translation> ++ </message> ++ <message> ++ <source>Sequence</source> ++ <translation>Sequenza</translation> ++ </message> ++ <message> ++ <source>Default sequence</source> ++ <translation>Sequenza predefinita</translation> ++ </message> ++</context> ++<context> ++ <name>AutoTypeSelectDialog</name> ++ <message> ++ <source>Auto-Type - KeePassX</source> ++ <translation>Auto-Type - KeePassX</translation> ++ </message> ++ <message> ++ <source>Select entry to Auto-Type:</source> ++ <translation>Selezionare una voce per Auto-Type:</translation> ++ </message> ++</context> ++<context> ++ <name>ChangeMasterKeyWidget</name> ++ <message> ++ <source>Password</source> ++ <translation>Password</translation> ++ </message> ++ <message> ++ <source>Enter password:</source> ++ <translation>Inserire password:</translation> ++ </message> ++ <message> ++ <source>Repeat password:</source> ++ <translation>Ripetere password:</translation> ++ </message> ++ <message> ++ <source>Key file</source> ++ <translation>File chiave</translation> ++ </message> ++ <message> ++ <source>Browse</source> ++ <translation>Sfogliare</translation> ++ </message> ++ <message> ++ <source>Create</source> ++ <translation>Creare</translation> ++ </message> ++ <message> ++ <source>Key files</source> ++ <translation>File chiave</translation> ++ </message> ++ <message> ++ <source>All files</source> ++ <translation>Tutti i file</translation> ++ </message> ++ <message> ++ <source>Create Key File...</source> ++ <translation>Creare file chiave...</translation> ++ </message> ++ <message> ++ <source>Error</source> ++ <translation>Errore</translation> ++ </message> ++ <message> ++ <source>Unable to create Key File : </source> ++ <translation>Impossibile creare file chiave:</translation> ++ </message> ++ <message> ++ <source>Select a key file</source> ++ <translation>Selezionare file chiave</translation> ++ </message> ++ <message> ++ <source>Question</source> ++ <translation>Domanda</translation> ++ </message> ++ <message> ++ <source>Do you really want to use an empty string as password?</source> ++ <translation>Vuoi veramente usare una stringa vuota come password?</translation> ++ </message> ++ <message> ++ <source>Different passwords supplied.</source> ++ <translation>Sono state fornite password differenti.</translation> ++ </message> ++</context> ++<context> ++ <name>DatabaseOpenWidget</name> ++ <message> ++ <source>Enter master key</source> ++ <translation>Inserire password</translation> ++ </message> ++ <message> ++ <source>Key File:</source> ++ <translation>File Chiave:</translation> ++ </message> ++ <message> ++ <source>Password:</source> ++ <translation>Password:</translation> ++ </message> ++ <message> ++ <source>Browse</source> ++ <translation>Sfogliare</translation> ++ </message> ++ <message> ++ <source>Error</source> ++ <translation>Errore</translation> ++ </message> ++ <message> ++ <source>Unable to open the database.</source> ++ <translation>Impossibile aprire il database.</translation> ++ </message> ++ <message> ++ <source>Can't open key file</source> ++ <translation>Impossibile aprire il file chiave</translation> ++ </message> ++ <message> ++ <source>All files</source> ++ <translation>Tutti i file</translation> ++ </message> ++ <message> ++ <source>Key files</source> ++ <translation>File chiave</translation> ++ </message> ++ <message> ++ <source>Select key file</source> ++ <translation>Selezionare file chiave</translation> ++ </message> ++</context> ++<context> ++ <name>DatabaseSettingsWidget</name> ++ <message> ++ <source>Database name:</source> ++ <translation>Nome database:</translation> ++ </message> ++ <message> ++ <source>Database description:</source> ++ <translation>Descrizione database:</translation> ++ </message> ++ <message> ++ <source>Transform rounds:</source> ++ <translation>Round di trasformazione:</translation> ++ </message> ++ <message> ++ <source>Default username:</source> ++ <translation>Nome utente predefinito:</translation> ++ </message> ++ <message> ++ <source>Use recycle bin:</source> ++ <translation>Utilizzare cestino:</translation> ++ </message> ++ <message> ++ <source> MiB</source> ++ <translation>MiB</translation> ++ </message> ++ <message> ++ <source>Benchmark</source> ++ <translation>Benchmark</translation> ++ </message> ++ <message> ++ <source>Max. history items:</source> ++ <translation>Max. oggetti nella cronologia:</translation> ++ </message> ++ <message> ++ <source>Max. history size:</source> ++ <translation>Max. grandezza della cronologia:</translation> ++ </message> ++</context> ++<context> ++ <name>DatabaseTabWidget</name> ++ <message> ++ <source>Root</source> ++ <translation>Root</translation> ++ </message> ++ <message> ++ <source>KeePass 2 Database</source> ++ <translation>Database KeePass 2</translation> ++ </message> ++ <message> ++ <source>All files</source> ++ <translation>Tutti i file</translation> ++ </message> ++ <message> ++ <source>Open database</source> ++ <translation>Aprire database</translation> ++ </message> ++ <message> ++ <source>Warning</source> ++ <translation>Avviso</translation> ++ </message> ++ <message> ++ <source>File not found!</source> ++ <translation>File non trovato!</translation> ++ </message> ++ <message> ++ <source>Open KeePass 1 database</source> ++ <translation>Aprire database KeePass 1</translation> ++ </message> ++ <message> ++ <source>KeePass 1 database</source> ++ <translation>Database KeePass 1</translation> ++ </message> ++ <message> ++ <source>All files (*)</source> ++ <translation>Tutti i file (*)</translation> ++ </message> ++ <message> ++ <source>Close?</source> ++ <translation>Chiudere?</translation> ++ </message> ++ <message> ++ <source>"%1" is in edit mode. ++Close anyway?</source> ++ <translation>"%1" è in modalità modifica. ++Chiudere comunque?</translation> ++ </message> ++ <message> ++ <source>Save changes?</source> ++ <translation>Salvare modifiche?</translation> ++ </message> ++ <message> ++ <source>"%1" was modified. ++Save changes?</source> ++ <translation>"%1" è stata modificata. ++Salvare le modifiche?</translation> ++ </message> ++ <message> ++ <source>Error</source> ++ <translation>Errore</translation> ++ </message> ++ <message> ++ <source>Writing the database failed.</source> ++ <translation>Scrittura del database fallita.</translation> ++ </message> ++ <message> ++ <source>Save database as</source> ++ <translation>Salvare database come</translation> ++ </message> ++ <message> ++ <source>New database</source> ++ <translation>Nuovo database</translation> ++ </message> ++ <message> ++ <source>locked</source> ++ <translation>bloccato</translation> ++ </message> ++</context> ++<context> ++ <name>DatabaseWidget</name> ++ <message> ++ <source>Change master key</source> ++ <translation>Cambiare password principale</translation> ++ </message> ++ <message> ++ <source>Delete entry?</source> ++ <translation>Eliminare voce?</translation> ++ </message> ++ <message> ++ <source>Do you really want to delete the entry "%1" for good?</source> ++ <translation>Vuoi veramente eliminare la voce "%1"?</translation> ++ </message> ++ <message> ++ <source>Delete entries?</source> ++ <translation>Eliminare voci?</translation> ++ </message> ++ <message> ++ <source>Do you really want to delete %1 entries for good?</source> ++ <translation>Vuoi veramente eliminare %1 voci?</translation> ++ </message> ++ <message> ++ <source>Move entries to recycle bin?</source> ++ <translation>Muovere le voci nel cestino?</translation> ++ </message> ++ <message numerus="yes"> ++ <source>Do you really want to move %n entry(s) to the recycle bin?</source> ++ <translation><numerusform>Vuoi veramente spostare %n voce(i) nel cestino?</numerusform><numerusform>Vuoi veramente spostare %n voce(i) nel cestino?</numerusform></translation> ++ </message> ++ <message> ++ <source>Delete group?</source> ++ <translation>Eliminare gruppo?</translation> ++ </message> ++ <message> ++ <source>Do you really want to delete the group "%1" for good?</source> ++ <translation>Vuoi veramente eliminare il gruppo "%1"?</translation> ++ </message> ++ <message> ++ <source>Current group</source> ++ <translation>Gruppo corrente</translation> ++ </message> ++</context> ++<context> ++ <name>EditEntryWidget</name> ++ <message> ++ <source>Entry</source> ++ <translation>Voce</translation> ++ </message> ++ <message> ++ <source>Advanced</source> ++ <translation>Avanzate</translation> ++ </message> ++ <message> ++ <source>Icon</source> ++ <translation>Icona</translation> ++ </message> ++ <message> ++ <source>Auto-Type</source> ++ <translation>Auto-Type</translation> ++ </message> ++ <message> ++ <source>Properties</source> ++ <translation>Proprietà</translation> ++ </message> ++ <message> ++ <source>History</source> ++ <translation>Cronologia</translation> ++ </message> ++ <message> ++ <source>Entry history</source> ++ <translation>Cronologia voce</translation> ++ </message> ++ <message> ++ <source>Add entry</source> ++ <translation>Aggiungere voce</translation> ++ </message> ++ <message> ++ <source>Edit entry</source> ++ <translation>Modificare voce</translation> ++ </message> ++ <message> ++ <source>Error</source> ++ <translation>Errore</translation> ++ </message> ++ <message> ++ <source>Different passwords supplied.</source> ++ <translation>Sono state immesse password differenti.</translation> ++ </message> ++ <message> ++ <source>New attribute</source> ++ <translation>Nuovo attributo</translation> ++ </message> ++ <message> ++ <source>Select file</source> ++ <translation>Selezionare file</translation> ++ </message> ++ <message> ++ <source>Unable to open file</source> ++ <translation>Impossibile aprire il file</translation> ++ </message> ++ <message> ++ <source>Save attachment</source> ++ <translation>Salvare l'allegato</translation> ++ </message> ++ <message> ++ <source>Unable to save the attachment: ++</source> ++ <translation>Impossibile salvare l'allegato ++</translation> ++ </message> ++ <message> ++ <source>Tomorrow</source> ++ <translation>Domani</translation> ++ </message> ++ <message numerus="yes"> ++ <source>%n week(s)</source> ++ <translation><numerusform>%n settimana(e)</numerusform><numerusform>%n settimana(e)</numerusform></translation> ++ </message> ++ <message numerus="yes"> ++ <source>%n month(s)</source> ++ <translation><numerusform>%n mese(i)</numerusform><numerusform>%n mese(i)</numerusform></translation> ++ </message> ++ <message> ++ <source>1 year</source> ++ <translation>1 anno</translation> ++ </message> ++</context> ++<context> ++ <name>EditEntryWidgetAdvanced</name> ++ <message> ++ <source>Additional attributes</source> ++ <translation>Attributi addizionali</translation> ++ </message> ++ <message> ++ <source>Add</source> ++ <translation>Aggiungere</translation> ++ </message> ++ <message> ++ <source>Edit</source> ++ <translation>Modificare</translation> ++ </message> ++ <message> ++ <source>Remove</source> ++ <translation>Rimuovere</translation> ++ </message> ++ <message> ++ <source>Attachments</source> ++ <translation>Allegati</translation> ++ </message> ++ <message> ++ <source>Save</source> ++ <translation>Salvare</translation> ++ </message> ++</context> ++<context> ++ <name>EditEntryWidgetAutoType</name> ++ <message> ++ <source>Enable Auto-Type for this entry</source> ++ <translation>Abilitare Auto-Type per questa voce</translation> ++ </message> ++ <message> ++ <source>Inherit default Auto-Type sequence from the group</source> ++ <translation>Ereditare la sequenza predefinita di Auto-Type dal gruppo</translation> ++ </message> ++ <message> ++ <source>Use custom Auto-Type sequence:</source> ++ <translation>Usare sequenza personalizzata di Auto-Type:</translation> ++ </message> ++ <message> ++ <source>+</source> ++ <translation>+</translation> ++ </message> ++ <message> ++ <source>-</source> ++ <translation>-</translation> ++ </message> ++ <message> ++ <source>Window title:</source> ++ <translation>Titolo finestra:</translation> ++ </message> ++ <message> ++ <source>Use default sequence</source> ++ <translation>Usare sequenza predefinita</translation> ++ </message> ++ <message> ++ <source>Set custom sequence:</source> ++ <translation>Impostare sequenza personalizzata:</translation> ++ </message> ++</context> ++<context> ++ <name>EditEntryWidgetHistory</name> ++ <message> ++ <source>Show</source> ++ <translation>Mostrare</translation> ++ </message> ++ <message> ++ <source>Restore</source> ++ <translation>Ripristinare</translation> ++ </message> ++ <message> ++ <source>Delete</source> ++ <translation>Eliminare</translation> ++ </message> ++ <message> ++ <source>Delete all</source> ++ <translation>Eliminare tutti</translation> ++ </message> ++</context> ++<context> ++ <name>EditEntryWidgetMain</name> ++ <message> ++ <source>Title:</source> ++ <translation>Titolo:</translation> ++ </message> ++ <message> ++ <source>Username:</source> ++ <translation>Nome utente:</translation> ++ </message> ++ <message> ++ <source>Password:</source> ++ <translation>Password:</translation> ++ </message> ++ <message> ++ <source>Repeat:</source> ++ <translation>Ripetere:</translation> ++ </message> ++ <message> ++ <source>Gen.</source> ++ <translation>Gen.</translation> ++ </message> ++ <message> ++ <source>URL:</source> ++ <translation>URL:</translation> ++ </message> ++ <message> ++ <source>Expires</source> ++ <translation>Scade:</translation> ++ </message> ++ <message> ++ <source>Presets</source> ++ <translation>Programmare</translation> ++ </message> ++ <message> ++ <source>Notes:</source> ++ <translation>Note:</translation> ++ </message> ++</context> ++<context> ++ <name>EditGroupWidget</name> ++ <message> ++ <source>Group</source> ++ <translation>Gruppo</translation> ++ </message> ++ <message> ++ <source>Icon</source> ++ <translation>Icona</translation> ++ </message> ++ <message> ++ <source>Properties</source> ++ <translation>Proprietà</translation> ++ </message> ++ <message> ++ <source>Add group</source> ++ <translation>Aggiungere gruppo</translation> ++ </message> ++ <message> ++ <source>Edit group</source> ++ <translation>Modificare gruppo</translation> ++ </message> ++ <message> ++ <source>Enable</source> ++ <translation>Abilitare</translation> ++ </message> ++ <message> ++ <source>Disable</source> ++ <translation>Disabilitare</translation> ++ </message> ++ <message> ++ <source>Inherit from parent group (%1)</source> ++ <translation>Ereditare dal gruppo genitore (%1)</translation> ++ </message> ++</context> ++<context> ++ <name>EditGroupWidgetMain</name> ++ <message> ++ <source>Name</source> ++ <translation>Nome</translation> ++ </message> ++ <message> ++ <source>Notes</source> ++ <translation>Note</translation> ++ </message> ++ <message> ++ <source>Expires</source> ++ <translation>Scade</translation> ++ </message> ++ <message> ++ <source>Search</source> ++ <translation>Cercare</translation> ++ </message> ++ <message> ++ <source>Auto-type</source> ++ <translation>Auto-Type</translation> ++ </message> ++</context> ++<context> ++ <name>EditWidgetIcons</name> ++ <message> ++ <source>Use default icon</source> ++ <translation>Usare icona predefinita</translation> ++ </message> ++ <message> ++ <source>Use custom icon</source> ++ <translation>Usare icona personalizzata</translation> ++ </message> ++ <message> ++ <source>Add custom icon</source> ++ <translation>Aggiungere icona personalizzata</translation> ++ </message> ++ <message> ++ <source>Delete custom icon</source> ++ <translation>Rimuovere icona personalizzata</translation> ++ </message> ++ <message> ++ <source>Images</source> ++ <translation>Immagini</translation> ++ </message> ++ <message> ++ <source>All files</source> ++ <translation>Tutti i file</translation> ++ </message> ++ <message> ++ <source>Select Image</source> ++ <translation>Selezionare Immagine</translation> ++ </message> ++ <message> ++ <source>Can't delete icon!</source> ++ <translation>Impossibile eliminare icona!</translation> ++ </message> ++ <message numerus="yes"> ++ <source>Can't delete icon. Still used by %n item(s).</source> ++ <translation><numerusform>Impossibile eliminare l'icona in quanto è in uso da %n voce(i).</numerusform><numerusform>Impossibile eliminare l'icona in quanto è in uso da %n voce(i).</numerusform></translation> ++ </message> ++</context> ++<context> ++ <name>EditWidgetProperties</name> ++ <message> ++ <source>Created:</source> ++ <translation>Creato:</translation> ++ </message> ++ <message> ++ <source>Modified:</source> ++ <translation>Modificato:</translation> ++ </message> ++ <message> ++ <source>Accessed:</source> ++ <translation>Accesso:</translation> ++ </message> ++ <message> ++ <source>Uuid:</source> ++ <translation>Uuid:</translation> ++ </message> ++</context> ++<context> ++ <name>EntryAttributesModel</name> ++ <message> ++ <source>Name</source> ++ <translation>Nome</translation> ++ </message> ++</context> ++<context> ++ <name>EntryHistoryModel</name> ++ <message> ++ <source>Last modified</source> ++ <translation>Ultima modifica</translation> ++ </message> ++ <message> ++ <source>Title</source> ++ <translation>Titolo</translation> ++ </message> ++ <message> ++ <source>Username</source> ++ <translation>Nome utente</translation> ++ </message> ++ <message> ++ <source>URL</source> ++ <translation>URL</translation> ++ </message> ++</context> ++<context> ++ <name>EntryModel</name> ++ <message> ++ <source>Group</source> ++ <translation>Gruppo</translation> ++ </message> ++ <message> ++ <source>Title</source> ++ <translation>Titolo</translation> ++ </message> ++ <message> ++ <source>Username</source> ++ <translation>Nome Utente</translation> ++ </message> ++ <message> ++ <source>URL</source> ++ <translation>URL</translation> ++ </message> ++</context> ++<context> ++ <name>Group</name> ++ <message> ++ <source>Recycle Bin</source> ++ <translation>Cestino (Gruppo)</translation> ++ </message> ++</context> ++<context> ++ <name>KeePass1OpenWidget</name> ++ <message> ++ <source>Import KeePass1 database</source> ++ <translation>Importare database KeePass1</translation> ++ </message> ++ <message> ++ <source>Error</source> ++ <translation>Errore</translation> ++ </message> ++ <message> ++ <source>Unable to open the database.</source> ++ <translation>Impossibile aprire il database.</translation> ++ </message> ++</context> ++<context> ++ <name>KeePass1Reader</name> ++ <message> ++ <source>Unable to read keyfile.</source> ++ <translation>Impossibile leggere il file chiave.</translation> ++ </message> ++ <message> ++ <source>Not a KeePass database.</source> ++ <translation>Non è un database KeePass.</translation> ++ </message> ++ <message> ++ <source>Unsupported encryption algorithm.</source> ++ <translation>Algoritmo di cifratura non supportato.</translation> ++ </message> ++ <message> ++ <source>Unsupported KeePass database version.</source> ++ <translation>Versione database non supportata</translation> ++ </message> ++ <message> ++ <source>Root</source> ++ <translation>Root (KeePass1Reader)</translation> ++ </message> ++</context> ++<context> ++ <name>KeePass2Reader</name> ++ <message> ++ <source>Not a KeePass database.</source> ++ <translation>Non è un database KeePass.</translation> ++ </message> ++ <message> ++ <source>Unsupported KeePass database version.</source> ++ <translation>Versione database non supportata</translation> ++ </message> ++ <message> ++ <source>Wrong key or database file is corrupt.</source> ++ <translation>Password errata o database corrotto.</translation> ++ </message> ++</context> ++<context> ++ <name>MainWindow</name> ++ <message> ++ <source>Database</source> ++ <translation>Database</translation> ++ </message> ++ <message> ++ <source>Recent databases</source> ++ <translation>Database recenti</translation> ++ </message> ++ <message> ++ <source>Help</source> ++ <translation>Aiuto</translation> ++ </message> ++ <message> ++ <source>Entries</source> ++ <translation>Voci</translation> ++ </message> ++ <message> ++ <source>Copy attribute to clipboard</source> ++ <translation>Copiare attributi negli appunti</translation> ++ </message> ++ <message> ++ <source>Groups</source> ++ <translation>Gruppi</translation> ++ </message> ++ <message> ++ <source>Extras</source> ++ <translation>Extra</translation> ++ </message> ++ <message> ++ <source>View</source> ++ <translation>Visualizzare</translation> ++ </message> ++ <message> ++ <source>Quit</source> ++ <translation>Uscire</translation> ++ </message> ++ <message> ++ <source>About</source> ++ <translation>A Proposito</translation> ++ </message> ++ <message> ++ <source>Open database</source> ++ <translation>Aprire database</translation> ++ </message> ++ <message> ++ <source>Save database</source> ++ <translation>Salvare database</translation> ++ </message> ++ <message> ++ <source>Close database</source> ++ <translation>Chiudere database</translation> ++ </message> ++ <message> ++ <source>New database</source> ++ <translation>Nuovo database</translation> ++ </message> ++ <message> ++ <source>Add new entry</source> ++ <translation>Aggiungere nuova voce</translation> ++ </message> ++ <message> ++ <source>View/Edit entry</source> ++ <translation>Visualizzare/Modificare voce</translation> ++ </message> ++ <message> ++ <source>Delete entry</source> ++ <translation>Eliminare voce</translation> ++ </message> ++ <message> ++ <source>Add new group</source> ++ <translation>Aggiungere nuovo gruppo</translation> ++ </message> ++ <message> ++ <source>Edit group</source> ++ <translation>Modificare gruppo</translation> ++ </message> ++ <message> ++ <source>Delete group</source> ++ <translation>Eliminare gruppo</translation> ++ </message> ++ <message> ++ <source>Save database as</source> ++ <translation>Salvare database come</translation> ++ </message> ++ <message> ++ <source>Change master key</source> ++ <translation>Cambiare password principale</translation> ++ </message> ++ <message> ++ <source>Database settings</source> ++ <translation>Impostazioni database</translation> ++ </message> ++ <message> ++ <source>Import KeePass 1 database</source> ++ <translation>Importare database KeePass 1</translation> ++ </message> ++ <message> ++ <source>Clone entry</source> ++ <translation>Clona voce</translation> ++ </message> ++ <message> ++ <source>Find</source> ++ <translation>Trovare</translation> ++ </message> ++ <message> ++ <source>Username</source> ++ <translation>Nome Utente</translation> ++ </message> ++ <message> ++ <source>Copy username to clipboard</source> ++ <translation>Copiare nome utente negli appunti</translation> ++ </message> ++ <message> ++ <source>Password</source> ++ <translation>Password</translation> ++ </message> ++ <message> ++ <source>Copy password to clipboard</source> ++ <translation>Copiare password negli appunti</translation> ++ </message> ++ <message> ++ <source>Settings</source> ++ <translation>Impostazioni</translation> ++ </message> ++ <message> ++ <source>Perform Auto-Type</source> ++ <translation>Eseguire Auto-Type</translation> ++ </message> ++ <message> ++ <source>Open URL</source> ++ <translation>Aprire URL</translation> ++ </message> ++ <message> ++ <source>Lock databases</source> ++ <translation>Bloccare database</translation> ++ </message> ++ <message> ++ <source>Title</source> ++ <translation>Titolo</translation> ++ </message> ++ <message> ++ <source>URL</source> ++ <translation>URL</translation> ++ </message> ++ <message> ++ <source>Notes</source> ++ <translation>Note</translation> ++ </message> ++ <message> ++ <source>Show toolbar</source> ++ <translation>Mostrare barra degli strumenti</translation> ++ </message> ++ <message> ++ <source>read-only</source> ++ <translation>sola lettura</translation> ++ </message> ++</context> ++<context> ++ <name>PasswordGeneratorWidget</name> ++ <message> ++ <source>Password:</source> ++ <translation>Password:</translation> ++ </message> ++ <message> ++ <source>Length:</source> ++ <translation>Lunghezza:</translation> ++ </message> ++ <message> ++ <source>Character Types</source> ++ <translation>Tipi di carattere</translation> ++ </message> ++ <message> ++ <source>Upper Case Letters</source> ++ <translation>Lettere maiuscole</translation> ++ </message> ++ <message> ++ <source>Lower Case Letters</source> ++ <translation>Lettere minuscole</translation> ++ </message> ++ <message> ++ <source>Numbers</source> ++ <translation>Numeri</translation> ++ </message> ++ <message> ++ <source>Special Characters</source> ++ <translation>Caratteri speciali</translation> ++ </message> ++ <message> ++ <source>Exclude look-alike characters</source> ++ <translation>Escludere caratteri simili</translation> ++ </message> ++ <message> ++ <source>Ensure that the password contains characters from every group</source> ++ <translation>Assicurare che la password contenga caratteri di ogni gruppo</translation> ++ </message> ++ <message> ++ <source>Accept</source> ++ <translation>Accettare</translation> ++ </message> ++</context> ++<context> ++ <name>QCommandLineParser</name> ++ <message> ++ <source>Displays version information.</source> ++ <translation>Mostrare informazioni sulla versione.</translation> ++ </message> ++ <message> ++ <source>Displays this help.</source> ++ <translation>Mostrare questo aiuto.</translation> ++ </message> ++ <message> ++ <source>Unknown option '%1'.</source> ++ <translation>Opzione sconosciuta '%1'.</translation> ++ </message> ++ <message> ++ <source>Unknown options: %1.</source> ++ <translation>Opzioni sconosciute '%1'.</translation> ++ </message> ++ <message> ++ <source>Missing value after '%1'.</source> ++ <translation>Manca valore dopo '%1'.</translation> ++ </message> ++ <message> ++ <source>Unexpected value after '%1'.</source> ++ <translation>Valore inaspettato dopo '%1'.</translation> ++ </message> ++ <message> ++ <source>[options]</source> ++ <translation>[opzioni]</translation> ++ </message> ++ <message> ++ <source>Usage: %1</source> ++ <translation>Uso: %1</translation> ++ </message> ++ <message> ++ <source>Options:</source> ++ <translation>Opzioni:</translation> ++ </message> ++ <message> ++ <source>Arguments:</source> ++ <translation>Argomenti:</translation> ++ </message> ++</context> ++<context> ++ <name>QSaveFile</name> ++ <message> ++ <source>Existing file %1 is not writable</source> ++ <translation>Il file esistente %1 non è scrivibile</translation> ++ </message> ++ <message> ++ <source>Writing canceled by application</source> ++ <translation>Scrittura cancellata dall'applicazione</translation> ++ </message> ++ <message> ++ <source>Partial write. Partition full?</source> ++ <translation>Scrittura parziale. Partizione piena?</translation> ++ </message> ++</context> ++<context> ++ <name>QtIOCompressor</name> ++ <message> ++ <source>Internal zlib error when compressing: </source> ++ <translation>Errore interno di zlib durante la compressione:</translation> ++ </message> ++ <message> ++ <source>Error writing to underlying device: </source> ++ <translation>Errore durante la scrittura nel dispositivo:</translation> ++ </message> ++ <message> ++ <source>Error opening underlying device: </source> ++ <translation>Errore durante l'apertura dal dispositivo:</translation> ++ </message> ++ <message> ++ <source>Error reading data from underlying device: </source> ++ <translation>Errore durante la lettura dal dispositivo:</translation> ++ </message> ++ <message> ++ <source>Internal zlib error when decompressing: </source> ++ <translation>Errore interno di zlib durante la decompressione:</translation> ++ </message> ++</context> ++<context> ++ <name>QtIOCompressor::open</name> ++ <message> ++ <source>The gzip format not supported in this version of zlib.</source> ++ <translation>Formato gzip non supportato da questa versione di zlib.</translation> ++ </message> ++ <message> ++ <source>Internal zlib error: </source> ++ <translation>Errore interno di zlib:</translation> ++ </message> ++</context> ++<context> ++ <name>SearchWidget</name> ++ <message> ++ <source>Find:</source> ++ <translation>Trovare:</translation> ++ </message> ++ <message> ++ <source>Case sensitive</source> ++ <translation>Case sensitive</translation> ++ </message> ++ <message> ++ <source>Current group</source> ++ <translation>Gruppo corrente</translation> ++ </message> ++ <message> ++ <source>Root group</source> ++ <translation>Gruppo radice</translation> ++ </message> ++</context> ++<context> ++ <name>SettingsWidget</name> ++ <message> ++ <source>Application Settings</source> ++ <translation>Impostazioni applicazione</translation> ++ </message> ++ <message> ++ <source>General</source> ++ <translation>Generale</translation> ++ </message> ++ <message> ++ <source>Security</source> ++ <translation>Sicurezza</translation> ++ </message> ++</context> ++<context> ++ <name>SettingsWidgetGeneral</name> ++ <message> ++ <source>Remember last databases</source> ++ <translation>Ricordare ultimo database</translation> ++ </message> ++ <message> ++ <source>Open previous databases on startup</source> ++ <translation>Aprire precedente database all'avvio</translation> ++ </message> ++ <message> ++ <source>Mark as modified on expanded state changes</source> ++ <translation>Marcare come modificata quando la voce viene espansa</translation> ++ </message> ++ <message> ++ <source>Automatically save on exit</source> ++ <translation>Salvare automaticamente all'uscita</translation> ++ </message> ++ <message> ++ <source>Automatically save after every change</source> ++ <translation>Salvare automaticamente dopo ogni modifica</translation> ++ </message> ++ <message> ++ <source>Minimize when copying to clipboard</source> ++ <translation>Minimizzare quando si copia negli appunti</translation> ++ </message> ++ <message> ++ <source>Use group icon on entry creation</source> ++ <translation>Usare l'icona del gruppo alla creazione di una voce</translation> ++ </message> ++ <message> ++ <source>Global Auto-Type shortcut</source> ++ <translation>Scorciatoia Auto-Type globale</translation> ++ </message> ++ <message> ++ <source>Use entry title to match windows for global auto-type</source> ++ <translation>Utilizzare il titolo della voce per abbinare la finestra per auto-type globale</translation> ++ </message> ++</context> ++<context> ++ <name>SettingsWidgetSecurity</name> ++ <message> ++ <source>Clear clipboard after</source> ++ <translation>Pulire appunti dopo</translation> ++ </message> ++ <message> ++ <source> sec</source> ++ <translation>sec</translation> ++ </message> ++ <message> ++ <source>Lock databases after inactivity of</source> ++ <translation>Bloccare database dopo un'inattività di</translation> ++ </message> ++ <message> ++ <source>Show passwords in cleartext by default</source> ++ <translation>Mostrare la password in chiaro in maniera predefinita</translation> ++ </message> ++ <message> ++ <source>Always ask before performing auto-type</source> ++ <translation>Chiedere sempre prima di eseguire auto-type</translation> ++ </message> ++</context> ++<context> ++ <name>UnlockDatabaseWidget</name> ++ <message> ++ <source>Unlock database</source> ++ <translation>Sbloccare database</translation> ++ </message> ++ <message> ++ <source>Error</source> ++ <translation>Errore</translation> ++ </message> ++ <message> ++ <source>Wrong key.</source> ++ <translation>Password errata.</translation> ++ </message> ++</context> ++<context> ++ <name>WelcomeWidget</name> ++ <message> ++ <source>Welcome!</source> ++ <translation>Benvenuto/a!</translation> ++ </message> ++</context> ++<context> ++ <name>main</name> ++ <message> ++ <source>KeePassX - cross-platform password manager</source> ++ <translation>KeePassX - gestore di password cross-platform</translation> ++ </message> ++ <message> ++ <source>filename of the password database to open (*.kdbx)</source> ++ <translation>nome del file del database da aprire (*.kdbx)</translation> ++ </message> ++ <message> ++ <source>path to a custom config file</source> ++ <translation>percorso ad un file di configurazione personalizzato</translation> ++ </message> ++ <message> ++ <source>password of the database (DANGEROUS!)</source> ++ <translation>password del database (PERICOLOSO!)</translation> ++ </message> ++ <message> ++ <source>key file of the database</source> ++ <translation>file chiave del database</translation> ++ </message> ++</context> ++</TS> +\ 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 @@ ++<?xml version="1.0" ?><!DOCTYPE TS><TS language="nl_NL" version="2.0"> ++<context> ++ <name>AboutDialog</name> ++ <message> ++ <source>About KeePassX</source> ++ <translation>Over KeePassX</translation> ++ </message> ++ <message> ++ <source>KeePassX is distributed under the term of the GNU General Public License (GPL) version 2 or (at your option) version 3.</source> ++ <translation>KeePassX wordt verspreid onder de bepalingen van de GNU General Public License (GPL) versie 2 of (als u wenst) versie 3.</translation> ++ </message> ++</context> ++<context> ++ <name>AutoType</name> ++ <message> ++ <source>Auto-Type - KeePassX</source> ++ <translation>Auto-typen - KeePassX</translation> ++ </message> ++ <message> ++ <source>Couldn't find an entry that matches the window title.</source> ++ <translation>Kon geen element vinden dat overeenkomt met de venstertitel.</translation> ++ </message> ++</context> ++<context> ++ <name>AutoTypeAssociationsModel</name> ++ <message> ++ <source>Window</source> ++ <translation>Venster</translation> ++ </message> ++ <message> ++ <source>Sequence</source> ++ <translation>Volgorde</translation> ++ </message> ++ <message> ++ <source>Default sequence</source> ++ <translation>Standaardvolgorde</translation> ++ </message> ++</context> ++<context> ++ <name>AutoTypeSelectDialog</name> ++ <message> ++ <source>Auto-Type - KeePassX</source> ++ <translation>Auto-typen - KeePassX</translation> ++ </message> ++ <message> ++ <source>Select entry to Auto-Type:</source> ++ <translation>Kies element om automatisch te typen:</translation> ++ </message> ++</context> ++<context> ++ <name>ChangeMasterKeyWidget</name> ++ <message> ++ <source>Password</source> ++ <translation>Wachtwoord</translation> ++ </message> ++ <message> ++ <source>Enter password:</source> ++ <translation>Geef wachtwoord:</translation> ++ </message> ++ <message> ++ <source>Repeat password:</source> ++ <translation>Herhaal wachtwoord:</translation> ++ </message> ++ <message> ++ <source>Key file</source> ++ <translation>Sleutelbestand</translation> ++ </message> ++ <message> ++ <source>Browse</source> ++ <translation>Bladeren</translation> ++ </message> ++ <message> ++ <source>Create</source> ++ <translation>Aanmaken</translation> ++ </message> ++ <message> ++ <source>Key files</source> ++ <translation>Sleutelbestanden</translation> ++ </message> ++ <message> ++ <source>All files</source> ++ <translation>Alle bestanden</translation> ++ </message> ++ <message> ++ <source>Create Key File...</source> ++ <translation>Genereer sleutelbestand...</translation> ++ </message> ++ <message> ++ <source>Error</source> ++ <translation>Fout</translation> ++ </message> ++ <message> ++ <source>Unable to create Key File : </source> ++ <translation>Niet mogelijk om sleutelbestand aan te maken:</translation> ++ </message> ++ <message> ++ <source>Select a key file</source> ++ <translation>Kies een sleutelbestand</translation> ++ </message> ++ <message> ++ <source>Question</source> ++ <translation>Vraag</translation> ++ </message> ++ <message> ++ <source>Do you really want to use an empty string as password?</source> ++ <translation>Weet u zeker dat u een leeg veld als wachtwoord wilt gebruiken?</translation> ++ </message> ++ <message> ++ <source>Different passwords supplied.</source> ++ <translation>Verschillende wachtwoorden opgegeven.</translation> ++ </message> ++</context> ++<context> ++ <name>DatabaseOpenWidget</name> ++ <message> ++ <source>Enter master key</source> ++ <translation>Geef hoofdsleutel</translation> ++ </message> ++ <message> ++ <source>Key File:</source> ++ <translation>Sleutelbestand:</translation> ++ </message> ++ <message> ++ <source>Password:</source> ++ <translation>Wachtwoord:</translation> ++ </message> ++ <message> ++ <source>Browse</source> ++ <translation>Bladeren</translation> ++ </message> ++ <message> ++ <source>Error</source> ++ <translation>Fout</translation> ++ </message> ++ <message> ++ <source>Unable to open the database.</source> ++ <translation>Niet mogelijk om de database te openen.</translation> ++ </message> ++ <message> ++ <source>Can't open key file</source> ++ <translation>Niet mogelijk om het sleutelbestand te openen</translation> ++ </message> ++ <message> ++ <source>All files</source> ++ <translation>Alle bestanden</translation> ++ </message> ++ <message> ++ <source>Key files</source> ++ <translation>Sleutelbestanden</translation> ++ </message> ++ <message> ++ <source>Select key file</source> ++ <translation>Kies sleutelbestand</translation> ++ </message> ++</context> ++<context> ++ <name>DatabaseSettingsWidget</name> ++ <message> ++ <source>Database name:</source> ++ <translation>Naam van de database:</translation> ++ </message> ++ <message> ++ <source>Database description:</source> ++ <translation>Beschrijving van de database:</translation> ++ </message> ++ <message> ++ <source>Transform rounds:</source> ++ <translation>Transformatierondes:</translation> ++ </message> ++ <message> ++ <source>Default username:</source> ++ <translation>Standaard gebruikersnaam:</translation> ++ </message> ++ <message> ++ <source>Use recycle bin:</source> ++ <translation>Gebruik prullenbak:</translation> ++ </message> ++ <message> ++ <source> MiB</source> ++ <translation>MiB</translation> ++ </message> ++ <message> ++ <source>Benchmark</source> ++ <translation>Test</translation> ++ </message> ++ <message> ++ <source>Max. history items:</source> ++ <translation>Max. items in geschiedenis:</translation> ++ </message> ++ <message> ++ <source>Max. history size:</source> ++ <translation>Max. grootte geschiedenis:</translation> ++ </message> ++</context> ++<context> ++ <name>DatabaseTabWidget</name> ++ <message> ++ <source>Root</source> ++ <translation>Alles</translation> ++ </message> ++ <message> ++ <source>KeePass 2 Database</source> ++ <translation>KeePass 2 Database</translation> ++ </message> ++ <message> ++ <source>All files</source> ++ <translation>Alle bestanden</translation> ++ </message> ++ <message> ++ <source>Open database</source> ++ <translation>Open database</translation> ++ </message> ++ <message> ++ <source>Warning</source> ++ <translation>Waarschuwing</translation> ++ </message> ++ <message> ++ <source>File not found!</source> ++ <translation>Bestand niet gevonden!</translation> ++ </message> ++ <message> ++ <source>Open KeePass 1 database</source> ++ <translation>Open KeePass 1 database</translation> ++ </message> ++ <message> ++ <source>KeePass 1 database</source> ++ <translation>KeePass 1 database</translation> ++ </message> ++ <message> ++ <source>All files (*)</source> ++ <translation>Alle bestanden (*)</translation> ++ </message> ++ <message> ++ <source>Close?</source> ++ <translation>Sluiten?</translation> ++ </message> ++ <message> ++ <source>"%1" is in edit mode. ++Close anyway?</source> ++ <translation>"%1" is in bewerkmodus. ++Toch sluiten?</translation> ++ </message> ++ <message> ++ <source>Save changes?</source> ++ <translation>Wijzigingen opslaan?</translation> ++ </message> ++ <message> ++ <source>"%1" was modified. ++Save changes?</source> ++ <translation>"%1" is gewijzigd. ++Opslaan?</translation> ++ </message> ++ <message> ++ <source>Error</source> ++ <translation>Fout</translation> ++ </message> ++ <message> ++ <source>Writing the database failed.</source> ++ <translation>Opslaan van de database is mislukt.</translation> ++ </message> ++ <message> ++ <source>Save database as</source> ++ <translation>Database opslaan als</translation> ++ </message> ++ <message> ++ <source>New database</source> ++ <translation>Nieuwe database</translation> ++ </message> ++ <message> ++ <source>locked</source> ++ <translation>vergrendeld</translation> ++ </message> ++</context> ++<context> ++ <name>DatabaseWidget</name> ++ <message> ++ <source>Change master key</source> ++ <translation>Wijzig hoofdsleutel</translation> ++ </message> ++ <message> ++ <source>Delete entry?</source> ++ <translation>Element verwijderen?</translation> ++ </message> ++ <message> ++ <source>Do you really want to delete the entry "%1" for good?</source> ++ <translation>Weet u zeker dat u het element "%1" wilt verwijderen?</translation> ++ </message> ++ <message> ++ <source>Delete entries?</source> ++ <translation>Elementen wissen?</translation> ++ </message> ++ <message> ++ <source>Do you really want to delete %1 entries for good?</source> ++ <translation>Weet u zeker dat u %1 elementen wilt wissen?</translation> ++ </message> ++ <message> ++ <source>Move entries to recycle bin?</source> ++ <translation>Elementen naar de prullenbak verplaatsen?</translation> ++ </message> ++ <message numerus="yes"> ++ <source>Do you really want to move %n entry(s) to the recycle bin?</source> ++ <translation><numerusform>Weet u zeker dat u %n element naar de prullenbak wilt verplaatsen?</numerusform><numerusform>Weet u zeker dat u %n elementen naar de prullenbak wilt verplaatsen?</numerusform></translation> ++ </message> ++ <message> ++ <source>Delete group?</source> ++ <translation>Groep verwijderen?</translation> ++ </message> ++ <message> ++ <source>Do you really want to delete the group "%1" for good?</source> ++ <translation>Weet u zeker dat u de groep "%1" wilt verwijderen?</translation> ++ </message> ++ <message> ++ <source>Current group</source> ++ <translation>Huidige groep</translation> ++ </message> ++</context> ++<context> ++ <name>EditEntryWidget</name> ++ <message> ++ <source>Entry</source> ++ <translation>Element</translation> ++ </message> ++ <message> ++ <source>Advanced</source> ++ <translation>Geavanceerd</translation> ++ </message> ++ <message> ++ <source>Icon</source> ++ <translation>Icoon</translation> ++ </message> ++ <message> ++ <source>Auto-Type</source> ++ <translation>Auto-typen - KeePassX</translation> ++ </message> ++ <message> ++ <source>Properties</source> ++ <translation>Eigenschappen</translation> ++ </message> ++ <message> ++ <source>History</source> ++ <translation>Geschiedenis</translation> ++ </message> ++ <message> ++ <source>Entry history</source> ++ <translation>Geschiedenis van element</translation> ++ </message> ++ <message> ++ <source>Add entry</source> ++ <translation>Element toevoegen</translation> ++ </message> ++ <message> ++ <source>Edit entry</source> ++ <translation>Element wijzigen</translation> ++ </message> ++ <message> ++ <source>Error</source> ++ <translation>Fout</translation> ++ </message> ++ <message> ++ <source>Different passwords supplied.</source> ++ <translation>Verschillende wachtwoorden opgegeven.</translation> ++ </message> ++ <message> ++ <source>New attribute</source> ++ <translation>Nieuwe eigenschap</translation> ++ </message> ++ <message> ++ <source>Select file</source> ++ <translation>Kies bestand</translation> ++ </message> ++ <message> ++ <source>Unable to open file</source> ++ <translation>Niet mogelijk om bestand te openen</translation> ++ </message> ++ <message> ++ <source>Save attachment</source> ++ <translation>Bijlage opslaan</translation> ++ </message> ++ <message> ++ <source>Unable to save the attachment: ++</source> ++ <translation>Niet mogelijk om de bijlage op te slaan: ++</translation> ++ </message> ++ <message> ++ <source>Tomorrow</source> ++ <translation>Morgen</translation> ++ </message> ++ <message numerus="yes"> ++ <source>%n week(s)</source> ++ <translation><numerusform>%n week</numerusform><numerusform>%n weken</numerusform></translation> ++ </message> ++ <message numerus="yes"> ++ <source>%n month(s)</source> ++ <translation><numerusform>%n maand</numerusform><numerusform>%n maanden</numerusform></translation> ++ </message> ++ <message> ++ <source>1 year</source> ++ <translation>1 jaar</translation> ++ </message> ++</context> ++<context> ++ <name>EditEntryWidgetAdvanced</name> ++ <message> ++ <source>Additional attributes</source> ++ <translation>Extra eigenschappen</translation> ++ </message> ++ <message> ++ <source>Add</source> ++ <translation>Toevoegen</translation> ++ </message> ++ <message> ++ <source>Edit</source> ++ <translation>Wijzigen</translation> ++ </message> ++ <message> ++ <source>Remove</source> ++ <translation>Verwijderen</translation> ++ </message> ++ <message> ++ <source>Attachments</source> ++ <translation>Bijlagen</translation> ++ </message> ++ <message> ++ <source>Save</source> ++ <translation>Opslaan</translation> ++ </message> ++</context> ++<context> ++ <name>EditEntryWidgetAutoType</name> ++ <message> ++ <source>Enable Auto-Type for this entry</source> ++ <translation>Auto-typen inschakelen voor dit element</translation> ++ </message> ++ <message> ++ <source>Inherit default Auto-Type sequence from the group</source> ++ <translation>Erf standaard auto-typevolgorde van de groep</translation> ++ </message> ++ <message> ++ <source>Use custom Auto-Type sequence:</source> ++ <translation>Gebruik aangepaste auto-typevolgorde:</translation> ++ </message> ++ <message> ++ <source>+</source> ++ <translation>+</translation> ++ </message> ++ <message> ++ <source>-</source> ++ <translation>-</translation> ++ </message> ++ <message> ++ <source>Window title:</source> ++ <translation>Venstertitel:</translation> ++ </message> ++ <message> ++ <source>Use default sequence</source> ++ <translation>Gebruik standaardvolgorde</translation> ++ </message> ++ <message> ++ <source>Set custom sequence:</source> ++ <translation>Aangepaste volgorde:</translation> ++ </message> ++</context> ++<context> ++ <name>EditEntryWidgetHistory</name> ++ <message> ++ <source>Show</source> ++ <translation>Tonen</translation> ++ </message> ++ <message> ++ <source>Restore</source> ++ <translation>Herstellen</translation> ++ </message> ++ <message> ++ <source>Delete</source> ++ <translation>Verwijderen</translation> ++ </message> ++ <message> ++ <source>Delete all</source> ++ <translation>Alles verwijderen</translation> ++ </message> ++</context> ++<context> ++ <name>EditEntryWidgetMain</name> ++ <message> ++ <source>Title:</source> ++ <translation>Titel:</translation> ++ </message> ++ <message> ++ <source>Username:</source> ++ <translation>Gebruikersnaam:</translation> ++ </message> ++ <message> ++ <source>Password:</source> ++ <translation>Wachtwoord:</translation> ++ </message> ++ <message> ++ <source>Repeat:</source> ++ <translation>Herhalen:</translation> ++ </message> ++ <message> ++ <source>Gen.</source> ++ <translation>Gen.</translation> ++ </message> ++ <message> ++ <source>URL:</source> ++ <translation>URL:</translation> ++ </message> ++ <message> ++ <source>Expires</source> ++ <translation>Verloopt</translation> ++ </message> ++ <message> ++ <source>Presets</source> ++ <translation>Ingebouwd</translation> ++ </message> ++ <message> ++ <source>Notes:</source> ++ <translation>Opmerkingen:</translation> ++ </message> ++</context> ++<context> ++ <name>EditGroupWidget</name> ++ <message> ++ <source>Group</source> ++ <translation>Groep</translation> ++ </message> ++ <message> ++ <source>Icon</source> ++ <translation>Icoon</translation> ++ </message> ++ <message> ++ <source>Properties</source> ++ <translation>Eigenschappen</translation> ++ </message> ++ <message> ++ <source>Add group</source> ++ <translation>Groep toevoegen</translation> ++ </message> ++ <message> ++ <source>Edit group</source> ++ <translation>Groep wijzigen</translation> ++ </message> ++ <message> ++ <source>Enable</source> ++ <translation>Inschakelen</translation> ++ </message> ++ <message> ++ <source>Disable</source> ++ <translation>Uitschakelen</translation> ++ </message> ++ <message> ++ <source>Inherit from parent group (%1)</source> ++ <translation>Erf van bovenliggende groep (%1)</translation> ++ </message> ++</context> ++<context> ++ <name>EditGroupWidgetMain</name> ++ <message> ++ <source>Name</source> ++ <translation>Naam</translation> ++ </message> ++ <message> ++ <source>Notes</source> ++ <translation>Opmerkingen</translation> ++ </message> ++ <message> ++ <source>Expires</source> ++ <translation>Verloopt</translation> ++ </message> ++ <message> ++ <source>Search</source> ++ <translation>Zoeken</translation> ++ </message> ++ <message> ++ <source>Auto-type</source> ++ <translation>Auto-typen</translation> ++ </message> ++</context> ++<context> ++ <name>EditWidgetIcons</name> ++ <message> ++ <source>Use default icon</source> ++ <translation>Gebruik standaardicoon</translation> ++ </message> ++ <message> ++ <source>Use custom icon</source> ++ <translation>Gebruik aangepast icoon</translation> ++ </message> ++ <message> ++ <source>Add custom icon</source> ++ <translation>Voeg icoon toe</translation> ++ </message> ++ <message> ++ <source>Delete custom icon</source> ++ <translation>Verwijder icoon</translation> ++ </message> ++ <message> ++ <source>Images</source> ++ <translation>Afbeeldingen</translation> ++ </message> ++ <message> ++ <source>All files</source> ++ <translation>Alle bestanden</translation> ++ </message> ++ <message> ++ <source>Select Image</source> ++ <translation>Kies afbeelding</translation> ++ </message> ++ <message> ++ <source>Can't delete icon!</source> ++ <translation>Kan icoon niet verwijderen!</translation> ++ </message> ++ <message numerus="yes"> ++ <source>Can't delete icon. Still used by %n item(s).</source> ++ <translation><numerusform>Kan icoon niet verwijderen. Het wordt nog gebruikt door %n element.</numerusform><numerusform>Kan icoon niet verwijderen. Het wordt nog gebruikt door %n elementen.</numerusform></translation> ++ </message> ++</context> ++<context> ++ <name>EditWidgetProperties</name> ++ <message> ++ <source>Created:</source> ++ <translation>Aangemaakt:</translation> ++ </message> ++ <message> ++ <source>Modified:</source> ++ <translation>Gewijzigd:</translation> ++ </message> ++ <message> ++ <source>Accessed:</source> ++ <translation>Gelezen:</translation> ++ </message> ++ <message> ++ <source>Uuid:</source> ++ <translation>Uuid:</translation> ++ </message> ++</context> ++<context> ++ <name>EntryAttributesModel</name> ++ <message> ++ <source>Name</source> ++ <translation>Naam</translation> ++ </message> ++</context> ++<context> ++ <name>EntryHistoryModel</name> ++ <message> ++ <source>Last modified</source> ++ <translation>Laatst gewijzigd</translation> ++ </message> ++ <message> ++ <source>Title</source> ++ <translation>Titel</translation> ++ </message> ++ <message> ++ <source>Username</source> ++ <translation>Gebruikersnaam</translation> ++ </message> ++ <message> ++ <source>URL</source> ++ <translation>URL</translation> ++ </message> ++</context> ++<context> ++ <name>EntryModel</name> ++ <message> ++ <source>Group</source> ++ <translation>Groep</translation> ++ </message> ++ <message> ++ <source>Title</source> ++ <translation>Titel</translation> ++ </message> ++ <message> ++ <source>Username</source> ++ <translation>Gebruikersnaam</translation> ++ </message> ++ <message> ++ <source>URL</source> ++ <translation>URL</translation> ++ </message> ++</context> ++<context> ++ <name>Group</name> ++ <message> ++ <source>Recycle Bin</source> ++ <translation>Prullenbak</translation> ++ </message> ++</context> ++<context> ++ <name>KeePass1OpenWidget</name> ++ <message> ++ <source>Import KeePass1 database</source> ++ <translation>Importeer Keepass 1-database</translation> ++ </message> ++ <message> ++ <source>Error</source> ++ <translation>Fout</translation> ++ </message> ++ <message> ++ <source>Unable to open the database.</source> ++ <translation>Niet mogelijk om de database te openen.</translation> ++ </message> ++</context> ++<context> ++ <name>KeePass1Reader</name> ++ <message> ++ <source>Unable to read keyfile.</source> ++ <translation>Niet mogelijk om sleutelbestand te lezen</translation> ++ </message> ++ <message> ++ <source>Not a KeePass database.</source> ++ <translation>Geen Keepass-database</translation> ++ </message> ++ <message> ++ <source>Unsupported encryption algorithm.</source> ++ <translation>Niet-ondersteund encryptie-algoritme</translation> ++ </message> ++ <message> ++ <source>Unsupported KeePass database version.</source> ++ <translation>Niet-ondersteunde versie van Keepass-database</translation> ++ </message> ++ <message> ++ <source>Root</source> ++ <translation>Alles</translation> ++ </message> ++</context> ++<context> ++ <name>KeePass2Reader</name> ++ <message> ++ <source>Not a KeePass database.</source> ++ <translation>Geen Keepass-database.</translation> ++ </message> ++ <message> ++ <source>Unsupported KeePass database version.</source> ++ <translation>Niet-ondersteunde versie van Keepass-database.</translation> ++ </message> ++ <message> ++ <source>Wrong key or database file is corrupt.</source> ++ <translation>Verkeerde sleutel of corrupte database.</translation> ++ </message> ++</context> ++<context> ++ <name>MainWindow</name> ++ <message> ++ <source>Database</source> ++ <translation>Database</translation> ++ </message> ++ <message> ++ <source>Recent databases</source> ++ <translation>Recente databases</translation> ++ </message> ++ <message> ++ <source>Help</source> ++ <translation>Help</translation> ++ </message> ++ <message> ++ <source>Entries</source> ++ <translation>Elementen</translation> ++ </message> ++ <message> ++ <source>Copy attribute to clipboard</source> ++ <translation>Kopieer eigenschap naar klembord</translation> ++ </message> ++ <message> ++ <source>Groups</source> ++ <translation>Groepen</translation> ++ </message> ++ <message> ++ <source>Extras</source> ++ <translation>Extra's</translation> ++ </message> ++ <message> ++ <source>View</source> ++ <translation>Beeld</translation> ++ </message> ++ <message> ++ <source>Quit</source> ++ <translation>Afsluiten</translation> ++ </message> ++ <message> ++ <source>About</source> ++ <translation>Over</translation> ++ </message> ++ <message> ++ <source>Open database</source> ++ <translation>Open database</translation> ++ </message> ++ <message> ++ <source>Save database</source> ++ <translation>Sla database op</translation> ++ </message> ++ <message> ++ <source>Close database</source> ++ <translation>Sluit database</translation> ++ </message> ++ <message> ++ <source>New database</source> ++ <translation>Nieuwe database</translation> ++ </message> ++ <message> ++ <source>Add new entry</source> ++ <translation>Voeg element toe</translation> ++ </message> ++ <message> ++ <source>View/Edit entry</source> ++ <translation>Bekijk/bewerk element</translation> ++ </message> ++ <message> ++ <source>Delete entry</source> ++ <translation>Verwijder element</translation> ++ </message> ++ <message> ++ <source>Add new group</source> ++ <translation>Voeg groep toe</translation> ++ </message> ++ <message> ++ <source>Edit group</source> ++ <translation>Bewerk groep</translation> ++ </message> ++ <message> ++ <source>Delete group</source> ++ <translation>Verwijder groep</translation> ++ </message> ++ <message> ++ <source>Save database as</source> ++ <translation>Database opslaan als</translation> ++ </message> ++ <message> ++ <source>Change master key</source> ++ <translation>Hoofdsleutel wijzigen</translation> ++ </message> ++ <message> ++ <source>Database settings</source> ++ <translation>Database-instellingen</translation> ++ </message> ++ <message> ++ <source>Import KeePass 1 database</source> ++ <translation>Importeer Keepass 1-database</translation> ++ </message> ++ <message> ++ <source>Clone entry</source> ++ <translation>Element klonen</translation> ++ </message> ++ <message> ++ <source>Find</source> ++ <translation>Vind</translation> ++ </message> ++ <message> ++ <source>Username</source> ++ <translation>Gebruikersnaam</translation> ++ </message> ++ <message> ++ <source>Copy username to clipboard</source> ++ <translation>Kopieer gebruikersnaam naar klembord</translation> ++ </message> ++ <message> ++ <source>Password</source> ++ <translation>Wachtwoord</translation> ++ </message> ++ <message> ++ <source>Copy password to clipboard</source> ++ <translation>Kopieer wachtwoord naar klembord</translation> ++ </message> ++ <message> ++ <source>Settings</source> ++ <translation>Instellingen</translation> ++ </message> ++ <message> ++ <source>Perform Auto-Type</source> ++ <translation>Voer auto-typen uit</translation> ++ </message> ++ <message> ++ <source>Open URL</source> ++ <translation>Open URL</translation> ++ </message> ++ <message> ++ <source>Lock databases</source> ++ <translation>Vergrendel databases</translation> ++ </message> ++ <message> ++ <source>Title</source> ++ <translation>Titel</translation> ++ </message> ++ <message> ++ <source>URL</source> ++ <translation>URL</translation> ++ </message> ++ <message> ++ <source>Notes</source> ++ <translation>Opmerkingen</translation> ++ </message> ++ <message> ++ <source>Show toolbar</source> ++ <translation>Werkbalk weergeven</translation> ++ </message> ++ <message> ++ <source>read-only</source> ++ <translation>alleen-lezen</translation> ++ </message> ++</context> ++<context> ++ <name>PasswordGeneratorWidget</name> ++ <message> ++ <source>Password:</source> ++ <translation>Wachtwoord:</translation> ++ </message> ++ <message> ++ <source>Length:</source> ++ <translation>Lengte:</translation> ++ </message> ++ <message> ++ <source>Character Types</source> ++ <translation>Tekens</translation> ++ </message> ++ <message> ++ <source>Upper Case Letters</source> ++ <translation>Hoofdletters</translation> ++ </message> ++ <message> ++ <source>Lower Case Letters</source> ++ <translation>Kleine letters</translation> ++ </message> ++ <message> ++ <source>Numbers</source> ++ <translation>Cijfers</translation> ++ </message> ++ <message> ++ <source>Special Characters</source> ++ <translation>Speciale tekens</translation> ++ </message> ++ <message> ++ <source>Exclude look-alike characters</source> ++ <translation>Geen op elkaar lijkende tekens</translation> ++ </message> ++ <message> ++ <source>Ensure that the password contains characters from every group</source> ++ <translation>Zorg dat het wachtwoord tekens uit iedere groep bevat</translation> ++ </message> ++ <message> ++ <source>Accept</source> ++ <translation>Accepteren</translation> ++ </message> ++</context> ++<context> ++ <name>QCommandLineParser</name> ++ <message> ++ <source>Displays version information.</source> ++ <translation>Toont versie-informatie.</translation> ++ </message> ++ <message> ++ <source>Displays this help.</source> ++ <translation>Toont deze helptekst.</translation> ++ </message> ++ <message> ++ <source>Unknown option '%1'.</source> ++ <translation>Onbekende optie '%1'.</translation> ++ </message> ++ <message> ++ <source>Unknown options: %1.</source> ++ <translation>Onbekende opties: %1.</translation> ++ </message> ++ <message> ++ <source>Missing value after '%1'.</source> ++ <translation>Ontbrekende waarde na '%1'.</translation> ++ </message> ++ <message> ++ <source>Unexpected value after '%1'.</source> ++ <translation>Onverwachte waarde na '%1'.</translation> ++ </message> ++ <message> ++ <source>[options]</source> ++ <translation>[opties]</translation> ++ </message> ++ <message> ++ <source>Usage: %1</source> ++ <translation>Gebruik: %1</translation> ++ </message> ++ <message> ++ <source>Options:</source> ++ <translation>Opties:</translation> ++ </message> ++ <message> ++ <source>Arguments:</source> ++ <translation>Argumenten:</translation> ++ </message> ++</context> ++<context> ++ <name>QSaveFile</name> ++ <message> ++ <source>Existing file %1 is not writable</source> ++ <translation>Bestaand bestand %1 is niet schrijfbaar</translation> ++ </message> ++ <message> ++ <source>Writing canceled by application</source> ++ <translation>Schrijven afgebroken door programma</translation> ++ </message> ++ <message> ++ <source>Partial write. Partition full?</source> ++ <translation>Slechts deels geschreven. Is de schijf vol?</translation> ++ </message> ++</context> ++<context> ++ <name>QtIOCompressor</name> ++ <message> ++ <source>Internal zlib error when compressing: </source> ++ <translation>Interne fout in zlib bij inpakken:</translation> ++ </message> ++ <message> ++ <source>Error writing to underlying device: </source> ++ <translation>Fout bij schrijven naar onderliggend apparaat:</translation> ++ </message> ++ <message> ++ <source>Error opening underlying device: </source> ++ <translation>Fout bij openen van onderliggend apparaat:</translation> ++ </message> ++ <message> ++ <source>Error reading data from underlying device: </source> ++ <translation>Fout bij lezen van gegevens van onderliggend apparaat:</translation> ++ </message> ++ <message> ++ <source>Internal zlib error when decompressing: </source> ++ <translation>Interne fout in zlib bij uitpakken:</translation> ++ </message> ++</context> ++<context> ++ <name>QtIOCompressor::open</name> ++ <message> ++ <source>The gzip format not supported in this version of zlib.</source> ++ <translation>Gzip wordt niet ondersteund in deze versie van zlib.</translation> ++ </message> ++ <message> ++ <source>Internal zlib error: </source> ++ <translation>Interne fout in zlib:</translation> ++ </message> ++</context> ++<context> ++ <name>SearchWidget</name> ++ <message> ++ <source>Find:</source> ++ <translation>Vind:</translation> ++ </message> ++ <message> ++ <source>Case sensitive</source> ++ <translation>Hoofdlettergevoelig</translation> ++ </message> ++ <message> ++ <source>Current group</source> ++ <translation>Huidige groep</translation> ++ </message> ++ <message> ++ <source>Root group</source> ++ <translation>Hoofdgroep</translation> ++ </message> ++</context> ++<context> ++ <name>SettingsWidget</name> ++ <message> ++ <source>Application Settings</source> ++ <translation>Programma-instellingen</translation> ++ </message> ++ <message> ++ <source>General</source> ++ <translation>Algemeen</translation> ++ </message> ++ <message> ++ <source>Security</source> ++ <translation>Beveiliging</translation> ++ </message> ++</context> ++<context> ++ <name>SettingsWidgetGeneral</name> ++ <message> ++ <source>Remember last databases</source> ++ <translation>Onthoud laatste databases</translation> ++ </message> ++ <message> ++ <source>Open previous databases on startup</source> ++ <translation>Open vorige databases bij starten</translation> ++ </message> ++ <message> ++ <source>Mark as modified on expanded state changes</source> ++ <translation>Markeer database als gewijzigd bij wijzigen van de status</translation> ++ </message> ++ <message> ++ <source>Automatically save on exit</source> ++ <translation>Automatisch opslaan bij afsluiten</translation> ++ </message> ++ <message> ++ <source>Automatically save after every change</source> ++ <translation>Automatisch opslaan na iedere wijziging</translation> ++ </message> ++ <message> ++ <source>Minimize when copying to clipboard</source> ++ <translation>Minimaliseer bij kopieeren naar klembord</translation> ++ </message> ++ <message> ++ <source>Use group icon on entry creation</source> ++ <translation>Gebruik icoon van de groep voor nieuwe elementen</translation> ++ </message> ++ <message> ++ <source>Global Auto-Type shortcut</source> ++ <translation>Globale sneltoets voor auto-typen</translation> ++ </message> ++ <message> ++ <source>Use entry title to match windows for global auto-type</source> ++ <translation>Gebruik naam van element als vensternaam voor auto-typen</translation> ++ </message> ++</context> ++<context> ++ <name>SettingsWidgetSecurity</name> ++ <message> ++ <source>Clear clipboard after</source> ++ <translation>Leeg klembord na</translation> ++ </message> ++ <message> ++ <source> sec</source> ++ <translation>sec</translation> ++ </message> ++ <message> ++ <source>Lock databases after inactivity of</source> ++ <translation>Vergrendel databases na inactiviteit van</translation> ++ </message> ++ <message> ++ <source>Show passwords in cleartext by default</source> ++ <translation>Laat wachtwoorden standaard zien</translation> ++ </message> ++ <message> ++ <source>Always ask before performing auto-type</source> ++ <translation>Altijd vragen alvorens auto-type uit te voeren</translation> ++ </message> ++</context> ++<context> ++ <name>UnlockDatabaseWidget</name> ++ <message> ++ <source>Unlock database</source> ++ <translation>Database ontgrendelen</translation> ++ </message> ++ <message> ++ <source>Error</source> ++ <translation>Fout</translation> ++ </message> ++ <message> ++ <source>Wrong key.</source> ++ <translation>Verkeerd wachtwoord</translation> ++ </message> ++</context> ++<context> ++ <name>WelcomeWidget</name> ++ <message> ++ <source>Welcome!</source> ++ <translation>Welkom!</translation> ++ </message> ++</context> ++<context> ++ <name>main</name> ++ <message> ++ <source>KeePassX - cross-platform password manager</source> ++ <translation>KeepassX - multi-platform wachtwoordbeheerder</translation> ++ </message> ++ <message> ++ <source>filename of the password database to open (*.kdbx)</source> ++ <translation>bestandsnaam van de te openen wachtwoorddatabase (*.kdbx)</translation> ++ </message> ++ <message> ++ <source>path to a custom config file</source> ++ <translation>pad naar een configuratiebestand</translation> ++ </message> ++ <message> ++ <source>password of the database (DANGEROUS!)</source> ++ <translation>wachtwoord van de database (GEVAARLIJK!)</translation> ++ </message> ++ <message> ++ <source>key file of the database</source> ++ <translation>sleutelbestand van de database</translation> ++ </message> ++</context> ++</TS> +\ 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 @@ ++<?xml version="1.0" ?><!DOCTYPE TS><TS language="sv" version="2.0"> ++<context> ++ <name>AboutDialog</name> ++ <message> ++ <source>About KeePassX</source> ++ <translation>Om KeePassX</translation> ++ </message> ++ <message> ++ <source>KeePassX is distributed under the term of the GNU General Public License (GPL) version 2 or (at your option) version 3.</source> ++ <translation>Keepassx distribueras enligt villkoren i GNU General Public License (GPL) version 2 eller (om du vill) version 3.</translation> ++ </message> ++</context> ++<context> ++ <name>AutoType</name> ++ <message> ++ <source>Auto-Type - KeePassX</source> ++ <translation>Auto-skriv - KeePassX</translation> ++ </message> ++ <message> ++ <source>Couldn't find an entry that matches the window title.</source> ++ <translation>Kunde inte hitta en post som matchar fönstertiteln.</translation> ++ </message> ++</context> ++<context> ++ <name>AutoTypeAssociationsModel</name> ++ <message> ++ <source>Window</source> ++ <translation>Fönster</translation> ++ </message> ++ <message> ++ <source>Sequence</source> ++ <translation>Sekvens</translation> ++ </message> ++ <message> ++ <source>Default sequence</source> ++ <translation>Standard sekvens</translation> ++ </message> ++</context> ++<context> ++ <name>AutoTypeSelectDialog</name> ++ <message> ++ <source>Auto-Type - KeePassX</source> ++ <translation>Auto-skriv - KeePassX</translation> ++ </message> ++ <message> ++ <source>Select entry to Auto-Type:</source> ++ <translation>Välj post att auto-skriva</translation> ++ </message> ++</context> ++<context> ++ <name>ChangeMasterKeyWidget</name> ++ <message> ++ <source>Password</source> ++ <translation>Lösenord</translation> ++ </message> ++ <message> ++ <source>Enter password:</source> ++ <translation>Ange lösenord:</translation> ++ </message> ++ <message> ++ <source>Repeat password:</source> ++ <translation>Repetera lösenord:</translation> ++ </message> ++ <message> ++ <source>Key file</source> ++ <translation>Nyckel-fil</translation> ++ </message> ++ <message> ++ <source>Browse</source> ++ <translation>Bläddra</translation> ++ </message> ++ <message> ++ <source>Create</source> ++ <translation>Skapa</translation> ++ </message> ++ <message> ++ <source>Key files</source> ++ <translation>Nyckel-filer</translation> ++ </message> ++ <message> ++ <source>All files</source> ++ <translation>Alla filer</translation> ++ </message> ++ <message> ++ <source>Create Key File...</source> ++ <translation>Skapa nyckel-fil...</translation> ++ </message> ++ <message> ++ <source>Error</source> ++ <translation>Fel</translation> ++ </message> ++ <message> ++ <source>Unable to create Key File : </source> ++ <translation>Kunde inte skapa nyckel-fil</translation> ++ </message> ++ <message> ++ <source>Select a key file</source> ++ <translation>Välj nyckel-fil</translation> ++ </message> ++ <message> ++ <source>Question</source> ++ <translation>Fråga</translation> ++ </message> ++ <message> ++ <source>Do you really want to use an empty string as password?</source> ++ <translation>Vill du verkligen vill använda en tom sträng som lösenord?</translation> ++ </message> ++ <message> ++ <source>Different passwords supplied.</source> ++ <translation>Olika lösenord angivna</translation> ++ </message> ++</context> ++<context> ++ <name>DatabaseOpenWidget</name> ++ <message> ++ <source>Enter master key</source> ++ <translation>Ange huvud lösenord</translation> ++ </message> ++ <message> ++ <source>Key File:</source> ++ <translation>Nyckel-fil:</translation> ++ </message> ++ <message> ++ <source>Password:</source> ++ <translation>Lösenord:</translation> ++ </message> ++ <message> ++ <source>Browse</source> ++ <translation>Bläddra</translation> ++ </message> ++ <message> ++ <source>Error</source> ++ <translation>Fel</translation> ++ </message> ++ <message> ++ <source>Unable to open the database.</source> ++ <translation>Kunde inte öppna databas.</translation> ++ </message> ++ <message> ++ <source>Can't open key file</source> ++ <translation>Kan inte öppna nyckel-fil</translation> ++ </message> ++ <message> ++ <source>All files</source> ++ <translation>Alla filer</translation> ++ </message> ++ <message> ++ <source>Key files</source> ++ <translation>Nyckel-filer</translation> ++ </message> ++ <message> ++ <source>Select key file</source> ++ <translation>Välj nyckel-fil</translation> ++ </message> ++</context> ++<context> ++ <name>DatabaseSettingsWidget</name> ++ <message> ++ <source>Database name:</source> ++ <translation>Databasnamn:</translation> ++ </message> ++ <message> ++ <source>Database description:</source> ++ <translation>Databasbeskrivning:</translation> ++ </message> ++ <message> ++ <source>Transform rounds:</source> ++ <translation>Transformerings varv:</translation> ++ </message> ++ <message> ++ <source>Default username:</source> ++ <translation>Standard användarnamn:</translation> ++ </message> ++ <message> ++ <source>Use recycle bin:</source> ++ <translation>Använd papperskorg:</translation> ++ </message> ++ <message> ++ <source> MiB</source> ++ <translation>MiB</translation> ++ </message> ++ <message> ++ <source>Benchmark</source> ++ <translation>Benchmark</translation> ++ </message> ++ <message> ++ <source>Max. history items:</source> ++ <translation>Maxantal historik poster:</translation> ++ </message> ++ <message> ++ <source>Max. history size:</source> ++ <translation>Maximal historik storlek:</translation> ++ </message> ++</context> ++<context> ++ <name>DatabaseTabWidget</name> ++ <message> ++ <source>Root</source> ++ <translation>Root</translation> ++ </message> ++ <message> ++ <source>KeePass 2 Database</source> ++ <translation>KeePass 2 Databas</translation> ++ </message> ++ <message> ++ <source>All files</source> ++ <translation>Alla filer</translation> ++ </message> ++ <message> ++ <source>Open database</source> ++ <translation>Öppna databas</translation> ++ </message> ++ <message> ++ <source>Warning</source> ++ <translation>Varning</translation> ++ </message> ++ <message> ++ <source>File not found!</source> ++ <translation>Filen kunde inte hittas!</translation> ++ </message> ++ <message> ++ <source>Open KeePass 1 database</source> ++ <translation>Öppna KeePass 1 databas</translation> ++ </message> ++ <message> ++ <source>KeePass 1 database</source> ++ <translation>KeePass 1 databas</translation> ++ </message> ++ <message> ++ <source>All files (*)</source> ++ <translation>Alla filer (*)</translation> ++ </message> ++ <message> ++ <source>Close?</source> ++ <translation>Stäng?</translation> ++ </message> ++ <message> ++ <source>"%1" is in edit mode. ++Close anyway?</source> ++ <translation>"%1" är i redigerar-läge. ++Stäng ändå?</translation> ++ </message> ++ <message> ++ <source>Save changes?</source> ++ <translation>Spara ändringar?</translation> ++ </message> ++ <message> ++ <source>"%1" was modified. ++Save changes?</source> ++ <translation>"%1" har ändrats. ++Spara ändringarna?</translation> ++ </message> ++ <message> ++ <source>Error</source> ++ <translation>Fel</translation> ++ </message> ++ <message> ++ <source>Writing the database failed.</source> ++ <translation>Kunde inte skriva till databasen.</translation> ++ </message> ++ <message> ++ <source>Save database as</source> ++ <translation>Spara databas som</translation> ++ </message> ++ <message> ++ <source>New database</source> ++ <translation>Ny databas</translation> ++ </message> ++ <message> ++ <source>locked</source> ++ <translation>låst</translation> ++ </message> ++</context> ++<context> ++ <name>DatabaseWidget</name> ++ <message> ++ <source>Change master key</source> ++ <translation>Ändra huvud lösenord</translation> ++ </message> ++ <message> ++ <source>Delete entry?</source> ++ <translation>Ta bort post?</translation> ++ </message> ++ <message> ++ <source>Do you really want to delete the entry "%1" for good?</source> ++ <translation>Vill du verkligen ta bort "%1" för gott?</translation> ++ </message> ++ <message> ++ <source>Delete entries?</source> ++ <translation>Ta bort poster?</translation> ++ </message> ++ <message> ++ <source>Do you really want to delete %1 entries for good?</source> ++ <translation>Vill du verkligen ta bort %1 poser för gott?</translation> ++ </message> ++ <message> ++ <source>Move entries to recycle bin?</source> ++ <translation>Lägg poster i papperskorgen?</translation> ++ </message> ++ <message numerus="yes"> ++ <source>Do you really want to move %n entry(s) to the recycle bin?</source> ++ <translation><numerusform>Vill du verkligen flytta %n post till papperskorgen?</numerusform><numerusform>Vill du verkligen flytta %n poster till papperskorgen?</numerusform></translation> ++ </message> ++ <message> ++ <source>Delete group?</source> ++ <translation>Ta bort grupp?</translation> ++ </message> ++ <message> ++ <source>Do you really want to delete the group "%1" for good?</source> ++ <translation>Vill du verkligen ta bort gruppen "%1" för gott?</translation> ++ </message> ++ <message> ++ <source>Current group</source> ++ <translation>Nuvarande grupp</translation> ++ </message> ++</context> ++<context> ++ <name>EditEntryWidget</name> ++ <message> ++ <source>Entry</source> ++ <translation>Post</translation> ++ </message> ++ <message> ++ <source>Advanced</source> ++ <translation>Avancerat</translation> ++ </message> ++ <message> ++ <source>Icon</source> ++ <translation>Ikon</translation> ++ </message> ++ <message> ++ <source>Auto-Type</source> ++ <translation>Auto-skriv</translation> ++ </message> ++ <message> ++ <source>Properties</source> ++ <translation>Egenskaper</translation> ++ </message> ++ <message> ++ <source>History</source> ++ <translation>Historik</translation> ++ </message> ++ <message> ++ <source>Entry history</source> ++ <translation>Posthistork</translation> ++ </message> ++ <message> ++ <source>Add entry</source> ++ <translation>Lägg till post</translation> ++ </message> ++ <message> ++ <source>Edit entry</source> ++ <translation>Ändra post</translation> ++ </message> ++ <message> ++ <source>Error</source> ++ <translation>Fel</translation> ++ </message> ++ <message> ++ <source>Different passwords supplied.</source> ++ <translation>Olika lösenord angivna</translation> ++ </message> ++ <message> ++ <source>New attribute</source> ++ <translation>Nytt attribut</translation> ++ </message> ++ <message> ++ <source>Select file</source> ++ <translation>Välj fil</translation> ++ </message> ++ <message> ++ <source>Unable to open file</source> ++ <translation>Kunde inte öppna filen.</translation> ++ </message> ++ <message> ++ <source>Save attachment</source> ++ <translation>Spara bifogad fil</translation> ++ </message> ++ <message> ++ <source>Unable to save the attachment: ++</source> ++ <translation>Kunde inte spara bifogad fil: ++</translation> ++ </message> ++ <message> ++ <source>Tomorrow</source> ++ <translation>Imorgon</translation> ++ </message> ++ <message numerus="yes"> ++ <source>%n week(s)</source> ++ <translation><numerusform>%n vecka</numerusform><numerusform>%n veckor</numerusform></translation> ++ </message> ++ <message numerus="yes"> ++ <source>%n month(s)</source> ++ <translation><numerusform>%n månad</numerusform><numerusform>%n månader</numerusform></translation> ++ </message> ++ <message> ++ <source>1 year</source> ++ <translation>1 år</translation> ++ </message> ++</context> ++<context> ++ <name>EditEntryWidgetAdvanced</name> ++ <message> ++ <source>Additional attributes</source> ++ <translation>Ytterligare attribut</translation> ++ </message> ++ <message> ++ <source>Add</source> ++ <translation>Lägg till</translation> ++ </message> ++ <message> ++ <source>Edit</source> ++ <translation>Ändra</translation> ++ </message> ++ <message> ++ <source>Remove</source> ++ <translation>Ta bort</translation> ++ </message> ++ <message> ++ <source>Attachments</source> ++ <translation>Bilagor</translation> ++ </message> ++ <message> ++ <source>Save</source> ++ <translation>Spara</translation> ++ </message> ++</context> ++<context> ++ <name>EditEntryWidgetAutoType</name> ++ <message> ++ <source>Enable Auto-Type for this entry</source> ++ <translation>Slå på auto-skriv för denna post</translation> ++ </message> ++ <message> ++ <source>Inherit default Auto-Type sequence from the group</source> ++ <translation>Ärv standard auto-skriv sekvens för grupp</translation> ++ </message> ++ <message> ++ <source>Use custom Auto-Type sequence:</source> ++ <translation>Använd egen auto-skriv sekvens:</translation> ++ </message> ++ <message> ++ <source>+</source> ++ <translation>+</translation> ++ </message> ++ <message> ++ <source>-</source> ++ <translation>-</translation> ++ </message> ++ <message> ++ <source>Window title:</source> ++ <translation>Fönster titel:</translation> ++ </message> ++ <message> ++ <source>Use default sequence</source> ++ <translation>Använd standard sekvens</translation> ++ </message> ++ <message> ++ <source>Set custom sequence:</source> ++ <translation>Egen sekvens:</translation> ++ </message> ++</context> ++<context> ++ <name>EditEntryWidgetHistory</name> ++ <message> ++ <source>Show</source> ++ <translation>Visa</translation> ++ </message> ++ <message> ++ <source>Restore</source> ++ <translation>Återställ</translation> ++ </message> ++ <message> ++ <source>Delete</source> ++ <translation>Ta bort</translation> ++ </message> ++ <message> ++ <source>Delete all</source> ++ <translation>Ta bort alla</translation> ++ </message> ++</context> ++<context> ++ <name>EditEntryWidgetMain</name> ++ <message> ++ <source>Title:</source> ++ <translation>Titel:</translation> ++ </message> ++ <message> ++ <source>Username:</source> ++ <translation>Användarnamn:</translation> ++ </message> ++ <message> ++ <source>Password:</source> ++ <translation>Lösenord:</translation> ++ </message> ++ <message> ++ <source>Repeat:</source> ++ <translation>Repetera:</translation> ++ </message> ++ <message> ++ <source>Gen.</source> ++ <translation>Gen.</translation> ++ </message> ++ <message> ++ <source>URL:</source> ++ <translation>URL:</translation> ++ </message> ++ <message> ++ <source>Expires</source> ++ <translation>Går ut</translation> ++ </message> ++ <message> ++ <source>Presets</source> ++ <translation>Förinställningar</translation> ++ </message> ++ <message> ++ <source>Notes:</source> ++ <translation>Anteckningar:</translation> ++ </message> ++</context> ++<context> ++ <name>EditGroupWidget</name> ++ <message> ++ <source>Group</source> ++ <translation>Grupp</translation> ++ </message> ++ <message> ++ <source>Icon</source> ++ <translation>Ikon</translation> ++ </message> ++ <message> ++ <source>Properties</source> ++ <translation>Egenskaper</translation> ++ </message> ++ <message> ++ <source>Add group</source> ++ <translation>Lägg till grupp</translation> ++ </message> ++ <message> ++ <source>Edit group</source> ++ <translation>Ändra grupp</translation> ++ </message> ++ <message> ++ <source>Enable</source> ++ <translation>Slå på</translation> ++ </message> ++ <message> ++ <source>Disable</source> ++ <translation>Stäng av</translation> ++ </message> ++ <message> ++ <source>Inherit from parent group (%1)</source> ++ <translation>Ärv från förälder grupp (%1)</translation> ++ </message> ++</context> ++<context> ++ <name>EditGroupWidgetMain</name> ++ <message> ++ <source>Name</source> ++ <translation>Namn</translation> ++ </message> ++ <message> ++ <source>Notes</source> ++ <translation>Anteckningar</translation> ++ </message> ++ <message> ++ <source>Expires</source> ++ <translation>Går ut</translation> ++ </message> ++ <message> ++ <source>Search</source> ++ <translation>Sök</translation> ++ </message> ++ <message> ++ <source>Auto-type</source> ++ <translation>Auto-skriv</translation> ++ </message> ++</context> ++<context> ++ <name>EditWidgetIcons</name> ++ <message> ++ <source>Use default icon</source> ++ <translation>Använd standard ikon</translation> ++ </message> ++ <message> ++ <source>Use custom icon</source> ++ <translation>Använd egen ikon</translation> ++ </message> ++ <message> ++ <source>Add custom icon</source> ++ <translation>Lägg till egen ikon</translation> ++ </message> ++ <message> ++ <source>Delete custom icon</source> ++ <translation>Ta bort egen ikon</translation> ++ </message> ++ <message> ++ <source>Images</source> ++ <translation>Bilder</translation> ++ </message> ++ <message> ++ <source>All files</source> ++ <translation>Alla filer</translation> ++ </message> ++ <message> ++ <source>Select Image</source> ++ <translation>Välj bild</translation> ++ </message> ++ <message> ++ <source>Can't delete icon!</source> ++ <translation>Kan inte ta bort ikon!</translation> ++ </message> ++ <message numerus="yes"> ++ <source>Can't delete icon. Still used by %n item(s).</source> ++ <translation><numerusform>Kan inte ta bort ikonen. Den används fortfarande av %n post</numerusform><numerusform>Kan inte ta bort ikonen. Den används fortfarande av %n poster</numerusform></translation> ++ </message> ++</context> ++<context> ++ <name>EditWidgetProperties</name> ++ <message> ++ <source>Created:</source> ++ <translation>Skapad:</translation> ++ </message> ++ <message> ++ <source>Modified:</source> ++ <translation>Ändrad:</translation> ++ </message> ++ <message> ++ <source>Accessed:</source> ++ <translation>Läst:</translation> ++ </message> ++ <message> ++ <source>Uuid:</source> ++ <translation>UUID:</translation> ++ </message> ++</context> ++<context> ++ <name>EntryAttributesModel</name> ++ <message> ++ <source>Name</source> ++ <translation>Namn</translation> ++ </message> ++</context> ++<context> ++ <name>EntryHistoryModel</name> ++ <message> ++ <source>Last modified</source> ++ <translation>Senast ändrad</translation> ++ </message> ++ <message> ++ <source>Title</source> ++ <translation>Titel</translation> ++ </message> ++ <message> ++ <source>Username</source> ++ <translation>Användarnamn</translation> ++ </message> ++ <message> ++ <source>URL</source> ++ <translation>URL</translation> ++ </message> ++</context> ++<context> ++ <name>EntryModel</name> ++ <message> ++ <source>Group</source> ++ <translation>Grupp</translation> ++ </message> ++ <message> ++ <source>Title</source> ++ <translation>Titel</translation> ++ </message> ++ <message> ++ <source>Username</source> ++ <translation>Användarnamn</translation> ++ </message> ++ <message> ++ <source>URL</source> ++ <translation>URL</translation> ++ </message> ++</context> ++<context> ++ <name>Group</name> ++ <message> ++ <source>Recycle Bin</source> ++ <translation>Papperskorg</translation> ++ </message> ++</context> ++<context> ++ <name>KeePass1OpenWidget</name> ++ <message> ++ <source>Import KeePass1 database</source> ++ <translation>Importera KeePass1 databas</translation> ++ </message> ++ <message> ++ <source>Error</source> ++ <translation>Fel</translation> ++ </message> ++ <message> ++ <source>Unable to open the database.</source> ++ <translation>Kunde inte öppna databas.</translation> ++ </message> ++</context> ++<context> ++ <name>KeePass1Reader</name> ++ <message> ++ <source>Unable to read keyfile.</source> ++ <translation>Kunde inte läsa nyckel-filen.</translation> ++ </message> ++ <message> ++ <source>Not a KeePass database.</source> ++ <translation>Inte en KeePass databas</translation> ++ </message> ++ <message> ++ <source>Unsupported encryption algorithm.</source> ++ <translation>Krypteringsalgoritnmen stöds ej</translation> ++ </message> ++ <message> ++ <source>Unsupported KeePass database version.</source> ++ <translation>KeePass databas versionen stöds ej.</translation> ++ </message> ++ <message> ++ <source>Root</source> ++ <translation>Root</translation> ++ </message> ++</context> ++<context> ++ <name>KeePass2Reader</name> ++ <message> ++ <source>Not a KeePass database.</source> ++ <translation>Inte en KeePass databas.</translation> ++ </message> ++ <message> ++ <source>Unsupported KeePass database version.</source> ++ <translation>KeePass databas versionen stöds ej.</translation> ++ </message> ++ <message> ++ <source>Wrong key or database file is corrupt.</source> ++ <translation>Fel lösenord eller korrupt databas-fil</translation> ++ </message> ++</context> ++<context> ++ <name>MainWindow</name> ++ <message> ++ <source>Database</source> ++ <translation>Databas</translation> ++ </message> ++ <message> ++ <source>Recent databases</source> ++ <translation>Senast använda databser</translation> ++ </message> ++ <message> ++ <source>Help</source> ++ <translation>Hjälp</translation> ++ </message> ++ <message> ++ <source>Entries</source> ++ <translation>Poster</translation> ++ </message> ++ <message> ++ <source>Copy attribute to clipboard</source> ++ <translation>Kopiera attribut</translation> ++ </message> ++ <message> ++ <source>Groups</source> ++ <translation>Grupper</translation> ++ </message> ++ <message> ++ <source>Extras</source> ++ <translation>Extra</translation> ++ </message> ++ <message> ++ <source>View</source> ++ <translation>Vy</translation> ++ </message> ++ <message> ++ <source>Quit</source> ++ <translation>Avsluta</translation> ++ </message> ++ <message> ++ <source>About</source> ++ <translation>Om</translation> ++ </message> ++ <message> ++ <source>Open database</source> ++ <translation>Öppna databas</translation> ++ </message> ++ <message> ++ <source>Save database</source> ++ <translation>Spara databas</translation> ++ </message> ++ <message> ++ <source>Close database</source> ++ <translation>Stäng databas</translation> ++ </message> ++ <message> ++ <source>New database</source> ++ <translation>Ny databas</translation> ++ </message> ++ <message> ++ <source>Add new entry</source> ++ <translation>Lägg till ny post</translation> ++ </message> ++ <message> ++ <source>View/Edit entry</source> ++ <translation>Visa/ändra post</translation> ++ </message> ++ <message> ++ <source>Delete entry</source> ++ <translation>Ta bort post</translation> ++ </message> ++ <message> ++ <source>Add new group</source> ++ <translation>Lägg till ny grupp</translation> ++ </message> ++ <message> ++ <source>Edit group</source> ++ <translation>Ändra grupp</translation> ++ </message> ++ <message> ++ <source>Delete group</source> ++ <translation>Ta bort grupp</translation> ++ </message> ++ <message> ++ <source>Save database as</source> ++ <translation>Spara databas som</translation> ++ </message> ++ <message> ++ <source>Change master key</source> ++ <translation>Ändra huvud lösenord</translation> ++ </message> ++ <message> ++ <source>Database settings</source> ++ <translation>Databasinställningar</translation> ++ </message> ++ <message> ++ <source>Import KeePass 1 database</source> ++ <translation>Importera KeePass1 databas</translation> ++ </message> ++ <message> ++ <source>Clone entry</source> ++ <translation>Klona post</translation> ++ </message> ++ <message> ++ <source>Find</source> ++ <translation>Sök</translation> ++ </message> ++ <message> ++ <source>Username</source> ++ <translation>Användarnamn</translation> ++ </message> ++ <message> ++ <source>Copy username to clipboard</source> ++ <translation>Kopiera användarnamn</translation> ++ </message> ++ <message> ++ <source>Password</source> ++ <translation>Lösenord</translation> ++ </message> ++ <message> ++ <source>Copy password to clipboard</source> ++ <translation>Kopiera lösenord</translation> ++ </message> ++ <message> ++ <source>Settings</source> ++ <translation>Inställningar</translation> ++ </message> ++ <message> ++ <source>Perform Auto-Type</source> ++ <translation>Utför auto-skriv</translation> ++ </message> ++ <message> ++ <source>Open URL</source> ++ <translation>Öppna URL</translation> ++ </message> ++ <message> ++ <source>Lock databases</source> ++ <translation>Lås databaser</translation> ++ </message> ++ <message> ++ <source>Title</source> ++ <translation>Titel</translation> ++ </message> ++ <message> ++ <source>URL</source> ++ <translation>URL</translation> ++ </message> ++ <message> ++ <source>Notes</source> ++ <translation>Anteckningar</translation> ++ </message> ++ <message> ++ <source>Show toolbar</source> ++ <translation>Visa verktygsfält</translation> ++ </message> ++ <message> ++ <source>read-only</source> ++ <translation>läs bara</translation> ++ </message> ++</context> ++<context> ++ <name>PasswordGeneratorWidget</name> ++ <message> ++ <source>Password:</source> ++ <translation>Lösenord:</translation> ++ </message> ++ <message> ++ <source>Length:</source> ++ <translation>Längd:</translation> ++ </message> ++ <message> ++ <source>Character Types</source> ++ <translation>Teckentyper</translation> ++ </message> ++ <message> ++ <source>Upper Case Letters</source> ++ <translation>Versaler</translation> ++ </message> ++ <message> ++ <source>Lower Case Letters</source> ++ <translation>Gemener</translation> ++ </message> ++ <message> ++ <source>Numbers</source> ++ <translation>Siffror</translation> ++ </message> ++ <message> ++ <source>Special Characters</source> ++ <translation>Specialtecken</translation> ++ </message> ++ <message> ++ <source>Exclude look-alike characters</source> ++ <translation>Uteslut liknande tecken</translation> ++ </message> ++ <message> ++ <source>Ensure that the password contains characters from every group</source> ++ <translation>Säkerställ att lösenordet innehåller tecken från varje grupp</translation> ++ </message> ++ <message> ++ <source>Accept</source> ++ <translation>Acceptera</translation> ++ </message> ++</context> ++<context> ++ <name>QCommandLineParser</name> ++ <message> ++ <source>Displays version information.</source> ++ <translation>Visar versionsinformation.</translation> ++ </message> ++ <message> ++ <source>Displays this help.</source> ++ <translation>Visa denna hjälp.</translation> ++ </message> ++ <message> ++ <source>Unknown option '%1'.</source> ++ <translation>Okänt alternativ: '%1'</translation> ++ </message> ++ <message> ++ <source>Unknown options: %1.</source> ++ <translation>Okända alternativ: '%1'</translation> ++ </message> ++ <message> ++ <source>Missing value after '%1'.</source> ++ <translation>Saknar värde efter '%1'</translation> ++ </message> ++ <message> ++ <source>Unexpected value after '%1'.</source> ++ <translation>Oväntat värde efter '%1'</translation> ++ </message> ++ <message> ++ <source>[options]</source> ++ <translation>[alternativ]</translation> ++ </message> ++ <message> ++ <source>Usage: %1</source> ++ <translation>Användning: %1</translation> ++ </message> ++ <message> ++ <source>Options:</source> ++ <translation>Alternativ:</translation> ++ </message> ++ <message> ++ <source>Arguments:</source> ++ <translation>Argument:</translation> ++ </message> ++</context> ++<context> ++ <name>QSaveFile</name> ++ <message> ++ <source>Existing file %1 is not writable</source> ++ <translation>Den existerande filen %1 är inte skrivbar</translation> ++ </message> ++ <message> ++ <source>Writing canceled by application</source> ++ <translation>Skrivning avbruten av applikation</translation> ++ </message> ++ <message> ++ <source>Partial write. Partition full?</source> ++ <translation>Delvis skrivet. Är partitionen full?</translation> ++ </message> ++</context> ++<context> ++ <name>QtIOCompressor</name> ++ <message> ++ <source>Internal zlib error when compressing: </source> ++ <translation>Internt zlib fel vid komprimering:</translation> ++ </message> ++ <message> ++ <source>Error writing to underlying device: </source> ++ <translation>Fel vid skrivning till underliggande enhet:</translation> ++ </message> ++ <message> ++ <source>Error opening underlying device: </source> ++ <translation>Fel vid öppning av underliggande enhet:</translation> ++ </message> ++ <message> ++ <source>Error reading data from underlying device: </source> ++ <translation>Fel vid läsning från underliggande enhet:</translation> ++ </message> ++ <message> ++ <source>Internal zlib error when decompressing: </source> ++ <translation>Internt zlib fel vid extrahering:</translation> ++ </message> ++</context> ++<context> ++ <name>QtIOCompressor::open</name> ++ <message> ++ <source>The gzip format not supported in this version of zlib.</source> ++ <translation>Gzip formatet stöds inte av denna version av zlib.</translation> ++ </message> ++ <message> ++ <source>Internal zlib error: </source> ++ <translation>Internt zlib fel:</translation> ++ </message> ++</context> ++<context> ++ <name>SearchWidget</name> ++ <message> ++ <source>Find:</source> ++ <translation>Sök:</translation> ++ </message> ++ <message> ++ <source>Case sensitive</source> ++ <translation>Skiftlägeskänslig</translation> ++ </message> ++ <message> ++ <source>Current group</source> ++ <translation>Nuvarande grupp</translation> ++ </message> ++ <message> ++ <source>Root group</source> ++ <translation>Root grupp</translation> ++ </message> ++</context> ++<context> ++ <name>SettingsWidget</name> ++ <message> ++ <source>Application Settings</source> ++ <translation>Applikationsinställningar</translation> ++ </message> ++ <message> ++ <source>General</source> ++ <translation>Allmän</translation> ++ </message> ++ <message> ++ <source>Security</source> ++ <translation>Säkerhet</translation> ++ </message> ++</context> ++<context> ++ <name>SettingsWidgetGeneral</name> ++ <message> ++ <source>Remember last databases</source> ++ <translation>Komihåg senaste databasen</translation> ++ </message> ++ <message> ++ <source>Open previous databases on startup</source> ++ <translation>Öppna senaste databasen är programmet startar</translation> ++ </message> ++ <message> ++ <source>Mark as modified on expanded state changes</source> ++ <translation>Markera som ändrad när utökat läge ändras</translation> ++ </message> ++ <message> ++ <source>Automatically save on exit</source> ++ <translation>Spara automatiskt är applikationen anslutas</translation> ++ </message> ++ <message> ++ <source>Automatically save after every change</source> ++ <translation>Spara automatiskt efter varje ändring</translation> ++ </message> ++ <message> ++ <source>Minimize when copying to clipboard</source> ++ <translation>Minimera vid kopiering</translation> ++ </message> ++ <message> ++ <source>Use group icon on entry creation</source> ++ <translation>Använd gruppens ikon för nya poster</translation> ++ </message> ++ <message> ++ <source>Global Auto-Type shortcut</source> ++ <translation>Globalt auto-skriv kortkommando</translation> ++ </message> ++ <message> ++ <source>Use entry title to match windows for global auto-type</source> ++ <translation>Använda postens titel till matchning med fönster för globalt auto-skriv</translation> ++ </message> ++</context> ++<context> ++ <name>SettingsWidgetSecurity</name> ++ <message> ++ <source>Clear clipboard after</source> ++ <translation>Rensa urklipp efter</translation> ++ </message> ++ <message> ++ <source> sec</source> ++ <translation>sek</translation> ++ </message> ++ <message> ++ <source>Lock databases after inactivity of</source> ++ <translation>Lås databaser efter inaktivitet i</translation> ++ </message> ++ <message> ++ <source>Show passwords in cleartext by default</source> ++ <translation>Visa lösenord i klartext som standard</translation> ++ </message> ++ <message> ++ <source>Always ask before performing auto-type</source> ++ <translation>Fråga alltid innan auto-skriv utförs</translation> ++ </message> ++</context> ++<context> ++ <name>UnlockDatabaseWidget</name> ++ <message> ++ <source>Unlock database</source> ++ <translation>Lås upp databas</translation> ++ </message> ++ <message> ++ <source>Error</source> ++ <translation>Fel</translation> ++ </message> ++ <message> ++ <source>Wrong key.</source> ++ <translation>Fel lösenord</translation> ++ </message> ++</context> ++<context> ++ <name>WelcomeWidget</name> ++ <message> ++ <source>Welcome!</source> ++ <translation>Välkommen!</translation> ++ </message> ++</context> ++<context> ++ <name>main</name> ++ <message> ++ <source>KeePassX - cross-platform password manager</source> ++ <translation>KeePassX - plattformsoberoende lösenordshanterare</translation> ++ </message> ++ <message> ++ <source>filename of the password database to open (*.kdbx)</source> ++ <translation>namn på databas fil att öppna (*.kdbx)</translation> ++ </message> ++ <message> ++ <source>path to a custom config file</source> ++ <translation>Sökväg till egen konfigurations-fil</translation> ++ </message> ++ <message> ++ <source>password of the database (DANGEROUS!)</source> ++ <translation>lösenord för databasen (FARLIGT!)</translation> ++ </message> ++ <message> ++ <source>key file of the database</source> ++ <translation>nyckel-fil för databas</translation> ++ </message> ++</context> ++</TS> +\ 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<Database*>& 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<char*>(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<char*>(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 <class T> 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 <blueice@fobos.de> ++ * ++ * 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 <http://www.gnu.org/licenses/>. ++ */ ++ ++#include "EntrySearcher.h" ++ ++#include "core/Group.h" ++ ++QList<Entry*> EntrySearcher::search(const QString &searchTerm, const Group* group, Qt::CaseSensitivity caseSensitivity) ++{ ++ if (!group->resolveSearchingEnabled()) { ++ return QList<Entry*>(); ++ } ++ ++ return searchEntries(searchTerm, group, caseSensitivity); ++} ++ ++QList<Entry*> EntrySearcher::searchEntries(const QString& searchTerm, const Group* group, Qt::CaseSensitivity caseSensitivity) ++{ ++ QList<Entry*> 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<Entry*> 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<Entry*>(); ++ } ++ } ++ ++ return QList<Entry*>() << 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 <debfx@fobos.de> ++ * ++ * 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 <http://www.gnu.org/licenses/>. ++ */ ++ ++#ifndef KEEPASSX_ENTRYSEARCHER_H ++#define KEEPASSX_ENTRYSEARCHER_H ++ ++#include <QString> ++ ++ ++class Group; ++class Entry; ++ ++class EntrySearcher ++{ ++public: ++ QList<Entry*> search(const QString& searchTerm, const Group* group, Qt::CaseSensitivity caseSensitivity); ++private: ++ QList<Entry*> searchEntries(const QString& searchTerm, const Group* group, Qt::CaseSensitivity caseSensitivity); ++ QList<Entry*> 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<Uuid> 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<Entry*> Group::search(const QString& searchTerm, Qt::CaseSensitivity caseSensitivity, +- bool resolveInherit) ++bool Group::resolveSearchingEnabled() const + { +- QList<Entry*> 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<Entry*> 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<Database> 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 <debfx@fobos.de> ++ * Copyright (C) 2014 Florian Geyer <blueice@fobos.de> ++ * ++ * 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 <http://www.gnu.org/licenses/>. ++ */ ++ ++#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<Uuid> 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 <debfx@fobos.de> ++ * Copyright (C) 2014 Florian Geyer <blueice@fobos.de> ++ * ++ * 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 <http://www.gnu.org/licenses/>. ++ */ ++ ++#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 <debfx@fobos.de> ++ * ++ * 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 <http://www.gnu.org/licenses/>. ++ */ ++ ++#include "Translator.h" ++ ++#include <QCoreApplication> ++#include <QDir> ++#include <QLibraryInfo> ++#include <QLocale> ++#include <QRegExp> ++#include <QTranslator> ++ ++#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<QPair<QString, QString> > Translator::availableLanguages() ++{ ++ QStringList paths; ++#ifdef QT_DEBUG ++ paths.append(QString("%1/share/translations").arg(KEEPASSX_BINARY_DIR)); ++#endif ++ paths.append(filePath()->dataPath("translations")); ++ ++ QList<QPair<QString, QString> > languages; ++ languages.append(QPair<QString, QString>("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<QString, QString>(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 <debfx@fobos.de> ++ * ++ * 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 <http://www.gnu.org/licenses/>. ++ */ ++ ++#ifndef KEEPASSX_TRANSLATOR_H ++#define KEEPASSX_TRANSLATOR_H ++ ++#include <QPair> ++#include <QString> ++ ++class Translator ++{ ++public: ++ static void installTranslator(); ++ static QList<QPair<QString, QString> > 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 <gcrypt.h> + ++#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 <QString> ++ + #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<Database*, DatabaseManagerStruct> 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<Database*, DatabaseManagerStruct> 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<int> DatabaseWidget::splitterSizes() const + { +- return m_groupView; ++ return m_splitter->sizes(); + } + +-EntryView* DatabaseWidget::entryView() ++void DatabaseWidget::setSplitterSizes(const QList<int>& sizes) + { +- return m_entryView; ++ m_splitter->setSizes(sizes); ++} ++ ++QList<int> DatabaseWidget::entryHeaderViewSizes() const ++{ ++ QList<int> 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<int>& 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<Entry*> searchResult = searchGroup->search(m_searchUi->searchEdit->text(), sensitivity); + ++ QList<Entry*> 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<int> splitterSizes() const; ++ void setSplitterSizes(const QList<int>& sizes); ++ QList<int> entryHeaderViewSizes() const; ++ void setEntryViewHeaderSizes(const QList<int>& 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<Ui::SearchWidget> 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 <debfx@fobos.de> ++ * Copyright (C) 2014 Florian Geyer <blueice@fobos.de> ++ * ++ * 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 <http://www.gnu.org/licenses/>. ++ */ ++ ++#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<int> DatabaseWidgetStateSync::variantToIntList(const QVariant& variant) ++{ ++ QVariantList list = variant.toList(); ++ QList<int> 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<int>& 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 <debfx@fobos.de> ++ * Copyright (C) 2014 Florian Geyer <blueice@fobos.de> ++ * ++ * 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 <http://www.gnu.org/licenses/>. ++ */ ++ ++#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<int> variantToIntList(const QVariant& variant); ++ static QVariant intListToVariant(const QList<int>& list); ++ ++ DatabaseWidget* m_activeDbWidget; ++ ++ bool m_blockUpdates; ++ QList<int> m_splitterSizes; ++ QList<int> m_columnSizesList; ++ QList<int> 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<QAction*> 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 <QActionGroup> + #include <QMainWindow> ++#include <QSystemTrayIcon> + + #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<Ui::MainWindow> 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 @@ + <string>Upper Case Letters</string> + </property> + <property name="text"> +- <string>A-Z</string> ++ <string notr="true">A-Z</string> + </property> + <property name="checkable"> + <bool>true</bool> +@@ -116,7 +116,7 @@ + <string>Lower Case Letters</string> + </property> + <property name="text"> +- <string>a-z</string> ++ <string notr="true">a-z</string> + </property> + <property name="checkable"> + <bool>true</bool> +@@ -132,7 +132,7 @@ + <string>Numbers</string> + </property> + <property name="text"> +- <string>0-9</string> ++ <string notr="true">0-9</string> + </property> + <property name="checkable"> + <bool>true</bool> +@@ -148,7 +148,7 @@ + <string>Special Characters</string> + </property> + <property name="text"> +- <string>/*_& ...</string> ++ <string notr="true">/*_& ...</string> + </property> + <property name="checkable"> + <bool>true</bool> +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 @@ + </rect> + </property> + <layout class="QGridLayout" name="gridLayout"> +- <property name="margin"> ++ <property name="leftMargin"> ++ <number>0</number> ++ </property> ++ <property name="topMargin"> ++ <number>0</number> ++ </property> ++ <property name="rightMargin"> ++ <number>0</number> ++ </property> ++ <property name="bottomMargin"> + <number>0</number> + </property> + <item row="0" column="1"> +@@ -21,6 +30,9 @@ + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QToolButton" name="closeSearchButton"> ++ <property name="focusPolicy"> ++ <enum>Qt::ClickFocus</enum> ++ </property> + <property name="autoRaise"> + <bool>true</bool> + </property> +@@ -38,7 +50,16 @@ + <item row="1" column="1"> + <widget class="QWidget" name="optionsWidget" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout_2"> +- <property name="margin"> ++ <property name="leftMargin"> ++ <number>0</number> ++ </property> ++ <property name="topMargin"> ++ <number>0</number> ++ </property> ++ <property name="rightMargin"> ++ <number>0</number> ++ </property> ++ <property name="bottomMargin"> + <number>0</number> + </property> + <item> +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<QPair<QString, QString> > 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<Qt::Key>(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 @@ + <x>0</x> + <y>0</y> + <width>456</width> +- <height>185</height> ++ <height>340</height> + </rect> + </property> + <layout class="QFormLayout" name="formLayout"> ++ <property name="fieldGrowthPolicy"> ++ <enum>QFormLayout::AllNonFixedFieldsGrow</enum> ++ </property> + <item row="0" column="0"> + <widget class="QCheckBox" name="rememberLastDatabasesCheckBox"> + <property name="text"> +@@ -21,6 +24,13 @@ + </property> + </widget> + </item> ++ <item row="1" column="0"> ++ <widget class="QCheckBox" name="openPreviousDatabasesOnStartupCheckBox"> ++ <property name="text"> ++ <string>Open previous databases on startup</string> ++ </property> ++ </widget> ++ </item> + <item row="2" column="0"> + <widget class="QCheckBox" name="modifiedExpandedChangedCheckBox"> + <property name="text"> +@@ -31,6 +41,13 @@ + </property> + </widget> + </item> ++ <item row="3" column="0"> ++ <widget class="QCheckBox" name="autoSaveOnExitCheckBox"> ++ <property name="text"> ++ <string>Automatically save on exit</string> ++ </property> ++ </widget> ++ </item> + <item row="4" column="0"> + <widget class="QCheckBox" name="autoSaveAfterEveryChangeCheckBox"> + <property name="text"> +@@ -38,34 +55,61 @@ + </property> + </widget> + </item> +- <item row="3" column="0"> +- <widget class="QCheckBox" name="autoSaveOnExitCheckBox"> ++ <item row="5" column="0"> ++ <widget class="QCheckBox" name="minimizeOnCopyCheckBox"> + <property name="text"> +- <string>Automatically save on exit</string> ++ <string>Minimize when copying to clipboard</string> + </property> + </widget> + </item> + <item row="6" column="0"> ++ <widget class="QCheckBox" name="useGroupIconOnEntryCreationCheckBox"> ++ <property name="text"> ++ <string>Use group icon on entry creation</string> ++ </property> ++ </widget> ++ </item> ++ <item row="7" column="0"> + <widget class="QLabel" name="autoTypeShortcutLabel"> + <property name="text"> + <string>Global Auto-Type shortcut</string> + </property> + </widget> + </item> +- <item row="6" column="1"> ++ <item row="7" column="1"> + <widget class="ShortcutWidget" name="autoTypeShortcutWidget"/> + </item> +- <item row="1" column="0"> +- <widget class="QCheckBox" name="openPreviousDatabasesOnStartupCheckBox"> ++ <item row="8" column="0"> ++ <widget class="QCheckBox" name="autoTypeEntryTitleMatchCheckBox"> + <property name="text"> +- <string>Open previous databases on startup</string> ++ <string>Use entry title to match windows for global auto-type</string> + </property> + </widget> + </item> +- <item row="5" column="0"> +- <widget class="QCheckBox" name="minimizeOnCopyCheckBox"> ++ <item row="9" column="0"> ++ <widget class="QLabel" name="languageLabel"> + <property name="text"> +- <string>Minimize when copying to clipboard</string> ++ <string>Language</string> ++ </property> ++ </widget> ++ </item> ++ <item row="9" column="1"> ++ <widget class="QComboBox" name="languageComboBox"/> ++ </item> ++ <item row="10" column="0"> ++ <widget class="QCheckBox" name="systrayShowCheckBox"> ++ <property name="text"> ++ <string>Show a system tray icon</string> ++ </property> ++ </widget> ++ </item> ++ <item row="11" column="0"> ++ <widget class="QCheckBox" name="systrayMinimizeToTrayCheckBox"> ++ <property name="enabled"> ++ <bool>false</bool> ++ </property> ++ <property name="text"> ++ <string>Hide window to system tray when minimized</string> + </property> + </widget> + </item> +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 @@ + </property> + </widget> + </item> ++ <item row="3" column="0"> ++ <widget class="QCheckBox" name="autoTypeAskCheckBox"> ++ <property name="text"> ++ <string>Always ask before performing auto-type</string> ++ </property> ++ </widget> ++ </item> + </layout> + </widget> + <tabstops> +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 <QHeaderView> + #include <QKeyEvent> + + #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<Entry*>& 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<Entry*>& 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 @@ + <item row="4" column="0"> + <widget class="QLabel" name="autotypeLabel"> + <property name="text"> +- <string>Autotype</string> ++ <string>Auto-type</string> + </property> + </widget> + </item> +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 <http://www.gnu.org/licenses/>. + +-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 <QTest> + + #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<Database*> 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<Database*> 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<Database*> 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>("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 <blueice@fobos.de> ++ * ++ * 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 <http://www.gnu.org/licenses/>. ++ */ ++ ++#include "TestEntrySearcher.h" ++ ++#include <QTest> ++ ++#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 <blueice@fobos.de> ++ * ++ * 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 <http://www.gnu.org/licenses/>. ++ */ ++ ++ ++#ifndef KEEPASSX_TESTENTRYSEARCHER_H ++#define KEEPASSX_TESTENTRYSEARCHER_H ++ ++#include <QObject> ++ ++#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<Entry*> 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 <debfx@fobos.de> ++ * Copyright (C) 2014 Florian Geyer <blueice@fobos.de> ++ * ++ * 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 <http://www.gnu.org/licenses/>. ++ */ ++ ++#include "TestExporter.h" ++ ++#include <QTest> ++ ++#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 <debfx@fobos.de> ++ * Copyright (C) 2014 Florian Geyer <blueice@fobos.de> ++ * ++ * 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 <http://www.gnu.org/licenses/>. ++ */ ++ ++#ifndef KEEPASSX_TESTEXPORTER_H ++#define KEEPASSX_TESTEXPORTER_H ++ ++#include <QObject> ++ ++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*>("Entry*"); + qRegisterMetaType<Group*>("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<Entry*> 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<Entry*> 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>("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> + ++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<DatabaseTabWidget*>("tabWidget"); +@@ -83,7 +83,7 @@ void TestGui::testTabs() + + void TestGui::testEditEntry() + { +- EntryView* entryView = m_dbWidget->entryView(); ++ EntryView* entryView = m_dbWidget->findChild<EntryView*>("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*>("groupView"); ++ EntryView* entryView = m_dbWidget->findChild<EntryView*>("entryView"); + QToolBar* toolBar = m_mainWindow->findChild<QToolBar*>("toolBar"); + QAction* entryDeleteAction = m_mainWindow->findChild<QAction*>("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*>("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*>("entryView"); ++ GroupView* groupView = m_dbWidget->findChild<GroupView*>("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*>("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<GroupModel*>(m_dbWidget->groupView()->model()); ++ GroupModel* groupModel = qobject_cast<GroupModel*>(m_dbWidget->findChild<GroupView*>("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))) { |