Tray application for Linux

Change-Id: I55862204ef71f69bc88c79fe2259f7cb8365699a
diff --git a/linux/tray-menu.cpp b/linux/tray-menu.cpp
new file mode 100644
index 0000000..3d96ac9
--- /dev/null
+++ b/linux/tray-menu.cpp
@@ -0,0 +1,364 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * @copyright See LICENCE for copyright and license information.
+ *
+ * @author Ilya Moiseenko <iliamo@ucla.edu>
+ */
+
+#include "tray-menu.h"
+#include "ui_traymenu.h"   //generated from traymenu.ui
+#include "quit-dialog.h"
+#include "fib-input-dialog.h"
+
+#include <QMenu>
+#include <QCloseEvent>
+#include <QDesktopServices>
+#include <QMessageBox>
+#include <QUrl>
+#include <QCheckBox>
+#include <QLabel>
+#include <QHBoxLayout>
+#include <QLineEdit>
+#include <QProcess>
+#include <QXmlStreamReader>
+#include <QXmlQuery>
+#include <QDebug>
+#include <QtXml>
+#include <QStandardItemModel>
+
+TrayMenu::TrayMenu(QWidget *parent) :
+    QMainWindow(parent),
+    ui(new Ui::TrayMenu)
+{
+    ui->setupUi(this);
+
+    createTrayIcon();
+    setIcon(true);
+    createToolbar();
+    createTableView();
+
+    startDaemon();
+
+    connect(ui->openTrafficMapButton, SIGNAL(pressed()), this, SLOT(openTrafficMap()));
+    connect(ui->openRoutingStatusButton, SIGNAL(pressed()), this, SLOT(openRoutingStatus()));
+    connect(ui->addFibButton, SIGNAL(pressed()), this, SLOT(showFibInputDialog()));
+    connect(ui->deleteFibButton, SIGNAL(released()), this, SLOT(deleteFibEntry()));
+    connect(ui->softwareUpdateCheckbox, SIGNAL(stateChanged(int)), this, SLOT(changeSoftwareUpdate()));
+    connect(ui->hubDiscoveryCheckbox, SIGNAL(stateChanged(int)), this, SLOT(changeHubDiscovery()));
+    connect(ui->loginStartCheckbox, SIGNAL(stateChanged(int)), this, SLOT(changeLoginStart()));
+    connect(ui->shutdownCheckbox, SIGNAL(stateChanged(int)), this, SLOT(changeShutdownExit()));
+    connect(ui->tableView, SIGNAL(clicked(QModelIndex)), this, SLOT(selectTableRow()));
+
+    statusUpdateThread = new QThread();
+    statusUpdateThread->start();
+
+    daemonStatusTimer = new QTimer(statusUpdateThread);
+    connect(daemonStatusTimer, SIGNAL(timeout()), this, SLOT(daemonStatusUpdate()));
+    daemonStatusTimer->start(1000);
+
+    trayIcon->show();
+}
+
+void TrayMenu::changeSoftwareUpdate()
+{
+    if(ui->softwareUpdateCheckbox->isChecked())
+        allowAutomaticUpdates = true;
+    else
+        allowAutomaticUpdates = false;
+}
+
+void TrayMenu::changeHubDiscovery()
+{
+    if(ui->hubDiscoveryCheckbox->isChecked())
+        enableHubDiscovery = true;
+    else
+        enableHubDiscovery = false;
+}
+
+void TrayMenu::changeLoginStart()
+{
+    if(ui->loginStartCheckbox->isChecked())
+        enableStartOnLogin = true;
+    else
+        enableStartOnLogin = false;
+}
+
+void TrayMenu::changeShutdownExit()
+{
+    if(ui->shutdownCheckbox->isChecked())
+        shutdownOnExit = true;
+    else
+        shutdownOnExit = false;
+}
+
+void TrayMenu::showFibInputDialog()
+{
+    dialog = new FibInputDialog(this);
+    dialog->exec();
+}
+
+void TrayMenu::openTrafficMap()
+{
+    QDesktopServices::openUrl(QUrl("http://ndnmap.arl.wustl.edu/", QUrl::TolerantMode));
+}
+
+void TrayMenu::openRoutingStatus()
+{
+    QDesktopServices::openUrl(QUrl("http://netlab.cs.memphis.edu/script/htm/status.htm", QUrl::TolerantMode));
+}
+
+void TrayMenu::createTrayIcon()
+{
+    trayIconMenu = new QMenu(this);
+
+    statusIndicator = new QAction(tr("Inactive"), this);
+    trayIconMenu->addAction(statusIndicator);
+
+    trayIconMenu->addSeparator();
+
+    QAction *displayStatus = new QAction(tr("Status"), this);
+    connect(displayStatus, SIGNAL(triggered()), this, SLOT(displayPopup()));
+    trayIconMenu->addAction(displayStatus);
+
+    trayIconMenu->addSeparator();
+
+    open = new QAction(tr("Preferences..."), this);
+    connect(open, SIGNAL(triggered()), this, SLOT(show()));
+    trayIconMenu->addAction(open);
+
+    close = new QAction(tr("Quit..."), this);
+    connect(close, SIGNAL(triggered()), this, SLOT(confirmQuit()));
+    trayIconMenu->addAction(close);
+
+    trayIcon = new QSystemTrayIcon(this);
+    trayIcon->setContextMenu(trayIconMenu);
+
+    connect(
+            trayIcon,
+            SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
+            this,
+            SLOT(trayIconClicked(QSystemTrayIcon::ActivationReason))
+           );
+}
+
+void TrayMenu::createToolbar()
+{
+    toolBar = new QToolBar(this);
+    toolBar->setFloatable(false);
+    toolBar->setMovable(false);
+    toolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
+    toolBar->setAllowedAreas(Qt::TopToolBarArea);
+    toolBar->setOrientation(Qt::Horizontal);
+    toolBar->setIconSize(QSize(32,32));
+    toolBar->resize(this->width(), 64);
+
+    openGeneralSettings = new QAction(tr("General"), this);
+    openGeneralSettings->setIcon(QIcon(":/resource/Resources/preferences-desktop.png"));
+    connect(openGeneralSettings,SIGNAL(triggered()),this, SLOT(generalSettingsClicked()));
+
+    openForwardingSettings = new QAction(tr("Forwarding"), this);
+    openForwardingSettings->setIcon(QIcon(":/resource/Resources/emblem-web.png"));
+    connect(openForwardingSettings,SIGNAL(triggered()),this, SLOT(forwardingSettingsClicked()));
+
+    openSecuritySettings = new QAction(tr("Security"), this);
+    openSecuritySettings->setIcon(QIcon(":/resource/Resources/emblem-system.png"));
+    connect(openSecuritySettings,SIGNAL(triggered()),this, SLOT(securitySettingsClicked()));
+
+    toolBar->addAction(openGeneralSettings);
+    toolBar->addAction(openForwardingSettings);
+    toolBar->addAction(openSecuritySettings);
+}
+
+void TrayMenu::generalSettingsClicked()
+{
+    ui->generalSettingsWidget->show();
+    ui->forwardingSettingsWidget->hide();
+    ui->securitySettingsWidget->hide();
+}
+
+void TrayMenu::forwardingSettingsClicked()
+{
+    ui->generalSettingsWidget->hide();
+    ui->forwardingSettingsWidget->show();
+    ui->securitySettingsWidget->hide();
+}
+
+void TrayMenu::securitySettingsClicked()
+{
+    ui->generalSettingsWidget->hide();
+    ui->forwardingSettingsWidget->hide();
+    ui->securitySettingsWidget->show();
+}
+
+void TrayMenu::displayPopup()
+{
+    trayIcon->showMessage(tr("NDNx Status"), statusXml);
+}
+
+void TrayMenu::addFibEntry()
+{
+    QString name = dialog->getPrefixName();
+    QString tunnelType = dialog->getTunnelType();
+    QString endpoint = dialog->getEndpoint();
+
+    QStringList arguments;
+    arguments << "add" << name << tunnelType << endpoint;
+
+    dialog->hide();
+
+    QProcess *process = new QProcess(this);
+    process->start(NDND_FIB_COMMAND,arguments);
+}
+
+void TrayMenu::confirmQuit()
+{
+    QuitDialog dialog(this);
+    dialog.exec();
+}
+
+void TrayMenu::terminateDaemonAndClose()
+{
+    QProcess *process = new QProcess(this);
+    process->start(NDND_STOP_COMMAND);
+    connect(process,SIGNAL(finished(int)), qApp, SLOT(quit()));
+}
+
+void TrayMenu::closeEvent(QCloseEvent *event)
+{
+    if (trayIcon->isVisible())
+    {
+        hide();
+        event->ignore();
+    }
+}
+
+void TrayMenu::showEvent(QShowEvent * event)
+{
+    ui->generalSettingsWidget->show();
+    ui->forwardingSettingsWidget->hide();
+    ui->securitySettingsWidget->hide();
+}
+
+void TrayMenu::trayIconClicked(QSystemTrayIcon::ActivationReason reason)
+{
+    if(reason == QSystemTrayIcon::Trigger)
+        this->show();
+}
+
+void TrayMenu::setIcon(bool isConnected)
+{
+    if(isConnected)
+        trayIcon->setIcon(QIcon(":/resource/Resources/icon-connected-white.png"));
+    else
+        trayIcon->setIcon(QIcon(":/resource/Resources/icon-disconnected-white.png"));
+}
+
+void TrayMenu::startDaemon()
+{
+    QProcess *process = new QProcess(this);
+    process->start(NDND_START_COMMAND);
+}
+
+void TrayMenu::daemonStatusUpdate()
+{
+    QXmlQuery query(QXmlQuery::XSLT20);
+    query.setFocus(QUrl("http://localhost:9695/?f=xml"));
+
+    query.setQuery(QUrl("qrc:/resource/Resources/status.xslt")); // TODO: I suspect it's being read from HDD each time
+    query.evaluateTo(&statusXml);
+
+    query.setQuery(QUrl("qrc:/resource/Resources/status-to-fib.xslt"));  // TODO: I suspect it's being read from HDD each time
+    query.evaluateTo(&fibContentsXml);
+
+    QDomDocument xmldoc;
+    QDomElement root;
+
+    xmldoc.setContent(fibContentsXml);
+    root=xmldoc.documentElement();
+
+    model = new QStandardItemModel(root.childNodes().count(),3);
+    model->setHorizontalHeaderItem(0, new QStandardItem(tr("NDN prefix")));
+    model->setHorizontalHeaderItem(1, new QStandardItem(tr("Face ID")));
+    model->setHorizontalHeaderItem(2, new QStandardItem(tr("Endpoint")));
+
+    int row = 0;
+    QDomNode fibEntry=root.firstChild();
+    while (!fibEntry.isNull())
+    {
+        QDomNodeList properties = fibEntry.childNodes();
+
+        QDomNode faceID = properties.at(0);
+        QDomNode ip =  properties.at(1);
+        QDomNode prefix = properties.at(2);
+
+        // bad: causes scroll to go up every time and overall flickering
+        /*QList<QStandardItem*> row = QList<QStandardItem*>() << new QStandardItem(prefix.toElement().text())
+                                                                       << new QStandardItem(faceID.toElement().text())
+                                                                       << new QStandardItem(ip.toElement().text());
+        model->appendRow(row);*/
+
+        model->setItem(row, 0, new QStandardItem(prefix.toElement().text()));
+        model->setItem(row, 1, new QStandardItem(faceID.toElement().text()));
+        model->setItem(row, 2, new QStandardItem(ip.toElement().text()));
+
+        fibEntry = fibEntry.nextSibling();
+        row++;
+   }
+
+    ui->tableView->setModel(model);
+
+    if(selectedRow >= 0)
+        ui->tableView->selectRow(selectedRow);
+}
+
+void TrayMenu::createTableView()
+{
+    ui->tableView->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
+    ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection);
+    ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
+
+    selectedRow = -1;
+}
+
+void TrayMenu::selectTableRow()
+{
+    selectedRow = ui->tableView->selectionModel()->selection().indexes().at(0).row();
+}
+
+void TrayMenu::deleteFibEntry()
+{
+    if(selectedRow < 0)
+        return;
+
+    QStandardItem *prefix = model->item(selectedRow,0);
+    if(prefix == NULL)
+        return;
+
+    QStandardItem *faceID = model->item(selectedRow,1);
+    if(faceID == NULL)
+        return;
+
+    QStringList arguments;
+    arguments << "del" << prefix->text() << "face" << faceID->text();
+
+    QProcess *process = new QProcess(this);
+    process->start(NDND_FIB_COMMAND,arguments);
+}
+
+TrayMenu::~TrayMenu()
+{
+    daemonStatusTimer->stop();
+    statusUpdateThread->exit();
+    delete ui;
+    delete trayIcon;
+    delete trayIconMenu;
+    delete open;
+    delete close;
+    delete openGeneralSettings;
+    delete openForwardingSettings;
+    delete openSecuritySettings;
+    delete toolBar;
+    delete statusUpdateThread;
+    delete daemonStatusTimer;
+    delete dialog;
+}