Implemented major autoreload functionality

* Ignore autoreload on save / save-as
* Consolidated db save code
* Corrected bug (crash) in merge entry code due to not cloning the entry
* Enhanced known modified status of database
* Implemented test cases for autoreload
This commit is contained in:
Jonathan White 2016-11-11 17:58:47 -05:00
parent 20c3ca7d37
commit 7fb33653ad
No known key found for this signature in database
GPG key ID: 506BDC439519BC13
9 changed files with 190 additions and 55 deletions

View file

@ -29,7 +29,6 @@
#include <QProcess>
#include <QHeaderView>
#include <QApplication>
#include <QtDebug>
#include "autotype/AutoType.h"
#include "core/Config.h"
@ -162,9 +161,14 @@ DatabaseWidget::DatabaseWidget(Database* db, QWidget* parent)
connect(m_unlockDatabaseDialog, SIGNAL(unlockDone(bool)), SLOT(unlockDatabase(bool)));
connect(&m_fileWatcher, SIGNAL(fileChanged(QString)), this, SLOT(onWatchedFileChanged()));
connect(&m_fileWatchTimer, SIGNAL(timeout()), this, SLOT(reloadDatabaseFile()));
connect(&m_ignoreWatchTimer, SIGNAL(timeout()), this, SLOT(onWatchedFileChanged()));
connect(this, SIGNAL(currentChanged(int)), this, SLOT(emitCurrentModeChanged()));
m_databaseModified = false;
m_fileWatchTimer.setSingleShot(true);
m_ignoreWatchTimer.setSingleShot(true);
m_ignoreNextAutoreload = false;
m_searchCaseSensitive = false;
m_searchCurrentGroup = false;
@ -298,7 +302,7 @@ void DatabaseWidget::replaceDatabase(Database* db)
Database* oldDb = m_db;
m_db = db;
m_groupView->changeDatabase(m_db);
Q_EMIT databaseChanged(m_db);
Q_EMIT databaseChanged(m_db, m_databaseModified);
delete oldDb;
}
@ -818,6 +822,16 @@ void DatabaseWidget::switchToImportKeepass1(const QString& fileName)
setCurrentWidget(m_keepass1OpenWidget);
}
void DatabaseWidget::databaseModified()
{
m_databaseModified = true;
}
void DatabaseWidget::databaseSaved()
{
m_databaseModified = false;
}
void DatabaseWidget::search(const QString& searchtext)
{
if (searchtext.isEmpty())
@ -956,15 +970,34 @@ void DatabaseWidget::lock()
void DatabaseWidget::updateFilename(const QString& fileName)
{
if (! m_filename.isEmpty()) {
m_fileWatcher.removePath(m_filename);
}
m_fileWatcher.addPath(fileName);
m_filename = fileName;
}
void DatabaseWidget::ignoreNextAutoreload()
{
m_ignoreNextAutoreload = true;
m_ignoreWatchTimer.start(100);
}
void DatabaseWidget::onWatchedFileChanged()
{
if (m_fileWatchTimer.isActive())
return;
if (m_ignoreNextAutoreload) {
// Reset the watch
m_ignoreNextAutoreload = false;
m_ignoreWatchTimer.stop();
m_fileWatcher.addPath(m_filename);
}
else {
if (m_fileWatchTimer.isActive())
return;
m_fileWatchTimer.start(500);
m_fileWatchTimer.start(500);
}
}
void DatabaseWidget::reloadDatabaseFile()
@ -972,16 +1005,16 @@ void DatabaseWidget::reloadDatabaseFile()
if (m_db == nullptr)
return;
// TODO: Also check if db is currently modified before reloading
if (! config()->get("AutoReloadOnChange").toBool()) {
// Ask if we want to reload the db
QMessageBox::StandardButton mb = MessageBox::question(this, tr("Reload database file"),
QMessageBox::StandardButton mb = MessageBox::question(this, tr("Autoreload Request"),
tr("The database file has changed. Do you want to load the changes?"),
QMessageBox::Yes | QMessageBox::No);
if (mb == QMessageBox::No) {
// TODO: taint database
// Notify everyone the database does not match the file
emit m_db->modified();
m_databaseModified = true;
// Rewatch the database file
m_fileWatcher.addPath(m_filename);
return;
@ -993,14 +1026,37 @@ void DatabaseWidget::reloadDatabaseFile()
if (file.open(QIODevice::ReadOnly)) {
Database* db = reader.readDatabase(&file, database()->key());
if (db != nullptr) {
if (m_databaseModified) {
// Ask if we want to merge changes into new database
QMessageBox::StandardButton mb = MessageBox::question(this, tr("Merge Request"),
tr("The database file has changed and you have unsaved changes."
"Do you want to merge your changes?"),
QMessageBox::Yes | QMessageBox::No);
if (mb == QMessageBox::Yes) {
// Merge the old database into the new one
m_db->setEmitModified(false);
db->merge(m_db);
}
else {
// Since we are accepting the new file as-is, internally mark as unmodified
// TODO: when saving is moved out of DatabaseTabWidget, this should be replaced
m_databaseModified = false;
}
}
replaceDatabase(db);
}
else {
// TODO: error message for failure to read the new db
MessageBox::critical(this, tr("Autoreload Failed"),
tr("Could not parse or unlock the new database file while attempting"
"to autoreload this database."));
}
}
else {
// TODO: error message for failure to open db file
MessageBox::critical(this, tr("Autoreload Failed"),
tr("Could not open the new database file while attempting to autoreload"
"this database."));
}
// Rewatch the database file