/**
* @class ndgui
*
* @brief the GUI.
*
* This class is responsible for creating and displaying the user interface.
* It also connects the webView via QWebBridge to javascript functions inside the html files.
*/
#include "ndgui.h"
#include <log4cxx/logger.h>
#include "qlog4cxx.h"
using namespace log4cxx;
using namespace log4cxx::helpers;
LoggerPtr ndLogger(Logger::getLogger("fbgui.nd"));
QString gServerIp("");
bool gAutoUp = true;
QString gSocketServerPath("");
QString gPathToDhcpExe("");
/**
* constructor
*/
ndgui::ndgui(QMainWindow *parent) :
QMainWindow(parent) {
}
/**
* destructor
*/
ndgui::~ndgui() {
delete _debugConsole;
delete _toggleDebugConsole;
delete _allowUserChoice;
delete _tryAgain;
delete _webView;
delete _networkDiscovery;
}
/**
* @brief initialize all variables and prepare everything for a successful run
*/
void ndgui::init() {
_started = false;
_userChoice = false;
_ifNameList.clear();
_manConfList.clear();
setupLayout();
createAction();
_networkDiscovery = new NetworkDiscovery();
connect(_networkDiscovery, SIGNAL(addInterface(const QString &)), this,
SLOT(addInterface( const QString &)));
connect(_networkDiscovery,
SIGNAL(changeProgressBarValue(const QString & , const int& )),
this, SLOT(updateIfProgressBar(const QString & , const int&)));
connect(_networkDiscovery, SIGNAL(connectionEstablished(QString)), this,
SLOT(handleConnectionEstablished(QString)));
connect(_networkDiscovery, SIGNAL(abortBoot(QString)), this,
SLOT(abortBoot(const QString)));
connect(_networkDiscovery, SIGNAL(updateIfStatus(QString,QString)), this,
SLOT(updateIfStatus(const QString &, const QString &)));
connect(_networkDiscovery, SIGNAL(updateStatus(QString)), this,
SLOT(updateStatus(const QString&)));
connect(_networkDiscovery, SIGNAL(allProcessesFinished()), this,
SLOT(handleAllProcessesFinished()));
connect(_networkDiscovery, SIGNAL(continueBoot(QString)), this,
SLOT(continueBoot(QString)));
connect(_networkDiscovery, SIGNAL(continueBootWithoutCheck(QString )),
this, SLOT(continueBootWithoutCheck(QString)));
connect(_webView->page()->mainFrame(), SIGNAL(
javaScriptWindowObjectCleared()), this, SLOT(attachToDOM()));
connect(_webView, SIGNAL(loadFinished(bool)), this, SLOT(startSingleShot()));
setWindowTitle(tr("NetD"));
setAttribute(Qt::WA_QuitOnClose, true);
setWindowFlags(Qt::FramelessWindowHint);
showFullScreen();
if (debugMode > -1) {
_webView->load(QUrl("qrc:html/networkdiscovery_debug.html"));
} else {
_webView->load(QUrl("qrc:html/networkdiscovery.html"));
}
_webView->show();
}
/**
* @brief This method sets the used Layout.
*
* This method sets the used Layout. Possible layout are:
* - browser mode: only the browser is visible
* - debug mode: the screen is divided into the browser and a debug
* out console
*/
void ndgui::setupLayout() {
// setup layout of the gui: debug split or browser
_webView = new QWebView(this);
_webView->setContextMenuPolicy(Qt::NoContextMenu); // if this does not work try Qt::CustomContextMenu
if (debugMode == 1) {
// split main window in browser & debug console
createDebugConsole();
_splitter = new QSplitter(Qt::Vertical, this);
_splitter->addWidget(_webView);
_splitter->addWidget(_debugConsole);
setCentralWidget(_splitter);
} else {
_webView->page()->mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff);
setCentralWidget(_webView);
}
}
/**
* @brief This method creates a debug console as a widget.
*
* It is basicly a QTextEdit widget as provided by QT's Framework.
* An action to toggle this widget is implemented (CTRL + D).
*
* @see fbgui::toggleDebugConsole()
*/
void ndgui::createDebugConsole() {
// create the debug console widget
_debugConsole = new QTextEdit(this);
_debugConsole->setWindowFlags(Qt::FramelessWindowHint);
// fanciness
QPalette pal;
pal.setColor(QPalette::Base, Qt::black);
_debugConsole->setPalette(pal);
_debugConsole->setTextColor(Qt::white);
// enable custom logger engine
// qxtLog->addLoggerEngine("fb_logger", new LoggerEngine_fb(_debugConsole));
//qxtLog->initLoggerEngine("fb_logger");
// qxtLog->setMinimumLevel("fb_logger", QxtLogger::DebugLevel);
// CTRL + D toggles debug window
_toggleDebugConsole = new QAction(tr("&toggleDebug"), this);
_toggleDebugConsole->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_D));
addAction(_toggleDebugConsole);
connect(_toggleDebugConsole, SIGNAL(triggered()), this, SLOT(
toggleDebugConsole()));
}
/**
* @brief This method toggles the debug console.
*
* Toggle the visibility of the debug console if the action _toggleDebugConsole is triggered.
*
* @see fbgui::createDebugConsole()
*/
void ndgui::toggleDebugConsole() {
(_debugConsole->isVisible()) ? _debugConsole->hide() : _debugConsole->show();
}
/**
* @brief Create actions
*
* creates an action which you can trigger with the F5 and F9 Button.
*/
void ndgui::createAction() {
_allowUserChoice = new QAction(tr("&userChoice"), this);
_allowUserChoice->setShortcut(QKeySequence(Qt::Key_F5));
connect(_allowUserChoice, SIGNAL(triggered()), this, SLOT(setUserChoiceTrue()));
this->addAction(_allowUserChoice);
_tryAgain = new QAction(tr("&tryAgain"), this);
_tryAgain->setShortcut(QKeySequence(Qt::Key_F9));
connect(_tryAgain, SIGNAL(triggered()), this, SLOT(tryAgain()));
this->addAction(_tryAgain);
}
/**
* @brief set userChoice true
*
* is the connected to the triggered action pressing the F5 button.
* set the _userChoice member true
*/
void ndgui::setUserChoiceTrue() {
_userChoice = true;
}
/**
* @brief starts a singleshot event.
*
* is connected to the singleShot event. Triggering this method means
* that we go on with the main NetworkDiscovery screen.
* connects the loadFinished signal of the _webView with the
* startNetworkDiscovery slot and removes the
* action.
*/
void ndgui::startSingleShot() {
LOG4CXX_DEBUG(ndLogger, "start single shot");
QTimer::singleShot(3000, this, SLOT(startNetworkDiscovery()));
}
/**
* @brief start the network discovery
*
* main starting point of the whole procedure.
* disconnect the loadFinished signal with the startNetworkDiscovery
* and starts the networkDiscovery.
*/
void ndgui::startNetworkDiscovery() {
disconnect(_webView, SIGNAL(loadFinished(bool)), this,
SLOT(startSingleShot()));
if (!_started) {
_started = true;
_networkDiscovery->initAndRun(gServerIp, _userChoice, gAutoUp,
logFilePath, gSocketServerPath, gPathToDhcpExe);
} else {
LOG4CXX_DEBUG(ndLogger, "NetworkDiscovery already started");
}
}
/**
* @brief handle if a interface is able to connect
*
* if we have a user choice (_userChoice = true) than networkDiscovery will
* emit connectionEstablished signals.
* Add the interface name to a _ifNameList. This list holds all interfaces
* the user can choose out of.
*/
void ndgui::handleConnectionEstablished(QString ifName) {
_ifNameList.append(ifName);
}
/**
* @brief determines if we continue the boot sequence or if we show the chooseInterface or abortBoot dialog
*
* if we have a user choice (_userChoice = true) than networkDiscovery will
* emit a allProcessesFinished signal if all processes are done.
* This method determines if user will see an abort boot dialog (no interface names in
* the ifNameList list) or an
* choose interface dialog (one or more interface names in the list (add with
* handleConnectionEstablished)).
*/
void ndgui::handleAllProcessesFinished() {
LOG4CXX_DEBUG(ndLogger, "all Processes finished");
_allowUserChoice->setEnabled(false);
if (_ifNameList.size() > 0) {
if (_userChoice) {
QString jsonArr = "[";
for (int i = 0; i < _ifNameList.size() - 1; i++) {
jsonArr += "\"" + _ifNameList.value(i) + "\",";
}
jsonArr += "\"" + _ifNameList.last() + "\"]";
chooseInterfaceDialog(jsonArr);
} else {
foreach(QString i, _ifNameList)
{
if (_networkDiscovery->checkConnectivity(i)) {
continueBootWithoutCheck(i);
break;
}
}
}
} else {
LOG4CXX_DEBUG(ndLogger, " No usable interfaces found!: " << _networkDiscovery->GetErrorStr());
LOG4CXX_DEBUG(ndLogger, " list is empty");
abortBoot("No usable interfaces found!"
+ _networkDiscovery->GetErrorStr());
}
}
/**
* @brief restart the system
*
* this method will restart the system.
* triggered through a button click in the gui.
*/
void ndgui::restartSystem() {
QFile file("/proc/sysrq-trigger");
if (file.open(QIODevice::WriteOnly)) {
file.write("b");
file.close();
} else {
LOG4CXX_DEBUG(ndLogger, "Could not open /proc/sysrq-trigger");
}
}
/**
* @brief shut down the system
*
* this method will restart the system.
* triggered through a button click in the gui.
*/
void ndgui::shutDownSystem() {
QFile file("/proc/sysrq-trigger");
if (file.open(QIODevice::WriteOnly)) {
file.write("o");
file.close();
} else {
LOG4CXX_DEBUG(ndLogger, "Could not open /proc/sysrq-trigger");
}
}
/**
* @brief continue the boot sequence
*
* represents the end of the NetworkDiscovery life time.
* will start the fbgui screen. All networkDiscovery signals
* will be ignored after this point.
*/
//void ndgui::continueBoot(QString ifName, int userChoice) {
void ndgui::continueBoot(QString ifName) {
if (_networkDiscovery->checkConnectivity(ifName)) {
LOG4CXX_DEBUG(ndLogger, " continue with interface: " << ifName);
emit initFbgui();
this->close();
} else {
abortBoot(
"Interface was suddenly made unusable. Please check the log and try again.");
}
}
/**
* @brief continue the boot sequence without further checking if the connection is still possible.
*/
void ndgui::continueBootWithoutCheck(QString ifName) {
LOG4CXX_DEBUG(ndLogger, " continue with interface: " << ifName);
emit initFbgui();
this->close();
}
/**
* @brief read the log file. Log File will be presented inside of a dialog.
*/
QString ndgui::readLogFile() {
LOG4CXX_DEBUG(ndLogger, "show log");
return _networkDiscovery->readLogFile();
}
/**
* @brief starts the whole application again.
*/
void ndgui::tryAgain() {
LOG4CXX_DEBUG(ndLogger, " try again ");
_networkDiscovery->prepareTryAgain();
if(debugMode > -1) {
delete _splitter;
delete _debugConsole;
delete _toggleDebugConsole;
}
delete _allowUserChoice;
delete _tryAgain;
delete _webView;
delete _networkDiscovery;
init();
}
/*test html gui version*/
/**
* @brief fills the drop down box of the manual interface configuration
* dialog.
*/
QVariantList ndgui::getManualConfInterfaces() {
LOG4CXX_DEBUG(ndLogger, "call getManualConfInterfaces");
QVariantList jsonArr;
QString debugOut;
foreach (QString s, _manConfList) {
QVariant e(s);
jsonArr << e;
debugOut += s + "; ";
}
LOG4CXX_DEBUG(ndLogger, "value of jsonArr:" << debugOut);
return jsonArr;
}
/**
* @brief return a json formated interface configuration
*
* @param ifName
* the name of the interface
*/
QVariantMap ndgui::getInterfaceConf(QString ifName) {
return _networkDiscovery->getInterfaceConfig(ifName);
}
/**
* @brief takes the entered manual configuration dates and delivers it
* to the networkDiscovery for further actions.
*
* @param jsonArr
* a jsonArr which contains the manual entered interface configuration
*/
int ndgui::ip4_setManualConfiguration(QVariantMap jsonArr) {
return _networkDiscovery->ip4_setManualConfiguration(jsonArr);
}
/* slots */
/************************************************/
//////////////////////////////////////////////////
/************************************************/
/**
* @brief stellt ein ndgui/fbgui Objekt zur verwendung durch die html bereit.
*/
void ndgui::attachToDOM(){
_webView->page()->mainFrame()->addToJavaScriptWindowObject(QString("fbgui"), this);
loadJQuery();
}
/**
* @brief load jQuery and js scripts into the page so that all javascript functions will work.
*/
void ndgui::loadJQuery() {
QString js;
QString pathToJsDir(":/html");
pathToJsDir.append("/js");
QDir qrcJSDir(pathToJsDir);
QFileInfoList fiList = qrcJSDir.entryInfoList();
QFileInfo fi;
foreach(fi, fiList)
{
if (fi.suffix() == "js") {
//LOG4CXX_DEBUG(ndLogger, fi.fileName());
//LOG4CXX_DEBUG(ndLogger, fi.fileName());
//if (fi.fileName() != "test.js" && fi.fileName() != "nd-functions.js") {
QFile file;
file.setFileName(pathToJsDir + "/" + fi.fileName());
file.open(QIODevice::ReadOnly);
js = file.readAll();
file.close();
_webView->page()->mainFrame()->evaluateJavaScript(js);
//LOG4CXX_DEBUG(ndLogger, "evaluated " + fi.fileName());
//}
}
}
}
/**
* @brief show abortBoot dialog
*
* @param msg
* the message, displayed in the dialog.
*/
void ndgui::abortBoot(const QString msg) {
QString code = QString("abortBootDialog('\%1')").arg(msg);
_webView->page()->mainFrame()->evaluateJavaScript(code);
}
/**
* @brief opens ths chooseInterfaceDialog
*
* @param msg
* the interfaces as json formated string. will be displayed in a select box.
*/
void ndgui::chooseInterfaceDialog(const QString msg) {
QString code = QString("chooseInterfaceDialog(\%1)").arg(msg);
_webView->page()->mainFrame()->evaluateJavaScript(code);
}
/**
* @brief updates the over all status
*
* @param status
* the new status message
*/
void ndgui::updateStatus(const QString &status) {
if (status == "")
return;
QString code = QString("updateStatus('\%1')").arg(status);
_webView->page()->mainFrame()->evaluateJavaScript(code);
}
/**
* @brief updates the progress bar for each interface.
*
* @param ifname
* the name ot the interface to update
*
* @param percent
* the progress in percent
*/
void ndgui::updateIfProgressBar(const QString &ifName, const int& percent) {
if (percent == 0)
return;
QString code = QString("updateIfProgressBar('\%1',\%2)").arg(ifName).arg(percent);
_webView->page()->mainFrame()->evaluateJavaScript(code);
}
/**
* @brief update the status for each interface
*
* @param ifName
* the name ot the interface to update
*
* @param status
* the new status of the interface.
*/
void ndgui::updateIfStatus(const QString &ifName, const QString &status) {
if (ifName == "")
return;
QString code = QString("updateIfStatus('\%1','\%2')").arg(ifName).arg(status);
_webView->page()->mainFrame()->evaluateJavaScript(code);
}
/**
* @brief adds an interface to the DOM tree. Creates its progress bar and it's status label.
*
* @param ifName
* name of the new interface.
*/
void ndgui::addInterface(const QString &ifName) {
if (ifName == "")
return;
_manConfList.append(ifName);
QString code = QString("addInterface('\%1')").arg(ifName);
_webView->page()->mainFrame()->evaluateJavaScript(code);
}
/**
* @brief just for debugging.
*/
void ndgui::notifyCall(QString msg){
LOG4CXX_DEBUG(ndLogger, "------ called:" << msg);
}