File indexing completed on 2024-05-12 04:41:11

0001 /* AtCore KDE Libary for 3D Printers
0002     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0003     SPDX-FileCopyrightText: 2016-2020 Chris Rizzitello <rizzitello@kde.org>
0004     SPDX-FileCopyrightText: 2018 Patrick José Pereira <patrickjp@kde.org>
0005 */
0006 
0007 #include "logwidget.h"
0008 
0009 #include <QFileDialog>
0010 #include <QPlainTextEdit>
0011 #include <QPushButton>
0012 #include <QStackedWidget>
0013 #include <QStyle>
0014 #include <QTemporaryFile>
0015 #include <QTime>
0016 #include <QToolButton>
0017 #include <QVBoxLayout>
0018 
0019 namespace
0020 {
0021 static constexpr QChar _newLine = QChar::fromLatin1('\n');
0022 static constexpr QChar _return = QChar::fromLatin1('\r');
0023 }
0024 
0025 LogWidget::LogWidget(QWidget *parent)
0026 : QWidget(parent)
0027 {
0028     logFile = new QTemporaryFile();
0029 
0030     initialize();
0031 }
0032 
0033 LogWidget::LogWidget(QTemporaryFile *tempFile, QWidget *parent)
0034     : QWidget(parent)
0035     , logFile(tempFile)
0036 {
0037     if (!logFile) {
0038         logFile = new QTemporaryFile();
0039     }
0040 
0041     initialize();
0042 }
0043 
0044 void LogWidget::initialize()
0045 {
0046     QSize iconSize = QSize(fontMetrics().height(), fontMetrics().height());
0047     auto page = new QWidget(this);
0048     textLog = new QPlainTextEdit(this);
0049     textLog->setReadOnly(true);
0050     textLog->setMaximumBlockCount(1000);
0051     auto pageLayout = new QVBoxLayout;
0052     pageLayout->addWidget(textLog);
0053     page->setLayout(pageLayout);
0054 
0055     auto mainStack = new QStackedWidget(this);
0056     mainStack->insertWidget(0, page);
0057 
0058     page = new QWidget(this);
0059     auto textbox = new QTextEdit(this);
0060     textbox->setReadOnly(true);
0061     textbox->setHtml(
0062         tr("\
0063                         <h4>Special Log Entries</h4> \
0064                         <p><strong>Failed to open device in read/write mode.</strong></p> \
0065                         <p>&nbsp;&nbsp;&nbsp; The Device was not able to be opened.</p> \
0066                         <p>&nbsp; &nbsp; &nbsp;&nbsp; Check the device is not opened by another program.</p> \
0067                         <p>&nbsp; &nbsp; &nbsp;&nbsp; Check you have the correct permissions to open the device.</p> \
0068                         <p><strong>No plugin found for &lt;Detected Firmware&gt;</strong></p> \
0069                         <p>&nbsp;&nbsp;&nbsp; Firmware plugins are missing or your firmware is not currently supported.</p> \
0070                         <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Manually select the Marlin or Repetier plugin.</p> \
0071                         <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; If your firmware does not have a plugin please let us know.</p> \
0072                         <p><strong>Lots of &ldquo;Waiting for firmware detect&rdquo;</strong></p> \
0073                         <p>&nbsp;&nbsp;&nbsp; Unable to send the firmware detect waiting for printer to restart</p> \
0074                         <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Push the restart button on your printer or turn it on and off. </p> \
0075                         <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Select a firmware plugin in place of auto detect.</p>"));
0076     pageLayout = new QVBoxLayout;
0077     pageLayout->addWidget(textbox);
0078     page->setLayout(pageLayout);
0079     mainStack->insertWidget(1, page);
0080 
0081     auto saveButton = new QPushButton(QIcon::fromTheme(QStringLiteral("document-save"), style()->standardIcon(QStyle::SP_DialogSaveButton)), tr("Save Session Log"), this);
0082     saveButton->setIconSize(iconSize);
0083     connect(saveButton, &QPushButton::clicked, this, &LogWidget::savePressed);
0084 
0085     auto helpButton = new QToolButton(this);
0086     helpButton->setCheckable(true);
0087     helpButton->setChecked(false);
0088     helpButton->setIconSize(iconSize);
0089     helpButton->setIcon(QIcon::fromTheme(QStringLiteral("help-about"), style()->standardIcon(QStyle::SP_DialogHelpButton)));
0090     connect(helpButton, &QToolButton::clicked, this, [mainStack](bool checked) { mainStack->setCurrentIndex(checked); });
0091 
0092     auto buttonLayout = new QHBoxLayout;
0093     buttonLayout->addWidget(saveButton);
0094     buttonLayout->addWidget(helpButton);
0095 
0096     auto mainLayout = new QVBoxLayout;
0097     mainLayout->addWidget(mainStack);
0098     mainLayout->addLayout(buttonLayout);
0099     setLayout(mainLayout);
0100 }
0101 
0102 QString LogWidget::getTime()
0103 {
0104     return QTime::currentTime().toString(QStringLiteral("hh:mm:ss:zzz"));
0105 }
0106 
0107 void LogWidget::appendLog(const QString &msg)
0108 {
0109     QString message(QStringLiteral("[%1]  %2").arg(getTime(), msg));
0110     textLog->appendPlainText(message);
0111     writeTempFile(message);
0112 }
0113 
0114 void LogWidget::appendRLog(const QByteArray &bmsg)
0115 {
0116     QString message(QStringLiteral("[%1]< %2").arg(getTime(), QString::fromUtf8(bmsg)));
0117     textLog->appendPlainText(message);
0118     writeTempFile(message);
0119 }
0120 
0121 void LogWidget::appendSLog(const QByteArray &bmsg)
0122 {
0123     QString msg = QString::fromUtf8(bmsg);
0124     msg.replace(_newLine, QStringLiteral("\\n"));
0125     msg.replace(_return, QStringLiteral("\\r"));
0126     QString message(QStringLiteral("[%1]> %2").arg(getTime(), msg));
0127     textLog->appendPlainText(message);
0128     writeTempFile(message);
0129 }
0130 
0131 void LogWidget::writeTempFile(const QString &text)
0132 {
0133     // Add text to our unsynced string list when that hits 100 sync to the temp file.
0134     unsyncedStrings.append(text);
0135     if (unsyncedStrings.count() > 100) {
0136         flushTemp();
0137     }
0138 }
0139 
0140 void LogWidget::flushTemp()
0141 {
0142     /*
0143     A QTemporaryFile will always be opened in QIODevice::ReadWrite mode,
0144     this allows easy access to the data in the file. This function will
0145     return true upon success and will set the fileName() to the unique
0146     filename used.
0147     */
0148     logFile->open();
0149     logFile->seek(logFile->size());
0150     for (const auto &string : qAsConst(unsyncedStrings)) {
0151         logFile->write(string.toLatin1());
0152         logFile->putChar('\n');
0153     }
0154     logFile->close();
0155     unsyncedStrings.clear();
0156 }
0157 
0158 void LogWidget::savePressed()
0159 {
0160     // If saving be sure we have flushed to temp.
0161     flushTemp();
0162     // Note that if a file with the name newName already exists, copy() returns false (i.e. QFile will not overwrite it).
0163     QString fileName = QDir::homePath() + QChar::fromLatin1('/') + QFileInfo(logFile->fileName()).fileName() + QStringLiteral(".txt");
0164     QString saveFileName = QFileDialog::getSaveFileName(this, tr("Save Log to file"), fileName);
0165     QFile::copy(logFile->fileName(), saveFileName);
0166     logFile->close();
0167 }
0168 
0169 bool LogWidget::endsWith(const QString &string)
0170 {
0171     return textLog->toPlainText().endsWith(string);
0172 }