keepassxc/src/gui/MainWindow.cpp

814 lines
31 KiB
C++
Raw Normal View History

2010-09-19 10:59:32 -04:00
/*
* Copyright (C) 2010 Felix Geyer <debfx@fobos.de>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "MainWindow.h"
#include "ui_MainWindow.h"
2010-09-19 10:59:32 -04:00
#include <QCloseEvent>
#include <QShortcut>
#include <QTimer>
#if defined(Q_OS_LINUX) && ! defined(QT_NO_DBUS)
#include <QList>
#include <QtDBus/QtDBus>
#endif
#include "config-keepassx.h"
#include "autotype/AutoType.h"
#include "core/Config.h"
2012-07-18 14:44:28 -04:00
#include "core/FilePath.h"
#include "core/InactivityTimer.h"
2010-09-19 10:59:32 -04:00
#include "core/Metadata.h"
#include "format/KeePass2Writer.h"
2012-05-02 09:37:21 -04:00
#include "gui/AboutDialog.h"
2011-07-08 08:51:14 -04:00
#include "gui/DatabaseWidget.h"
#include "gui/DatabaseRepairWidget.h"
#include "gui/FileDialog.h"
#include "gui/MessageBox.h"
#include "gui/SearchWidget.h"
2010-09-19 10:59:32 -04:00
#ifdef WITH_XC_HTTP
#include "http/Service.h"
#include "http/HttpSettings.h"
#include "http/OptionDialog.h"
#endif
#include "gui/SettingsWidget.h"
#include "gui/PasswordGeneratorWidget.h"
#ifdef WITH_XC_HTTP
class HttpPlugin: public ISettingsPage
{
public:
HttpPlugin(DatabaseTabWidget * tabWidget) {
m_service = new Service(tabWidget);
}
virtual ~HttpPlugin() {
//delete m_service;
}
virtual QString name() {
return QObject::tr("Http");
}
virtual QWidget * createWidget() {
OptionDialog * dlg = new OptionDialog();
QObject::connect(dlg, SIGNAL(removeSharedEncryptionKeys()), m_service, SLOT(removeSharedEncryptionKeys()));
QObject::connect(dlg, SIGNAL(removeStoredPermissions()), m_service, SLOT(removeStoredPermissions()));
return dlg;
}
virtual void loadSettings(QWidget * widget) {
qobject_cast<OptionDialog*>(widget)->loadSettings();
}
virtual void saveSettings(QWidget * widget) {
qobject_cast<OptionDialog*>(widget)->saveSettings();
if (HttpSettings::isEnabled())
m_service->start();
else
m_service->stop();
}
private:
Service *m_service;
};
#endif
const QString MainWindow::BaseWindowTitle = "KeePassXC";
2012-08-01 04:40:18 -04:00
2010-09-19 10:59:32 -04:00
MainWindow::MainWindow()
: m_ui(new Ui::MainWindow())
2015-07-24 12:28:12 -04:00
, m_trayIcon(nullptr)
2010-09-19 10:59:32 -04:00
{
appExitCalled = false;
m_ui->setupUi(this);
2010-09-19 10:59:32 -04:00
// Setup the search widget in the toolbar
SearchWidget *search = new SearchWidget();
search->connectSignals(m_actionMultiplexer);
m_searchWidgetAction = m_ui->toolBar->addWidget(search);
m_searchWidgetAction->setEnabled(false);
m_countDefaultAttributes = m_ui->menuEntryCopyAttribute->actions().size();
restoreGeometry(config()->get("GUI/MainWindowGeometry").toByteArray());
#ifdef WITH_XC_HTTP
m_ui->settingsWidget->addSettingsPage(new HttpPlugin(m_ui->tabWidget));
#endif
2014-03-22 07:21:49 -04:00
2012-07-18 14:44:28 -04:00
setWindowIcon(filePath()->applicationIcon());
QAction* toggleViewAction = m_ui->toolBar->toggleViewAction();
toggleViewAction->setText(tr("Show toolbar"));
m_ui->menuView->addAction(toggleViewAction);
bool showToolbar = config()->get("ShowToolbar").toBool();
m_ui->toolBar->setVisible(showToolbar);
connect(m_ui->toolBar, SIGNAL(visibilityChanged(bool)), this, SLOT(saveToolbarState(bool)));
2012-01-05 16:27:08 -05:00
m_clearHistoryAction = new QAction("Clear history", m_ui->menuFile);
m_lastDatabasesActions = new QActionGroup(m_ui->menuRecentDatabases);
connect(m_clearHistoryAction, SIGNAL(triggered()), this, SLOT(clearLastDatabases()));
connect(m_lastDatabasesActions, SIGNAL(triggered(QAction*)), this, SLOT(openRecentDatabase(QAction*)));
connect(m_ui->menuRecentDatabases, SIGNAL(aboutToShow()), this, SLOT(updateLastDatabasesMenu()));
m_copyAdditionalAttributeActions = new QActionGroup(m_ui->menuEntryCopyAttribute);
m_actionMultiplexer.connect(m_copyAdditionalAttributeActions, SIGNAL(triggered(QAction*)),
SLOT(copyAttribute(QAction*)));
connect(m_ui->menuEntryCopyAttribute, SIGNAL(aboutToShow()),
this, SLOT(updateCopyAttributesMenu()));
Qt::Key globalAutoTypeKey = static_cast<Qt::Key>(config()->get("GlobalAutoTypeKey").toInt());
Qt::KeyboardModifiers globalAutoTypeModifiers = static_cast<Qt::KeyboardModifiers>(
config()->get("GlobalAutoTypeModifiers").toInt());
if (globalAutoTypeKey > 0 && globalAutoTypeModifiers > 0) {
autoType()->registerGlobalShortcut(globalAutoTypeKey, globalAutoTypeModifiers);
}
m_ui->actionEntryAutoType->setVisible(autoType()->isAvailable());
m_inactivityTimer = new InactivityTimer(this);
connect(m_inactivityTimer, SIGNAL(inactivityDetected()),
this, SLOT(lockDatabasesAfterInactivity()));
applySettingsChanges();
2012-05-15 12:16:04 -04:00
setShortcut(m_ui->actionDatabaseOpen, QKeySequence::Open, Qt::CTRL + Qt::Key_O);
setShortcut(m_ui->actionDatabaseSave, QKeySequence::Save, Qt::CTRL + Qt::Key_S);
setShortcut(m_ui->actionDatabaseSaveAs, QKeySequence::SaveAs);
setShortcut(m_ui->actionDatabaseClose, QKeySequence::Close, Qt::CTRL + Qt::Key_W);
2012-10-12 06:12:00 -04:00
m_ui->actionLockDatabases->setShortcut(Qt::CTRL + Qt::Key_L);
2012-05-15 12:16:04 -04:00
setShortcut(m_ui->actionQuit, QKeySequence::Quit, Qt::CTRL + Qt::Key_Q);
m_ui->actionEntryNew->setShortcut(Qt::CTRL + Qt::Key_N);
m_ui->actionEntryEdit->setShortcut(Qt::CTRL + Qt::Key_E);
m_ui->actionEntryDelete->setShortcut(Qt::CTRL + Qt::Key_D);
m_ui->actionEntryClone->setShortcut(Qt::CTRL + Qt::Key_K);
m_ui->actionEntryCopyUsername->setShortcut(Qt::CTRL + Qt::Key_B);
m_ui->actionEntryCopyPassword->setShortcut(Qt::CTRL + Qt::Key_C);
2012-07-12 16:35:51 -04:00
setShortcut(m_ui->actionEntryAutoType, QKeySequence::Paste, Qt::CTRL + Qt::Key_V);
m_ui->actionEntryOpenUrl->setShortcut(Qt::CTRL + Qt::Key_U);
m_ui->actionEntryCopyURL->setShortcut(Qt::CTRL + Qt::ALT + Qt::Key_U);
2012-05-15 12:16:04 -04:00
new QShortcut(Qt::CTRL + Qt::Key_M, this, SLOT(showMinimized()));
2012-07-18 14:44:28 -04:00
m_ui->actionDatabaseNew->setIcon(filePath()->icon("actions", "document-new"));
m_ui->actionDatabaseOpen->setIcon(filePath()->icon("actions", "document-open"));
m_ui->actionDatabaseSave->setIcon(filePath()->icon("actions", "document-save"));
m_ui->actionDatabaseSaveAs->setIcon(filePath()->icon("actions", "document-save-as"));
m_ui->actionDatabaseClose->setIcon(filePath()->icon("actions", "document-close"));
m_ui->actionChangeDatabaseSettings->setIcon(filePath()->icon("actions", "document-edit"));
m_ui->actionChangeMasterKey->setIcon(filePath()->icon("actions", "database-change-key", false));
2012-10-12 06:12:00 -04:00
m_ui->actionLockDatabases->setIcon(filePath()->icon("actions", "document-encrypt", false));
2012-07-18 14:44:28 -04:00
m_ui->actionQuit->setIcon(filePath()->icon("actions", "application-exit"));
2012-05-27 09:39:32 -04:00
2012-07-18 14:44:28 -04:00
m_ui->actionEntryNew->setIcon(filePath()->icon("actions", "entry-new", false));
m_ui->actionEntryClone->setIcon(filePath()->icon("actions", "entry-clone", false));
m_ui->actionEntryEdit->setIcon(filePath()->icon("actions", "entry-edit", false));
m_ui->actionEntryDelete->setIcon(filePath()->icon("actions", "entry-delete", false));
2013-03-22 14:51:39 -04:00
m_ui->actionEntryAutoType->setIcon(filePath()->icon("actions", "auto-type", false));
m_ui->actionEntryCopyUsername->setIcon(filePath()->icon("actions", "username-copy", false));
m_ui->actionEntryCopyPassword->setIcon(filePath()->icon("actions", "password-copy", false));
2012-05-27 06:46:22 -04:00
2012-07-18 14:44:28 -04:00
m_ui->actionGroupNew->setIcon(filePath()->icon("actions", "group-new", false));
m_ui->actionGroupEdit->setIcon(filePath()->icon("actions", "group-edit", false));
m_ui->actionGroupDelete->setIcon(filePath()->icon("actions", "group-delete", false));
2012-05-27 09:39:32 -04:00
2012-07-18 14:44:28 -04:00
m_ui->actionSettings->setIcon(filePath()->icon("actions", "configure"));
m_ui->actionPasswordGenerator->setIcon(filePath()->icon("actions", "password-generator", false));
2012-05-27 09:39:32 -04:00
2012-07-18 14:44:28 -04:00
m_ui->actionAbout->setIcon(filePath()->icon("actions", "help-about"));
2012-05-27 13:54:18 -04:00
m_actionMultiplexer.connect(SIGNAL(currentModeChanged(DatabaseWidget::Mode)),
this, SLOT(setMenuActionState(DatabaseWidget::Mode)));
m_actionMultiplexer.connect(SIGNAL(groupChanged()),
this, SLOT(setMenuActionState()));
m_actionMultiplexer.connect(SIGNAL(entrySelectionChanged()),
this, SLOT(setMenuActionState()));
m_actionMultiplexer.connect(SIGNAL(groupContextMenuRequested(QPoint)),
this, SLOT(showGroupContextMenu(QPoint)));
m_actionMultiplexer.connect(SIGNAL(entryContextMenuRequested(QPoint)),
this, SLOT(showEntryContextMenu(QPoint)));
// Notify search when the active database changes
connect(m_ui->tabWidget, SIGNAL(activateDatabaseChanged(DatabaseWidget*)),
search, SLOT(databaseChanged(DatabaseWidget*)));
2012-04-25 14:22:55 -04:00
connect(m_ui->tabWidget, SIGNAL(tabNameChanged()),
SLOT(updateWindowTitle()));
connect(m_ui->tabWidget, SIGNAL(currentChanged(int)),
SLOT(updateWindowTitle()));
connect(m_ui->tabWidget, SIGNAL(currentChanged(int)),
SLOT(databaseTabChanged(int)));
connect(m_ui->tabWidget, SIGNAL(currentChanged(int)),
SLOT(setMenuActionState()));
2016-10-08 12:55:05 -04:00
connect(m_ui->tabWidget, SIGNAL(databaseLocked(DatabaseWidget*)),
SLOT(databaseStatusChanged(DatabaseWidget*)));
connect(m_ui->tabWidget, SIGNAL(databaseUnlocked(DatabaseWidget*)),
SLOT(databaseStatusChanged(DatabaseWidget*)));
connect(m_ui->stackedWidget, SIGNAL(currentChanged(int)), SLOT(setMenuActionState()));
connect(m_ui->stackedWidget, SIGNAL(currentChanged(int)), SLOT(updateWindowTitle()));
connect(m_ui->settingsWidget, SIGNAL(editFinished(bool)), SLOT(switchToDatabases()));
connect(m_ui->settingsWidget, SIGNAL(accepted()), SLOT(applySettingsChanges()));
2012-04-25 14:22:55 -04:00
connect(m_ui->actionDatabaseNew, SIGNAL(triggered()), m_ui->tabWidget,
SLOT(newDatabase()));
connect(m_ui->actionDatabaseOpen, SIGNAL(triggered()), m_ui->tabWidget,
SLOT(openDatabase()));
connect(m_ui->actionDatabaseSave, SIGNAL(triggered()), m_ui->tabWidget,
SLOT(saveDatabase()));
connect(m_ui->actionDatabaseSaveAs, SIGNAL(triggered()), m_ui->tabWidget,
SLOT(saveDatabaseAs()));
connect(m_ui->actionDatabaseClose, SIGNAL(triggered()), m_ui->tabWidget,
SLOT(closeDatabase()));
connect(m_ui->actionDatabaseMerge, SIGNAL(triggered()), m_ui->tabWidget,
SLOT(mergeDatabase()));
2012-04-25 14:22:55 -04:00
connect(m_ui->actionChangeMasterKey, SIGNAL(triggered()), m_ui->tabWidget,
SLOT(changeMasterKey()));
connect(m_ui->actionChangeDatabaseSettings, SIGNAL(triggered()), m_ui->tabWidget,
SLOT(changeDatabaseSettings()));
connect(m_ui->actionImportKeePass1, SIGNAL(triggered()), m_ui->tabWidget,
SLOT(importKeePass1Database()));
connect(m_ui->actionRepairDatabase, SIGNAL(triggered()), this,
SLOT(repairDatabase()));
connect(m_ui->actionExportCsv, SIGNAL(triggered()), m_ui->tabWidget,
SLOT(exportToCsv()));
2012-10-12 06:12:00 -04:00
connect(m_ui->actionLockDatabases, SIGNAL(triggered()), m_ui->tabWidget,
SLOT(lockDatabases()));
connect(m_ui->actionQuit, SIGNAL(triggered()), SLOT(appExit()));
m_actionMultiplexer.connect(m_ui->actionEntryNew, SIGNAL(triggered()),
2012-04-25 14:22:55 -04:00
SLOT(createEntry()));
m_actionMultiplexer.connect(m_ui->actionEntryClone, SIGNAL(triggered()),
2012-05-15 15:10:39 -04:00
SLOT(cloneEntry()));
m_actionMultiplexer.connect(m_ui->actionEntryEdit, SIGNAL(triggered()),
SLOT(switchToEntryEdit()));
m_actionMultiplexer.connect(m_ui->actionEntryDelete, SIGNAL(triggered()),
2013-10-08 15:36:01 -04:00
SLOT(deleteEntries()));
m_actionMultiplexer.connect(m_ui->actionEntryCopyTitle, SIGNAL(triggered()),
SLOT(copyTitle()));
m_actionMultiplexer.connect(m_ui->actionEntryCopyUsername, SIGNAL(triggered()),
SLOT(copyUsername()));
m_actionMultiplexer.connect(m_ui->actionEntryCopyPassword, SIGNAL(triggered()),
SLOT(copyPassword()));
m_actionMultiplexer.connect(m_ui->actionEntryCopyURL, SIGNAL(triggered()),
SLOT(copyURL()));
m_actionMultiplexer.connect(m_ui->actionEntryCopyNotes, SIGNAL(triggered()),
SLOT(copyNotes()));
m_actionMultiplexer.connect(m_ui->actionEntryAutoType, SIGNAL(triggered()),
2012-07-12 16:35:51 -04:00
SLOT(performAutoType()));
m_actionMultiplexer.connect(m_ui->actionEntryOpenUrl, SIGNAL(triggered()),
SLOT(openUrl()));
m_actionMultiplexer.connect(m_ui->actionGroupNew, SIGNAL(triggered()),
2012-04-25 14:22:55 -04:00
SLOT(createGroup()));
m_actionMultiplexer.connect(m_ui->actionGroupEdit, SIGNAL(triggered()),
SLOT(switchToGroupEdit()));
m_actionMultiplexer.connect(m_ui->actionGroupDelete, SIGNAL(triggered()),
2012-04-25 14:22:55 -04:00
SLOT(deleteGroup()));
connect(m_ui->actionSettings, SIGNAL(triggered()), SLOT(switchToSettings()));
connect(m_ui->actionPasswordGenerator, SIGNAL(toggled(bool)), SLOT(switchToPasswordGen(bool)));
connect(m_ui->passwordGeneratorWidget, SIGNAL(dialogTerminated()), SLOT(closePasswordGen()));
connect(m_ui->actionAbout, SIGNAL(triggered()), SLOT(showAboutDialog()));
updateTrayIcon();
}
MainWindow::~MainWindow()
{
2010-09-19 10:59:32 -04:00
}
void MainWindow::appExit()
{
appExitCalled = true;
close();
}
2012-08-01 04:40:18 -04:00
void MainWindow::updateLastDatabasesMenu()
{
m_ui->menuRecentDatabases->clear();
const QStringList lastDatabases = config()->get("LastDatabases", QVariant()).toStringList();
for (const QString& database : lastDatabases) {
QAction* action = m_ui->menuRecentDatabases->addAction(database);
action->setData(database);
m_lastDatabasesActions->addAction(action);
}
m_ui->menuRecentDatabases->addSeparator();
m_ui->menuRecentDatabases->addAction(m_clearHistoryAction);
}
void MainWindow::updateCopyAttributesMenu()
{
DatabaseWidget* dbWidget = m_ui->tabWidget->currentDatabaseWidget();
if (!dbWidget) {
return;
}
if (dbWidget->numberOfSelectedEntries() != 1) {
return;
}
QList<QAction*> actions = m_ui->menuEntryCopyAttribute->actions();
2014-10-09 15:36:08 -04:00
for (int i = m_countDefaultAttributes; i < actions.size(); i++) {
delete actions[i];
}
const QStringList customEntryAttributes = dbWidget->customEntryAttributes();
for (const QString& key : customEntryAttributes) {
QAction* action = m_ui->menuEntryCopyAttribute->addAction(key);
m_copyAdditionalAttributeActions->addAction(action);
}
}
void MainWindow::openRecentDatabase(QAction* action)
{
openDatabase(action->data().toString());
}
void MainWindow::clearLastDatabases()
{
config()->set("LastDatabases", QVariant());
}
void MainWindow::openDatabase(const QString& fileName, const QString& pw, const QString& keyFile)
{
m_ui->tabWidget->openDatabase(fileName, pw, keyFile);
}
void MainWindow::setMenuActionState(DatabaseWidget::Mode mode)
{
int currentIndex = m_ui->stackedWidget->currentIndex();
bool inDatabaseTabWidget = (currentIndex == 0);
bool inWelcomeWidget = (currentIndex == 2);
if (inDatabaseTabWidget && m_ui->tabWidget->currentIndex() != -1) {
DatabaseWidget* dbWidget = m_ui->tabWidget->currentDatabaseWidget();
Q_ASSERT(dbWidget);
if (mode == DatabaseWidget::None) {
mode = dbWidget->currentMode();
}
switch (mode) {
case DatabaseWidget::ViewMode: {
bool inSearch = dbWidget->isInSearchMode();
bool singleEntrySelected = dbWidget->numberOfSelectedEntries() == 1;
bool entriesSelected = dbWidget->numberOfSelectedEntries() > 0;
bool groupSelected = dbWidget->isGroupSelected();
m_ui->actionEntryNew->setEnabled(!inSearch);
m_ui->actionEntryClone->setEnabled(singleEntrySelected);
m_ui->actionEntryEdit->setEnabled(singleEntrySelected);
2013-10-08 15:36:01 -04:00
m_ui->actionEntryDelete->setEnabled(entriesSelected);
m_ui->actionEntryCopyTitle->setEnabled(singleEntrySelected && dbWidget->currentEntryHasTitle());
m_ui->actionEntryCopyUsername->setEnabled(singleEntrySelected && dbWidget->currentEntryHasUsername());
m_ui->actionEntryCopyPassword->setEnabled(singleEntrySelected && dbWidget->currentEntryHasPassword());
m_ui->actionEntryCopyURL->setEnabled(singleEntrySelected && dbWidget->currentEntryHasUrl());
m_ui->actionEntryCopyNotes->setEnabled(singleEntrySelected && dbWidget->currentEntryHasNotes());
m_ui->menuEntryCopyAttribute->setEnabled(singleEntrySelected);
m_ui->actionEntryAutoType->setEnabled(singleEntrySelected);
m_ui->actionEntryOpenUrl->setEnabled(singleEntrySelected && dbWidget->currentEntryHasUrl());
m_ui->actionGroupNew->setEnabled(groupSelected);
m_ui->actionGroupEdit->setEnabled(groupSelected);
m_ui->actionGroupDelete->setEnabled(groupSelected && dbWidget->canDeleteCurrentGroup());
2012-04-25 14:22:55 -04:00
m_ui->actionChangeMasterKey->setEnabled(true);
m_ui->actionChangeDatabaseSettings->setEnabled(true);
m_ui->actionDatabaseSave->setEnabled(true);
m_ui->actionDatabaseSaveAs->setEnabled(true);
m_ui->actionExportCsv->setEnabled(true);
m_ui->actionDatabaseMerge->setEnabled(m_ui->tabWidget->currentIndex() != -1);
m_searchWidgetAction->setEnabled(true);
2012-04-25 14:22:55 -04:00
break;
}
2012-04-25 14:22:55 -04:00
case DatabaseWidget::EditMode:
case DatabaseWidget::LockedMode: {
const QList<QAction*> entryActions = m_ui->menuEntries->actions();
for (QAction* action : entryActions) {
action->setEnabled(false);
}
const QList<QAction*> groupActions = m_ui->menuGroups->actions();
for (QAction* action : groupActions) {
action->setEnabled(false);
}
m_ui->actionEntryCopyTitle->setEnabled(false);
m_ui->actionEntryCopyUsername->setEnabled(false);
m_ui->actionEntryCopyPassword->setEnabled(false);
m_ui->actionEntryCopyURL->setEnabled(false);
m_ui->actionEntryCopyNotes->setEnabled(false);
m_ui->menuEntryCopyAttribute->setEnabled(false);
2012-04-25 14:22:55 -04:00
m_ui->actionChangeMasterKey->setEnabled(false);
m_ui->actionChangeDatabaseSettings->setEnabled(false);
m_ui->actionDatabaseSave->setEnabled(false);
m_ui->actionDatabaseSaveAs->setEnabled(false);
m_ui->actionExportCsv->setEnabled(false);
m_ui->actionDatabaseMerge->setEnabled(false);
m_searchWidgetAction->setEnabled(false);
2012-04-25 14:22:55 -04:00
break;
}
2012-04-25 14:22:55 -04:00
default:
Q_ASSERT(false);
}
m_ui->actionDatabaseClose->setEnabled(true);
}
else {
const QList<QAction*> entryActions = m_ui->menuEntries->actions();
for (QAction* action : entryActions) {
action->setEnabled(false);
}
const QList<QAction*> groupActions = m_ui->menuGroups->actions();
for (QAction* action : groupActions) {
action->setEnabled(false);
}
m_ui->actionEntryCopyTitle->setEnabled(false);
m_ui->actionEntryCopyUsername->setEnabled(false);
m_ui->actionEntryCopyPassword->setEnabled(false);
m_ui->actionEntryCopyURL->setEnabled(false);
m_ui->actionEntryCopyNotes->setEnabled(false);
m_ui->menuEntryCopyAttribute->setEnabled(false);
m_ui->actionChangeMasterKey->setEnabled(false);
m_ui->actionChangeDatabaseSettings->setEnabled(false);
m_ui->actionDatabaseSave->setEnabled(false);
m_ui->actionDatabaseSaveAs->setEnabled(false);
m_ui->actionDatabaseClose->setEnabled(false);
m_ui->actionExportCsv->setEnabled(false);
m_ui->actionDatabaseMerge->setEnabled(false);
m_searchWidgetAction->setEnabled(false);
}
bool inDatabaseTabWidgetOrWelcomeWidget = inDatabaseTabWidget || inWelcomeWidget;
m_ui->actionDatabaseNew->setEnabled(inDatabaseTabWidgetOrWelcomeWidget);
m_ui->actionDatabaseOpen->setEnabled(inDatabaseTabWidgetOrWelcomeWidget);
m_ui->menuRecentDatabases->setEnabled(inDatabaseTabWidgetOrWelcomeWidget);
m_ui->actionImportKeePass1->setEnabled(inDatabaseTabWidgetOrWelcomeWidget);
m_ui->actionDatabaseMerge->setEnabled(inDatabaseTabWidget);
m_ui->actionRepairDatabase->setEnabled(inDatabaseTabWidgetOrWelcomeWidget);
2012-10-12 06:12:00 -04:00
m_ui->actionLockDatabases->setEnabled(m_ui->tabWidget->hasLockableDatabases());
if ((3 == currentIndex) != m_ui->actionPasswordGenerator->isChecked()) {
bool blocked = m_ui->actionPasswordGenerator->blockSignals(true);
m_ui->actionPasswordGenerator->toggle();
m_ui->actionPasswordGenerator->blockSignals(blocked);
}
}
void MainWindow::updateWindowTitle()
{
2012-11-01 20:00:50 -04:00
QString customWindowTitlePart;
int stackedWidgetIndex = m_ui->stackedWidget->currentIndex();
2012-11-01 20:00:50 -04:00
int tabWidgetIndex = m_ui->tabWidget->currentIndex();
if (stackedWidgetIndex == 0 && tabWidgetIndex != -1) {
customWindowTitlePart = m_ui->tabWidget->tabText(tabWidgetIndex);
if (m_ui->tabWidget->readOnly(tabWidgetIndex)) {
customWindowTitlePart.append(QString(" [%1]").arg(tr("read-only")));
}
} else if (stackedWidgetIndex == 1) {
2012-11-01 20:00:50 -04:00
customWindowTitlePart = tr("Settings");
}
QString windowTitle;
if (customWindowTitlePart.isEmpty()) {
windowTitle = BaseWindowTitle;
2012-11-01 20:00:50 -04:00
} else {
windowTitle = QString("%1 - %2").arg(customWindowTitlePart, BaseWindowTitle);
}
setWindowTitle(windowTitle);
}
2012-05-02 09:37:21 -04:00
void MainWindow::showAboutDialog()
{
AboutDialog* aboutDialog = new AboutDialog(this);
aboutDialog->show();
}
void MainWindow::switchToDatabases()
{
if (m_ui->tabWidget->currentIndex() == -1) {
m_ui->stackedWidget->setCurrentIndex(2);
}
else {
m_ui->stackedWidget->setCurrentIndex(0);
}
}
void MainWindow::switchToSettings()
{
m_ui->settingsWidget->loadSettings();
m_ui->stackedWidget->setCurrentIndex(1);
}
void MainWindow::switchToPasswordGen(bool enabled)
{
if (enabled == true) {
m_ui->passwordGeneratorWidget->loadSettings();
m_ui->passwordGeneratorWidget->regeneratePassword();
m_ui->passwordGeneratorWidget->setStandaloneMode(true);
m_ui->stackedWidget->setCurrentIndex(3);
} else {
m_ui->passwordGeneratorWidget->saveSettings();
switchToDatabases();
}
}
void MainWindow::closePasswordGen()
{
switchToPasswordGen(false);
}
2016-10-08 12:55:05 -04:00
void MainWindow::databaseStatusChanged(DatabaseWidget *)
{
updateTrayIcon();
}
void MainWindow::databaseTabChanged(int tabIndex)
{
if (tabIndex != -1 && m_ui->stackedWidget->currentIndex() == 2) {
m_ui->stackedWidget->setCurrentIndex(0);
}
else if (tabIndex == -1 && m_ui->stackedWidget->currentIndex() == 0) {
m_ui->stackedWidget->setCurrentIndex(2);
}
m_actionMultiplexer.setCurrentObject(m_ui->tabWidget->currentDatabaseWidget());
}
2012-06-29 18:22:07 -04:00
void MainWindow::closeEvent(QCloseEvent* event)
2014-03-22 07:21:49 -04:00
{
2015-10-08 10:27:29 -04:00
bool minimizeOnClose = isTrayIconEnabled() &&
config()->get("GUI/MinimizeOnClose").toBool();
if (minimizeOnClose && !appExitCalled)
{
event->ignore();
2017-02-08 09:37:13 -05:00
toggleWindow();
if (config()->get("security/lockdatabaseminimize").toBool()) {
m_ui->tabWidget->lockDatabases();
}
return;
}
bool accept = saveLastDatabases();
if (accept) {
saveWindowInformation();
event->accept();
QApplication::quit();
}
else {
event->ignore();
}
2014-03-22 07:21:49 -04:00
}
2015-10-15 12:02:31 -04:00
void MainWindow::changeEvent(QEvent* event)
{
if ((event->type() == QEvent::WindowStateChange) && isMinimized()) {
if (isTrayIconEnabled() && m_trayIcon && m_trayIcon->isVisible()
&& config()->get("GUI/MinimizeToTray").toBool())
{
event->ignore();
QTimer::singleShot(0, this, SLOT(hide()));
}
if (config()->get("security/lockdatabaseminimize").toBool()) {
m_ui->tabWidget->lockDatabases();
}
}
else {
QMainWindow::changeEvent(event);
}
}
void MainWindow::saveWindowInformation()
2012-06-29 18:22:07 -04:00
{
config()->set("GUI/MainWindowGeometry", saveGeometry());
}
bool MainWindow::saveLastDatabases()
{
bool accept;
2013-04-27 05:20:13 -04:00
m_openDatabases.clear();
bool openPreviousDatabasesOnStartup = config()->get("OpenPreviousDatabasesOnStartup").toBool();
if (openPreviousDatabasesOnStartup) {
2013-10-13 12:08:50 -04:00
connect(m_ui->tabWidget, SIGNAL(databaseWithFileClosed(QString)),
this, SLOT(rememberOpenDatabases(QString)));
}
if (!m_ui->tabWidget->closeAllDatabases()) {
accept = false;
}
else {
accept = true;
}
if (openPreviousDatabasesOnStartup) {
2013-10-13 12:08:50 -04:00
disconnect(m_ui->tabWidget, SIGNAL(databaseWithFileClosed(QString)),
this, SLOT(rememberOpenDatabases(QString)));
2013-04-27 05:20:13 -04:00
config()->set("LastOpenedDatabases", m_openDatabases);
}
2012-05-15 12:16:04 -04:00
return accept;
2014-03-22 07:21:49 -04:00
}
void MainWindow::updateTrayIcon()
{
if (isTrayIconEnabled()) {
if (!m_trayIcon) {
2016-10-08 12:55:05 -04:00
m_trayIcon = new QSystemTrayIcon(this);
QMenu* menu = new QMenu(this);
QAction* actionToggle = new QAction(tr("Toggle window"), menu);
menu->addAction(actionToggle);
menu->addAction(m_ui->actionQuit);
connect(m_trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
SLOT(trayIconTriggered(QSystemTrayIcon::ActivationReason)));
connect(actionToggle, SIGNAL(triggered()), SLOT(toggleWindow()));
m_trayIcon->setContextMenu(menu);
2016-10-08 12:55:05 -04:00
m_trayIcon->setIcon(filePath()->applicationIcon());
m_trayIcon->show();
}
2016-10-08 12:55:05 -04:00
if (m_ui->tabWidget->hasLockableDatabases()) {
m_trayIcon->setIcon(filePath()->trayIconUnlocked());
}
else {
m_trayIcon->setIcon(filePath()->trayIconLocked());
}
}
else {
if (m_trayIcon) {
m_trayIcon->hide();
delete m_trayIcon;
2015-07-24 12:28:12 -04:00
m_trayIcon = nullptr;
}
}
}
void MainWindow::showEntryContextMenu(const QPoint& globalPos)
{
m_ui->menuEntries->popup(globalPos);
}
void MainWindow::showGroupContextMenu(const QPoint& globalPos)
{
m_ui->menuGroups->popup(globalPos);
}
void MainWindow::saveToolbarState(bool value)
{
config()->set("ShowToolbar", value);
}
2012-05-15 12:16:04 -04:00
void MainWindow::setShortcut(QAction* action, QKeySequence::StandardKey standard, int fallback)
{
if (!QKeySequence::keyBindings(standard).isEmpty()) {
action->setShortcuts(standard);
}
else if (fallback != 0) {
action->setShortcut(QKeySequence(fallback));
}
}
2013-04-27 05:20:13 -04:00
void MainWindow::rememberOpenDatabases(const QString& filePath)
{
2013-04-27 05:20:13 -04:00
m_openDatabases.append(filePath);
}
void MainWindow::applySettingsChanges()
{
int timeout = config()->get("security/lockdatabaseidlesec").toInt() * 1000;
if (timeout <= 0) {
timeout = 60;
}
m_inactivityTimer->setInactivityTimeout(timeout);
if (config()->get("security/lockdatabaseidle").toBool()) {
m_inactivityTimer->activate();
}
else {
m_inactivityTimer->deactivate();
}
updateTrayIcon();
}
void MainWindow::trayIconTriggered(QSystemTrayIcon::ActivationReason reason)
{
if (reason == QSystemTrayIcon::Trigger) {
toggleWindow();
}
}
void MainWindow::toggleWindow()
{
if ((QApplication::activeWindow() == this) && isVisible() && !isMinimized()) {
2017-02-08 09:37:13 -05:00
setWindowState(windowState() | Qt::WindowMinimized);
QTimer::singleShot(0, this, SLOT(hide()));
if (config()->get("security/lockdatabaseminimize").toBool()) {
m_ui->tabWidget->lockDatabases();
}
} else {
ensurePolished();
2017-02-08 09:37:13 -05:00
setWindowState(windowState() & ~Qt::WindowMinimized);
show();
raise();
activateWindow();
2017-02-09 10:29:01 -05:00
#if defined(Q_OS_LINUX) && ! defined(QT_NO_DBUS)
// re-register global D-Bus menu (needed on Ubuntu with Unity)
// see https://github.com/keepassxreboot/keepassxc/issues/271
// and https://bugreports.qt.io/browse/QTBUG-58723
// check for !isVisible(), because isNativeMenuBar() does not work with appmenu-qt5
if (!m_ui->menubar->isVisible()) {
QDBusMessage msg = QDBusMessage::createMethodCall(
"com.canonical.AppMenu.Registrar",
"/com/canonical/AppMenu/Registrar",
"com.canonical.AppMenu.Registrar",
"RegisterWindow");
QList<QVariant> args;
args << QVariant::fromValue(static_cast<uint32_t>(winId()))
<< QVariant::fromValue(QDBusObjectPath("/MenuBar/1"));
msg.setArguments(args);
QDBusConnection::sessionBus().send(msg);
}
#endif
}
}
void MainWindow::lockDatabasesAfterInactivity()
{
// ignore event if a modal dialog is open (such as a message box or file dialog)
if (QApplication::activeModalWidget()) {
return;
}
m_ui->tabWidget->lockDatabases();
}
void MainWindow::repairDatabase()
{
QString filter = QString("%1 (*.kdbx);;%2 (*)").arg(tr("KeePass 2 Database"), tr("All files"));
QString fileName = fileDialog()->getOpenFileName(this, tr("Open database"), QString(),
filter);
if (fileName.isEmpty()) {
return;
}
QScopedPointer<QDialog> dialog(new QDialog(this));
DatabaseRepairWidget* dbRepairWidget = new DatabaseRepairWidget(dialog.data());
connect(dbRepairWidget, SIGNAL(success()), dialog.data(), SLOT(accept()));
connect(dbRepairWidget, SIGNAL(error()), dialog.data(), SLOT(reject()));
dbRepairWidget->load(fileName);
if (dialog->exec() == QDialog::Accepted && dbRepairWidget->database()) {
QString saveFileName = fileDialog()->getSaveFileName(this, tr("Save repaired database"), QString(),
tr("KeePass 2 Database").append(" (*.kdbx)"),
nullptr, 0, "kdbx");
if (!saveFileName.isEmpty()) {
KeePass2Writer writer;
writer.writeDatabase(saveFileName, dbRepairWidget->database());
if (writer.hasError()) {
QMessageBox::critical(this, tr("Error"),
tr("Writing the database failed.").append("\n\n").append(writer.errorString()));
}
}
}
}
bool MainWindow::isTrayIconEnabled() const
{
#ifdef Q_OS_MAC
// systray not useful on OS X
return false;
#else
return config()->get("GUI/ShowTrayIcon").toBool()
&& QSystemTrayIcon::isSystemTrayAvailable();
#endif
}