source: ogBrowser-Git/src/mainwindow.cpp @ cad017d

jenkinsmain
Last change on this file since cad017d was cad017d, checked in by Vadim Troshchinskiy Shmelev <vtroshchinskiy@…>, 18 months ago

Modo quisco

  • Property mode set to 100644
File size: 16.5 KB
Line 
1#include "mainwindow.h"
2#include <QtWebEngineWidgets>
3#include <QStringList>
4#include <QWebEngineView>
5#include <QDockWidget>
6#include <QtDebug>
7#include <QWebEnginePage>
8#include <QProcess>
9#include <QTextEdit>
10#include <QMessageBox>
11#include <QPushButton>
12#include <QDateTime>
13#include <QProgressBar>
14#include <QTabWidget>
15#include <QLineEdit>
16#include <QNetworkReply>
17#include <QSslError>
18#include <QTimer>
19#include <QRegularExpression>
20#include <QStringList>
21#include <QString>
22
23
24#include <libintl.h>
25
26#include "qtermwidget.h"
27#include "digitalclock.h"
28#include "ogurlhandler.h"
29
30#define BUFFERSIZE 2048
31#define REGEXP_STRING "^\\[(\\d+)\\]"
32
33#define CURRENT_TIME() QDateTime::currentDateTime().toString("dd/MM/yyyy hh:mm:ss")
34
35MainWindow::MainWindow(QWidget *parent)
36    : QMainWindow(parent),m_web(new QWebEngineView()),m_output(new QTextEdit()),
37      m_logfile(0),m_logstream(0),m_numberTerminal(0)
38{
39    // Graphic
40    setWindowTitle(tr("OpenGnsys Browser"));
41    setCentralWidget(m_web);
42    readEnvironmentValues();
43
44    m_is_admin = qgetenv("ogactiveadmin") == "true";
45    m_kiosk_mode = qgetenv("OGKIOSKMODE") == "true";
46
47    // Open the log file for append
48    if(m_env.contains("OGLOGFILE") && m_env["OGLOGFILE"]!="")
49    {
50        QFile* m_logfile=new QFile(m_env["OGLOGFILE"]);
51        if(!m_logfile->open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append))
52        {
53            delete m_logfile;
54            print(tr(gettext("El fichero de log no ha podido ser abierto: "))+m_env["OGLOGFILE"]+".");
55        }
56        else
57        {
58            m_logstream=new QTextStream(m_logfile);
59        }
60    }
61
62    // Output
63    m_output->setReadOnly(true);
64    m_output->setFontPointSize(16);
65
66    // Button Dock
67    QDockWidget* dock=new QDockWidget();
68    dock->setAllowedAreas(Qt::BottomDockWidgetArea);
69    QWidget* dummy=new QWidget();
70    dummy->setMaximumHeight(0);
71    dock->setTitleBarWidget(dummy);
72
73    // TabWidget
74    m_tabs=new QTabWidget(dock);
75    QPushButton *button=new QPushButton(tr(gettext("&Nueva Terminal")));
76    button->setFocusPolicy(Qt::TabFocus);
77    m_tabs->setCornerWidget(button);
78    m_tabs->setFocusPolicy(Qt::NoFocus);
79    m_tabs->addTab(m_output,tr(gettext("Salida")));
80    slotCreateTerminal();
81    // Assign tabs to dock
82    dock->setWidget(m_tabs);
83    // Assign tabs dock to the mainwindow if admin mode is active
84    if(isAdmin())
85        addDockWidget(Qt::BottomDockWidgetArea,dock);
86
87    // Top Dock
88    dock=new QDockWidget();
89    dock->setAllowedAreas(Qt::TopDockWidgetArea);
90    QWidget* dummy2=new QWidget();
91    dummy2->setMaximumHeight(0);
92    dock->setTitleBarWidget(dummy2);
93    // WebBar
94    m_webBar=new QLineEdit(dock);
95    // WebBar to dock
96    dock->setWidget(m_webBar);
97    // Assign top dock to the mainwindow if admin mode is active
98    if(isAdmin())
99        addDockWidget(Qt::TopDockWidgetArea,dock);
100
101    // Status bar
102    QStatusBar* st=statusBar();
103    st->setSizeGripEnabled(false);
104    // OpenGnsys logo (or alternate text)
105    m_logo=new QLabel();
106    QPixmap logo;
107    if(logo.load("/opt/opengnsys/lib/pictures/oglogo.png"))
108        m_logo->setPixmap(logo);
109    else
110        m_logo->setText("OG");
111    m_logo->setToolTip(tr(gettext("Proyecto OpenGnsys"))+"\nhttps://opengnsys.es");
112    // Progress bar
113    m_progressBar=new QProgressBar(this);
114    m_progressBar->setRange(0,100);
115    // Connection speed
116    QString speed=readSpeed();
117    m_speedInfo=new QLabel(speed);
118    m_speedInfo->setAlignment(Qt::AlignCenter);
119    if(m_env.contains("DEFAULTSPEED") && m_env["DEFAULTSPEED"]!="")
120        if(speed.compare(m_env["DEFAULTSPEED"])!=0)
121            m_speedInfo->setStyleSheet("background-color: darkred; color: white; font-weight: bold;");
122    // Clock
123    m_clock=new DigitalClock(this);
124
125    connect(m_web,SIGNAL(loadStarted()),this,SLOT(slotWebLoadStarted()));
126    connect(m_web,SIGNAL(loadFinished(bool)),this,SLOT(slotWebLoadFinished(bool)));
127    connect(m_web,SIGNAL(loadProgress(int)),this,SLOT(slotWebLoadProgress(int)));
128    connect(m_web,SIGNAL(urlChanged(const QUrl&)),this,SLOT(slotUrlChanged(const QUrl&)));
129    // Ignore SSL errors.
130
131
132    // Qindel:
133    //connect(m_web->page()->networkAccessManager(),
134//            SIGNAL(sslErrors(QNetworkReply*, const QList<QSslError> &)), this,
135//            SLOT(slotSslErrors(QNetworkReply*)));
136
137
138    // Dock signals
139    connect(button,SIGNAL(clicked()),this,SLOT(slotCreateTerminal()));
140
141    // All schemes need registering first, then their handlers.
142    registerScheme("command");
143    registerScheme("command+output");
144    registerScheme("command+confirm");
145    registerScheme("command+confirm+output");
146    registerScheme("command+output+confirm");
147
148
149    registerHandler("command", false, false);
150    registerHandler("command+output", false, true);
151    registerHandler("command+confirm", true, false);
152    registerHandler("command+confirm+output", true, true);
153    registerHandler("command+output+confirm", true, true);
154
155
156    QStringList arguments=QCoreApplication::arguments();
157    m_webBar->setText(arguments.at(1));
158    m_web->load(QUrl(arguments.at(1)));
159
160
161
162
163
164    showMaximized();
165    showFullScreen();
166}
167
168void MainWindow::closeEvent(QCloseEvent *event) {
169    if (isKioskMode()) {
170        qInfo() << "Modo quiosco activado, ignorando intento de cerrar ventana";
171        event->ignore();
172    }
173}
174
175
176MainWindow::~MainWindow()
177{
178    if(m_logfile)
179    {
180        m_logfile->close();
181        delete m_logfile;
182    }
183    if(m_logstream)
184        delete m_logstream;
185}
186
187void MainWindow::registerScheme(const QString &name) {
188    QWebEngineUrlScheme scheme(name.toLatin1());
189    scheme.setSyntax(QWebEngineUrlScheme::Syntax::Path);
190    scheme.setDefaultPort(0);
191    scheme.setFlags(QWebEngineUrlScheme::LocalScheme);
192    QWebEngineUrlScheme::registerScheme(scheme);
193}
194
195
196void MainWindow::registerHandler(const QString &commandName, bool confirm, bool returnOutput) {
197    OGBrowserUrlHandlerCommand *handler = new OGBrowserUrlHandlerCommand(this);
198    connect(handler, &OGBrowserUrlHandlerCommand::command, this, &MainWindow::commandQueued);
199    handler->setAskConfirmation(confirm);
200    handler->setReturnOutput(returnOutput);
201    QWebEngineProfile::defaultProfile()->installUrlSchemeHandler(commandName.toLatin1(), handler);
202}
203
204void MainWindow::commandQueued(const QString &command, bool confirm, bool returnOutput) {
205    //PendingCommand cmd;
206
207    qInfo() << "Queued command:" << command;
208
209    if (confirm) {
210        QMessageBox msgBox;
211        msgBox.setWindowFlags(Qt::CustomizeWindowHint | Qt::WindowTitleHint);
212        msgBox.setWindowTitle(tr(gettext("AVISO")));
213        msgBox.setIcon(QMessageBox::Question);
214        msgBox.setTextFormat(Qt::RichText);
215        msgBox.setText(tr(gettext("La siguiente acci&oacute;n puede modificar datos o tardar varios minutos. El equipo no podr&aacute; ser utilizado durante su ejecuci&oacute;n.")));
216        QPushButton *execButton = msgBox.addButton(tr(gettext("Ejecutar")), QMessageBox::ActionRole);
217        msgBox.addButton(tr(gettext("Cancelar")), QMessageBox::RejectRole);
218        msgBox.setDefaultButton(execButton);
219        msgBox.exec();
220
221        if (msgBox.clickedButton() != execButton) {
222            qInfo() << "User rejected running the command";
223            return;
224        }
225    }
226
227    if (returnOutput && !isAdmin()) {
228        int w=MainWindow::width(), h=MainWindow::height();
229        m_output->setWindowFlags(Qt::Window);
230        m_output->move(100, 100);
231        m_output->setFixedSize(w*0.8-100, h*0.8-100);
232        m_output->show();
233    }
234
235
236    m_command.command = command;
237    m_command.confirm = confirm;
238    m_command.returnOutput = returnOutput;
239
240
241
242
243    QStringList list=command.split(" ",Qt::SkipEmptyParts);
244    QString program=list.takeFirst();
245
246    m_command.process = new QProcess(this);
247    m_command.process->setReadChannel(QProcess::StandardOutput);
248    m_command.process->setEnvironment(QProcess::systemEnvironment());
249
250    // Process signals
251    connect(m_command.process, &QProcess::started,this, &MainWindow::slotProcessStarted);
252    connect(m_command.process, &QProcess::finished,this,&MainWindow::slotProcessFinished);
253    connect(m_command.process, &QProcess::errorOccurred, this,&MainWindow::slotProcessError);
254    connect(m_command.process, &QProcess::readyReadStandardOutput,this,&MainWindow::slotProcessOutput);
255    connect(m_command.process, &QProcess::readyReadStandardError,this,&MainWindow::slotProcessErrorOutput);
256
257
258    if(isAdmin()) {
259        m_output->setTextColor(QColor(Qt::darkGreen));
260        print(tr(gettext("Lanzando el comando: "))+command);
261        m_output->setTextColor(QColor(Qt::black));
262    } else {
263        write(tr(gettext("Lanzando el comando: "))+command);
264    }
265
266    m_command.process->start(program,list);
267    startProgressBar();
268
269}
270
271void MainWindow::slotWebLoadStarted()
272{
273    startProgressBar();
274    m_progressBar->setFormat(gettext("%p% Cargando"));
275}
276
277void MainWindow::slotWebLoadProgress(int progress)
278{
279    m_progressBar->setValue(progress);
280}
281
282void MainWindow::slotWebLoadFinished(bool ok)
283{
284    // If any error ocurred, show a pop up
285    // Sometimes when the url hasn't got a dot, i.e /var/www/pageweb,
286    // the return value is always true so we check the bytes received too
287    qWarning() << "Load finished. URL: " << m_web->url() << "; ok = " << ok;
288
289    finishProgressBar();
290
291}
292
293void MainWindow::slotUrlChanged(const QUrl &url)
294{
295    m_webBar->setText(url.toString());
296}
297
298void MainWindow::slotSslErrors(QNetworkReply* reply)
299{
300    reply->ignoreSslErrors();
301}
302
303void MainWindow::slotProcessStarted()
304{
305    startProgressBar();
306}
307
308void MainWindow::slotProcessOutput()
309{
310    m_command.process->setReadChannel(QProcess::StandardOutput);
311    char buf[BUFFERSIZE];
312    while((m_command.process->readLine(buf,BUFFERSIZE) > 0))
313    {
314        QString s(buf);
315        qInfo() << "OUT: " << buf;
316
317        if(isAdmin())
318        {
319            m_output->insertPlainText(tr("Proc. stdout: "));
320        }
321        print(s);
322        captureOutputForStatusBar(s);
323    }
324}
325
326void MainWindow::slotProcessErrorOutput()
327{
328
329   // QProcess *process = qobject_cast<QProcess*>(sender());
330   // QVector<PendingCommand>::iterator it=std::find(m_commands.begin(), m_commands.end(), []())
331
332    m_command.process->setReadChannel(QProcess::StandardError);
333    char buf[BUFFERSIZE];
334    while((m_command.process->readLine(buf,BUFFERSIZE) > 0))
335    {
336        QString s(buf);
337        qInfo() << "ERR: " << buf;
338
339        if(isAdmin())
340        {
341            m_output->insertPlainText(tr("Proc. stderr: "));
342        }
343        m_output->setTextColor(QColor(Qt::darkBlue));
344        print(s);
345        m_output->setTextColor(QColor(Qt::black));
346    }
347}
348
349void MainWindow::slotProcessFinished(int code, QProcess::ExitStatus status)
350{
351
352    qInfo() << "Finished: " << m_command.command << "with status" << status;
353
354    if(isAdmin())
355    {
356        // Admin user: show process status
357        if(status==QProcess::NormalExit)
358        {
359            if(code > 0)
360            {
361                m_output->setTextColor(QColor(Qt::darkRed));
362            }
363            print("\n"+tr(gettext("Fin del proceso. Valor de retorno: "))+QString::number(code));
364        }
365        else
366        {
367            m_output->setTextColor(QColor(Qt::darkRed));
368            print("\n"+tr(gettext("El proceso ha fallado inesperadamente. Salida: ")+code));
369        }
370        m_output->setTextColor(QColor(Qt::black));
371    }
372    else
373    {
374        // Non-admin user: show instruction to close the popup window
375        write(tr(gettext("Fin del proceso. Valor de retorno: "))+QString::number(code));
376        m_output->setFontUnderline(true);
377        print("\n\n"+tr(gettext("AVISO: Pulsar el botón superior derecho para cerrar"))+" [X]");
378        m_output->setFontUnderline(false);
379    }
380    // On error, show a message box
381    if(code > 0 && ! m_output->isActiveWindow())
382    {
383        showErrorMessage(gettext("Código de salida: ")+QString::number(code));
384    }
385    finishProgressBar();
386}
387
388void MainWindow::slotProcessError(QProcess::ProcessError error)
389{
390    qCritical() << "Error: " << m_command.command << "with status" << error;
391
392    QString errorMsg;
393    switch(error)
394    {
395        case QProcess::FailedToStart:
396            errorMsg=tr(gettext("Imposible lanzar el proceso."));
397            break;
398        case QProcess::WriteError:
399            errorMsg=tr(gettext("Error de escritura en el proceso."));
400            break;
401        case QProcess::ReadError:
402            errorMsg=tr(gettext("Error de lectura del proceso."));
403            break;
404        // No capturo crashed porque la pillo por finished
405        case QProcess::Crashed:
406        case QProcess::Timedout:
407            break;
408        case QProcess::UnknownError:
409        default:
410            errorMsg=tr(gettext("Error desconocido."));
411            break;
412    }
413    // Print error and show message box with timeout.
414    if(!errorMsg.isNull()) {
415        m_output->setTextColor(QColor(Qt::darkRed));
416        print(errorMsg);
417        m_output->setTextColor(QColor(Qt::black));
418        showErrorMessage(errorMsg);
419    }
420    finishProgressBar();
421}
422
423void MainWindow::slotCreateTerminal()
424{
425    QTermWidget* console = new QTermWidget(1,this);
426    QFont font = QApplication::font();
427    font.setFamily("DejaVu Sans Mono");
428    font.setPointSize(12);
429
430    console->setTerminalFont(font);
431    console->setFocusPolicy(Qt::StrongFocus);
432    console->setScrollBarPosition(QTermWidget::ScrollBarRight);
433
434    ++m_numberTerminal;
435
436    connect(console,SIGNAL(finished()),this,SLOT(slotDeleteTerminal()));
437
438    QString name=tr("Term ")+QString::number(m_numberTerminal);
439    m_tabs->addTab(console,name);
440}
441
442void MainWindow::slotDeleteTerminal()
443{
444    QWidget *widget = qobject_cast<QWidget *>(sender());
445    Q_ASSERT(widget);
446    m_tabs->removeTab(m_tabs->indexOf(widget));
447    delete widget;
448}
449
450int MainWindow::readEnvironmentValues()
451{
452    // The return value
453    int ret=true;
454
455    // Get all environment variables
456    QStringList environmentlist=QProcess::systemEnvironment();
457    // This is the list of the important variables
458    QStringList variablelist=QString(ENVIRONMENT).split(",");
459
460    // This is an auxiliar variable
461    QStringList stringlist;
462
463    foreach (QString str,variablelist)
464    {
465        // Look for the variable in the environment
466        stringlist=environmentlist.filter(str+"=");
467
468        if(stringlist.isEmpty())
469        {
470            m_env[str]="";
471            ret=false;
472        }
473        else
474        {
475            // Get the first element and get the value part
476            m_env[str]=(stringlist.first().split("="))[1];
477        }
478    }
479
480    return ret;
481}
482
483// Write a string to the log file
484void MainWindow::write(QString s)
485{
486    if(! s.endsWith("\n"))
487        s+="\n";
488    if(m_logstream)
489    {
490        *m_logstream<<CURRENT_TIME()<<": browser: "<<s;
491        m_logstream->flush();
492    }
493}
494
495// Print and log a string
496void MainWindow::print(QString s)
497{
498    if(! s.endsWith("\n"))
499        s+="\n";
500    write(s);
501    if(m_output)
502        m_output->insertPlainText(s);
503}
504
505// Show message in status bar
506void MainWindow::captureOutputForStatusBar(QString output)
507{
508    // Modify the status bar
509    output=output.trimmed();
510    // Get percentage (string starts with "[Number]")
511    QRegularExpression regexp(REGEXP_STRING);
512    QRegularExpressionMatch match = regexp.match(output);
513
514    if(match.hasMatch())
515    {
516        int pass=match.captured(1).toInt();
517        output.replace(regexp,"");
518        m_progressBar->setValue(pass);
519        m_progressBar->setFormat("%p%"+output);
520    }
521}
522
523// Init status bar
524void MainWindow::startProgressBar()
525{
526    QStatusBar* st=statusBar();
527    st->clearMessage();
528    st->addWidget(m_logo);
529    st->addWidget(m_progressBar,90);
530    st->addWidget(m_speedInfo,5);
531    st->addWidget(m_clock,5);
532    m_progressBar->show();
533    m_clock->show();
534    m_web->setEnabled(false);
535}
536
537// Reset status bar
538void MainWindow::finishProgressBar()
539{
540    m_progressBar->reset();
541    m_web->setEnabled(true);
542}
543
544
545// Returns communication speed
546QString MainWindow::readSpeed() {
547    if(m_env.contains("OGLOGFILE"))
548    {
549        QString infoFile=m_env["OGLOGFILE"].replace(".log", ".info.html");
550        //QString command="grep -hoe \"[0-9]*Mb/s\" "+infoFile+" 2>/dev/null";
551        QProcess process;
552        process.start("grep", QStringList({"-hoe", "[0-9]*Mb/s", infoFile}));
553        process.waitForFinished();
554        QString speed(process.readAllStandardOutput());
555        return speed.simplified();
556    }
557    else
558    {
559        return QString("");
560    }
561}
562
563// Show an error box with timeout
564void MainWindow::showErrorMessage(QString text)
565{
566    QMessageBox* msgBox=new QMessageBox();
567    msgBox->setWindowFlags(Qt::CustomizeWindowHint | Qt::WindowTitleHint);
568    msgBox->setWindowTitle(gettext("ERROR"));
569    msgBox->setIcon(QMessageBox::Warning);
570    msgBox->setText(text);
571    msgBox->show();
572    QTimer::singleShot(5000, msgBox, SLOT(close()));
573}
Note: See TracBrowser for help on using the repository browser.