From 4cdb9a645d8af65ea37e3af41e668540f8a1b30c Mon Sep 17 00:00:00 2001 From: Felix Geyer Date: Sun, 2 Nov 2014 10:15:44 +0100 Subject: [PATCH] Add an option to display a tray icon. Also implement "Minimize to tray" functionality. --- src/core/Config.cpp | 2 ++ src/gui/MainWindow.cpp | 73 ++++++++++++++++++++++++++++++++++++++++ src/gui/MainWindow.h | 7 ++++ src/gui/SettingsWidget.cpp | 9 +++++ src/gui/SettingsWidgetGeneral.ui | 19 ++++++++++- src/main.cpp | 2 ++ 6 files changed, 111 insertions(+), 1 deletion(-) diff --git a/src/core/Config.cpp b/src/core/Config.cpp index d47541e..03b5129 100644 --- a/src/core/Config.cpp +++ b/src/core/Config.cpp @@ -104,6 +104,8 @@ void Config::init(const QString& fileName) m_defaults.insert("security/passwordscleartext", false); m_defaults.insert("security/autotypeask", true); m_defaults.insert("GUI/Language", "system"); + m_defaults.insert("GUI/ShowTrayIcon", false); + m_defaults.insert("GUI/MinimizeToTray", false); } Config* Config::instance() diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index 48baa4c..dd77989 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -33,6 +33,7 @@ const QString MainWindow::BaseWindowTitle = "KeePassX"; MainWindow::MainWindow() : m_ui(new Ui::MainWindow()) + , m_trayIcon(Q_NULLPTR) { m_ui->setupUi(this); @@ -201,6 +202,8 @@ MainWindow::MainWindow() m_actionMultiplexer.connect(m_ui->actionSearch, SIGNAL(triggered()), SLOT(toggleSearch())); + + updateTrayIcon(); } MainWindow::~MainWindow() @@ -429,12 +432,26 @@ void MainWindow::closeEvent(QCloseEvent* event) saveWindowInformation(); event->accept(); + QApplication::quit(); } else { event->ignore(); } } +void MainWindow::changeEvent(QEvent *event) +{ + if ((event->type() == QEvent::WindowStateChange) && isMinimized() + && isTrayIconEnabled() && config()->get("GUI/MinimizeToTray").toBool()) + { + event->ignore(); + hide(); + } + else { + QMainWindow::changeEvent(event); + } +} + void MainWindow::saveWindowInformation() { config()->set("GUI/MainWindowGeometry", saveGeometry()); @@ -467,6 +484,35 @@ bool MainWindow::saveLastDatabases() return accept; } +void MainWindow::updateTrayIcon() +{ + if (isTrayIconEnabled()) { + if (!m_trayIcon) { + m_trayIcon = new QSystemTrayIcon(filePath()->applicationIcon(), 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); + m_trayIcon->show(); + } + } + else { + if (m_trayIcon) { + delete m_trayIcon; + m_trayIcon = Q_NULLPTR; + } + } +} + void MainWindow::showEntryContextMenu(const QPoint& globalPos) { m_ui->menuEntries->popup(globalPos); @@ -511,4 +557,31 @@ void MainWindow::applySettingsChanges() else { m_inactivityTimer->deactivate(); } + + updateTrayIcon(); +} + +void MainWindow::trayIconTriggered(QSystemTrayIcon::ActivationReason reason) +{ + if (reason == QSystemTrayIcon::Trigger) { + toggleWindow(); + } +} + +void MainWindow::toggleWindow() +{ + if (QApplication::activeWindow() == this) { + hide(); + } + else { + show(); + raise(); + activateWindow(); + } +} + +bool MainWindow::isTrayIconEnabled() const +{ + return config()->get("GUI/ShowTrayIcon").toBool() + && QSystemTrayIcon::isSystemTrayAvailable(); } diff --git a/src/gui/MainWindow.h b/src/gui/MainWindow.h index e904426..b966703 100644 --- a/src/gui/MainWindow.h +++ b/src/gui/MainWindow.h @@ -20,6 +20,7 @@ #include #include +#include #include "core/SignalMultiplexer.h" #include "gui/DatabaseWidget.h" @@ -44,6 +45,7 @@ public Q_SLOTS: protected: void closeEvent(QCloseEvent* event) Q_DECL_OVERRIDE; + void changeEvent(QEvent* event) Q_DECL_OVERRIDE; private Q_SLOTS: void setMenuActionState(DatabaseWidget::Mode mode = DatabaseWidget::None); @@ -61,6 +63,8 @@ private Q_SLOTS: void saveToolbarState(bool value); void rememberOpenDatabases(const QString& filePath); void applySettingsChanges(); + void trayIconTriggered(QSystemTrayIcon::ActivationReason reason); + void toggleWindow(); private: static void setShortcut(QAction* action, QKeySequence::StandardKey standard, int fallback = 0); @@ -69,6 +73,8 @@ private Q_SLOTS: void saveWindowInformation(); bool saveLastDatabases(); + void updateTrayIcon(); + bool isTrayIconEnabled() const; const QScopedPointer m_ui; SignalMultiplexer m_actionMultiplexer; @@ -78,6 +84,7 @@ private Q_SLOTS: QStringList m_openDatabases; InactivityTimer* m_inactivityTimer; int m_countDefaultAttributes; + QSystemTrayIcon* m_trayIcon; Q_DISABLE_COPY(MainWindow) }; diff --git a/src/gui/SettingsWidget.cpp b/src/gui/SettingsWidget.cpp index 929db37..a7863ea 100644 --- a/src/gui/SettingsWidget.cpp +++ b/src/gui/SettingsWidget.cpp @@ -47,6 +47,8 @@ SettingsWidget::SettingsWidget(QWidget* parent) connect(m_generalUi->autoSaveAfterEveryChangeCheckBox, SIGNAL(toggled(bool)), this, SLOT(enableAutoSaveOnExit(bool))); + connect(m_generalUi->systrayShowCheckBox, SIGNAL(toggled(bool)), + m_generalUi->systrayMinimizeToTrayCheckBox, SLOT(setEnabled(bool))); connect(m_secUi->clearClipboardCheckBox, SIGNAL(toggled(bool)), m_secUi->clearClipboardSpinBox, SLOT(setEnabled(bool))); @@ -80,6 +82,9 @@ void SettingsWidget::loadSettings() m_generalUi->languageComboBox->setCurrentIndex(defaultIndex); } + m_generalUi->systrayShowCheckBox->setChecked(config()->get("GUI/ShowTrayIcon").toBool()); + m_generalUi->systrayMinimizeToTrayCheckBox->setChecked(config()->get("GUI/MinimizeToTray").toBool()); + if (autoType()->isAvailable()) { m_globalAutoTypeKey = static_cast(config()->get("GlobalAutoTypeKey").toInt()); m_globalAutoTypeModifiers = static_cast(config()->get("GlobalAutoTypeModifiers").toInt()); @@ -118,6 +123,10 @@ void SettingsWidget::saveSettings() m_generalUi->autoTypeEntryTitleMatchCheckBox->isChecked()); int currentLangIndex = m_generalUi->languageComboBox->currentIndex(); config()->set("GUI/Language", m_generalUi->languageComboBox->itemData(currentLangIndex).toString()); + + config()->set("GUI/ShowTrayIcon", m_generalUi->systrayShowCheckBox->isChecked()); + config()->set("GUI/MinimizeToTray", m_generalUi->systrayMinimizeToTrayCheckBox->isChecked()); + if (autoType()->isAvailable()) { config()->set("GlobalAutoTypeKey", m_generalUi->autoTypeShortcutWidget->key()); config()->set("GlobalAutoTypeModifiers", diff --git a/src/gui/SettingsWidgetGeneral.ui b/src/gui/SettingsWidgetGeneral.ui index f3dc079..cbad7e5 100644 --- a/src/gui/SettingsWidgetGeneral.ui +++ b/src/gui/SettingsWidgetGeneral.ui @@ -7,7 +7,7 @@ 0 0 456 - 288 + 340 @@ -96,6 +96,23 @@ + + + + Show a system tray icon + + + + + + + false + + + Hide window to system tray when minimized + + + diff --git a/src/main.cpp b/src/main.cpp index b9659e4..2bdef5b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -39,6 +39,8 @@ int main(int argc, char** argv) // don't set organizationName as that changes the return value of // QDesktopServices::storageLocation(QDesktopServices::DataLocation) + QApplication::setQuitOnLastWindowClosed(false); + if (!Crypto::init()) { QString error = QCoreApplication::translate("Main", "Fatal error while testing the cryptographic functions.");