diff --git a/CMakeLists.txt b/CMakeLists.txt index 28deb054f..8c901045d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -149,9 +149,9 @@ elseif(APPLE) else() include(GNUInstallDirs) - set(BIN_INSTALL_DIR "${CMAKE_INSTALL_BINDIR}") - set(PLUGIN_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/keepassx") - set(DATA_INSTALL_DIR "${CMAKE_INSTALL_DATAROOTDIR}/keepassx") + set(BIN_INSTALL_DIR "${CMAKE_INSTALL_FULL_BINDIR}") + set(PLUGIN_INSTALL_DIR "${CMAKE_INSTALL_FULL_LIBDIR}/keepassx") + set(DATA_INSTALL_DIR "${CMAKE_INSTALL_FULL_DATADIR}/keepassx") endif() if(WITH_TESTS) diff --git a/src/config-keepassx.h.cmake b/src/config-keepassx.h.cmake index 805700a9f..305da341f 100644 --- a/src/config-keepassx.h.cmake +++ b/src/config-keepassx.h.cmake @@ -10,6 +10,8 @@ #define KEEPASSX_PLUGIN_DIR "${PLUGIN_INSTALL_DIR}" +#define KEEPASSX_DATA_DIR "${DATA_INSTALL_DIR}" + #cmakedefine HAVE_PR_SET_DUMPABLE 1 #cmakedefine HAVE_RLIMIT_CORE 1 #cmakedefine HAVE_PT_DENY_ATTACH 1 diff --git a/src/core/FilePath.cpp b/src/core/FilePath.cpp index 52db1ed28..e414fdec1 100644 --- a/src/core/FilePath.cpp +++ b/src/core/FilePath.cpp @@ -173,6 +173,8 @@ FilePath::FilePath() #if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) else if (testSetDir(QCoreApplication::applicationDirPath() + "/../share/keepassx")) { } + else if (testSetDir(KEEPASSX_DATA_DIR)) { + } #endif #ifdef Q_OS_MAC else if (testSetDir(QCoreApplication::applicationDirPath() + "/../Resources")) { diff --git a/src/core/Group.cpp b/src/core/Group.cpp index e96b857ba..57e0bae95 100644 --- a/src/core/Group.cpp +++ b/src/core/Group.cpp @@ -434,6 +434,20 @@ QList Group::groupsRecursive(bool includeSelf) const groupList.append(this); } + Q_FOREACH (const Group* group, m_children) { + groupList.append(group->groupsRecursive(true)); + } + + return groupList; +} + +QList Group::groupsRecursive(bool includeSelf) +{ + QList groupList; + if (includeSelf) { + groupList.append(this); + } + Q_FOREACH (Group* group, m_children) { groupList.append(group->groupsRecursive(true)); } diff --git a/src/core/Group.h b/src/core/Group.h index 7391f886d..3d3618044 100644 --- a/src/core/Group.h +++ b/src/core/Group.h @@ -101,6 +101,7 @@ public: const QList& entries() const; QList entriesRecursive(bool includeHistoryItems = false) const; QList groupsRecursive(bool includeSelf) const; + QList groupsRecursive(bool includeSelf); QSet customIconsRecursive() const; /** * Creates a duplicate of this group including all child entries and groups. diff --git a/src/core/Metadata.cpp b/src/core/Metadata.cpp index 402734c7b..3256ca05e 100644 --- a/src/core/Metadata.cpp +++ b/src/core/Metadata.cpp @@ -347,9 +347,9 @@ void Metadata::addCustomIconScaled(const Uuid& uuid, const QImage& icon) { QImage iconScaled; - // scale down to 64x64 if icon is larger - if (icon.width() > 64 || icon.height() > 64) { - iconScaled = icon.scaled(QSize(64, 64), Qt::KeepAspectRatio, + // scale down to 128x128 if icon is larger + if (icon.width() > 128 || icon.height() > 128) { + iconScaled = icon.scaled(QSize(128, 128), Qt::KeepAspectRatio, Qt::SmoothTransformation); } else { diff --git a/src/gui/DatabaseTabWidget.cpp b/src/gui/DatabaseTabWidget.cpp index 7f9984615..db9e034a7 100644 --- a/src/gui/DatabaseTabWidget.cpp +++ b/src/gui/DatabaseTabWidget.cpp @@ -256,7 +256,7 @@ bool DatabaseTabWidget::closeAllDatabases() return true; } -void DatabaseTabWidget::saveDatabase(Database* db) +bool DatabaseTabWidget::saveDatabase(Database* db) { DatabaseManagerStruct& dbStruct = m_dbList[db]; @@ -272,18 +272,20 @@ void DatabaseTabWidget::saveDatabase(Database* db) if (result) { dbStruct.modified = false; updateTabName(db); + return true; } else { MessageBox::critical(this, tr("Error"), tr("Writing the database failed.") + "\n\n" + saveFile.errorString()); + return false; } } else { - saveDatabaseAs(db); + return saveDatabaseAs(db); } } -void DatabaseTabWidget::saveDatabaseAs(Database* db) +bool DatabaseTabWidget::saveDatabaseAs(Database* db) { DatabaseManagerStruct& dbStruct = m_dbList[db]; QString oldFileName; @@ -311,12 +313,17 @@ void DatabaseTabWidget::saveDatabaseAs(Database* db) dbStruct.dbWidget->updateFilename(dbStruct.filePath); updateTabName(db); updateLastDatabases(dbStruct.filePath); + return true; } else { MessageBox::critical(this, tr("Error"), tr("Writing the database failed.") + "\n\n" + saveFile.errorString()); + return false; } } + else { + return false; + } } bool DatabaseTabWidget::closeDatabase(int index) @@ -340,21 +347,22 @@ void DatabaseTabWidget::closeDatabaseFromSender() closeDatabase(db); } -void DatabaseTabWidget::saveDatabase(int index) +bool DatabaseTabWidget::saveDatabase(int index) { if (index == -1) { index = currentIndex(); } - saveDatabase(indexDatabase(index)); + return saveDatabase(indexDatabase(index)); } -void DatabaseTabWidget::saveDatabaseAs(int index) +bool DatabaseTabWidget::saveDatabaseAs(int index) { if (index == -1) { index = currentIndex(); } - saveDatabaseAs(indexDatabase(index)); + + return saveDatabaseAs(indexDatabase(index)); } void DatabaseTabWidget::changeMasterKey() @@ -525,16 +533,69 @@ bool DatabaseTabWidget::hasLockableDatabases() const void DatabaseTabWidget::lockDatabases() { - QHashIterator i(m_dbList); - while (i.hasNext()) { - i.next(); - DatabaseWidget::Mode mode = i.value().dbWidget->currentMode(); + for (int i = 0; i < count(); i++) { + DatabaseWidget* dbWidget = static_cast(widget(i)); + Database* db = databaseFromDatabaseWidget(dbWidget); - if ((mode == DatabaseWidget::ViewMode || mode == DatabaseWidget::EditMode) - && i.value().dbWidget->dbHasKey()) { - i.value().dbWidget->lock(); - updateTabName(i.key()); + DatabaseWidget::Mode mode = dbWidget->currentMode(); + + if ((mode != DatabaseWidget::ViewMode && mode != DatabaseWidget::EditMode) + || !dbWidget->dbHasKey()) { + continue; } + + // show the correct tab widget before we are asking questions about it + setCurrentWidget(dbWidget); + + if (mode == DatabaseWidget::EditMode) { + QMessageBox::StandardButton result = + MessageBox::question( + this, tr("Lock database"), + tr("Can't lock the database as you are currently editing it.\nPlease press cancel to finish your changes or discard them."), + QMessageBox::Discard | QMessageBox::Cancel, QMessageBox::Cancel); + if (result == QMessageBox::Cancel) { + continue; + } + } + + + 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 dabatase 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) { + QMessageBox::StandardButton result = + MessageBox::question( + this, tr("Lock database"), + tr("This database has been modified.\nDo you want to save the database before locking it?\nOtherwise your changes are lost."), + QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel, QMessageBox::Cancel); + if (result == QMessageBox::Save) { + if (!saveDatabase(db)) { + continue; + } + } + else if (result == QMessageBox::Discard) { + m_dbList[db].modified = false; + } + else if (result == QMessageBox::Cancel) { + continue; + } + } + + dbWidget->lock(); + // database has changed so we can't use the db variable anymore + updateTabName(dbWidget->database()); } } diff --git a/src/gui/DatabaseTabWidget.h b/src/gui/DatabaseTabWidget.h index 25d34f304..dc5f1b139 100644 --- a/src/gui/DatabaseTabWidget.h +++ b/src/gui/DatabaseTabWidget.h @@ -62,8 +62,8 @@ public Q_SLOTS: void newDatabase(); void openDatabase(); void importKeePass1Database(); - void saveDatabase(int index = -1); - void saveDatabaseAs(int index = -1); + bool saveDatabase(int index = -1); + bool saveDatabaseAs(int index = -1); bool closeDatabase(int index = -1); void closeDatabaseFromSender(); bool closeAllDatabases(); @@ -88,8 +88,8 @@ private Q_SLOTS: void emitActivateDatabaseChanged(); private: - void saveDatabase(Database* db); - void saveDatabaseAs(Database* db); + bool saveDatabase(Database* db); + bool saveDatabaseAs(Database* db); bool closeDatabase(Database* db); void deleteDatabase(Database* db); int databaseIndex(Database* db); diff --git a/src/gui/DatabaseWidget.cpp b/src/gui/DatabaseWidget.cpp index dd63b4df2..369c69037 100644 --- a/src/gui/DatabaseWidget.cpp +++ b/src/gui/DatabaseWidget.cpp @@ -188,14 +188,7 @@ DatabaseWidget::Mode DatabaseWidget::currentMode() const bool DatabaseWidget::isInEditMode() const { - if (currentMode() == DatabaseWidget::LockedMode) { - return m_widgetBeforeLock != Q_NULLPTR - && m_widgetBeforeLock != m_mainWidget - && m_widgetBeforeLock != m_unlockDatabaseWidget; - } - else { - return currentMode() == DatabaseWidget::EditMode; - } + return currentMode() == DatabaseWidget::EditMode; } QList DatabaseWidget::splitterSizes() const @@ -231,6 +224,13 @@ void DatabaseWidget::setEntryViewHeaderSizes(const QList& sizes) } } +void DatabaseWidget::clearAllWidgets() +{ + m_editEntryWidget->clear(); + m_historyEditEntryWidget->clear(); + m_editGroupWidget->clear(); +} + void DatabaseWidget::emitCurrentModeChanged() { Q_EMIT currentModeChanged(currentMode()); @@ -274,6 +274,15 @@ void DatabaseWidget::setIconFromParent() } } +void DatabaseWidget::replaceDatabase(Database* db) +{ + Database* oldDb = m_db; + m_db = db; + m_groupView->changeDatabase(m_db); + Q_EMIT databaseChanged(m_db); + delete oldDb; +} + void DatabaseWidget::cloneEntry() { Entry* currentEntry = m_entryView->currentEntry(); @@ -604,11 +613,7 @@ void DatabaseWidget::updateMasterKey(bool accepted) void DatabaseWidget::openDatabase(bool accepted) { if (accepted) { - Database* oldDb = m_db; - m_db = static_cast(sender())->database(); - m_groupView->changeDatabase(m_db); - Q_EMIT databaseChanged(m_db); - delete oldDb; + replaceDatabase(static_cast(sender())->database()); setCurrentWidget(m_mainWidget); // We won't need those anymore and KeePass1OpenWidget closes @@ -628,11 +633,24 @@ void DatabaseWidget::openDatabase(bool accepted) void DatabaseWidget::unlockDatabase(bool accepted) { - // cancel button is disabled - Q_ASSERT(accepted); - Q_UNUSED(accepted); + if (!accepted) { + Q_EMIT closeRequest(); + return; + } - setCurrentWidget(m_widgetBeforeLock); + replaceDatabase(static_cast(sender())->database()); + + QList groups = m_db->rootGroup()->groupsRecursive(true); + Q_FOREACH (Group* group, groups) { + if (group->uuid() == m_groupBeforeLock) { + m_groupView->setCurrentGroup(group); + break; + } + } + + m_groupBeforeLock = Uuid(); + setCurrentWidget(m_mainWidget); + m_unlockDatabaseWidget->clearForms(); Q_EMIT unlockedDatabase(); } @@ -855,9 +873,13 @@ void DatabaseWidget::lock() { Q_ASSERT(currentMode() != DatabaseWidget::LockedMode); - m_widgetBeforeLock = currentWidget(); - m_unlockDatabaseWidget->load(m_filename, m_db); + m_groupBeforeLock = m_groupView->currentGroup()->uuid(); + clearAllWidgets(); + m_unlockDatabaseWidget->load(m_filename); setCurrentWidget(m_unlockDatabaseWidget); + Database* newDb = new Database(); + newDb->metadata()->setName(m_db->metadata()->name()); + replaceDatabase(newDb); } void DatabaseWidget::updateFilename(const QString& fileName) diff --git a/src/gui/DatabaseWidget.h b/src/gui/DatabaseWidget.h index 45de74629..a38af731e 100644 --- a/src/gui/DatabaseWidget.h +++ b/src/gui/DatabaseWidget.h @@ -22,6 +22,7 @@ #include #include "core/Global.h" +#include "core/Uuid.h" #include "gui/entry/EntryModel.h" @@ -78,6 +79,7 @@ public: void setSplitterSizes(const QList& sizes); QList entryHeaderViewSizes() const; void setEntryViewHeaderSizes(const QList& sizes); + void clearAllWidgets(); Q_SIGNALS: void closeRequest(); @@ -143,6 +145,7 @@ private Q_SLOTS: private: void setClipboardTextAndMinimize(const QString& text); void setIconFromParent(); + void replaceDatabase(Database* db); Database* m_db; const QScopedPointer m_searchUi; @@ -164,8 +167,8 @@ private: Group* m_newParent; Group* m_lastGroup; QTimer* m_searchTimer; - QWidget* m_widgetBeforeLock; QString m_filename; + Uuid m_groupBeforeLock; }; #endif // KEEPASSX_DATABASEWIDGET_H diff --git a/src/gui/EditWidgetIcons.cpp b/src/gui/EditWidgetIcons.cpp index bcc36077f..5ea4db736 100644 --- a/src/gui/EditWidgetIcons.cpp +++ b/src/gui/EditWidgetIcons.cpp @@ -168,7 +168,7 @@ void EditWidgetIcons::removeCustomIcon() } } - QList allGroups = m_database->rootGroup()->groupsRecursive(true); + QList allGroups = m_database->rootGroup()->groupsRecursive(true); Q_FOREACH (const Group* group, allGroups) { if (iconUuid == group->iconUuid() && m_currentUuid != group->uuid()) { iconUsedCount++; diff --git a/src/gui/MainWindow.ui b/src/gui/MainWindow.ui index 09e1c412e..eb7001cdf 100644 --- a/src/gui/MainWindow.ui +++ b/src/gui/MainWindow.ui @@ -15,7 +15,16 @@ - + + 0 + + + 0 + + + 0 + + 0 @@ -25,7 +34,16 @@ - + + 0 + + + 0 + + + 0 + + 0 @@ -45,7 +63,16 @@ - + + 0 + + + 0 + + + 0 + + 0 @@ -94,7 +121,6 @@ - @@ -138,10 +164,11 @@ - + - Extras + Tools + @@ -153,7 +180,7 @@ - + diff --git a/src/gui/UnlockDatabaseWidget.cpp b/src/gui/UnlockDatabaseWidget.cpp index 7ad089a94..944198be1 100644 --- a/src/gui/UnlockDatabaseWidget.cpp +++ b/src/gui/UnlockDatabaseWidget.cpp @@ -25,33 +25,6 @@ UnlockDatabaseWidget::UnlockDatabaseWidget(QWidget* parent) : DatabaseOpenWidget(parent) { m_ui->labelHeadline->setText(tr("Unlock database")); - - m_ui->buttonBox->removeButton(m_ui->buttonBox->button(QDialogButtonBox::Cancel)); - connect(this, SIGNAL(editFinished(bool)), SLOT(clearForms())); -} - -void UnlockDatabaseWidget::load(const QString& filename, Database* db) -{ - Q_ASSERT(db); - - DatabaseOpenWidget::load(filename); - m_db = db; -} - -void UnlockDatabaseWidget::openDatabase() -{ - CompositeKey masterKey = databaseKey(); - if (masterKey.isEmpty()) { - return; - } - - if (m_db->verifyKey(masterKey)) { - Q_EMIT editFinished(true); - } - else { - MessageBox::warning(this, tr("Error"), tr("Wrong key.")); - m_ui->editPassword->clear(); - } } void UnlockDatabaseWidget::clearForms() @@ -60,4 +33,5 @@ void UnlockDatabaseWidget::clearForms() m_ui->comboKeyFile->clear(); m_ui->checkPassword->setChecked(false); m_ui->checkKeyFile->setChecked(false); + m_db = Q_NULLPTR; } diff --git a/src/gui/UnlockDatabaseWidget.h b/src/gui/UnlockDatabaseWidget.h index c6ae5a702..052578b76 100644 --- a/src/gui/UnlockDatabaseWidget.h +++ b/src/gui/UnlockDatabaseWidget.h @@ -26,12 +26,6 @@ class UnlockDatabaseWidget : public DatabaseOpenWidget public: explicit UnlockDatabaseWidget(QWidget* parent = Q_NULLPTR); - void load(const QString& filename, Database* db); - -protected: - void openDatabase() Q_DECL_OVERRIDE; - -private Q_SLOTS: void clearForms(); }; diff --git a/src/gui/entry/EditEntryWidget.cpp b/src/gui/entry/EditEntryWidget.cpp index 9621ca9e4..e95f2e79d 100644 --- a/src/gui/entry/EditEntryWidget.cpp +++ b/src/gui/entry/EditEntryWidget.cpp @@ -453,12 +453,7 @@ void EditEntryWidget::saveEntry() } - m_entry = Q_NULLPTR; - m_database = Q_NULLPTR; - m_entryAttributes->clear(); - m_entryAttachments->clear(); - m_autoTypeAssoc->clear(); - m_historyModel->clear(); + clear(); Q_EMIT editFinished(true); } @@ -466,12 +461,8 @@ void EditEntryWidget::saveEntry() void EditEntryWidget::cancel() { if (m_history) { - m_entry = Q_NULLPTR; - m_database = Q_NULLPTR; - m_entryAttributes->clear(); - m_entryAttachments->clear(); + clear(); Q_EMIT editFinished(false); - return; } if (!m_entry->iconUuid().isNull() && @@ -479,14 +470,19 @@ void EditEntryWidget::cancel() m_entry->setIcon(Entry::DefaultIconNumber); } - m_entry = 0; - m_database = 0; + clear(); + + Q_EMIT editFinished(false); +} + +void EditEntryWidget::clear() +{ + m_entry = Q_NULLPTR; + m_database = Q_NULLPTR; m_entryAttributes->clear(); m_entryAttachments->clear(); m_autoTypeAssoc->clear(); m_historyModel->clear(); - - Q_EMIT editFinished(false); } void EditEntryWidget::togglePasswordGeneratorButton(bool checked) diff --git a/src/gui/entry/EditEntryWidget.h b/src/gui/entry/EditEntryWidget.h index 144347629..03811bf82 100644 --- a/src/gui/entry/EditEntryWidget.h +++ b/src/gui/entry/EditEntryWidget.h @@ -60,6 +60,7 @@ public: void createPresetsMenu(QMenu* expirePresetsMenu); QString entryTitle() const; + void clear(); Q_SIGNALS: void editFinished(bool accepted); diff --git a/src/gui/entry/EntryModel.cpp b/src/gui/entry/EntryModel.cpp index 369a4abb0..7ee1df8fb 100644 --- a/src/gui/entry/EntryModel.cpp +++ b/src/gui/entry/EntryModel.cpp @@ -85,7 +85,10 @@ void EntryModel::setEntryList(const QList& entries) Q_FOREACH (Database* db, databases) { Q_ASSERT(db); - m_allGroups.append(db->rootGroup()->groupsRecursive(true)); + Q_FOREACH (const Group* group, db->rootGroup()->groupsRecursive(true)) { + m_allGroups.append(group); + } + if (db->metadata()->recycleBin()) { m_allGroups.removeOne(db->metadata()->recycleBin()); } diff --git a/src/gui/group/EditGroupWidget.cpp b/src/gui/group/EditGroupWidget.cpp index b26fe4c97..092af4a06 100644 --- a/src/gui/group/EditGroupWidget.cpp +++ b/src/gui/group/EditGroupWidget.cpp @@ -109,8 +109,7 @@ void EditGroupWidget::save() m_group->setIcon(iconStruct.uuid); } - m_group = Q_NULLPTR; - m_database = Q_NULLPTR; + clear(); Q_EMIT editFinished(true); } @@ -121,9 +120,14 @@ void EditGroupWidget::cancel() m_group->setIcon(Entry::DefaultIconNumber); } + clear(); + Q_EMIT editFinished(false); +} + +void EditGroupWidget::clear() +{ m_group = Q_NULLPTR; m_database = Q_NULLPTR; - Q_EMIT editFinished(false); } void EditGroupWidget::addTriStateItems(QComboBox* comboBox, bool inheritDefault) diff --git a/src/gui/group/EditGroupWidget.h b/src/gui/group/EditGroupWidget.h index 971b6de20..c6d91a564 100644 --- a/src/gui/group/EditGroupWidget.h +++ b/src/gui/group/EditGroupWidget.h @@ -41,6 +41,7 @@ public: ~EditGroupWidget(); void loadGroup(Group* group, bool create, Database* database); + void clear(); Q_SIGNALS: void editFinished(bool accepted); diff --git a/tests/gui/TestGui.cpp b/tests/gui/TestGui.cpp index 26c8be077..c3d95b35e 100644 --- a/tests/gui/TestGui.cpp +++ b/tests/gui/TestGui.cpp @@ -421,10 +421,12 @@ void TestGui::testKeePass1Import() void TestGui::testDatabaseLocking() { + MessageBox::setNextAnswer(QMessageBox::Cancel); + triggerAction("actionLockDatabases"); QCOMPARE(m_tabWidget->tabText(0), QString("Save [locked]")); - QCOMPARE(m_tabWidget->tabText(1), QString("basic [New database] [locked]*")); + QCOMPARE(m_tabWidget->tabText(1), QString("basic [New database]*")); QWidget* dbWidget = m_tabWidget->currentDatabaseWidget(); QWidget* unlockDatabaseWidget = dbWidget->findChild("unlockDatabaseWidget");