system-tray: support system tray icon

This commit is contained in:
Le Tan 2017-07-25 19:52:25 +08:00
parent b2bae39715
commit 60e65d1781
8 changed files with 200 additions and 15 deletions

View File

@ -108,17 +108,28 @@ const QVector<QString> VGeneralTab::c_availableLangs = { "System", "English", "C
VGeneralTab::VGeneralTab(QWidget *p_parent)
: QWidget(p_parent)
{
QLabel *langLabel = new QLabel(tr("&Language:"));
// Language combo.
m_langCombo = new QComboBox(this);
m_langCombo->setToolTip(tr("Choose the language of VNote interface"));
m_langCombo->addItem(tr("System"), "System");
auto langs = VUtils::getAvailableLanguages();
for (auto const &lang : langs) {
m_langCombo->addItem(lang.second, lang.first);
}
langLabel->setBuddy(m_langCombo);
QLabel *langLabel = new QLabel(tr("Language:"), this);
langLabel->setToolTip(m_langCombo->toolTip());
// System tray checkbox.
m_systemTray = new QCheckBox(this);
m_systemTray->setToolTip(tr("Minimized to the system tray after closing VNote"));
QLabel *trayLabel = new QLabel(tr("System tray:"), this);
trayLabel->setToolTip(m_systemTray->toolTip());
QFormLayout *optionLayout = new QFormLayout();
optionLayout->addRow(langLabel, m_langCombo);
optionLayout->addRow(trayLabel, m_systemTray);
QVBoxLayout *mainLayout = new QVBoxLayout();
mainLayout->addLayout(optionLayout);
@ -131,6 +142,11 @@ bool VGeneralTab::loadConfiguration()
if (!loadLanguage()) {
return false;
}
if (!loadSystemTray()) {
return false;
}
return true;
}
@ -139,6 +155,11 @@ bool VGeneralTab::saveConfiguration()
if (!saveLanguage()) {
return false;
}
if (!saveSystemTray()) {
return false;
}
return true;
}
@ -174,6 +195,18 @@ bool VGeneralTab::saveLanguage()
return true;
}
bool VGeneralTab::loadSystemTray()
{
m_systemTray->setChecked(vconfig.getMinimizeToStystemTray() != 0);
return true;
}
bool VGeneralTab::saveSystemTray()
{
vconfig.setMinimizeToSystemTray(m_systemTray->isChecked() ? 1 : 0);
return true;
}
VReadEditTab::VReadEditTab(QWidget *p_parent)
: QWidget(p_parent)
{

View File

@ -25,9 +25,15 @@ private:
bool loadLanguage();
bool saveLanguage();
bool loadSystemTray();
bool saveSystemTray();
// Language
QComboBox *m_langCombo;
// System tray
QCheckBox *m_systemTray;
static const QVector<QString> c_availableLangs;
};

View File

@ -60,6 +60,12 @@ enable_smart_im_in_vim_mode=true
; 0 - None, 1 - Absolute, 2 - Relative
editor_line_number=0
; Whether minimize to system tray when closing the app
; -1: uninitialized, prompt user for the behavior
; 0: do not minimize to system tray
; 1: minimize to system tray
minimize_to_system_tray=-1
[session]
tools_dock_checked=true

View File

@ -157,6 +157,12 @@ void VConfigManager::initialize()
m_editorLineNumber = getConfigFromSettings("global",
"editor_line_number").toInt();
m_minimizeToSystemTray = getConfigFromSettings("global",
"minimize_to_system_tray").toInt();
if (m_minimizeToSystemTray > 1 || m_minimizeToSystemTray < -1) {
setMinimizeToSystemTray(0);
}
readShortcutsFromSettings();
}

View File

