blob: daf28d577ef4b9fbd1b75d2203ab8e39f3e5916f [file] [log] [blame]
Ilya Moiseenko18c8a132013-10-24 01:52:52 -07001/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
2/*
3 * @copyright See LICENCE for copyright and license information.
4 *
5 * @author Ilya Moiseenko <iliamo@ucla.edu>
6 */
7
8#include "tray-menu.h"
9#include "ui_traymenu.h" //generated from traymenu.ui
10#include "quit-dialog.h"
11#include "fib-input-dialog.h"
Ilya Moiseenko656d52d2013-10-25 14:19:10 -070012#include "network-manager.h"
Ilya Moiseenko18c8a132013-10-24 01:52:52 -070013
14#include <QMenu>
15#include <QCloseEvent>
16#include <QDesktopServices>
17#include <QMessageBox>
18#include <QUrl>
19#include <QCheckBox>
20#include <QLabel>
21#include <QHBoxLayout>
22#include <QLineEdit>
23#include <QProcess>
24#include <QXmlStreamReader>
25#include <QXmlQuery>
26#include <QDebug>
27#include <QtXml>
28#include <QStandardItemModel>
Ilya Moiseenko393cbdc2013-10-29 00:45:40 -070029#include <QDir>
Ilya Moiseenko18c8a132013-10-24 01:52:52 -070030
31TrayMenu::TrayMenu(QWidget *parent) :
32 QMainWindow(parent),
33 ui(new Ui::TrayMenu)
34{
Ilya Moiseenko393cbdc2013-10-29 00:45:40 -070035 networkManager = new NetworkManager();
36
37 QCoreApplication::setOrganizationName("UCLA");
38 QCoreApplication::setOrganizationDomain("named-data.net");
39 QCoreApplication::setApplicationName("NDNx Control Center");
40
41 persistentSettings = new QSettings();
42
Ilya Moiseenko18c8a132013-10-24 01:52:52 -070043 ui->setupUi(this);
44
45 createTrayIcon();
46 setIcon(true);
47 createToolbar();
48 createTableView();
49
Ilya Moiseenko393cbdc2013-10-29 00:45:40 -070050 loadSettings();
Ilya Moiseenko656d52d2013-10-25 14:19:10 -070051
Ilya Moiseenko18c8a132013-10-24 01:52:52 -070052 connect(ui->openTrafficMapButton, SIGNAL(pressed()), this, SLOT(openTrafficMap()));
53 connect(ui->openRoutingStatusButton, SIGNAL(pressed()), this, SLOT(openRoutingStatus()));
54 connect(ui->addFibButton, SIGNAL(pressed()), this, SLOT(showFibInputDialog()));
55 connect(ui->deleteFibButton, SIGNAL(released()), this, SLOT(deleteFibEntry()));
56 connect(ui->softwareUpdateCheckbox, SIGNAL(stateChanged(int)), this, SLOT(changeSoftwareUpdate()));
57 connect(ui->hubDiscoveryCheckbox, SIGNAL(stateChanged(int)), this, SLOT(changeHubDiscovery()));
58 connect(ui->loginStartCheckbox, SIGNAL(stateChanged(int)), this, SLOT(changeLoginStart()));
59 connect(ui->shutdownCheckbox, SIGNAL(stateChanged(int)), this, SLOT(changeShutdownExit()));
60 connect(ui->tableView, SIGNAL(clicked(QModelIndex)), this, SLOT(selectTableRow()));
Ilya Moiseenko393cbdc2013-10-29 00:45:40 -070061 connect(ui->openNdnCertificationButton, SIGNAL(released()), this, SLOT(openCertificationPage()));
Ilya Moiseenko18c8a132013-10-24 01:52:52 -070062
63 statusUpdateThread = new QThread();
64 statusUpdateThread->start();
65
66 daemonStatusTimer = new QTimer(statusUpdateThread);
67 connect(daemonStatusTimer, SIGNAL(timeout()), this, SLOT(daemonStatusUpdate()));
68 daemonStatusTimer->start(1000);
69
70 trayIcon->show();
71}
72
Ilya Moiseenko393cbdc2013-10-29 00:45:40 -070073void TrayMenu::loadSettings()
74{
75 QVariant value;
76
77 value = persistentSettings->value(ALLOW_SOFTWARE_UPDATES);
78 if(!value.isNull())
79 {
80 allowAutomaticUpdates = value.toBool();
81 ui->softwareUpdateCheckbox->setChecked(allowAutomaticUpdates);
82 }
83 else
84 {
85 ui->softwareUpdateCheckbox->setChecked(true);
86 changeSoftwareUpdate();
87 }
88
89 value = persistentSettings->value(ENABLE_HUB_DISCOVERY);
90 if(!value.isNull())
91 {
92 enableHubDiscovery = value.toBool();
93 ui->hubDiscoveryCheckbox->setChecked(enableHubDiscovery);
94 }
95 else
96 {
97 ui->hubDiscoveryCheckbox->setChecked(true);
98 changeHubDiscovery();
99 }
100
101 value = persistentSettings->value(ENABLE_START_ON_LOGIN);
102 if(!value.isNull())
103 {
104 enableStartOnLogin = value.toBool();
105 ui->loginStartCheckbox->setChecked(enableStartOnLogin);
106 }
107 else
108 {
109 ui->loginStartCheckbox->setChecked(false);
110 changeLoginStart();
111 }
112
113 value = persistentSettings->value(SHUTDOWN_ON_EXIT);
114 if(!value.isNull())
115 {
116 shutdownOnExit = value.toBool();
117 ui->shutdownCheckbox->setChecked(shutdownOnExit);
118 }
119 else
120 {
121 ui->shutdownCheckbox->setChecked(false);
122 changeShutdownExit();
123 }
124}
125
Ilya Moiseenko18c8a132013-10-24 01:52:52 -0700126void TrayMenu::changeSoftwareUpdate()
127{
128 if(ui->softwareUpdateCheckbox->isChecked())
Ilya Moiseenko393cbdc2013-10-29 00:45:40 -0700129 {
Ilya Moiseenko18c8a132013-10-24 01:52:52 -0700130 allowAutomaticUpdates = true;
Ilya Moiseenko393cbdc2013-10-29 00:45:40 -0700131 persistentSettings->setValue(ALLOW_SOFTWARE_UPDATES, true);
132 }
Ilya Moiseenko18c8a132013-10-24 01:52:52 -0700133 else
Ilya Moiseenko393cbdc2013-10-29 00:45:40 -0700134 {
Ilya Moiseenko18c8a132013-10-24 01:52:52 -0700135 allowAutomaticUpdates = false;
Ilya Moiseenko393cbdc2013-10-29 00:45:40 -0700136 persistentSettings->setValue(ALLOW_SOFTWARE_UPDATES, false);
137 }
Ilya Moiseenko18c8a132013-10-24 01:52:52 -0700138}
139
140void TrayMenu::changeHubDiscovery()
141{
142 if(ui->hubDiscoveryCheckbox->isChecked())
Ilya Moiseenko393cbdc2013-10-29 00:45:40 -0700143 {
Ilya Moiseenko18c8a132013-10-24 01:52:52 -0700144 enableHubDiscovery = true;
Ilya Moiseenko393cbdc2013-10-29 00:45:40 -0700145 persistentSettings->setValue(ENABLE_HUB_DISCOVERY, true);
146 }
Ilya Moiseenko18c8a132013-10-24 01:52:52 -0700147 else
Ilya Moiseenko393cbdc2013-10-29 00:45:40 -0700148 {
Ilya Moiseenko18c8a132013-10-24 01:52:52 -0700149 enableHubDiscovery = false;
Ilya Moiseenko393cbdc2013-10-29 00:45:40 -0700150 persistentSettings->setValue(ENABLE_HUB_DISCOVERY, false);
151 }
Ilya Moiseenko18c8a132013-10-24 01:52:52 -0700152}
153
154void TrayMenu::changeLoginStart()
155{
156 if(ui->loginStartCheckbox->isChecked())
Ilya Moiseenko393cbdc2013-10-29 00:45:40 -0700157 {
Ilya Moiseenko18c8a132013-10-24 01:52:52 -0700158 enableStartOnLogin = true;
Ilya Moiseenko393cbdc2013-10-29 00:45:40 -0700159 persistentSettings->setValue(ENABLE_START_ON_LOGIN, true);
160 makeAutostartDirectory();
161 }
Ilya Moiseenko18c8a132013-10-24 01:52:52 -0700162 else
Ilya Moiseenko393cbdc2013-10-29 00:45:40 -0700163 {
Ilya Moiseenko18c8a132013-10-24 01:52:52 -0700164 enableStartOnLogin = false;
Ilya Moiseenko393cbdc2013-10-29 00:45:40 -0700165 persistentSettings->setValue(ENABLE_START_ON_LOGIN, false);
166
167 QProcess *process = new QProcess();
168 QStringList arguments;
169 arguments << QDir::homePath() + AUTOSTART_DIRECTORY + SHORTCUT_FILE;
170 process->start("rm", arguments);
171 }
172}
173
174void TrayMenu::makeAutostartDirectory()
175{
176 QProcess *process = new QProcess();
177 connect(process, SIGNAL(finished(int)), this, SLOT(copyFile()));
178 QStringList arguments;
179 arguments << QDir::homePath() + AUTOSTART_DIRECTORY;
180 process->start("mkdir", arguments);
181}
182
183void TrayMenu::copyFile()
184{
185 QProcess *process = new QProcess();
186 QStringList arguments;
187 arguments << QApplication::applicationDirPath() + "/" + SHORTCUT_FILE << QDir::homePath() + AUTOSTART_DIRECTORY;
188 process->start("cp",arguments);
Ilya Moiseenko18c8a132013-10-24 01:52:52 -0700189}
190
191void TrayMenu::changeShutdownExit()
192{
193 if(ui->shutdownCheckbox->isChecked())
Ilya Moiseenko393cbdc2013-10-29 00:45:40 -0700194 {
Ilya Moiseenko18c8a132013-10-24 01:52:52 -0700195 shutdownOnExit = true;
Ilya Moiseenko393cbdc2013-10-29 00:45:40 -0700196 persistentSettings->setValue(SHUTDOWN_ON_EXIT, true);
197 }
Ilya Moiseenko18c8a132013-10-24 01:52:52 -0700198 else
Ilya Moiseenko393cbdc2013-10-29 00:45:40 -0700199 {
Ilya Moiseenko18c8a132013-10-24 01:52:52 -0700200 shutdownOnExit = false;
Ilya Moiseenko393cbdc2013-10-29 00:45:40 -0700201 persistentSettings->setValue(SHUTDOWN_ON_EXIT, false);
202 }
Ilya Moiseenko18c8a132013-10-24 01:52:52 -0700203}
204
205void TrayMenu::showFibInputDialog()
206{
207 dialog = new FibInputDialog(this);
208 dialog->exec();
209}
210
211void TrayMenu::openTrafficMap()
212{
213 QDesktopServices::openUrl(QUrl("http://ndnmap.arl.wustl.edu/", QUrl::TolerantMode));
214}
215
216void TrayMenu::openRoutingStatus()
217{
218 QDesktopServices::openUrl(QUrl("http://netlab.cs.memphis.edu/script/htm/status.htm", QUrl::TolerantMode));
219}
220
Ilya Moiseenko393cbdc2013-10-29 00:45:40 -0700221void TrayMenu::openCertificationPage()
222{
223 QDesktopServices::openUrl(QUrl("http://ndncert.named-data.net", QUrl::TolerantMode));
224}
225
Ilya Moiseenko18c8a132013-10-24 01:52:52 -0700226void TrayMenu::createTrayIcon()
227{
228 trayIconMenu = new QMenu(this);
229
230 statusIndicator = new QAction(tr("Inactive"), this);
231 trayIconMenu->addAction(statusIndicator);
232
233 trayIconMenu->addSeparator();
234
235 QAction *displayStatus = new QAction(tr("Status"), this);
236 connect(displayStatus, SIGNAL(triggered()), this, SLOT(displayPopup()));
237 trayIconMenu->addAction(displayStatus);
238
239 trayIconMenu->addSeparator();
240
241 open = new QAction(tr("Preferences..."), this);
242 connect(open, SIGNAL(triggered()), this, SLOT(show()));
243 trayIconMenu->addAction(open);
244
245 close = new QAction(tr("Quit..."), this);
246 connect(close, SIGNAL(triggered()), this, SLOT(confirmQuit()));
247 trayIconMenu->addAction(close);
248
249 trayIcon = new QSystemTrayIcon(this);
250 trayIcon->setContextMenu(trayIconMenu);
251
252 connect(
253 trayIcon,
254 SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
255 this,
256 SLOT(trayIconClicked(QSystemTrayIcon::ActivationReason))
257 );
258}
259
260void TrayMenu::createToolbar()
261{
262 toolBar = new QToolBar(this);
263 toolBar->setFloatable(false);
264 toolBar->setMovable(false);
265 toolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
266 toolBar->setAllowedAreas(Qt::TopToolBarArea);
267 toolBar->setOrientation(Qt::Horizontal);
268 toolBar->setIconSize(QSize(32,32));
269 toolBar->resize(this->width(), 64);
270
271 openGeneralSettings = new QAction(tr("General"), this);
272 openGeneralSettings->setIcon(QIcon(":/resource/Resources/preferences-desktop.png"));
273 connect(openGeneralSettings,SIGNAL(triggered()),this, SLOT(generalSettingsClicked()));
274
275 openForwardingSettings = new QAction(tr("Forwarding"), this);
276 openForwardingSettings->setIcon(QIcon(":/resource/Resources/emblem-web.png"));
277 connect(openForwardingSettings,SIGNAL(triggered()),this, SLOT(forwardingSettingsClicked()));
278
279 openSecuritySettings = new QAction(tr("Security"), this);
280 openSecuritySettings->setIcon(QIcon(":/resource/Resources/emblem-system.png"));
281 connect(openSecuritySettings,SIGNAL(triggered()),this, SLOT(securitySettingsClicked()));
282
283 toolBar->addAction(openGeneralSettings);
284 toolBar->addAction(openForwardingSettings);
285 toolBar->addAction(openSecuritySettings);
286}
287
288void TrayMenu::generalSettingsClicked()
289{
290 ui->generalSettingsWidget->show();
291 ui->forwardingSettingsWidget->hide();
292 ui->securitySettingsWidget->hide();
293}
294
295void TrayMenu::forwardingSettingsClicked()
296{
297 ui->generalSettingsWidget->hide();
298 ui->forwardingSettingsWidget->show();
299 ui->securitySettingsWidget->hide();
300}
301
302void TrayMenu::securitySettingsClicked()
303{
304 ui->generalSettingsWidget->hide();
305 ui->forwardingSettingsWidget->hide();
306 ui->securitySettingsWidget->show();
307}
308
309void TrayMenu::displayPopup()
310{
311 trayIcon->showMessage(tr("NDNx Status"), statusXml);
312}
313
314void TrayMenu::addFibEntry()
315{
316 QString name = dialog->getPrefixName();
317 QString tunnelType = dialog->getTunnelType();
318 QString endpoint = dialog->getEndpoint();
319
320 QStringList arguments;
321 arguments << "add" << name << tunnelType << endpoint;
322
323 dialog->hide();
324
Ilya Moiseenko393cbdc2013-10-29 00:45:40 -0700325 QProcess *process = new QProcess();
326 process->start(NDND_FIB_COMMAND, arguments);
Ilya Moiseenko18c8a132013-10-24 01:52:52 -0700327}
328
329void TrayMenu::confirmQuit()
330{
Ilya Moiseenko393cbdc2013-10-29 00:45:40 -0700331 if(shutdownOnExit)
332 terminateDaemonAndClose();
333 else
334 {
335 QuitDialog dialog(this);
336 dialog.exec();
337 }
Ilya Moiseenko18c8a132013-10-24 01:52:52 -0700338}
339
340void TrayMenu::terminateDaemonAndClose()
341{
342 QProcess *process = new QProcess(this);
343 process->start(NDND_STOP_COMMAND);
344 connect(process,SIGNAL(finished(int)), qApp, SLOT(quit()));
345}
346
347void TrayMenu::closeEvent(QCloseEvent *event)
348{
349 if (trayIcon->isVisible())
350 {
351 hide();
352 event->ignore();
353 }
354}
355
356void TrayMenu::showEvent(QShowEvent * event)
357{
358 ui->generalSettingsWidget->show();
359 ui->forwardingSettingsWidget->hide();
360 ui->securitySettingsWidget->hide();
361}
362
363void TrayMenu::trayIconClicked(QSystemTrayIcon::ActivationReason reason)
364{
365 if(reason == QSystemTrayIcon::Trigger)
366 this->show();
367}
368
369void TrayMenu::setIcon(bool isConnected)
370{
371 if(isConnected)
372 trayIcon->setIcon(QIcon(":/resource/Resources/icon-connected-white.png"));
373 else
374 trayIcon->setIcon(QIcon(":/resource/Resources/icon-disconnected-white.png"));
375}
376
Ilya Moiseenko18c8a132013-10-24 01:52:52 -0700377void TrayMenu::daemonStatusUpdate()
378{
379 QXmlQuery query(QXmlQuery::XSLT20);
380 query.setFocus(QUrl("http://localhost:9695/?f=xml"));
381
382 query.setQuery(QUrl("qrc:/resource/Resources/status.xslt")); // TODO: I suspect it's being read from HDD each time
383 query.evaluateTo(&statusXml);
384
Ilya Moiseenko393cbdc2013-10-29 00:45:40 -0700385 if(statusXml == "") // there was an error during Query evaluation
386 {
387 daemonStarted = false;
388 setIcon(false);
389 statusIndicator->setText(tr("Starting..."));
390
391 QProcess *process = new QProcess();
392 if(enableHubDiscovery)
393 connect(process, SIGNAL(finished(int)), networkManager, SLOT(autoconfigDaemon()));
394 process->start(NDND_START_COMMAND);
395 }
396 else
397 {
398 daemonStarted = true;
399 setIcon(true);
400 statusIndicator->setText(tr("Active"));
401 }
402
Ilya Moiseenko18c8a132013-10-24 01:52:52 -0700403 query.setQuery(QUrl("qrc:/resource/Resources/status-to-fib.xslt")); // TODO: I suspect it's being read from HDD each time
404 query.evaluateTo(&fibContentsXml);
405
Ilya Moiseenko393cbdc2013-10-29 00:45:40 -0700406 if ((enableHubDiscovery) && (fibContentsXml.indexOf("ndn:/autoconf-route",0,Qt::CaseInsensitive) == -1))
407 {
408 networkManager->autoconfigDaemon();
409 }
410
Ilya Moiseenko18c8a132013-10-24 01:52:52 -0700411 QDomDocument xmldoc;
412 QDomElement root;
413
414 xmldoc.setContent(fibContentsXml);
415 root=xmldoc.documentElement();
416
417 model = new QStandardItemModel(root.childNodes().count(),3);
418 model->setHorizontalHeaderItem(0, new QStandardItem(tr("NDN prefix")));
419 model->setHorizontalHeaderItem(1, new QStandardItem(tr("Face ID")));
420 model->setHorizontalHeaderItem(2, new QStandardItem(tr("Endpoint")));
421
422 int row = 0;
423 QDomNode fibEntry=root.firstChild();
424 while (!fibEntry.isNull())
425 {
426 QDomNodeList properties = fibEntry.childNodes();
427
428 QDomNode faceID = properties.at(0);
429 QDomNode ip = properties.at(1);
430 QDomNode prefix = properties.at(2);
431
Ilya Moiseenko18c8a132013-10-24 01:52:52 -0700432 model->setItem(row, 0, new QStandardItem(prefix.toElement().text()));
433 model->setItem(row, 1, new QStandardItem(faceID.toElement().text()));
434 model->setItem(row, 2, new QStandardItem(ip.toElement().text()));
435
436 fibEntry = fibEntry.nextSibling();
437 row++;
438 }
439
440 ui->tableView->setModel(model);
441
442 if(selectedRow >= 0)
443 ui->tableView->selectRow(selectedRow);
444}
445
446void TrayMenu::createTableView()
447{
448 ui->tableView->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
449 ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection);
450 ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
451
452 selectedRow = -1;
453}
454
455void TrayMenu::selectTableRow()
456{
457 selectedRow = ui->tableView->selectionModel()->selection().indexes().at(0).row();
458}
459
460void TrayMenu::deleteFibEntry()
461{
462 if(selectedRow < 0)
463 return;
464
465 QStandardItem *prefix = model->item(selectedRow,0);
466 if(prefix == NULL)
467 return;
468
469 QStandardItem *faceID = model->item(selectedRow,1);
470 if(faceID == NULL)
471 return;
472
473 QStringList arguments;
474 arguments << "del" << prefix->text() << "face" << faceID->text();
475
Ilya Moiseenko393cbdc2013-10-29 00:45:40 -0700476 QProcess *process = new QProcess();
477 process->start(NDND_FIB_COMMAND, arguments);
Ilya Moiseenko18c8a132013-10-24 01:52:52 -0700478}
479
480TrayMenu::~TrayMenu()
481{
482 daemonStatusTimer->stop();
483 statusUpdateThread->exit();
484 delete ui;
485 delete trayIcon;
486 delete trayIconMenu;
487 delete open;
488 delete close;
489 delete openGeneralSettings;
490 delete openForwardingSettings;
491 delete openSecuritySettings;
492 delete toolBar;
493 delete statusUpdateThread;
494 delete daemonStatusTimer;
495 delete dialog;
496}