blob: da9874db3b1f1e150e28701c0dae893165150de9 [file] [log] [blame]
Alexander Afanasyevb6392e32014-05-12 23:43:50 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2013-2014, Regents of the University of California,
4 *
5 * This file is part of NFD Control Center. See AUTHORS.md for complete list of NFD
6 * authors and contributors.
7 *
8 * NFD Control Center is free software: you can redistribute it and/or modify it under the
9 * terms of the GNU General Public License as published by the Free Software Foundation,
10 * either version 3 of the License, or (at your option) any later version.
11 *
12 * NFD Control Center is distributed in the hope that it will be useful, but WITHOUT ANY
13 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
14 * PARTICULAR PURPOSE. See the GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along with NFD
17 * Control Center, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * \author Ilya Moiseenko <iliamo@ucla.edu>
20 */
21
22#include "config.hpp"
23
24#include "tray-menu.hpp"
25#include "ui_traymenu.h" //generated from traymenu.ui
26
27#include "quit-dialog.hpp"
28// #include "fib-input-dialog.hpp"
29#include "network-manager.hpp"
30
31#include <QMenu>
32#include <QCloseEvent>
33#include <QDesktopServices>
34#include <QUrl>
35#include <QCheckBox>
36#include <QLabel>
37#include <QHBoxLayout>
38#include <QLineEdit>
39#include <QDir>
40#include <QScrollBar>
41#include <QHBoxLayout>
42#include <QVBoxLayout>
43
44TrayMenu::TrayMenu(QWidget *parent)
45 : QMainWindow(parent)
46 , ui(new Ui::TrayMenu)
47{
48 processLookup = new QProcess(this);
49 QStringList arguments;
50 arguments << "-al";
51 connect(processLookup,SIGNAL(finished(int)), this, SLOT(parseProcessLookup()));
52 processLookup->start("ps",arguments);
53
54 networkManager = new NetworkManager();
55
56 QCoreApplication::setOrganizationName("UCLA");
57 QCoreApplication::setOrganizationDomain("named-data.net");
58 QCoreApplication::setApplicationName("NDNx Control Center");
59
60 persistentSettings = new QSettings();
61
62 ui->setupUi(this);
63
64 createTrayIcon();
65 setIcon(true);
66 createToolbar();
67 createTableView();
68
69 loadSettings();
70
71 connect(ui->openTrafficMapButton, SIGNAL(pressed()), this, SLOT(openTrafficMap()));
72 connect(ui->openRoutingStatusButton, SIGNAL(pressed()), this, SLOT(openRoutingStatus()));
73 connect(ui->addFibButton, SIGNAL(pressed()), this, SLOT(showFibInputDialog()));
74 // connect(ui->deleteFibButton, SIGNAL(released()), this, SLOT(deleteFibEntry()));
75 connect(ui->hubDiscoveryCheckbox, SIGNAL(stateChanged(int)), this, SLOT(changeHubDiscovery()));
76 connect(ui->loginStartCheckbox, SIGNAL(stateChanged(int)), this, SLOT(changeLoginStart()));
77 connect(ui->tableView, SIGNAL(clicked(QModelIndex)), this, SLOT(selectTableRow()));
78 connect(ui->openNdnCertificationButton, SIGNAL(released()), this, SLOT(openCertificationPage()));
79
80 statusUpdateThread = new QThread();
81 statusUpdateThread->start();
82
83 // daemonStatusTimer = new QTimer(statusUpdateThread);
84 // connect(daemonStatusTimer, SIGNAL(timeout()), this, SLOT(daemonStatusUpdate()));
85 // daemonStatusTimer->start(2000);
86
87 trayIcon->show();
88 model = NULL;
89 // dialog = new FibInputDialog(this);
90
91 // urlManager = new QNetworkAccessManager(this);
92 // connect(urlManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(runXmlProc(QNetworkReply*)));
93}
94
95void TrayMenu::loadSettings()
96{
97 QVariant value;
98
99 value = persistentSettings->value(ENABLE_HUB_DISCOVERY);
100 if(!value.isNull())
101 {
102 enableHubDiscovery = value.toBool();
103 ui->hubDiscoveryCheckbox->setChecked(enableHubDiscovery);
104 }
105 else
106 {
107 ui->hubDiscoveryCheckbox->setChecked(true);
108 changeHubDiscovery();
109 }
110
111 value = persistentSettings->value(ENABLE_START_ON_LOGIN);
112 if(!value.isNull())
113 {
114 enableStartOnLogin = value.toBool();
115 ui->loginStartCheckbox->setChecked(enableStartOnLogin);
116 }
117 else
118 {
119 ui->loginStartCheckbox->setChecked(false);
120 changeLoginStart();
121 }
122}
123
124void TrayMenu::changeHubDiscovery()
125{
126 if(ui->hubDiscoveryCheckbox->isChecked())
127 {
128 enableHubDiscovery = true;
129 persistentSettings->setValue(ENABLE_HUB_DISCOVERY, true);
130 }
131 else
132 {
133 enableHubDiscovery = false;
134 persistentSettings->setValue(ENABLE_HUB_DISCOVERY, false);
135 }
136}
137
138void TrayMenu::changeLoginStart()
139{
140 if(ui->loginStartCheckbox->isChecked())
141 {
142 enableStartOnLogin = true;
143 persistentSettings->setValue(ENABLE_START_ON_LOGIN, true);
144 makeAutostartDirectory();
145 }
146 else
147 {
148 enableStartOnLogin = false;
149 persistentSettings->setValue(ENABLE_START_ON_LOGIN, false);
150
151 QProcess *process = new QProcess();
152 connect(process,SIGNAL(finished(int)),process, SLOT(deleteLater()));
153 QStringList arguments;
154 arguments << QDir::homePath() + AUTOSTART_DIRECTORY + SHORTCUT_FILE;
155 process->start("rm", arguments);
156 }
157}
158
159void TrayMenu::makeAutostartDirectory()
160{
161 QProcess *process = new QProcess();
162 connect(process, SIGNAL(finished(int)), this, SLOT(copyFile()));
163 connect(process,SIGNAL(finished(int)),process, SLOT(deleteLater()));
164 QStringList arguments;
165 arguments << QDir::homePath() + AUTOSTART_DIRECTORY;
166 process->start("mkdir", arguments);
167}
168
169void TrayMenu::copyFile()
170{
171 QProcess *process = new QProcess();
172 connect(process,SIGNAL(finished(int)),process, SLOT(deleteLater()));
173 QStringList arguments;
174 arguments << QString(RESOURCES_DIR) + "/" + SHORTCUT_FILE << QDir::homePath() + AUTOSTART_DIRECTORY;
175 process->start("cp",arguments);
176}
177
178void TrayMenu::showFibInputDialog()
179{
180 // dialog->clear();
181 // dialog->exec();
182}
183
184void TrayMenu::openTrafficMap()
185{
186 QDesktopServices::openUrl(QUrl("http://ndnmap.arl.wustl.edu/", QUrl::TolerantMode));
187}
188
189void TrayMenu::openRoutingStatus()
190{
191 QDesktopServices::openUrl(QUrl("http://netlab.cs.memphis.edu/script/htm/status.htm", QUrl::TolerantMode));
192}
193
194void TrayMenu::openCertificationPage()
195{
196 QDesktopServices::openUrl(QUrl("http://ndncert.named-data.net", QUrl::TolerantMode));
197}
198
199void TrayMenu::createTrayIcon()
200{
201 trayIconMenu = new QMenu(this);
202
203 statusIndicator = new QAction("Inactive", this);
204 trayIconMenu->addAction(statusIndicator);
205
206 trayIconMenu->addSeparator();
207
208 displayStatus = new QAction(" Sent / Recv ", this);
209 trayIconMenu->addAction(displayStatus);
210 interestSentRecv = new QAction("Interests 0 / 0", this);
211 trayIconMenu->addAction(interestSentRecv);
212 dataSentRecv = new QAction("Data 0 / 0", this);
213 trayIconMenu->addAction(dataSentRecv);
214
215 trayIconMenu->addSeparator();
216
217 open = new QAction("Preferences...", this);
218 connect(open, SIGNAL(triggered()), this, SLOT(show()));
219 trayIconMenu->addAction(open);
220
221 close = new QAction("Quit", this);
222 // connect(close, SIGNAL(triggered()), this, SLOT(confirmQuit()));
223 connect(close, SIGNAL(triggered()), qApp, SLOT(quit()));
224 trayIconMenu->addAction(close);
225
226 trayIcon = new QSystemTrayIcon(this);
227 trayIcon->setContextMenu(trayIconMenu);
228
229 connect(
230 trayIcon,
231 SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
232 this,
233 SLOT(trayIconClicked(QSystemTrayIcon::ActivationReason))
234 );
235}
236
237void TrayMenu::createToolbar()
238{
239 ui->toolBar->setFloatable(false);
240 ui->toolBar->setMovable(false);
241 ui->toolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
242 ui->toolBar->setAllowedAreas(Qt::TopToolBarArea);
243 ui->toolBar->setOrientation(Qt::Horizontal);
244 ui->toolBar->setIconSize(QSize(32,32));
245 ui->toolBar->resize(this->width(), 64);
246
247 openGeneralSettings = new QAction("General", this);
248 openGeneralSettings->setIcon(QIcon(":/resource/Resources/preferences-desktop.png"));
249 connect(openGeneralSettings,SIGNAL(triggered()),this, SLOT(generalSettingsClicked()));
250
251 openForwardingSettings = new QAction("Forwarding", this);
252 openForwardingSettings->setIcon(QIcon(":/resource/Resources/emblem-web.png"));
253 connect(openForwardingSettings,SIGNAL(triggered()),this, SLOT(forwardingSettingsClicked()));
254
255 openSecuritySettings = new QAction("Security", this);
256 openSecuritySettings->setIcon(QIcon(":/resource/Resources/emblem-system.png"));
257 connect(openSecuritySettings,SIGNAL(triggered()),this, SLOT(securitySettingsClicked()));
258
259 ui->toolBar->addAction(openGeneralSettings);
260 ui->toolBar->addAction(openForwardingSettings);
261 ui->toolBar->addAction(openSecuritySettings);
262}
263
264void TrayMenu::generalSettingsClicked()
265{
266 ui->generalSettingsWidget->show();
267 ui->forwardingSettingsWidget->hide();
268 ui->securitySettingsWidget->hide();
269}
270
271void TrayMenu::forwardingSettingsClicked()
272{
273 ui->generalSettingsWidget->hide();
274 ui->forwardingSettingsWidget->show();
275 ui->securitySettingsWidget->hide();
276}
277
278void TrayMenu::securitySettingsClicked()
279{
280 ui->generalSettingsWidget->hide();
281 ui->forwardingSettingsWidget->hide();
282 ui->securitySettingsWidget->show();
283}
284
285void TrayMenu::displayPopup()
286{
287 trayIcon->showMessage("NDNx Status", statusXml);
288}
289
290void TrayMenu::addFibEntry()
291{
292 // QString name = dialog->getPrefixName();
293 // QString tunnelType = dialog->getTunnelType();
294 // QString endpoint = dialog->getEndpoint();
295
296 // QStringList arguments;
297 // arguments << "add" << name << tunnelType << endpoint;
298
299 // dialog->hide();
300
301 // QProcess *process = new QProcess();
302 // connect(process,SIGNAL(finished(int)),process, SLOT(deleteLater()));
303 // process->start(NDND_FIB_COMMAND, arguments);
304}
305
306void TrayMenu::closeEvent(QCloseEvent *event)
307{
308 if (trayIcon->isVisible())
309 {
310 hide();
311 event->ignore();
312 }
313}
314
315void TrayMenu::showEvent(QShowEvent * event)
316{
317 ui->generalSettingsWidget->show();
318 ui->forwardingSettingsWidget->hide();
319 ui->securitySettingsWidget->hide();
320}
321
322void TrayMenu::trayIconClicked(QSystemTrayIcon::ActivationReason reason)
323{
324 if(reason == QSystemTrayIcon::Trigger)
325 this->show();
326}
327
328void TrayMenu::setIcon(bool isConnected)
329{
330 if(isConnected)
331 trayIcon->setIcon(QIcon(":/resource/Resources/icon-connected-white.png"));
332 else
333 trayIcon->setIcon(QIcon(":/resource/Resources/icon-disconnected-white.png"));
334}
335
336// void TrayMenu::daemonStatusUpdate()
337// {
338// urlManager->get(QNetworkRequest(QUrl("http://localhost:6363/?f=xml")));
339// }
340
341// void TrayMenu::runXmlProc(QNetworkReply *reply)
342// {
343// QByteArray buffer = reply->readAll();
344// applyStatusXslt = new QProcess();
345
346// QStringList arguments;
347// arguments << QString(RESOURCES_DIR) + "/" + STATUS_XSLT_FILE << "-";
348// connect(applyStatusXslt,SIGNAL(finished(int)), this, SLOT(parseStatusXml()));
349// //connect(applyStatusXslt,SIGNAL(finished(int)), applyStatusXslt, SLOT(deleteLater()));
350// applyStatusXslt->start(XSLTPROC,arguments);
351// applyStatusXslt->write(buffer);
352// applyStatusXslt->closeWriteChannel();
353
354// applyFibXslt = new QProcess();
355// QStringList args;
356// args << QString(RESOURCES_DIR) + "/" + FIB_XSLT_FILE << "-";
357// connect(applyFibXslt,SIGNAL(finished(int)), this, SLOT(parseFibXml()));
358// //connect(applyFibXslt,SIGNAL(finished(int)), applyFibXslt, SLOT(deleteLater()));
359// applyFibXslt->start(XSLTPROC,args);
360// applyFibXslt->write(buffer);
361// applyFibXslt->closeWriteChannel();
362// }
363
364// void TrayMenu::parseStatusXml()
365// {
366// QByteArray stdout = applyStatusXslt->readAllStandardOutput();
367// QByteArray stderr = applyStatusXslt->readAllStandardError();
368// applyStatusXslt->deleteLater();
369
370// statusXml = QString(stdout);
371
372// if((statusXml == "") || (stderr.length()>0)) // there was an error during Query evaluation
373// {
374// daemonStarted = false;
375// setIcon(false);
376// statusIndicator->setText("Inactive");
377
378// // QProcess *process = new QProcess();
379// // if(enableHubDiscovery)
380// // connect(process, SIGNAL(finished(int)), networkManager, SLOT(autoconfigDaemon()));
381// //
382// // connect(process,SIGNAL(finished(int)), process, SLOT(deleteLater()));
383// // process->start(NDND_START_COMMAND);
384// }
385// else
386// {
387// daemonStarted = true;
388// setIcon(true);
389// statusIndicator->setText("Active");
390
391// QString interestIn = statusXml.mid(statusXml.indexOf("<in>")+4, statusXml.indexOf("</in>") - (statusXml.indexOf("<in>")+4));
392// QString interestOut = statusXml.mid(statusXml.indexOf("<out>")+5, statusXml.indexOf("</out>") - (statusXml.indexOf("<out>")+5));
393// QString dataIn = statusXml.mid(statusXml.lastIndexOf("<in>")+4, statusXml.lastIndexOf("</in>") - (statusXml.lastIndexOf("<in>")+4));
394// QString dataOut = statusXml.mid(statusXml.lastIndexOf("<out>")+5, statusXml.lastIndexOf("</out>") - (statusXml.lastIndexOf("<out>")+5));
395
396// int i = 0;
397// int k = 0;
398// if((dataOut.length() - interestOut.length()) > 0)
399// {
400// i = dataOut.length() - interestOut.length();
401// i*=2; //because space takes less space than a letter
402// }
403
404// if((interestOut.length() - dataOut.length()) > 0)
405// {
406// k = interestOut.length() - dataOut.length();
407// k*=2; //because space takes less space than a letter
408// }
409
410// QString interestStats = QString("%1%2%3%4").arg("Interests",-16,' ').arg(interestOut,6+i,' ').arg(" / ",3).arg(interestIn,-6,' ');
411// QString dataStats = QString("%1%2%3%4").arg("Data",-20,' ').arg(dataOut,6+k,' ').arg(" / ",3).arg(dataIn,-6,' ');
412
413// //Now I try to align header "Sent / Recv" centrally with the upper line
414// QString padding;
415// for(int j = 0; j < interestStats.indexOf(interestOut); j++)
416// {
417// if(interestStats.at(j)==' ')
418// padding +=" ";
419// else
420// padding += " "; //because space takes less space than a letter
421// }
422
423// QString header;
424// int m = 0;
425// if(interestOut.length() - QString("Sent").length() > 0)
426// {
427// m = interestOut.length() - QString("Sent").length();
428// m *=3;
429// header = QString("%1%2").arg(padding).arg(" Sent / Recv",QString(" Sent / Recv").length() + m,' ');
430// }
431// else if(interestOut.length() - QString("Sent").length() < 0)
432// {
433// padding.truncate(padding.length()-(QString("Sent").length() - interestOut.length()));
434// header = padding + "Sent / Recv";
435// }
436// else
437// {
438// header = padding + " Sent / Recv";
439// }
440
441// interestSentRecv->setText(interestStats);
442// dataSentRecv->setText(dataStats);
443// displayStatus->setText(header);
444// }
445// }
446
447// void TrayMenu::parseFibXml()
448// {
449// QByteArray stdout = applyFibXslt->readAllStandardOutput();
450// QByteArray stderr = applyFibXslt->readAllStandardError();
451// applyFibXslt->deleteLater();
452
453// fibContentsXml = QString(stdout);
454
455// if((stdout == "") || (stderr.length()>0))
456// return;
457
458// if ((enableHubDiscovery) && (fibContentsXml.indexOf("ndn:/autoconf-route",0,Qt::CaseInsensitive) == -1))
459// {
460// networkManager->autoconfigDaemon();
461// }
462
463// QDomDocument xmldoc;
464// QDomElement root;
465
466// xmldoc.setContent(fibContentsXml);
467// root=xmldoc.documentElement();
468
469// if(model != NULL)
470// {
471// scrollPosition = ui->tableView->verticalScrollBar()->value();
472// model->clear();
473// delete model;
474// }
475
476// model = new QStandardItemModel(root.childNodes().count(),3);
477// model->setHorizontalHeaderItem(0, new QStandardItem("NDN prefix"));
478// model->setHorizontalHeaderItem(1, new QStandardItem("Face ID"));
479// model->setHorizontalHeaderItem(2, new QStandardItem("Endpoint"));
480
481// int row = 0;
482// QDomNode fibEntry=root.firstChild();
483
484// while (!fibEntry.isNull())
485// {
486// QDomNodeList properties = fibEntry.childNodes();
487
488// QDomNode faceID = properties.at(0);
489// QDomNode ip = properties.at(1);
490// QDomNode prefix = properties.at(2);
491
492// model->setItem(row, 0, new QStandardItem(prefix.toElement().text()));
493// model->setItem(row, 1, new QStandardItem(faceID.toElement().text()));
494// model->setItem(row, 2, new QStandardItem(ip.toElement().text()));
495
496// fibEntry = fibEntry.nextSibling();
497// row++;
498// }
499
500// ui->tableView->setModel(model);
501
502// ui->tableView->setColumnWidth(0, ui->tableView->size().width() / 2 );
503// ui->tableView->setColumnWidth(1, ui->tableView->size().width() / 6 );
504
505// if(selectedRow >= 0)
506// ui->tableView->selectRow(selectedRow);
507
508// if(scrollPosition >= 0)
509// ui->tableView->verticalScrollBar()->setValue(scrollPosition);
510// }
511
512void TrayMenu::createTableView()
513{
514 ui->tableView->horizontalHeader()->setResizeMode(QHeaderView::Fixed);
515 ui->tableView->horizontalHeader()->setStretchLastSection(true);
516 ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection);
517 ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
518
519 selectedRow = -1;
520 scrollPosition = -1;
521
522 QHBoxLayout *hlayout = new QHBoxLayout();
523 hlayout->addWidget(ui->addFibButton,0, Qt::AlignLeft);
524 // hlayout->addWidget(ui->deleteFibButton, 20, Qt::AlignLeft);
525
526 QVBoxLayout *vlayout = new QVBoxLayout();
527 vlayout->addWidget(ui->label);
528 vlayout->addWidget(ui->tableView);
529 vlayout->addLayout(hlayout);
530
531 ui->forwardingSettingsWidget->setLayout(vlayout);
532
533 QVBoxLayout *expanding = new QVBoxLayout();
534 expanding->addWidget(ui->forwardingSettingsWidget);
535 ui->centralWidget->setLayout(expanding);
536}
537
538void TrayMenu::selectTableRow()
539{
540 selectedRow = ui->tableView->selectionModel()->selection().indexes().at(0).row();
541}
542
543// void TrayMenu::deleteFibEntry()
544// {
545// if(selectedRow < 0)
546// return;
547
548// QStandardItem *prefix = model->item(selectedRow,0);
549// if(prefix == NULL)
550// return;
551
552// QStandardItem *faceID = model->item(selectedRow,1);
553// if(faceID == NULL)
554// return;
555
556// QStringList arguments;
557// arguments << "del" << prefix->text() << "face" << faceID->text();
558
559// QProcess *process = new QProcess();
560// connect(process,SIGNAL(finished(int)), process, SLOT(deleteLater()));
561// process->start(NDND_FIB_COMMAND, arguments);
562// }
563
564void TrayMenu::resizeEvent(QResizeEvent * event)
565{
566 ui->tableView->setColumnWidth(0, ui->tableView->size().width() / 2);
567 ui->tableView->setColumnWidth(1, ui->tableView->size().width() / 6);
568}
569
570
571void TrayMenu::parseProcessLookup()
572{
573 QByteArray stdout = processLookup->readAllStandardOutput();
574 processLookup->deleteLater();
575
576 QString s = QString(stdout);
577
578 if(s == "")
579 return;
580 else if(s.indexOf("ndnx-control") != s.lastIndexOf("ndnx-control"))
581 qApp->quit();
582}
583
584TrayMenu::~TrayMenu()
585{
586 daemonStatusTimer->stop();
587 statusUpdateThread->exit(0);
588 delete ui;
589 delete trayIcon;
590 delete trayIconMenu;
591 delete open;
592 delete close;
593 delete openGeneralSettings;
594 delete openForwardingSettings;
595 delete openSecuritySettings;
596 delete statusUpdateThread;
597 // delete dialog;
598 delete networkManager;
599 delete persistentSettings;
600}
601
602#if WAF
603#include "tray-menu.moc"
604#include "tray-menu.cpp.moc"
605#endif