Tray application for Linux

Change-Id: I55862204ef71f69bc88c79fe2259f7cb8365699a
diff --git a/linux/Resources/emblem-dropbox-unsyncable.png b/linux/Resources/emblem-dropbox-unsyncable.png
new file mode 100644
index 0000000..0192e41
--- /dev/null
+++ b/linux/Resources/emblem-dropbox-unsyncable.png
Binary files differ
diff --git a/linux/Resources/emblem-system.png b/linux/Resources/emblem-system.png
new file mode 100644
index 0000000..5ebfb3a
--- /dev/null
+++ b/linux/Resources/emblem-system.png
Binary files differ
diff --git a/linux/Resources/emblem-web.png b/linux/Resources/emblem-web.png
new file mode 100644
index 0000000..1fd9f76
--- /dev/null
+++ b/linux/Resources/emblem-web.png
Binary files differ
diff --git a/linux/Resources/gnome-system.png b/linux/Resources/gnome-system.png
new file mode 100644
index 0000000..168dee0
--- /dev/null
+++ b/linux/Resources/gnome-system.png
Binary files differ
diff --git a/linux/Resources/icon-connected-white.png b/linux/Resources/icon-connected-white.png
new file mode 100644
index 0000000..55f0dc4
--- /dev/null
+++ b/linux/Resources/icon-connected-white.png
Binary files differ
diff --git a/linux/Resources/icon-disconnected-white.png b/linux/Resources/icon-disconnected-white.png
new file mode 100644
index 0000000..39997cd
--- /dev/null
+++ b/linux/Resources/icon-disconnected-white.png
Binary files differ
diff --git a/linux/Resources/mail-send-receive.png b/linux/Resources/mail-send-receive.png
new file mode 100644
index 0000000..20fcbe2
--- /dev/null
+++ b/linux/Resources/mail-send-receive.png
Binary files differ
diff --git a/linux/Resources/preferences-desktop.png b/linux/Resources/preferences-desktop.png
new file mode 100644
index 0000000..8dd7ba6
--- /dev/null
+++ b/linux/Resources/preferences-desktop.png
Binary files differ
diff --git a/linux/Resources/status-to-fib.xslt b/linux/Resources/status-to-fib.xslt
new file mode 100644
index 0000000..c224ff5
--- /dev/null
+++ b/linux/Resources/status-to-fib.xslt
@@ -0,0 +1,29 @@
+<xsl:stylesheet version = '2.0'
+                xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
+
+<xsl:template match="/ndnd">
+<fibs>
+<xsl:apply-templates select="forwarding/fentry/dest" />
+</fibs>
+</xsl:template>
+
+<xsl:template match="dest">
+<fib>
+<xsl:apply-templates select="faceid" />
+<prefix><xsl:value-of select="../prefix"/></prefix>
+</fib>
+</xsl:template>
+
+<xsl:template match="faceid">
+<xsl:variable name="id"><xsl:value-of select="." /></xsl:variable>
+<faceID><xsl:copy-of select="$id" /></faceID>
+<ip>
+<xsl:choose>
+  <xsl:when test="count(//face/ip[../faceid=$id]) &gt; 0"><xsl:value-of select="//face/ip[../faceid=$id]" />
+  </xsl:when>
+  <xsl:otherwise>app</xsl:otherwise>
+</xsl:choose>
+</ip>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/linux/Resources/status.xslt b/linux/Resources/status.xslt
new file mode 100644
index 0000000..bf33e49
--- /dev/null
+++ b/linux/Resources/status.xslt
@@ -0,0 +1,28 @@
+<xsl:stylesheet version = '2.0'
+                xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
+
+<xsl:template match="/ndnd">
+<html><body>
+<xsl:apply-templates select="forwarding/fentry" />
+</body></html>
+</xsl:template>
+
+<xsl:template match="fentry">
+<xsl:apply-templates select="dest/faceid" />
+<xsl:text> </xsl:text>
+<xsl:value-of select="prefix"/>
+<br/>
+</xsl:template>
+
+<xsl:template match="faceid">
+<xsl:variable name="id"><xsl:value-of select="." /></xsl:variable>
+<b>face: <xsl:copy-of select="$id" />
+
+<xsl:choose>
+  <xsl:when test="count(//face/ip[../faceid=$id]) &gt; 0"> (<xsl:value-of select="//face/ip[../faceid=$id]" />)
+  </xsl:when>
+  <xsl:otherwise> (app)</xsl:otherwise>
+</xsl:choose></b>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/linux/Resources/system-run.png b/linux/Resources/system-run.png
new file mode 100644
index 0000000..17ceb32
--- /dev/null
+++ b/linux/Resources/system-run.png
Binary files differ
diff --git a/linux/fib-input-dialog.cpp b/linux/fib-input-dialog.cpp
new file mode 100644
index 0000000..5aef521
--- /dev/null
+++ b/linux/fib-input-dialog.cpp
@@ -0,0 +1,73 @@
+/* -*- 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 "fib-input-dialog.h"
+#include <QVBoxLayout>
+#include <QHBoxLayout>
+
+FibInputDialog::FibInputDialog(QWidget *parent)
+    : QDialog(parent)
+{
+    prefixLabel = new QLabel(tr("NDN name (prefix): "));
+    prefixTextField = new QLineEdit;
+    prefixLabel->setBuddy(prefixTextField);
+
+    tunnelLabel = new QLabel(tr("Tunnel type: "));
+    tunnelComboBox = new QComboBox;
+    tunnelComboBox->addItem(tr("TCP"));
+    tunnelComboBox->addItem(tr("UDP"));
+    tunnelComboBox->setEditable(false);
+    tunnelComboBox->setCurrentIndex(0);
+
+    endpointLabel = new QLabel(tr("Endpoint (IP address): "));
+    endpointTextField = new QLineEdit;
+    endpointLabel->setBuddy(endpointTextField);
+
+    okButton = new QPushButton(tr("&Ok"));
+    cancelButton = new QPushButton(tr("&Cancel"));
+
+    connect(okButton,SIGNAL(pressed()), parent, SLOT(addFibEntry()));
+    connect(cancelButton,SIGNAL(pressed()), this, SLOT(hide()));
+
+    buttonBox = new QDialogButtonBox(Qt::Horizontal);
+    buttonBox->addButton(cancelButton, QDialogButtonBox::ActionRole);
+    buttonBox->addButton(okButton, QDialogButtonBox::ActionRole);
+
+    QHBoxLayout *hlayout = new QHBoxLayout;
+    hlayout->addWidget(tunnelLabel);
+    hlayout->addWidget(tunnelComboBox);
+
+    QVBoxLayout *layout = new QVBoxLayout;
+    layout->addWidget(prefixLabel);
+    layout->addWidget(prefixTextField);
+    layout->addLayout(hlayout);
+    layout->addWidget(endpointLabel);
+    layout->addWidget(endpointTextField);
+    layout->addWidget(buttonBox);
+
+    setLayout(layout);
+
+    setWindowTitle(tr("NDNx Control Center"));
+}
+
+QString
+FibInputDialog::getPrefixName()
+{
+    return prefixTextField->text();
+}
+
+QString
+FibInputDialog::getEndpoint()
+{
+    return endpointTextField->text();
+}
+
+QString
+FibInputDialog::getTunnelType()
+{
+    return tunnelComboBox->currentText();
+}
diff --git a/linux/fib-input-dialog.h b/linux/fib-input-dialog.h
new file mode 100644
index 0000000..f4f8d27
--- /dev/null
+++ b/linux/fib-input-dialog.h
@@ -0,0 +1,44 @@
+/* -*- 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 <QDialog>
+#include <QLabel>
+#include <QDialogButtonBox>
+#include <QPushButton>
+#include <QLineEdit>
+#include <QComboBox>
+#include <QString>
+
+#ifndef FIBINPUTDIALOG_H
+#define FIBINPUTDIALOG_H
+
+class FibInputDialog : public QDialog
+{
+    Q_OBJECT
+
+public:
+    FibInputDialog(QWidget *parent = 0);
+    QString getPrefixName();
+    QString getEndpoint();
+    QString getTunnelType();
+
+private:
+    QLabel *prefixLabel;
+    QLineEdit *prefixTextField;
+
+    QLabel *tunnelLabel;
+    QComboBox *tunnelComboBox;
+
+    QLabel *endpointLabel;
+    QLineEdit *endpointTextField;
+
+    QDialogButtonBox *buttonBox;
+    QPushButton *okButton;
+    QPushButton *cancelButton;
+};
+
+#endif // FIBINPUTDIALOG_H
diff --git a/linux/main.cpp b/linux/main.cpp
new file mode 100644
index 0000000..f1fc24e
--- /dev/null
+++ b/linux/main.cpp
@@ -0,0 +1,17 @@
+/* -*- 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 <QtGui/QApplication>
+#include "traymenu.h"
+
+int main(int argc, char *argv[])
+{
+    QApplication a(argc, argv);
+    TrayMenu w;
+    
+    return a.exec();
+}
diff --git a/linux/quit-dialog.cpp b/linux/quit-dialog.cpp
new file mode 100644
index 0000000..bd53f24
--- /dev/null
+++ b/linux/quit-dialog.cpp
@@ -0,0 +1,40 @@
+/* -*- 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 "quit-dialog.h"
+#include <QVBoxLayout>
+#include <QApplication>
+
+QuitDialog::QuitDialog(QWidget *parent)
+    : QDialog(parent)
+{
+    question = new QLabel(tr("Shutdown NDN daemon as well?"));
+    information = new QLabel(tr("All NDN operations will become unavailable."));
+
+    confirmButton = new QPushButton(tr("Yes"));
+    noButton = new QPushButton(tr("No"));
+    cancelButton = new QPushButton(tr("Cancel"));
+    cancelButton->setDefault(true);
+
+    buttonBox = new QDialogButtonBox(Qt::Horizontal);
+    buttonBox->addButton(cancelButton, QDialogButtonBox::ActionRole);
+    buttonBox->addButton(noButton, QDialogButtonBox::ActionRole);
+    buttonBox->addButton(confirmButton, QDialogButtonBox::ActionRole);
+
+    connect(confirmButton,SIGNAL(pressed()), parent, SLOT(terminateDaemonAndClose()));
+    connect(noButton,SIGNAL(pressed()), qApp, SLOT(quit()));
+    connect(cancelButton,SIGNAL(pressed()), this, SLOT(hide()));
+
+    QVBoxLayout *layout = new QVBoxLayout;
+    layout->addWidget(question);
+    layout->addWidget(information);
+    layout->addWidget(buttonBox);
+
+    setLayout(layout);
+
+    setWindowTitle(tr("NDNx Control Center"));
+}
diff --git a/linux/quit-dialog.h b/linux/quit-dialog.h
new file mode 100644
index 0000000..e6fc7e3
--- /dev/null
+++ b/linux/quit-dialog.h
@@ -0,0 +1,32 @@
+/* -*- 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 <QDialog>
+#include <QLabel>
+#include <QDialogButtonBox>
+#include <QPushButton>
+
+#ifndef QUITDIALOG_H
+#define QUITDIALOG_H
+
+class QuitDialog : public QDialog
+{
+    Q_OBJECT
+
+public:
+    QuitDialog(QWidget *parent = 0);
+
+private:
+    QLabel *question;
+    QLabel *information;
+    QDialogButtonBox *buttonBox;
+    QPushButton *confirmButton;
+    QPushButton *noButton;
+    QPushButton *cancelButton;
+};
+
+#endif // QUITDIALOG_H
diff --git a/linux/resource.qrc b/linux/resource.qrc
new file mode 100644
index 0000000..77511fa
--- /dev/null
+++ b/linux/resource.qrc
@@ -0,0 +1,17 @@
+<RCC>
+    <qresource prefix="/resource">
+        <file>Resources/icon1.png</file>
+        <file>Resources/FlatConnected.png</file>
+        <file>Resources/emblem-dropbox-unsyncable.png</file>
+        <file>Resources/emblem-system.png</file>
+        <file>Resources/emblem-web.png</file>
+        <file>Resources/gnome-system.png</file>
+        <file>Resources/mail-send-receive.png</file>
+        <file>Resources/preferences-desktop.png</file>
+        <file>Resources/system-run.png</file>
+        <file>Resources/status.xslt</file>
+        <file>Resources/icon-connected-white.png</file>
+        <file>Resources/icon-disconnected-white.png</file>
+        <file>Resources/status-to-fib.xslt</file>
+    </qresource>
+</RCC>
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;
+}
diff --git a/linux/tray-menu.h b/linux/tray-menu.h
new file mode 100644
index 0000000..045bb09
--- /dev/null
+++ b/linux/tray-menu.h
@@ -0,0 +1,103 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * @copyright See LICENCE for copyright and license information.
+ *
+ * @author Ilya Moiseenko <iliamo@ucla.edu>
+ */
+
+#ifndef TRAYMENU_H
+#define TRAYMENU_H
+
+#include <QMainWindow>
+#include <QWidget>
+#include <QSystemTrayIcon>
+#include <QMenu>
+#include <QTimer>
+#include <QProcess>
+#include <QThread>
+#include <QXmlStreamReader>
+#include <QStandardItemModel>
+#include <QtXml>
+
+#include "FibInputDialog.h"
+#include "QuitDialog.h"
+
+#define NDND_START_COMMAND "/usr/local/bin/ndndstart"
+#define NDND_STOP_COMMAND "/usr/local/bin/ndndstop"
+#define NDND_STATUS_COMMAND "/usr/local/bin/ndndsmoketest"
+#define NDND_FIB_COMMAND "/usr/local/bin/ndndc"
+
+namespace Ui
+{
+    class TrayMenu;
+}
+
+class TrayMenu : public QMainWindow
+{
+    Q_OBJECT
+    
+public:
+    explicit TrayMenu(QWidget *parent = 0);
+    ~TrayMenu();
+
+private:
+    Ui::TrayMenu *ui;
+
+    void createTrayIcon();
+    void setIcon(bool isConnected);
+    void createToolbar();
+    void createTableView();
+    void closeEvent(QCloseEvent *); // Overriding the window's close event
+    void showEvent(QShowEvent * event); //Overriding the window's show event
+
+    void startDaemon();
+
+    QSystemTrayIcon *trayIcon;
+    QMenu *trayIconMenu;
+    QToolBar *toolBar;
+
+    QTimer *daemonStatusTimer;
+    QThread *statusUpdateThread;
+
+    QString statusXml;
+    QString fibContentsXml;
+
+    QStandardItemModel *model;
+    int selectedRow;
+
+    QAction *statusIndicator;
+    QAction *open;
+    QAction *close;
+    QAction *openGeneralSettings;
+    QAction *openForwardingSettings;
+    QAction *openSecuritySettings;
+
+    FibInputDialog *dialog;
+
+    bool allowAutomaticUpdates;
+    bool enableHubDiscovery;
+    bool enableStartOnLogin;
+    bool shutdownOnExit;
+
+private slots:
+    void trayIconClicked(QSystemTrayIcon::ActivationReason);
+    void generalSettingsClicked();
+    void forwardingSettingsClicked();
+    void securitySettingsClicked();
+    void openTrafficMap();
+    void openRoutingStatus();
+    void displayPopup();
+    void confirmQuit();
+    void showFibInputDialog();
+    void terminateDaemonAndClose();
+    void addFibEntry();
+    void daemonStatusUpdate();
+    void selectTableRow();
+    void deleteFibEntry();
+    void changeSoftwareUpdate();
+    void changeHubDiscovery();
+    void changeLoginStart();
+    void changeShutdownExit();
+};
+
+#endif // TRAYMENU_H
diff --git a/linux/traymenu.ui b/linux/traymenu.ui
new file mode 100644
index 0000000..428f343
--- /dev/null
+++ b/linux/traymenu.ui
@@ -0,0 +1,304 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>TrayMenu</class>
+ <widget class="QMainWindow" name="TrayMenu">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>551</width>
+    <height>332</height>
+   </rect>
+  </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="Maximum" vsizetype="Expanding">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
+  <property name="windowTitle">
+   <string>NDNx preferences</string>
+  </property>
+  <property name="animated">
+   <bool>true</bool>
+  </property>
+  <widget class="QWidget" name="centralWidget">
+   <widget class="QWidget" name="generalSettingsWidget" native="true">
+    <property name="geometry">
+     <rect>
+      <x>10</x>
+      <y>50</y>
+      <width>521</width>
+      <height>241</height>
+     </rect>
+    </property>
+    <widget class="QGroupBox" name="groupBox">
+     <property name="geometry">
+      <rect>
+       <x>10</x>
+       <y>0</y>
+       <width>471</width>
+       <height>141</height>
+      </rect>
+     </property>
+     <property name="styleSheet">
+      <string notr="true">QGroupBox#groupBox { 
+border: 2px solid gray; 
+border-radius: 7px; 
+}</string>
+     </property>
+     <property name="title">
+      <string/>
+     </property>
+     <property name="flat">
+      <bool>false</bool>
+     </property>
+     <widget class="QCheckBox" name="shutdownCheckbox">
+      <property name="geometry">
+       <rect>
+        <x>0</x>
+        <y>110</y>
+        <width>441</width>
+        <height>22</height>
+       </rect>
+      </property>
+      <property name="font">
+       <font>
+        <pointsize>13</pointsize>
+       </font>
+      </property>
+      <property name="text">
+       <string>Shutdown NDN daemon on exit</string>
+      </property>
+     </widget>
+     <widget class="QCheckBox" name="softwareUpdateCheckbox">
+      <property name="geometry">
+       <rect>
+        <x>0</x>
+        <y>80</y>
+        <width>441</width>
+        <height>22</height>
+       </rect>
+      </property>
+      <property name="font">
+       <font>
+        <pointsize>13</pointsize>
+       </font>
+      </property>
+      <property name="text">
+       <string>Check for software updates</string>
+      </property>
+     </widget>
+     <widget class="QCheckBox" name="hubDiscoveryCheckbox">
+      <property name="geometry">
+       <rect>
+        <x>0</x>
+        <y>50</y>
+        <width>431</width>
+        <height>22</height>
+       </rect>
+      </property>
+      <property name="font">
+       <font>
+        <pointsize>13</pointsize>
+       </font>
+      </property>
+      <property name="text">
+       <string>Discover nearest NDN-hub</string>
+      </property>
+     </widget>
+     <widget class="QCheckBox" name="loginStartCheckbox">
+      <property name="geometry">
+       <rect>
+        <x>0</x>
+        <y>20</y>
+        <width>451</width>
+        <height>22</height>
+       </rect>
+      </property>
+      <property name="font">
+       <font>
+        <pointsize>13</pointsize>
+       </font>
+      </property>
+      <property name="text">
+       <string>Automatically start NDNx Control Center at login</string>
+      </property>
+     </widget>
+     <zorder>shutdownCheckbox</zorder>
+     <zorder>softwareUpdateCheckbox</zorder>
+     <zorder>hubDiscoveryCheckbox</zorder>
+     <zorder>loginStartCheckbox</zorder>
+     <zorder>forwardingSettingsWidget</zorder>
+    </widget>
+    <widget class="QGroupBox" name="groupBox_2">
+     <property name="geometry">
+      <rect>
+       <x>10</x>
+       <y>150</y>
+       <width>471</width>
+       <height>81</height>
+      </rect>
+     </property>
+     <property name="styleSheet">
+      <string notr="true">QGroupBox#groupBox_2 { 
+border: 2px solid gray; 
+border-radius: 7px; 
+}</string>
+     </property>
+     <property name="title">
+      <string/>
+     </property>
+     <widget class="QPushButton" name="openTrafficMapButton">
+      <property name="geometry">
+       <rect>
+        <x>10</x>
+        <y>10</y>
+        <width>241</width>
+        <height>27</height>
+       </rect>
+      </property>
+      <property name="text">
+       <string>Open Testbed Traffic Map</string>
+      </property>
+     </widget>
+     <widget class="QPushButton" name="openRoutingStatusButton">
+      <property name="geometry">
+       <rect>
+        <x>10</x>
+        <y>40</y>
+        <width>241</width>
+        <height>27</height>
+       </rect>
+      </property>
+      <property name="text">
+       <string>Open Testbed Routing Status</string>
+      </property>
+     </widget>
+    </widget>
+   </widget>
+   <widget class="QWidget" name="forwardingSettingsWidget" native="true">
+    <property name="geometry">
+     <rect>
+      <x>10</x>
+      <y>50</y>
+      <width>521</width>
+      <height>251</height>
+     </rect>
+    </property>
+    <widget class="QLabel" name="label">
+     <property name="geometry">
+      <rect>
+       <x>10</x>
+       <y>10</y>
+       <width>66</width>
+       <height>17</height>
+      </rect>
+     </property>
+     <property name="styleSheet">
+      <string notr="true">font: 18pt;</string>
+     </property>
+     <property name="text">
+      <string>FIB</string>
+     </property>
+    </widget>
+    <widget class="QTableView" name="tableView">
+     <property name="geometry">
+      <rect>
+       <x>10</x>
+       <y>30</y>
+       <width>511</width>
+       <height>181</height>
+      </rect>
+     </property>
+    </widget>
+    <widget class="QToolButton" name="addFibButton">
+     <property name="geometry">
+      <rect>
+       <x>10</x>
+       <y>220</y>
+       <width>23</width>
+       <height>25</height>
+      </rect>
+     </property>
+     <property name="text">
+      <string>+</string>
+     </property>
+    </widget>
+    <widget class="QToolButton" name="deleteFibButton">
+     <property name="geometry">
+      <rect>
+       <x>40</x>
+       <y>220</y>
+       <width>23</width>
+       <height>25</height>
+      </rect>
+     </property>
+     <property name="text">
+      <string>-</string>
+     </property>
+    </widget>
+    <zorder>label</zorder>
+    <zorder>tableView</zorder>
+    <zorder>addFibButton</zorder>
+    <zorder>deleteFibButton</zorder>
+    <zorder>securitySettingsWidget</zorder>
+   </widget>
+   <widget class="QWidget" name="securitySettingsWidget" native="true">
+    <property name="geometry">
+     <rect>
+      <x>10</x>
+      <y>50</y>
+      <width>521</width>
+      <height>241</height>
+     </rect>
+    </property>
+   </widget>
+  </widget>
+  <widget class="QStatusBar" name="statusBar"/>
+  <widget class="QToolBar" name="toolBar">
+   <property name="enabled">
+    <bool>true</bool>
+   </property>
+   <property name="sizePolicy">
+    <sizepolicy hsizetype="Maximum" vsizetype="Maximum">
+     <horstretch>0</horstretch>
+     <verstretch>0</verstretch>
+    </sizepolicy>
+   </property>
+   <property name="contextMenuPolicy">
+    <enum>Qt::DefaultContextMenu</enum>
+   </property>
+   <property name="autoFillBackground">
+    <bool>false</bool>
+   </property>
+   <property name="styleSheet">
+    <string notr="true"/>
+   </property>
+   <property name="movable">
+    <bool>false</bool>
+   </property>
+   <property name="allowedAreas">
+    <set>Qt::TopToolBarArea</set>
+   </property>
+   <property name="iconSize">
+    <size>
+     <width>25</width>
+     <height>17</height>
+    </size>
+   </property>
+   <property name="toolButtonStyle">
+    <enum>Qt::ToolButtonTextUnderIcon</enum>
+   </property>
+   <attribute name="toolBarArea">
+    <enum>TopToolBarArea</enum>
+   </attribute>
+   <attribute name="toolBarBreak">
+    <bool>false</bool>
+   </attribute>
+  </widget>
+ </widget>
+ <layoutdefault spacing="6" margin="11"/>
+ <resources/>
+ <connections/>
+</ui>