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

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

Mas ajustes a traducciones

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