diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3d3d3f5f8..59ada8766 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -40,6 +40,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 diff --git a/src/core/Config.cpp b/src/core/Config.cpp index 58721c625..78834aa24 100644 --- a/src/core/Config.cpp +++ b/src/core/Config.cpp @@ -92,6 +92,7 @@ void Config::init(const QString& fileName) m_defaults.insert("RememberLastKeyFiles", true); m_defaults.insert("OpenPreviousDatabasesOnStartup", 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/core/Database.cpp b/src/core/Database.cpp index 6dc971b33..336820381 100644 --- a/src/core/Database.cpp +++ b/src/core/Database.cpp @@ -324,3 +324,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 6d2237d4c..3cd5ed1b1 100644 --- a/src/core/Database.h +++ b/src/core/Database.h @@ -88,6 +88,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 e330d99d0..8915e5c06 100644 --- a/src/gui/DatabaseWidget.cpp +++ b/src/gui/DatabaseWidget.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -28,6 +29,8 @@ #include #include #include +#include +#include #include "autotype/AutoType.h" #include "core/Config.h" @@ -36,6 +39,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" @@ -658,8 +662,11 @@ void DatabaseWidget::openDatabase(bool accepted) m_databaseOpenWidget = nullptr; delete m_keepass1OpenWidget; m_keepass1OpenWidget = nullptr; + if (config()->get("AutoReloadOnChange").toBool() ) + m_file_watcher.watchFile( m_filename ); } else { + m_file_watcher.stopWatching(); if (m_databaseOpenWidget->database()) { delete m_databaseOpenWidget->database(); } @@ -932,6 +939,31 @@ void DatabaseWidget::updateFilename(const QString& fileName) m_filename = fileName; } +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)) { + // 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; + } +} + int DatabaseWidget::numberOfSelectedEntries() const { return m_entryView->numberOfSelectedEntries(); diff --git a/src/gui/DatabaseWidget.h b/src/gui/DatabaseWidget.h index 8aa773fa2..57211c05f 100644 --- a/src/gui/DatabaseWidget.h +++ b/src/gui/DatabaseWidget.h @@ -24,6 +24,7 @@ #include "core/Uuid.h" #include "gui/entry/EntryModel.h" +#include "core/FileSystemWatcher.h" class ChangeMasterKeyWidget; class DatabaseOpenWidget; @@ -148,6 +149,7 @@ private Q_SLOTS: void updateMasterKey(bool accepted); void openDatabase(bool accepted); void mergeDatabase(bool accepted); + void databaseModifedExternally(); void unlockDatabase(bool accepted); void emitCurrentModeChanged(); void clearLastGroup(Group* group); @@ -183,6 +185,8 @@ private: QString m_lastSearchText; bool m_searchCaseSensitive; bool m_searchCurrentGroup; + + FileSystemWatcher m_file_watcher; }; #endif // KEEPASSX_DATABASEWIDGET_H diff --git a/src/gui/SettingsWidget.cpp b/src/gui/SettingsWidget.cpp index 254a7ebda..2a9e6945b 100644 --- a/src/gui/SettingsWidget.cpp +++ b/src/gui/SettingsWidget.cpp @@ -106,6 +106,7 @@ void SettingsWidget::loadSettings() config()->get("OpenPreviousDatabasesOnStartup").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()); @@ -159,6 +160,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 007cb771b..843e16fec 100644 --- a/src/gui/SettingsWidgetGeneral.ui +++ b/src/gui/SettingsWidgetGeneral.ui @@ -56,44 +56,51 @@ + + + Automatically reload when the database is expernally modified + + + + 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 - +