@ -214,6 +214,9 @@ public:
const QString &getEditorLineNumberBg() const;
const QString &getEditorLineNumberFg() const;
int getMinimizeToStystemTray() const;
void setMinimizeToSystemTray(int p_val);
// Return the configured key sequence of @p_operation.
// Return empty if there is no corresponding config.
QString getShortcutKeySequence(const QString &p_operation) const;
@ -429,6 +432,12 @@ private:
// Operation -> KeySequence.
QHash<QString, QString> m_shortcuts;
// Whether minimize to system tray icon when closing the app.
// -1: uninitialized;
// 0: do not minimize to the tay;
// 1: minimize to the tray.
int m_minimizeToSystemTray;
// The name of the config file in each directory, obsolete.
// Use c_dirConfigFile instead.
static const QString c_obsoleteDirConfigFile;
@ -1101,4 +1110,20 @@ inline const QString &VConfigManager::getEditorLineNumberFg() const
return m_editorLineNumberFg;
}
inline int VConfigManager::getMinimizeToStystemTray() const
{
return m_minimizeToSystemTray;
}
inline void VConfigManager::setMinimizeToSystemTray(int p_val)
{
if (m_minimizeToSystemTray == p_val) {
return;
}
m_minimizeToSystemTray = p_val;
setConfigToSettings("global", "minimize_to_system_tray",
m_minimizeToSystemTray);
}
#endif // VCONFIGMANAGER_H

View File

@ -38,7 +38,8 @@ extern QFile g_logFile;
#endif
VMainWindow::VMainWindow(VSingleInstanceGuard *p_guard, QWidget *p_parent)
: QMainWindow(p_parent), m_onePanel(false), m_guard(p_guard)
: QMainWindow(p_parent), m_onePanel(false), m_guard(p_guard),
m_windowOldState(Qt::WindowNoState), m_requestQuit(false)
{
setWindowIcon(QIcon(":/resources/icons/vnote.ico"));
vnote = new VNote(this);
@ -148,6 +149,8 @@ void VMainWindow::setupUI()
// Create and show the status bar
statusBar()->addPermanentWidget(m_vimIndicator);
statusBar()->addPermanentWidget(m_tabIndicator);
initTrayIcon();
}
QWidget *VMainWindow::setupDirectoryPanel()
@ -723,16 +726,22 @@ void VMainWindow::initFileMenu()
fileMenu->addSeparator();
// Exit.
QAction *exitAct = new QAction(tr("&Exit"), this);
exitAct->setToolTip(tr("Exit VNote"));
QAction *exitAct = new QAction(tr("&Quit"), this);
exitAct->setToolTip(tr("Quit VNote"));
exitAct->setShortcut(QKeySequence("Ctrl+Q"));
exitAct->setMenuRole(QAction::QuitRole);
connect(exitAct, &QAction::triggered,
this, &VMainWindow::close);
this, &VMainWindow::quitApp);
fileMenu->addAction(exitAct);
}
void VMainWindow::quitApp()
{
m_requestQuit = true;
close();
}
void VMainWindow::initEditMenu()
{
QMenu *editMenu = menuBar()->addMenu(tr("&Edit"));
@ -1527,13 +1536,42 @@ void VMainWindow::deleteCurNote()
void VMainWindow::closeEvent(QCloseEvent *event)
{
if (!editArea->closeAllFiles(false)) {
// Fail to close all the opened files, cancel closing app
event->ignore();
return;
bool isExit = m_requestQuit || !vconfig.getMinimizeToStystemTray();
m_requestQuit = false;
if (!isExit && vconfig.getMinimizeToStystemTray() == -1) {
// Not initialized yet. Prompt for user.
int ret = VUtils::showMessage(QMessageBox::Information,
tr("Close VNote"),
tr("Do you want to minimize VNote to system tray "
"instead of quitting it when closing VNote?"),
tr("You could change the option in Settings later."),
QMessageBox::Ok | QMessageBox::No | QMessageBox::Cancel,
QMessageBox::Ok,
this);
if (ret == QMessageBox::Ok) {
vconfig.setMinimizeToSystemTray(1);
} else if (ret == QMessageBox::No) {
vconfig.setMinimizeToSystemTray(0);
isExit = true;
} else {
return;
}
}
if (isExit) {
if (!editArea->closeAllFiles(false)) {
// Fail to close all the opened files, cancel closing app
event->ignore();
return;
}
saveStateAndGeometry();
QMainWindow::closeEvent(event);
} else {
hide();
event->ignore();
}
saveStateAndGeometry();
QMainWindow::closeEvent(event);
}
void VMainWindow::saveStateAndGeometry()
@ -1868,8 +1906,58 @@ void VMainWindow::checkSharedMemory()
qDebug() << "shared memory fetch files" << files;
openExternalFiles(files);
show();
activateWindow();
QApplication::alert(this, 5000);
showMainWindow();
}
}
void VMainWindow::initTrayIcon()
{
QMenu *menu = new QMenu(this);
QAction *showMainWindowAct = menu->addAction(tr("Show VNote"));
connect(showMainWindowAct, &QAction::triggered,
this, &VMainWindow::showMainWindow);
QAction *exitAct = menu->addAction(tr("Quit"));
connect(exitAct, &QAction::triggered,
this, &VMainWindow::quitApp);
m_trayIcon = new QSystemTrayIcon(QIcon(":/resources/icons/32x32/vnote.png"), this);
m_trayIcon->setToolTip(tr("VNote"));
m_trayIcon->setContextMenu(menu);
connect(m_trayIcon, &QSystemTrayIcon::activated,
this, [this](QSystemTrayIcon::ActivationReason p_reason){
if (p_reason == QSystemTrayIcon::Trigger) {
this->showMainWindow();
}
});
m_trayIcon->show();
}
void VMainWindow::changeEvent(QEvent *p_event)
{
if (p_event->type() == QEvent::WindowStateChange) {
QWindowStateChangeEvent *eve = dynamic_cast<QWindowStateChangeEvent *>(p_event);
m_windowOldState = eve->oldState();
}
QMainWindow::changeEvent(p_event);
}
void VMainWindow::showMainWindow()
{
if (this->isMinimized()) {
if (m_windowOldState & Qt::WindowMaximized) {
this->showMaximized();
} else if (m_windowOldState & Qt::WindowFullScreen) {
this->showFullScreen();
} else {
this->showNormal();
}
} else {
this->show();
}
this->activateWindow();
}

