From 7a8d4577f19fbfbab3777232763e7452332812ab Mon Sep 17 00:00:00 2001 From: Sebastien Fricker Date: Sat, 3 May 2014 16:59:41 +0200 Subject: [PATCH 1/2] Automatic reload of a database when it get modified When the database if modified by an other instance of KeePassX, KeePassX detect it and reload automatically the database. --- src/CMakeLists.txt | 2 + src/core/Database.cpp | 6 +++ src/core/Database.h | 1 + src/core/FileSystemWatcher.cpp | 75 ++++++++++++++++++++++++++++++++++ src/core/FileSystemWatcher.h | 47 +++++++++++++++++++++ src/gui/DatabaseWidget.cpp | 28 +++++++++++++ src/gui/DatabaseWidget.h | 3 ++ 7 files changed, 162 insertions(+) create mode 100644 src/core/FileSystemWatcher.cpp create mode 100644 src/core/FileSystemWatcher.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d57153e5f..d221418d3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -29,6 +29,7 @@ set(keepassx_SOURCES autotype/test/AutoTypeTestInterface.h core/AutoTypeAssociations.cpp core/Config.cpp + core/FileSystemWatcher.cpp core/Database.cpp core/DatabaseIcons.cpp core/Endian.cpp @@ -136,6 +137,7 @@ set(keepassx_MOC autotype/AutoTypeSelectView.h autotype/ShortcutWidget.h autotype/WindowSelectComboBox.h + core/FileSystemWatcher.h core/AutoTypeAssociations.h core/Config.h core/Database.h diff --git a/src/core/Database.cpp b/src/core/Database.cpp index 4c888eab9..91189d66d 100644 --- a/src/core/Database.cpp +++ b/src/core/Database.cpp @@ -297,3 +297,9 @@ void Database::startModifiedTimer() } m_timer->start(150); } + +const CompositeKey & Database::key() const +{ + return m_data.key; +} + diff --git a/src/core/Database.h b/src/core/Database.h index 0ee9a9659..70f43fba2 100644 --- a/src/core/Database.h +++ b/src/core/Database.h @@ -87,6 +87,7 @@ public: QByteArray transformSeed() const; quint64 transformRounds() const; QByteArray transformedMasterKey() const; + const CompositeKey & key() const; void setCipher(const Uuid& cipher); void setCompressionAlgo(Database::CompressionAlgorithm algo); diff --git a/src/core/FileSystemWatcher.cpp b/src/core/FileSystemWatcher.cpp new file mode 100644 index 000000000..93b4f6f3f --- /dev/null +++ b/src/core/FileSystemWatcher.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2012 Felix Geyer + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "FileSystemWatcher.h" +#include +#include +#include + +FileSystemWatcher::FileSystemWatcher (): QFileSystemWatcher ( ) +{ + connect(this,SIGNAL( fileChanged ( const QString & )), + this,SLOT( fileChangedSlot ( const QString & ))); + connect(this,SIGNAL( directoryChanged ( const QString & )), + this,SLOT( directoryChangedSlot ( const QString & ))); +} + +void FileSystemWatcher::watchFile(const QString &file) +{ + _file=file; + if (!files().isEmpty()) + removePaths(files()); + if (!directories().isEmpty()) + removePaths(directories()); + QFileInfo fileInfo(file); + if (fileInfo.exists()) + addPath(file); + QString filePath=fileInfo.absoluteDir().path(); + QFileInfo filePathInfo(filePath); + if (filePathInfo.exists()) + addPath(filePath); +} + +void FileSystemWatcher::stopWatching() +{ + watchFile( QString() ); +} + +void FileSystemWatcher::fileChangedSlot ( const QString & ) +{ + QFileInfo fileInfo(_file); + if ( fileInfo.exists() ) + fileChanged(); +} + +void FileSystemWatcher::directoryChangedSlot ( const QString & ) +{ + if (!files().contains(_file)) + { + QFileInfo fileInfo(_file); + if ( fileInfo.exists() ) + { + addPath(_file); + fileChanged(); + } + } +} + +FileSystemWatcher::~FileSystemWatcher() +{ +} + diff --git a/src/core/FileSystemWatcher.h b/src/core/FileSystemWatcher.h new file mode 100644 index 000000000..4721a98b7 --- /dev/null +++ b/src/core/FileSystemWatcher.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2012 Felix Geyer + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef FILE_SYSTEM_WATCHER_H +#define FILE_SYSTEM_WATCHER_H +#include +#include +#include + + +class FileSystemWatcher : public QFileSystemWatcher +{ + Q_OBJECT ; + +public: + FileSystemWatcher (); + void watchFile( const QString & ); + void stopWatching(); + + virtual ~FileSystemWatcher(); + +private: + QString _file; + +private Q_SLOTS: + void directoryChangedSlot ( const QString & ); + void fileChangedSlot ( const QString & ); +Q_SIGNALS: + void fileChanged(); +}; + +#endif + diff --git a/src/gui/DatabaseWidget.cpp b/src/gui/DatabaseWidget.cpp index 419028ab8..1dc694f69 100644 --- a/src/gui/DatabaseWidget.cpp +++ b/src/gui/DatabaseWidget.cpp @@ -22,9 +22,11 @@ #include #include #include +#include #include #include #include +#include #include "autotype/AutoType.h" #include "core/Config.h" @@ -32,6 +34,7 @@ #include "core/Group.h" #include "core/Metadata.h" #include "core/Tools.h" +#include "format/KeePass2Reader.h" #include "gui/ChangeMasterKeyWidget.h" #include "gui/Clipboard.h" #include "gui/DatabaseOpenWidget.h" @@ -159,6 +162,7 @@ DatabaseWidget::DatabaseWidget(Database* db, QWidget* parent) connect(m_searchUi->searchEdit, SIGNAL(returnPressed()), m_entryView, SLOT(setFocus())); connect(m_searchTimer, SIGNAL(timeout()), this, SLOT(search())); connect(closeAction, SIGNAL(triggered()), this, SLOT(closeSearch())); + connect( &m_file_watcher, SIGNAL( fileChanged() ), this, SLOT( databaseModifedExternally() ) ); setCurrentWidget(m_mainWidget); } @@ -580,8 +584,10 @@ void DatabaseWidget::openDatabase(bool accepted) m_databaseOpenWidget = Q_NULLPTR; delete m_keepass1OpenWidget; m_keepass1OpenWidget = Q_NULLPTR; + m_file_watcher.watchFile( m_filename ); } else { + m_file_watcher.stopWatching(); if (m_databaseOpenWidget->database()) { delete m_databaseOpenWidget->database(); } @@ -811,3 +817,25 @@ void DatabaseWidget::updateFilename(const QString& fileName) { m_filename = fileName; } + +void DatabaseWidget::databaseModifedExternally() +{ + if ( database() == Q_NULLPTR ) + return; + + KeePass2Reader reader; + QFile file(m_filename); + if (!file.open(QIODevice::ReadOnly)) { + // TODO: error message + return; + } + Database* db = reader.readDatabase(&file, database()->key() ); + if ( db ) + { + Database* oldDb = m_db; + m_db = db; + m_groupView->changeDatabase(m_db); + Q_EMIT databaseChanged(m_db); + delete oldDb; + } +} diff --git a/src/gui/DatabaseWidget.h b/src/gui/DatabaseWidget.h index b535a9b8f..a83f3206a 100644 --- a/src/gui/DatabaseWidget.h +++ b/src/gui/DatabaseWidget.h @@ -24,6 +24,7 @@ #include "core/Global.h" #include "gui/entry/EntryModel.h" +#include "core/FileSystemWatcher.h" class ChangeMasterKeyWidget; class DatabaseOpenWidget; @@ -118,6 +119,7 @@ private Q_SLOTS: void switchToGroupEdit(Group* entry, bool create); void updateMasterKey(bool accepted); void openDatabase(bool accepted); + void databaseModifedExternally(); void unlockDatabase(bool accepted); void emitCurrentModeChanged(); void clearLastGroup(Group* group); @@ -152,6 +154,7 @@ private: QTimer* m_searchTimer; QWidget* widgetBeforeLock; QString m_filename; + FileSystemWatcher m_file_watcher; }; #endif // KEEPASSX_DATABASEWIDGET_H From 06e08557ac09145cd32e6e20c43b66b014c20a96 Mon Sep 17 00:00:00 2001 From: Sebastien Fricker Date: Mon, 9 Jun 2014 10:51:24 +0200 Subject: [PATCH 2/2] New setting: enablin/disabling the automatic reload on changes --- src/core/Config.cpp | 1 + src/gui/DatabaseWidget.cpp | 6 +++++- src/gui/SettingsWidget.cpp | 2 ++ src/gui/SettingsWidgetGeneral.ui | 25 ++++++++++++++++--------- 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/core/Config.cpp b/src/core/Config.cpp index 8a455e27a..5d4304552 100644 --- a/src/core/Config.cpp +++ b/src/core/Config.cpp @@ -91,6 +91,7 @@ void Config::init(const QString& fileName) m_defaults.insert("OpenPreviousDatabasesOnStartup", true); m_defaults.insert("ModifiedOnExpandedStateChanges", true); m_defaults.insert("AutoSaveAfterEveryChange", false); + m_defaults.insert("AutoReloadOnChange", true); m_defaults.insert("AutoSaveOnExit", false); m_defaults.insert("ShowToolbar", true); m_defaults.insert("MinimizeOnCopy", false); diff --git a/src/gui/DatabaseWidget.cpp b/src/gui/DatabaseWidget.cpp index f22f33885..601dd5b87 100644 --- a/src/gui/DatabaseWidget.cpp +++ b/src/gui/DatabaseWidget.cpp @@ -621,7 +621,8 @@ void DatabaseWidget::openDatabase(bool accepted) m_databaseOpenWidget = Q_NULLPTR; delete m_keepass1OpenWidget; m_keepass1OpenWidget = Q_NULLPTR; - m_file_watcher.watchFile( m_filename ); + if (config()->get("AutoReloadOnChange").toBool() ) + m_file_watcher.watchFile( m_filename ); } else { m_file_watcher.stopWatching(); @@ -878,6 +879,9 @@ void DatabaseWidget::databaseModifedExternally() if ( database() == Q_NULLPTR ) return; + if ( ! config()->get("AutoReloadOnChange").toBool() ) + return; + KeePass2Reader reader; QFile file(m_filename); if (!file.open(QIODevice::ReadOnly)) { diff --git a/src/gui/SettingsWidget.cpp b/src/gui/SettingsWidget.cpp index 374e52d97..d45696d1a 100644 --- a/src/gui/SettingsWidget.cpp +++ b/src/gui/SettingsWidget.cpp @@ -66,6 +66,7 @@ void SettingsWidget::loadSettings() m_generalUi->modifiedExpandedChangedCheckBox->setChecked(config()->get("ModifiedOnExpandedStateChanges").toBool()); m_generalUi->autoSaveAfterEveryChangeCheckBox->setChecked(config()->get("AutoSaveAfterEveryChange").toBool()); m_generalUi->autoSaveOnExitCheckBox->setChecked(config()->get("AutoSaveOnExit").toBool()); + m_generalUi->autoReloadOnChangeCheckBox->setChecked(config()->get("AutoReloadOnChange").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()); @@ -110,6 +111,7 @@ void SettingsWidget::saveSettings() config()->set("AutoSaveAfterEveryChange", m_generalUi->autoSaveAfterEveryChangeCheckBox->isChecked()); config()->set("AutoSaveOnExit", m_generalUi->autoSaveOnExitCheckBox->isChecked()); + config()->set("AutoReloadOnChange", m_generalUi->autoReloadOnChangeCheckBox->isChecked()); config()->set("MinimizeOnCopy", m_generalUi->minimizeOnCopyCheckBox->isChecked()); config()->set("UseGroupIconOnEntryCreation", m_generalUi->useGroupIconOnEntryCreationCheckBox->isChecked()); diff --git a/src/gui/SettingsWidgetGeneral.ui b/src/gui/SettingsWidgetGeneral.ui index f3dc079e2..865ad6dc3 100644 --- a/src/gui/SettingsWidgetGeneral.ui +++ b/src/gui/SettingsWidgetGeneral.ui @@ -6,8 +6,8 @@ 0 0 - 456 - 288 + 541 + 311 @@ -55,47 +55,54 @@ - + Minimize when copying to clipboard - + Use group icon on entry creation - + Global Auto-Type shortcut - + - + Use entry title to match windows for global auto-type - + Language - + + + + + Automatically reload when the database is expernally modified + + +