| /* -*- 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 "config.h" |
| |
| #include "tray-menu.h" |
| #include "ui_traymenu.h" //generated from traymenu.ui |
| #include "quit-dialog.h" |
| #include "fib-input-dialog.h" |
| #include "network-manager.h" |
| |
| #include <QMenu> |
| #include <QCloseEvent> |
| #include <QDesktopServices> |
| #include <QUrl> |
| #include <QCheckBox> |
| #include <QLabel> |
| #include <QHBoxLayout> |
| #include <QLineEdit> |
| #include <QDir> |
| #include <QScrollBar> |
| |
| |
| TrayMenu::TrayMenu(QWidget *parent) : |
| QMainWindow(parent), |
| ui(new Ui::TrayMenu) |
| { |
| networkManager = new NetworkManager(); |
| |
| QCoreApplication::setOrganizationName("UCLA"); |
| QCoreApplication::setOrganizationDomain("named-data.net"); |
| QCoreApplication::setApplicationName("NDNx Control Center"); |
| |
| persistentSettings = new QSettings(); |
| |
| ui->setupUi(this); |
| |
| createTrayIcon(); |
| setIcon(true); |
| createToolbar(); |
| createTableView(); |
| |
| loadSettings(); |
| |
| 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())); |
| connect(ui->openNdnCertificationButton, SIGNAL(released()), this, SLOT(openCertificationPage())); |
| |
| statusUpdateThread = new QThread(); |
| statusUpdateThread->start(); |
| |
| daemonStatusTimer = new QTimer(statusUpdateThread); |
| connect(daemonStatusTimer, SIGNAL(timeout()), this, SLOT(daemonStatusUpdate())); |
| daemonStatusTimer->start(2000); |
| |
| trayIcon->show(); |
| model = NULL; |
| dialog = new FibInputDialog(this); |
| |
| urlManager = new QNetworkAccessManager(this); |
| connect(urlManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(runXmlProc(QNetworkReply*))); |
| } |
| |
| void TrayMenu::loadSettings() |
| { |
| QVariant value; |
| |
| value = persistentSettings->value(ALLOW_SOFTWARE_UPDATES); |
| if(!value.isNull()) |
| { |
| allowAutomaticUpdates = value.toBool(); |
| ui->softwareUpdateCheckbox->setChecked(allowAutomaticUpdates); |
| } |
| else |
| { |
| ui->softwareUpdateCheckbox->setChecked(true); |
| changeSoftwareUpdate(); |
| } |
| |
| value = persistentSettings->value(ENABLE_HUB_DISCOVERY); |
| if(!value.isNull()) |
| { |
| enableHubDiscovery = value.toBool(); |
| ui->hubDiscoveryCheckbox->setChecked(enableHubDiscovery); |
| } |
| else |
| { |
| ui->hubDiscoveryCheckbox->setChecked(true); |
| changeHubDiscovery(); |
| } |
| |
| value = persistentSettings->value(ENABLE_START_ON_LOGIN); |
| if(!value.isNull()) |
| { |
| enableStartOnLogin = value.toBool(); |
| ui->loginStartCheckbox->setChecked(enableStartOnLogin); |
| } |
| else |
| { |
| ui->loginStartCheckbox->setChecked(false); |
| changeLoginStart(); |
| } |
| |
| value = persistentSettings->value(SHUTDOWN_ON_EXIT); |
| if(!value.isNull()) |
| { |
| shutdownOnExit = value.toBool(); |
| ui->shutdownCheckbox->setChecked(shutdownOnExit); |
| } |
| else |
| { |
| ui->shutdownCheckbox->setChecked(false); |
| changeShutdownExit(); |
| } |
| } |
| |
| void TrayMenu::changeSoftwareUpdate() |
| { |
| if(ui->softwareUpdateCheckbox->isChecked()) |
| { |
| allowAutomaticUpdates = true; |
| persistentSettings->setValue(ALLOW_SOFTWARE_UPDATES, true); |
| } |
| else |
| { |
| allowAutomaticUpdates = false; |
| persistentSettings->setValue(ALLOW_SOFTWARE_UPDATES, false); |
| } |
| } |
| |
| void TrayMenu::changeHubDiscovery() |
| { |
| if(ui->hubDiscoveryCheckbox->isChecked()) |
| { |
| enableHubDiscovery = true; |
| persistentSettings->setValue(ENABLE_HUB_DISCOVERY, true); |
| } |
| else |
| { |
| enableHubDiscovery = false; |
| persistentSettings->setValue(ENABLE_HUB_DISCOVERY, false); |
| } |
| } |
| |
| void TrayMenu::changeLoginStart() |
| { |
| if(ui->loginStartCheckbox->isChecked()) |
| { |
| enableStartOnLogin = true; |
| persistentSettings->setValue(ENABLE_START_ON_LOGIN, true); |
| makeAutostartDirectory(); |
| } |
| else |
| { |
| enableStartOnLogin = false; |
| persistentSettings->setValue(ENABLE_START_ON_LOGIN, false); |
| |
| QProcess *process = new QProcess(); |
| connect(process,SIGNAL(finished(int)),process, SLOT(deleteLater())); |
| QStringList arguments; |
| arguments << QDir::homePath() + AUTOSTART_DIRECTORY + SHORTCUT_FILE; |
| process->start("rm", arguments); |
| } |
| } |
| |
| void TrayMenu::makeAutostartDirectory() |
| { |
| QProcess *process = new QProcess(); |
| connect(process, SIGNAL(finished(int)), this, SLOT(copyFile())); |
| connect(process,SIGNAL(finished(int)),process, SLOT(deleteLater())); |
| QStringList arguments; |
| arguments << QDir::homePath() + AUTOSTART_DIRECTORY; |
| process->start("mkdir", arguments); |
| } |
| |
| void TrayMenu::copyFile() |
| { |
| QProcess *process = new QProcess(); |
| connect(process,SIGNAL(finished(int)),process, SLOT(deleteLater())); |
| QStringList arguments; |
| arguments << QString(RESOURCES_DIR) + "/" + SHORTCUT_FILE << QDir::homePath() + AUTOSTART_DIRECTORY; |
| process->start("cp",arguments); |
| } |
| |
| void TrayMenu::changeShutdownExit() |
| { |
| if(ui->shutdownCheckbox->isChecked()) |
| { |
| shutdownOnExit = true; |
| persistentSettings->setValue(SHUTDOWN_ON_EXIT, true); |
| } |
| else |
| { |
| shutdownOnExit = false; |
| persistentSettings->setValue(SHUTDOWN_ON_EXIT, false); |
| } |
| } |
| |
| void TrayMenu::showFibInputDialog() |
| { |
| dialog->clear(); |
| 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::openCertificationPage() |
| { |
| QDesktopServices::openUrl(QUrl("http://ndncert.named-data.net", QUrl::TolerantMode)); |
| } |
| |
| void TrayMenu::createTrayIcon() |
| { |
| trayIconMenu = new QMenu(this); |
| |
| statusIndicator = new QAction("Inactive", this); |
| trayIconMenu->addAction(statusIndicator); |
| |
| trayIconMenu->addSeparator(); |
| |
| displayStatus = new QAction(" Sent / Recv ", this); |
| trayIconMenu->addAction(displayStatus); |
| interestSentRecv = new QAction("Interests 0 / 0", this); |
| trayIconMenu->addAction(interestSentRecv); |
| dataSentRecv = new QAction("Data 0 / 0", this); |
| trayIconMenu->addAction(dataSentRecv); |
| |
| trayIconMenu->addSeparator(); |
| |
| open = new QAction("Preferences...", this); |
| connect(open, SIGNAL(triggered()), this, SLOT(show())); |
| trayIconMenu->addAction(open); |
| |
| close = new QAction("Quit...", this); |
| // connect(close, SIGNAL(triggered()), this, SLOT(confirmQuit())); |
| connect(close, SIGNAL(triggered()), qApp, SLOT(quit())); |
| 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("General", this); |
| openGeneralSettings->setIcon(QIcon(":/resource/Resources/preferences-desktop.png")); |
| connect(openGeneralSettings,SIGNAL(triggered()),this, SLOT(generalSettingsClicked())); |
| |
| openForwardingSettings = new QAction("Forwarding", this); |
| openForwardingSettings->setIcon(QIcon(":/resource/Resources/emblem-web.png")); |
| connect(openForwardingSettings,SIGNAL(triggered()),this, SLOT(forwardingSettingsClicked())); |
| |
| openSecuritySettings = new QAction("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("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(); |
| connect(process,SIGNAL(finished(int)),process, SLOT(deleteLater())); |
| process->start(NDND_FIB_COMMAND, arguments); |
| } |
| |
| // void TrayMenu::confirmQuit() |
| // { |
| // if(shutdownOnExit) |
| // terminateDaemonAndClose(); |
| // else |
| // { |
| // 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())); |
| // connect(process,SIGNAL(finished(int)), process, SLOT(deleteLater())); |
| // } |
| |
| 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::daemonStatusUpdate() |
| { |
| urlManager->get(QNetworkRequest(QUrl("http://localhost:6363/?f=xml"))); |
| } |
| |
| void TrayMenu::runXmlProc(QNetworkReply *reply) |
| { |
| QByteArray buffer = reply->readAll(); |
| applyStatusXslt = new QProcess(); |
| |
| QStringList arguments; |
| arguments << QString(RESOURCES_DIR) + "/" + STATUS_XSLT_FILE << "-"; |
| connect(applyStatusXslt,SIGNAL(finished(int)), this, SLOT(parseStatusXml())); |
| //connect(applyStatusXslt,SIGNAL(finished(int)), applyStatusXslt, SLOT(deleteLater())); |
| applyStatusXslt->start(XSLTPROC,arguments); |
| applyStatusXslt->write(buffer); |
| applyStatusXslt->closeWriteChannel(); |
| |
| applyFibXslt = new QProcess(); |
| QStringList args; |
| args << QString(RESOURCES_DIR) + "/" + FIB_XSLT_FILE << "-"; |
| connect(applyFibXslt,SIGNAL(finished(int)), this, SLOT(parseFibXml())); |
| //connect(applyFibXslt,SIGNAL(finished(int)), applyFibXslt, SLOT(deleteLater())); |
| applyFibXslt->start(XSLTPROC,args); |
| applyFibXslt->write(buffer); |
| applyFibXslt->closeWriteChannel(); |
| } |
| |
| void TrayMenu::parseStatusXml() |
| { |
| QByteArray stdout = applyStatusXslt->readAllStandardOutput(); |
| QByteArray stderr = applyStatusXslt->readAllStandardError(); |
| applyStatusXslt->deleteLater(); |
| |
| statusXml = QString(stdout); |
| |
| if((statusXml == "") || (stderr.length()>0)) // there was an error during Query evaluation |
| { |
| daemonStarted = false; |
| setIcon(false); |
| statusIndicator->setText("Inactive"); |
| |
| // QProcess *process = new QProcess(); |
| // if(enableHubDiscovery) |
| // connect(process, SIGNAL(finished(int)), networkManager, SLOT(autoconfigDaemon())); |
| // |
| // connect(process,SIGNAL(finished(int)), process, SLOT(deleteLater())); |
| // process->start(NDND_START_COMMAND); |
| } |
| else |
| { |
| daemonStarted = true; |
| setIcon(true); |
| statusIndicator->setText("Active"); |
| |
| QString interestIn = statusXml.mid(statusXml.indexOf("<in>")+4, statusXml.indexOf("</in>") - (statusXml.indexOf("<in>")+4)); |
| QString interestOut = statusXml.mid(statusXml.indexOf("<out>")+5, statusXml.indexOf("</out>") - (statusXml.indexOf("<out>")+5)); |
| QString dataIn = statusXml.mid(statusXml.lastIndexOf("<in>")+4, statusXml.lastIndexOf("</in>") - (statusXml.lastIndexOf("<in>")+4)); |
| QString dataOut = statusXml.mid(statusXml.lastIndexOf("<out>")+5, statusXml.lastIndexOf("</out>") - (statusXml.lastIndexOf("<out>")+5)); |
| |
| int i = 0; |
| int k = 0; |
| if((dataOut.length() - interestOut.length()) > 0) |
| { |
| i = dataOut.length() - interestOut.length(); |
| i*=2; //because space takes less space than a letter |
| } |
| |
| if((interestOut.length() - dataOut.length()) > 0) |
| { |
| k = interestOut.length() - dataOut.length(); |
| k*=2; //because space takes less space than a letter |
| } |
| |
| QString interestStats = QString("%1%2%3%4").arg("Interests",-16,' ').arg(interestOut,6+i,' ').arg(" / ",3).arg(interestIn,-6,' '); |
| QString dataStats = QString("%1%2%3%4").arg("Data",-20,' ').arg(dataOut,6+k,' ').arg(" / ",3).arg(dataIn,-6,' '); |
| |
| //Now I try to align header "Sent / Recv" centrally with the upper line |
| QString padding; |
| for(int j = 0; j < interestStats.indexOf(interestOut); j++) |
| { |
| if(interestStats.at(j)==' ') |
| padding +=" "; |
| else |
| padding += " "; //because space takes less space than a letter |
| } |
| |
| QString header; |
| int m = 0; |
| if(interestOut.length() - QString("Sent").length() > 0) |
| { |
| m = interestOut.length() - QString("Sent").length(); |
| m *=3; |
| header = QString("%1%2").arg(padding).arg(" Sent / Recv",QString(" Sent / Recv").length() + m,' '); |
| } |
| else if(interestOut.length() - QString("Sent").length() < 0) |
| { |
| padding.truncate(padding.length()-(QString("Sent").length() - interestOut.length())); |
| header = padding + "Sent / Recv"; |
| } |
| else |
| { |
| header = padding + " Sent / Recv"; |
| } |
| |
| interestSentRecv->setText(interestStats); |
| dataSentRecv->setText(dataStats); |
| displayStatus->setText(header); |
| } |
| } |
| |
| void TrayMenu::parseFibXml() |
| { |
| QByteArray stdout = applyFibXslt->readAllStandardOutput(); |
| QByteArray stderr = applyFibXslt->readAllStandardError(); |
| applyFibXslt->deleteLater(); |
| |
| fibContentsXml = QString(stdout); |
| |
| if((stdout == "") || (stderr.length()>0)) |
| return; |
| |
| if ((enableHubDiscovery) && (fibContentsXml.indexOf("ndn:/autoconf-route",0,Qt::CaseInsensitive) == -1)) |
| { |
| networkManager->autoconfigDaemon(); |
| } |
| |
| QDomDocument xmldoc; |
| QDomElement root; |
| |
| xmldoc.setContent(fibContentsXml); |
| root=xmldoc.documentElement(); |
| |
| if(model != NULL) |
| { |
| scrollPosition = ui->tableView->verticalScrollBar()->value(); |
| model->clear(); |
| delete model; |
| } |
| |
| model = new QStandardItemModel(root.childNodes().count(),3); |
| model->setHorizontalHeaderItem(0, new QStandardItem("NDN prefix")); |
| model->setHorizontalHeaderItem(1, new QStandardItem("Face ID")); |
| model->setHorizontalHeaderItem(2, new QStandardItem("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); |
| |
| 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); |
| //ui->tableView->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents); |
| ui->tableView->horizontalHeader()->setResizeMode(QHeaderView::Fixed); |
| ui->tableView->setColumnWidth(0, 260); |
| ui->tableView->setColumnWidth(1, 57); |
| ui->tableView->setColumnWidth(2, 150); |
| |
| if(selectedRow >= 0) |
| ui->tableView->selectRow(selectedRow); |
| |
| if(scrollPosition >= 0) |
| ui->tableView->verticalScrollBar()->setValue(scrollPosition); |
| } |
| |
| void TrayMenu::createTableView() |
| { |
| ui->tableView->horizontalHeader()->setResizeMode(QHeaderView::Stretch); |
| ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection); |
| ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows); |
| |
| selectedRow = -1; |
| scrollPosition = -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(); |
| connect(process,SIGNAL(finished(int)), process, SLOT(deleteLater())); |
| process->start(NDND_FIB_COMMAND, arguments); |
| } |
| |
| TrayMenu::~TrayMenu() |
| { |
| daemonStatusTimer->stop(); |
| statusUpdateThread->exit(0); |
| delete ui; |
| delete trayIcon; |
| delete trayIconMenu; |
| delete open; |
| delete close; |
| delete openGeneralSettings; |
| delete openForwardingSettings; |
| delete openSecuritySettings; |
| delete toolBar; |
| delete statusUpdateThread; |
| delete dialog; |
| delete networkManager; |
| delete persistentSettings; |
| } |
| |
| #if WAF |
| #include "tray-menu.moc" |
| #include "tray-menu.cpp.moc" |
| #endif |