View File

@ -33,6 +33,7 @@ class VVimIndicator;
class VTabIndicator;
class VSingleInstanceGuard;
class QTimer;
class QSystemTrayIcon;
class VMainWindow : public QMainWindow
{
@ -109,11 +110,18 @@ private slots:
// files to open.
void checkSharedMemory();
void quitApp();
// Restore main window.
void showMainWindow();
protected:
void closeEvent(QCloseEvent *event) Q_DECL_OVERRIDE;
void resizeEvent(QResizeEvent *event) Q_DECL_OVERRIDE;
void keyPressEvent(QKeyEvent *event) Q_DECL_OVERRIDE;
void changeEvent(QEvent *p_event) Q_DECL_OVERRIDE;
private:
void setupUI();
QWidget *setupDirectoryPanel();
@ -167,6 +175,9 @@ private:
// VNote.
void initSharedMemoryWatcher();
// Init system tray icon and correspondign context menu.
void initTrayIcon();
VNote *vnote;
QPointer<VFile> m_curFile;
QPointer<VEditTab> m_curTab;
@ -233,6 +244,15 @@ private:
// Timer to check the shared memory between instances of VNote.
QTimer *m_sharedMemTimer;
// Tray icon.
QSystemTrayIcon *m_trayIcon;
// The old state of window.
Qt::WindowStates m_windowOldState;
// Whether user request VNote to quit.
bool m_requestQuit;
// Interval of the shared memory timer in ms.
static const int c_sharedMemTimerInterval;
};

View File

@ -116,5 +116,6 @@
<file>resources/icons/strikethrough.svg</file>
<file>resources/icons/inline_code.svg</file>
<file>resources/icons/close_note_tb.svg</file>
<file>resources/icons/32x32/vnote.png</file>
</qresource>
</RCC>