diff --git a/src/gui/DatabaseTabWidget.cpp b/src/gui/DatabaseTabWidget.cpp index 8cade696..09205fca 100644 --- a/src/gui/DatabaseTabWidget.cpp +++ b/src/gui/DatabaseTabWidget.cpp @@ -19,7 +19,6 @@ #include "DatabaseTabWidget.h" #include -#include #include #include @@ -42,8 +41,6 @@ DatabaseManagerStruct::DatabaseManagerStruct() : dbWidget(nullptr) - , lockFile(nullptr) - , saveToFilename(false) , modified(false) , readOnly(false) { @@ -107,7 +104,7 @@ void DatabaseTabWidget::newDatabase() void DatabaseTabWidget::openDatabase() { QString filter = QString("%1 (*.kdbx);;%2 (*)").arg(tr("KeePass 2 Database"), tr("All files")); - QString fileName = fileDialog()->getOpenFileName(this, tr("Open database"), QString(), + QString fileName = fileDialog()->getOpenFileName(this, tr("Open database"), QDir::homePath(), filter); if (!fileName.isEmpty()) { openDatabase(fileName); @@ -128,10 +125,10 @@ void DatabaseTabWidget::openDatabase(const QString& fileName, const QString& pw, QHashIterator i(m_dbList); while (i.hasNext()) { i.next(); - if (i.value().canonicalFilePath == canonicalFilePath) { + if (i.value().fileInfo.canonicalFilePath() == canonicalFilePath) { if (!i.value().dbWidget->dbHasKey() && !(pw.isNull() && keyFile.isEmpty())) { // If the database is locked and a pw or keyfile is provided, unlock it - i.value().dbWidget->switchToOpenDatabase(i.value().filePath, pw, keyFile); + i.value().dbWidget->switchToOpenDatabase(i.value().fileInfo.absoluteFilePath(), pw, keyFile); } else { setCurrentIndex(databaseIndex(i.key())); } @@ -157,49 +154,9 @@ void DatabaseTabWidget::openDatabase(const QString& fileName, const QString& pw, } file.close(); - QLockFile* lockFile = new QLockFile(QString("%1/.%2.lock").arg(fileInfo.canonicalPath(), fileInfo.fileName())); - lockFile->setStaleLockTime(0); - - if (!dbStruct.readOnly && !lockFile->tryLock()) { - // for now silently ignore if we can't create a lock file - // due to lack of permissions - if (lockFile->error() != QLockFile::PermissionError) { - QMessageBox msgBox; - msgBox.setWindowTitle(tr("Database already opened")); - msgBox.setText(tr("The database you are trying to open is locked by another instance of KeePassXC.\n\n" - "Do you want to open it anyway?")); - msgBox.setIcon(QMessageBox::Question); - msgBox.addButton(QMessageBox::Yes); - msgBox.addButton(QMessageBox::No); - auto readOnlyButton = msgBox.addButton(tr("Open read-only"), QMessageBox::NoRole); - msgBox.setDefaultButton(readOnlyButton); - msgBox.setEscapeButton(QMessageBox::No); - auto result = msgBox.exec(); - - if (msgBox.clickedButton() == readOnlyButton) { - dbStruct.readOnly = true; - delete lockFile; - lockFile = nullptr; - } else if (result == QMessageBox::Yes) { - // take over the lock file if possible - if (lockFile->removeStaleLockFile()) { - lockFile->tryLock(); - } - } else { - delete lockFile; - return; - } - } - } - Database* db = new Database(); dbStruct.dbWidget = new DatabaseWidget(db, this); - dbStruct.lockFile = lockFile; - dbStruct.saveToFilename = !dbStruct.readOnly; - - dbStruct.filePath = fileInfo.absoluteFilePath(); - dbStruct.canonicalFilePath = canonicalFilePath; - dbStruct.fileName = fileInfo.fileName(); + dbStruct.fileInfo = fileInfo; insertDatabase(db, dbStruct); @@ -207,13 +164,12 @@ void DatabaseTabWidget::openDatabase(const QString& fileName, const QString& pw, emit messageTab(tr("File opened in read only mode."), MessageWidget::Warning); } - updateLastDatabases(dbStruct.filePath); + updateLastDatabases(dbStruct.fileInfo.absoluteFilePath()); - if (!(pw.isNull() && keyFile.isEmpty())) { - dbStruct.dbWidget->switchToOpenDatabase(dbStruct.filePath, pw, keyFile); - } - else { - dbStruct.dbWidget->switchToOpenDatabase(dbStruct.filePath); + if (!pw.isNull() || !keyFile.isEmpty()) { + dbStruct.dbWidget->switchToOpenDatabase(dbStruct.fileInfo.absoluteFilePath(), pw, keyFile); + } else { + dbStruct.dbWidget->switchToOpenDatabase(dbStruct.fileInfo.absoluteFilePath()); } emit messageDismissGlobal(); } @@ -322,15 +278,14 @@ bool DatabaseTabWidget::closeDatabase(Database* db) void DatabaseTabWidget::deleteDatabase(Database* db) { const DatabaseManagerStruct dbStruct = m_dbList.value(db); - bool emitDatabaseWithFileClosed = dbStruct.saveToFilename; - QString filePath = dbStruct.filePath; + bool emitDatabaseWithFileClosed = dbStruct.fileInfo.exists() && !dbStruct.readOnly; + QString filePath = dbStruct.fileInfo.absoluteFilePath(); int index = databaseIndex(db); removeTab(index); toggleTabbar(); m_dbList.remove(db); - delete dbStruct.lockFile; delete dbStruct.dbWidget; delete db; @@ -349,24 +304,31 @@ bool DatabaseTabWidget::closeAllDatabases() return true; } -bool DatabaseTabWidget::saveDatabase(Database* db) +bool DatabaseTabWidget::saveDatabase(Database* db, QString filePath) { DatabaseManagerStruct& dbStruct = m_dbList[db]; + // Never allow saving a locked database; it causes corruption + Q_ASSERT(dbStruct.dbWidget->currentMode() != DatabaseWidget::LockedMode); + // Release build interlock if (dbStruct.dbWidget->currentMode() == DatabaseWidget::LockedMode) { - // Never allow saving a locked database; it causes corruption // We return true since a save is not required return true; } - if (dbStruct.saveToFilename) { + if (!dbStruct.readOnly) { + if (filePath.isEmpty()) { + filePath = dbStruct.fileInfo.canonicalFilePath(); + } + dbStruct.dbWidget->blockAutoReload(true); - QString errorMessage = db->saveToFile(dbStruct.canonicalFilePath); + QString errorMessage = db->saveToFile(filePath); dbStruct.dbWidget->blockAutoReload(false); if (errorMessage.isEmpty()) { // successfully saved database file dbStruct.modified = false; + dbStruct.fileInfo = QFileInfo(filePath); dbStruct.dbWidget->databaseSaved(); updateTabName(db); emit messageDismissTab(); @@ -387,76 +349,31 @@ bool DatabaseTabWidget::saveDatabaseAs(Database* db) { while (true) { DatabaseManagerStruct& dbStruct = m_dbList[db]; - QString oldFileName; - if (dbStruct.saveToFilename) { - oldFileName = dbStruct.filePath; + QString oldFilePath; + if (dbStruct.fileInfo.exists()) { + oldFilePath = dbStruct.fileInfo.absoluteFilePath(); } else { - oldFileName = tr("Passwords").append(".kdbx"); + oldFilePath = QDir::toNativeSeparators(QDir::homePath() + "/" + tr("Passwords").append(".kdbx")); } - QString fileName = fileDialog()->getSaveFileName(this, tr("Save database as"), - oldFileName, tr("KeePass 2 Database").append(" (*.kdbx)"), - nullptr, 0, "kdbx"); - if (!fileName.isEmpty()) { - QFileInfo fileInfo(fileName); - QString lockFilePath; - if (fileInfo.exists()) { - // returns empty string when file doesn't exist - lockFilePath = fileInfo.canonicalPath(); - } else { - lockFilePath = fileInfo.absolutePath(); - } - QString lockFileName = QString("%1/.%2.lock").arg(lockFilePath, fileInfo.fileName()); - QScopedPointer lockFile(new QLockFile(lockFileName)); - lockFile->setStaleLockTime(0); - if (!lockFile->tryLock()) { - // for now silently ignore if we can't create a lock file - // due to lack of permissions - if (lockFile->error() != QLockFile::PermissionError) { - QMessageBox::StandardButton result = MessageBox::question(this, tr("Save database as"), - tr("The database you are trying to save as is locked by another instance of KeePassXC.\n" - "Do you want to save it anyway?"), - QMessageBox::Yes | QMessageBox::No); + QString newFilePath = fileDialog()->getSaveFileName(this, tr("Save database as"), oldFilePath, + tr("KeePass 2 Database").append(" (*.kdbx)"), + nullptr, 0, "kdbx"); + if (!newFilePath.isEmpty()) { + // Ensure we don't recurse back into this function + dbStruct.readOnly = false; - if (result == QMessageBox::No) { - return false; - } else { - // take over the lock file if possible - if (lockFile->removeStaleLockFile()) { - lockFile->tryLock(); - } - } - } - } - - // setup variables so saveDatabase succeeds - dbStruct.saveToFilename = true; - dbStruct.canonicalFilePath = fileName; - - if (!saveDatabase(db)) { - // failed to save, revert back - dbStruct.saveToFilename = false; - dbStruct.canonicalFilePath = oldFileName; + if (!saveDatabase(db, newFilePath)) { + // Failed to save, try again continue; } - // refresh fileinfo since the file didn't exist before - fileInfo.refresh(); - - dbStruct.modified = false; - dbStruct.saveToFilename = true; - dbStruct.readOnly = false; - dbStruct.filePath = fileInfo.absoluteFilePath(); - dbStruct.canonicalFilePath = fileInfo.canonicalFilePath(); - dbStruct.fileName = fileInfo.fileName(); - dbStruct.dbWidget->updateFilename(dbStruct.filePath); - delete dbStruct.lockFile; - dbStruct.lockFile = lockFile.take(); - updateTabName(db); - updateLastDatabases(dbStruct.filePath); + dbStruct.dbWidget->updateFilePath(dbStruct.fileInfo.absoluteFilePath()); + updateLastDatabases(dbStruct.fileInfo.absoluteFilePath()); return true; - } else { - return false; } + + // Canceled file selection + return false; } } @@ -548,7 +465,7 @@ bool DatabaseTabWidget::canSave(int index) } const DatabaseManagerStruct& dbStruct = indexDatabaseManagerStruct(index); - return !dbStruct.saveToFilename || (dbStruct.modified && !dbStruct.readOnly); + return dbStruct.modified && !dbStruct.readOnly; } bool DatabaseTabWidget::isModified(int index) @@ -566,7 +483,7 @@ QString DatabaseTabWidget::databasePath(int index) index = currentIndex(); } - return indexDatabaseManagerStruct(index).filePath; + return indexDatabaseManagerStruct(index).fileInfo.absoluteFilePath(); } @@ -579,21 +496,18 @@ void DatabaseTabWidget::updateTabName(Database* db) QString tabName; - if (dbStruct.saveToFilename || dbStruct.readOnly) { + if (dbStruct.fileInfo.exists()) { if (db->metadata()->name().isEmpty()) { - tabName = dbStruct.fileName; - } - else { + tabName = dbStruct.fileInfo.fileName(); + } else { tabName = db->metadata()->name(); } - setTabToolTip(index, dbStruct.filePath); - } - else { + setTabToolTip(index, dbStruct.fileInfo.absoluteFilePath()); + } else { if (db->metadata()->name().isEmpty()) { tabName = tr("New database"); - } - else { + } else { tabName = QString("%1 [%2]").arg(db->metadata()->name(), tr("New database")); } } @@ -629,8 +543,7 @@ void DatabaseTabWidget::updateTabNameFromDbWidgetSender() Group *autoload = db->rootGroup()->findChildByName("AutoOpen"); if (autoload) { const DatabaseManagerStruct& dbStruct = m_dbList.value(db); - QFileInfo dbpath(dbStruct.canonicalFilePath); - QDir dbFolder(dbpath.canonicalPath()); + QDir dbFolder(dbStruct.fileInfo.canonicalPath()); for (auto entry : autoload->entries()) { if (entry->url().isEmpty() || entry->password().isEmpty()) { continue; @@ -756,17 +669,14 @@ void DatabaseTabWidget::lockDatabases() DatabaseWidget* dbWidget = static_cast(widget(i)); Database* db = databaseFromDatabaseWidget(dbWidget); - DatabaseWidget::Mode mode = dbWidget->currentMode(); - - if ((mode != DatabaseWidget::ViewMode && mode != DatabaseWidget::EditMode) - || !dbWidget->dbHasKey()) { + if (dbWidget->currentMode() == DatabaseWidget::LockedMode || !dbWidget->dbHasKey()) { continue; } // show the correct tab widget before we are asking questions about it setCurrentWidget(dbWidget); - if (mode == DatabaseWidget::EditMode && dbWidget->isEditWidgetModified()) { + if (dbWidget->currentMode() == DatabaseWidget::EditMode && dbWidget->isEditWidgetModified()) { QMessageBox::StandardButton result = MessageBox::question( this, tr("Lock database"), @@ -777,23 +687,7 @@ void DatabaseTabWidget::lockDatabases() } } - - if (m_dbList[db].modified && !m_dbList[db].saveToFilename) { - QMessageBox::StandardButton result = - MessageBox::question( - this, tr("Lock database"), - tr("This database has never been saved.\nYou can save the database or stop locking it."), - QMessageBox::Save | QMessageBox::Cancel, QMessageBox::Cancel); - if (result == QMessageBox::Save) { - if (!saveDatabase(db)) { - continue; - } - } - else if (result == QMessageBox::Cancel) { - continue; - } - } - else if (m_dbList[db].modified) { + if (m_dbList[db].modified) { QMessageBox::StandardButton result = MessageBox::question( this, tr("Lock database"), @@ -828,7 +722,7 @@ void DatabaseTabWidget::modified() Database* db = static_cast(sender()); DatabaseManagerStruct& dbStruct = m_dbList[db]; - if (config()->get("AutoSaveAfterEveryChange").toBool() && dbStruct.saveToFilename) { + if (config()->get("AutoSaveAfterEveryChange").toBool() && !dbStruct.readOnly) { saveDatabase(db); return; } diff --git a/src/gui/DatabaseTabWidget.h b/src/gui/DatabaseTabWidget.h index db237d98..875c3c90 100644 --- a/src/gui/DatabaseTabWidget.h +++ b/src/gui/DatabaseTabWidget.h @@ -21,6 +21,7 @@ #include #include +#include #include "gui/DatabaseWidget.h" #include "gui/MessageWidget.h" @@ -29,7 +30,6 @@ class DatabaseWidget; class DatabaseWidgetStateSync; class DatabaseOpenWidget; class QFile; -class QLockFile; class MessageWidget; struct DatabaseManagerStruct @@ -37,11 +37,7 @@ struct DatabaseManagerStruct DatabaseManagerStruct(); DatabaseWidget* dbWidget; - QLockFile* lockFile; - QString filePath; - QString canonicalFilePath; - QString fileName; - bool saveToFilename; + QFileInfo fileInfo; bool modified; bool readOnly; }; @@ -106,7 +102,7 @@ private slots: void emitDatabaseUnlockedFromDbWidgetSender(); private: - bool saveDatabase(Database* db); + bool saveDatabase(Database* db, QString filePath = ""); bool saveDatabaseAs(Database* db); bool closeDatabase(Database* db); void deleteDatabase(Database* db); diff --git a/src/gui/DatabaseWidget.cpp b/src/gui/DatabaseWidget.cpp index 387d5d2a..cc041d6f 100644 --- a/src/gui/DatabaseWidget.cpp +++ b/src/gui/DatabaseWidget.cpp @@ -839,10 +839,10 @@ void DatabaseWidget::openDatabase(bool accepted) m_databaseOpenWidget = nullptr; delete m_keepass1OpenWidget; m_keepass1OpenWidget = nullptr; - m_fileWatcher.addPath(m_filename); + m_fileWatcher.addPath(m_filePath); } else { - m_fileWatcher.removePath(m_filename); + m_fileWatcher.removePath(m_filePath); if (m_databaseOpenWidget->database()) { delete m_databaseOpenWidget->database(); } @@ -950,23 +950,23 @@ void DatabaseWidget::switchToDatabaseSettings() setCurrentWidget(m_databaseSettingsWidget); } -void DatabaseWidget::switchToOpenDatabase(const QString& fileName) +void DatabaseWidget::switchToOpenDatabase(const QString& filePath) { - updateFilename(fileName); + updateFilePath(filePath); if (m_databaseOpenWidget) { - m_databaseOpenWidget->load(fileName); + m_databaseOpenWidget->load(filePath); setCurrentWidget(m_databaseOpenWidget); } else if (m_unlockDatabaseWidget) { - m_unlockDatabaseWidget->load(fileName); + m_unlockDatabaseWidget->load(filePath); setCurrentWidget(m_unlockDatabaseWidget); } } -void DatabaseWidget::switchToOpenDatabase(const QString& fileName, const QString& password, +void DatabaseWidget::switchToOpenDatabase(const QString& filePath, const QString& password, const QString& keyFile) { - updateFilename(fileName); - switchToOpenDatabase(fileName); + updateFilePath(filePath); + switchToOpenDatabase(filePath); if (m_databaseOpenWidget) { m_databaseOpenWidget->enterKey(password, keyFile); } else if (m_unlockDatabaseWidget) { @@ -974,35 +974,35 @@ void DatabaseWidget::switchToOpenDatabase(const QString& fileName, const QString } } -void DatabaseWidget::switchToImportCsv(const QString& fileName) +void DatabaseWidget::switchToImportCsv(const QString& filePath) { - updateFilename(fileName); - m_csvImportWizard->load(fileName, m_db); + updateFilePath(filePath); + m_csvImportWizard->load(filePath, m_db); m_changeMasterKeyWidget->clearForms(); m_changeMasterKeyWidget->setCancelEnabled(false); setCurrentWidget(m_changeMasterKeyWidget); m_importingCsv = true; } -void DatabaseWidget::switchToOpenMergeDatabase(const QString& fileName) +void DatabaseWidget::switchToOpenMergeDatabase(const QString& filePath) { m_databaseOpenMergeWidget->clearForms(); - m_databaseOpenMergeWidget->load(fileName); + m_databaseOpenMergeWidget->load(filePath); setCurrentWidget(m_databaseOpenMergeWidget); } -void DatabaseWidget::switchToOpenMergeDatabase(const QString& fileName, const QString& password, +void DatabaseWidget::switchToOpenMergeDatabase(const QString& filePath, const QString& password, const QString& keyFile) { - switchToOpenMergeDatabase(fileName); + switchToOpenMergeDatabase(filePath); m_databaseOpenMergeWidget->enterKey(password, keyFile); } -void DatabaseWidget::switchToImportKeepass1(const QString& fileName) +void DatabaseWidget::switchToImportKeepass1(const QString& filePath) { - updateFilename(fileName); - m_keepass1OpenWidget->load(fileName); + updateFilePath(filePath); + m_keepass1OpenWidget->load(filePath); setCurrentWidget(m_keepass1OpenWidget); } @@ -1172,21 +1172,21 @@ void DatabaseWidget::lock() endSearch(); clearAllWidgets(); - m_unlockDatabaseWidget->load(m_filename); + m_unlockDatabaseWidget->load(m_filePath); setCurrentWidget(m_unlockDatabaseWidget); Database* newDb = new Database(); newDb->metadata()->setName(m_db->metadata()->name()); replaceDatabase(newDb); } -void DatabaseWidget::updateFilename(const QString& fileName) +void DatabaseWidget::updateFilePath(const QString &filePath) { - if (!m_filename.isEmpty()) { - m_fileWatcher.removePath(m_filename); + if (!m_filePath.isEmpty()) { + m_fileWatcher.removePath(m_filePath); } - m_fileWatcher.addPath(fileName); - m_filename = fileName; + m_fileWatcher.addPath(filePath); + m_filePath = filePath; } void DatabaseWidget::blockAutoReload(bool block) @@ -1202,7 +1202,7 @@ void DatabaseWidget::blockAutoReload(bool block) void DatabaseWidget::unblockAutoReload() { m_ignoreAutoReload = false; - updateFilename(m_filename); + updateFilePath(m_filePath); } void DatabaseWidget::onWatchedFileChanged() @@ -1237,13 +1237,13 @@ void DatabaseWidget::reloadDatabaseFile() emit m_db->modified(); m_databaseModified = true; // Rewatch the database file - m_fileWatcher.addPath(m_filename); + m_fileWatcher.addPath(m_filePath); return; } } KeePass2Reader reader; - QFile file(m_filename); + QFile file(m_filePath); if (file.open(QIODevice::ReadOnly)) { Database* db = reader.readDatabase(&file, database()->key()); if (db != nullptr) { @@ -1284,12 +1284,16 @@ void DatabaseWidget::reloadDatabaseFile() } } else { m_messageWidget->showMessage( - tr("Could not open the new database file while attempting to autoreload this database."), + tr("Could not open the new database file while attempting to autoreload this database.") + .append("\n").append(file.errorString()), MessageWidget::Error); + // HACK: Directly calling the database's signal + // Mark db as modified since existing data may differ from file or file was deleted + m_db->modified(); } // Rewatch the database file - m_fileWatcher.addPath(m_filename); + m_fileWatcher.addPath(m_filePath); } int DatabaseWidget::numberOfSelectedEntries() const @@ -1413,7 +1417,7 @@ EntryView* DatabaseWidget::entryView() { void DatabaseWidget::showUnlockDialog() { m_unlockDatabaseDialog->clearForms(); - m_unlockDatabaseDialog->setDBFilename(m_filename); + m_unlockDatabaseDialog->setFilePath(m_filePath); #if defined(Q_OS_MAC) autoType()->raiseWindow(); diff --git a/src/gui/DatabaseWidget.h b/src/gui/DatabaseWidget.h index e9428a70..3643bb03 100644 --- a/src/gui/DatabaseWidget.h +++ b/src/gui/DatabaseWidget.h @@ -82,7 +82,7 @@ public: void setCurrentWidget(QWidget* widget); DatabaseWidget::Mode currentMode() const; void lock(); - void updateFilename(const QString& filename); + void updateFilePath(const QString &filePath); int numberOfSelectedEntries() const; QStringList customEntryAttributes() const; bool isGroupSelected() const; @@ -155,13 +155,13 @@ public slots: void switchToGroupEdit(); void switchToMasterKeyChange(bool disableCancel = false); void switchToDatabaseSettings(); - void switchToOpenDatabase(const QString& fileName); - void switchToOpenDatabase(const QString& fileName, const QString& password, const QString& keyFile); - void switchToImportCsv(const QString& fileName); + void switchToOpenDatabase(const QString& filePath); + void switchToOpenDatabase(const QString& filePath, const QString& password, const QString& keyFile); + void switchToImportCsv(const QString& filePath); void csvImportFinished(bool accepted); - void switchToOpenMergeDatabase(const QString& fileName); - void switchToOpenMergeDatabase(const QString& fileName, const QString& password, const QString& keyFile); - void switchToImportKeepass1(const QString& fileName); + void switchToOpenMergeDatabase(const QString& filePath); + void switchToOpenMergeDatabase(const QString& filePath, const QString& password, const QString& keyFile); + void switchToImportKeepass1(const QString& filePath); void databaseModified(); void databaseSaved(); void emptyRecycleBin(); @@ -225,7 +225,7 @@ private: Group* m_newGroup; Entry* m_newEntry; Group* m_newParent; - QString m_filename; + QString m_filePath; Uuid m_groupBeforeLock; Uuid m_entryBeforeLock; MessageWidget* m_messageWidget; diff --git a/src/gui/UnlockDatabaseDialog.cpp b/src/gui/UnlockDatabaseDialog.cpp index a0c91546..cea5918a 100644 --- a/src/gui/UnlockDatabaseDialog.cpp +++ b/src/gui/UnlockDatabaseDialog.cpp @@ -30,9 +30,9 @@ UnlockDatabaseDialog::UnlockDatabaseDialog(QWidget* parent) connect(m_view, SIGNAL(editFinished(bool)), this, SLOT(complete(bool))); } -void UnlockDatabaseDialog::setDBFilename(const QString& filename) +void UnlockDatabaseDialog::setFilePath(const QString &filePath) { - m_view->load(filename); + m_view->load(filePath); } void UnlockDatabaseDialog::clearForms() diff --git a/src/gui/UnlockDatabaseDialog.h b/src/gui/UnlockDatabaseDialog.h index ef2eabb3..7dec0676 100644 --- a/src/gui/UnlockDatabaseDialog.h +++ b/src/gui/UnlockDatabaseDialog.h @@ -32,7 +32,7 @@ class UnlockDatabaseDialog : public QDialog Q_OBJECT public: explicit UnlockDatabaseDialog(QWidget* parent = nullptr); - void setDBFilename(const QString& filename); + void setFilePath(const QString &filePath); void clearForms(); Database* database();