better notification support; dock icon;
system tray icon;
notification is given when the new message is received
and the dialog is not active window;
notification requires growl in Mac OS X
icon also changes until the window is reactivated
diff --git a/.gitignore b/.gitignore
index 5cd902d..a8568fd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,4 @@
ui_*
moc_*
*.pb.*
+qrc*
diff --git a/chatdialog.cpp b/chatdialog.cpp
index 0f6e806..322c947 100644
--- a/chatdialog.cpp
+++ b/chatdialog.cpp
@@ -5,6 +5,7 @@
#include <iostream>
#include <QTimer>
#include <QMetaType>
+#include <QMessageBox>
#define BROADCAST_PREFIX_FOR_SYNC_DEMO "/ndn/broadcast/sync-demo"
@@ -67,12 +68,17 @@
std::exit(1);
}
}
-
+
+ createActions();
+ createTrayIcon();
connect(lineEdit, SIGNAL(returnPressed()), this, SLOT(returnPressed()));
connect(setButton, SIGNAL(pressed()), this, SLOT(buttonPressed()));
connect(this, SIGNAL(dataReceived(QString, const char *, size_t)), this, SLOT(processData(QString, const char *, size_t)));
connect(this, SIGNAL(treeUpdated(const std::vector<Sync::MissingDataInfo>)), this, SLOT(processTreeUpdate(const std::vector<Sync::MissingDataInfo>)));
- //testDraw();
+ connect(trayIcon, SIGNAL(messageClicked()), this, SLOT(showNormal()));
+ connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
+
+//testDraw();
}
ChatDialog::~ChatDialog()
@@ -84,6 +90,46 @@
}
}
+void
+ChatDialog::setVisible(bool visible)
+{
+ minimizeAction->setEnabled(visible);
+ maximizeAction->setEnabled(!isMaximized());
+ restoreAction->setEnabled(isMaximized() || !visible);
+ QDialog::setVisible(visible);
+}
+
+void
+ChatDialog::closeEvent(QCloseEvent *e)
+{
+ if (trayIcon->isVisible())
+ {
+ QMessageBox::information(this, tr("Sync-Demo"),
+ tr("The program will keep running in the "
+ "system tray. To terminate the program"
+ "choose <b>Quit</b> in the context memu"
+ "of the system tray entry."));
+ hide();
+ e->ignore();
+ }
+}
+
+void
+ChatDialog::changeEvent(QEvent *e)
+{
+ switch(e->type())
+ {
+ case QEvent::ActivationChange:
+ if (isActiveWindow())
+ {
+ trayIcon->setIcon(QIcon(":/images/icon_small.png"));
+ }
+ break;
+ default:
+ break;
+ }
+}
+
void
ChatDialog::appendMessage(const SyncDemo::ChatMessage msg)
{
@@ -111,6 +157,7 @@
table->cellAt(0, 1).firstCursorPosition().insertText(msg.data().c_str());
QScrollBar *bar = textEdit->verticalScrollBar();
bar->setValue(bar->maximum());
+ showMessage(from, msg.data().c_str());
}
void
@@ -375,6 +422,74 @@
}
}
+void
+ChatDialog::iconActivated(QSystemTrayIcon::ActivationReason reason)
+{
+ switch (reason)
+ {
+ case QSystemTrayIcon::Trigger:
+ case QSystemTrayIcon::DoubleClick:
+ break;
+ case QSystemTrayIcon::MiddleClick:
+ // showMessage();
+ break;
+ default:;
+ }
+}
+
+void
+ChatDialog::showMessage(QString from, QString data)
+{
+ // std::cout <<"Showing Message: " << from.toStdString() << ": " << data.toStdString() << std::endl;
+ if (!isActiveWindow())
+ {
+ trayIcon->showMessage(QString("Chatroom %1 has a new message").arg(m_user.getChatroom()), QString("<%1>: %2").arg(from).arg(data), QSystemTrayIcon::Information, 20000);
+ trayIcon->setIcon(QIcon(":/images/note.png"));
+ }
+}
+
+void
+ChatDialog::messageClicked()
+{
+ this->showMaximized();
+}
+
+void
+ChatDialog::createActions()
+{
+ minimizeAction = new QAction(tr("Mi&nimize"), this);
+ connect(minimizeAction, SIGNAL(triggered()), this, SLOT(hide()));
+
+ maximizeAction = new QAction(tr("Ma&ximize"), this);
+ connect(maximizeAction, SIGNAL(triggered()), this, SLOT(showMaximized()));
+
+ restoreAction = new QAction(tr("&Restore"), this);
+ connect(restoreAction, SIGNAL(triggered()), this, SLOT(showNormal()));
+
+ quitAction = new QAction(tr("Quit"), this);
+ connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
+}
+
+void
+ChatDialog::createTrayIcon()
+{
+ trayIconMenu = new QMenu(this);
+ trayIconMenu->addAction(minimizeAction);
+ trayIconMenu->addAction(maximizeAction);
+ trayIconMenu->addAction(restoreAction);
+ trayIconMenu->addSeparator();
+ trayIconMenu->addAction(quitAction);
+
+ trayIcon = new QSystemTrayIcon(this);
+ trayIcon->setContextMenu(trayIconMenu);
+
+ QIcon icon(":/images/icon_small.png");
+ trayIcon->setIcon(icon);
+ setWindowIcon(icon);
+ trayIcon->setToolTip("Sync-Demo System Tray Icon");
+ trayIcon->setVisible(true);
+}
+
void
ChatDialog::resizeEvent(QResizeEvent *e)
{
diff --git a/chatdialog.h b/chatdialog.h
index e5e0c34..116e20e 100644
--- a/chatdialog.h
+++ b/chatdialog.h
@@ -9,22 +9,31 @@
#include <sync-app-socket.h>
#include <sync-logic.h>
#include <sync-seq-no.h>
+#include <QSystemTrayIcon>
#define ORGANIZATION "IRL@UCLA"
#define APPLICATION "SYNC-DEMO"
+class QAction;
+class QMenu;
+
class ChatDialog : public QDialog, private Ui::ChatDialog
{
Q_OBJECT
public:
- ChatDialog(QWidget *parent = 0);
+ ChatDialog(QWidget *parent = 0);
~ChatDialog();
+ void setVisible(bool visible);
void processRemove(const std::string);
void appendMessage(const SyncDemo::ChatMessage msg);
void processTreeUpdateWrapper(const std::vector<Sync::MissingDataInfo>, Sync::SyncAppSocket *);
void processDataWrapper(std::string, const char *buf, size_t len);
+protected:
+ void closeEvent(QCloseEvent *e);
+ void changeEvent(QEvent *e);
+
public slots:
void processTreeUpdate(const std::vector<Sync::MissingDataInfo>);
void processData(QString name, const char *buf, size_t len);
@@ -38,6 +47,8 @@
void showEvent(QShowEvent *);
void fitView();
void testDraw();
+ void createTrayIcon();
+ void createActions();
private slots:
void returnPressed();
@@ -45,6 +56,11 @@
void checkSetting();
void settingUpdated(QString, QString, QString);
+ // icon related
+ void iconActivated(QSystemTrayIcon::ActivationReason reason);
+ void showMessage(QString, QString);
+ void messageClicked();
+
signals:
void dataReceived(QString name, const char *buf, size_t len);
void treeUpdated(const std::vector<Sync::MissingDataInfo>);
@@ -56,5 +72,13 @@
DigestTreeScene *m_scene;
boost::mutex m_msgMutex;
boost::mutex m_sceneMutex;
+
+ // icon related
+ QAction *minimizeAction;
+ QAction *maximizeAction;
+ QAction *restoreAction;
+ QAction *quitAction;
+ QSystemTrayIcon *trayIcon;
+ QMenu *trayIconMenu;
};
#endif
diff --git a/demo.icns b/demo.icns
new file mode 100644
index 0000000..c3661e6
--- /dev/null
+++ b/demo.icns
Binary files differ
diff --git a/demo.qrc b/demo.qrc
new file mode 100644
index 0000000..b17d550
--- /dev/null
+++ b/demo.qrc
@@ -0,0 +1,7 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/">
+ <file>images/icon_large.png</file>
+ <file>images/icon_small.png</file>
+ <file>images/note.png</file>
+</qresource>
+</RCC>
diff --git a/images/icon_large.png b/images/icon_large.png
new file mode 100644
index 0000000..b0bde46
--- /dev/null
+++ b/images/icon_large.png
Binary files differ
diff --git a/images/icon_small.png b/images/icon_small.png
new file mode 100644
index 0000000..a9630a8
--- /dev/null
+++ b/images/icon_small.png
Binary files differ
diff --git a/images/note.png b/images/note.png
new file mode 100644
index 0000000..2881ccd
--- /dev/null
+++ b/images/note.png
Binary files differ
diff --git a/main.cpp b/main.cpp
index 6b73923..c12375a 100644
--- a/main.cpp
+++ b/main.cpp
@@ -1,10 +1,27 @@
#include<QApplication>
#include "chatdialog.h"
+#include <QMessageBox>
int main(int argc, char *argv[])
{
+
+ Q_INIT_RESOURCE(demo);
QApplication app(argc, argv);
+
+ if (!QSystemTrayIcon::isSystemTrayAvailable()) {
+ QMessageBox::critical(0, QObject::tr("Systray"),
+ QObject::tr("I couldn't detect any system tray "
+ "on this system."));
+ return 1;
+ }
+ QApplication::setQuitOnLastWindowClosed(false);
+#ifdef __APPLE__
+ app.setWindowIcon(QIcon(":/demo.icns"));
+#else
+ app.setWindowIcon(QIcon(":/images/icon_large.png"));
+#endif
+
ChatDialog dialog;
dialog.show();
dialog.activateWindow();
diff --git a/sync-demo.pro b/sync-demo.pro
index 7eb99d0..a12f970 100644
--- a/sync-demo.pro
+++ b/sync-demo.pro
@@ -12,6 +12,9 @@
settingdialog.cpp \
treelayout.cpp
+RESOURCES = demo.qrc
+ICON = demo.icns
+QT += xml svg
FORMS = chatdialog.ui \
settingdialog.ui