Warning, file /office/skrooge/skgbasegui/skgwebview.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /***************************************************************************
0002  * SPDX-FileCopyrightText: 2022 S. MANKOWSKI stephane@mankowski.fr
0003  * SPDX-FileCopyrightText: 2022 G. DE BURE support@mankowski.fr
0004  * SPDX-License-Identifier: GPL-3.0-or-later
0005  ***************************************************************************/
0006 /** @file
0007  * A web viewer with more features.
0008  *
0009  * @author Stephane MANKOWSKI / Guillaume DE BURE
0010  */
0011 #include "skgwebview.h"
0012 
0013 #include <qapplication.h>
0014 #include <qclipboard.h>
0015 #include <qdesktopservices.h>
0016 #include <qevent.h>
0017 #include <qpointer.h>
0018 #include <qprintdialog.h>
0019 #include <qprintpreviewdialog.h>
0020 #include <qtextdocument.h>
0021 #include <qtextdocumentwriter.h>
0022 #ifdef SKG_WEBENGINE
0023 #include <qwebenginepage.h>
0024 #endif
0025 #ifdef SKG_WEBKIT
0026 #include <qwebframe.h>
0027 #endif
0028 #include <qfileinfo.h>
0029 #include <qmath.h>
0030 #include <qpainter.h>
0031 
0032 #include <kstandardaction.h>
0033 #include <qdir.h>
0034 #include <qdom.h>
0035 #include <qicon.h>
0036 #include <qmenu.h>
0037 #include <qnetworkreply.h>
0038 #include <qnetworkrequest.h>
0039 #include <qsavefile.h>
0040 
0041 #include <cmath>
0042 
0043 #include "skgmainpanel.h"
0044 #include "skgtraces.h"
0045 #ifdef SKG_WEBENGINE
0046 class SKGWebEnginePage : public QWebEnginePage
0047 {
0048     Q_DISABLE_COPY(SKGWebEnginePage)
0049 public:
0050     explicit SKGWebEnginePage(QObject* p = nullptr)
0051         : QWebEnginePage(p)
0052     {}
0053 
0054     virtual bool acceptNavigationRequest(const QUrl& url, NavigationType type, bool isMainFrame) override
0055     {
0056         if (type == QWebEnginePage::NavigationTypeLinkClicked) {
0057             if (url.toString().startsWith(QLatin1String("https://linkclicked/"))) {
0058                 SKGWebView* v = qobject_cast<SKGWebView*>(this->view());
0059                 if (v) {
0060                     v->emitLinkClicked(url);
0061                     return false;
0062                 }
0063             } else {
0064                 SKGMainPanel::getMainPanel()->openPage(url);
0065                 return false;
0066             }
0067         }
0068         return QWebEnginePage::acceptNavigationRequest(url, type, isMainFrame);
0069     }
0070 };
0071 
0072 SKGWebView::SKGWebView(QWidget* iParent, const char* name, bool iWithContextualMenu)
0073     : QWebEngineView(iParent), m_ContextualMenu(iWithContextualMenu)
0074 {
0075     setObjectName(name);
0076     setPage(new SKGWebEnginePage(this));
0077     if (m_ContextualMenu) {
0078         this->installEventFilter(this);
0079         page()->installEventFilter(this);
0080     }
0081 
0082     connect(this, &SKGWebView::fileExporter, this, [](const QString & iFileName) {
0083         QDesktopServices::openUrl(QUrl::fromLocalFile(iFileName));
0084     });
0085 }
0086 
0087 void SKGWebView::emitLinkClicked(const QUrl& iURL)
0088 {
0089     Q_EMIT linkClicked(iURL);
0090 }
0091 #endif
0092 #ifdef SKG_WEBKIT
0093 SKGWebView::SKGWebView(QWidget* iParent, const char* name)
0094     : QWebView(iParent)
0095 {
0096     setObjectName(name);
0097     this->installEventFilter(this);
0098     page()->installEventFilter(this);
0099 
0100     connect(this, &SKGWebView::fileExporter, this, [](const QString & iFileName) {
0101         QDesktopServices::openUrl(QUrl::fromLocalFile(iFileName));
0102     });
0103 
0104     connect(this, &SKGWebView::linkClicked, this, [ = ](const QUrl & val) {
0105         SKGMainPanel::getMainPanel()->openPage(val);
0106     });
0107 
0108     this->page()->setForwardUnsupportedContent(true);
0109     connect(this->page(), &QWebPage::unsupportedContent, this, [ = ](QNetworkReply * reply) {
0110         openReply(reply);
0111     });
0112     connect(this->page(), &QWebPage::downloadRequested, this, [ = ](const QNetworkRequest & request) {
0113         QNetworkAccessManager manager;
0114         openReply(manager.get(request));
0115     });
0116 }
0117 
0118 void SKGWebView::openReply(QNetworkReply* reply)
0119 {
0120     QString fileName = QDir::tempPath() + '/' + "export.csv";
0121     QFile file(fileName);
0122     if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
0123         file.write(reply->readAll());
0124         file.close();
0125     }
0126     QDesktopServices::openUrl(QUrl::fromLocalFile(fileName));
0127     reply->deleteLater();
0128 }
0129 #endif
0130 
0131 #if !defined(SKG_WEBENGINE) && !defined(SKG_WEBKIT)
0132 SKGWebView::SKGWebView(QWidget* iParent, const char* name) : QScrollArea(iParent)
0133 {
0134     auto label = new QLabel(this);
0135     setWidget(label);
0136     setWidgetResizable(true);
0137 
0138     setObjectName(name);
0139     label->setTextFormat(Qt::RichText);
0140     connect(label, &QLabel::linkActivated, this, [ = ](const QString & val) {
0141         SKGMainPanel::getMainPanel()->openPage(val);
0142     });
0143 }
0144 #endif
0145 
0146 SKGWebView::~SKGWebView()
0147     = default;
0148 
0149 QString SKGWebView::getState()
0150 {
0151     SKGTRACEINFUNC(10)
0152     QDomDocument doc(QStringLiteral("SKGML"));
0153     QDomElement root = doc.createElement(QStringLiteral("parameters"));
0154     doc.appendChild(root);
0155 #if defined(SKG_WEBENGINE) || defined(SKG_WEBKIT)
0156     root.setAttribute(QStringLiteral("zoomFactor"), SKGServices::intToString(qMax(qRound(30.0 * log10(zoomFactor())), -10)));
0157 #endif
0158     return doc.toString();
0159 }
0160 
0161 void SKGWebView::setState(const QString& iState)
0162 {
0163     SKGTRACEINFUNC(10)
0164     QDomDocument doc(QStringLiteral("SKGML"));
0165     doc.setContent(iState);
0166     QDomElement root = doc.documentElement();
0167 #if defined(SKG_WEBENGINE) || defined(SKG_WEBKIT)
0168     QString zoomPosition = root.attribute(QStringLiteral("zoomFactor"));
0169     if (zoomPosition.isEmpty()) {
0170         zoomPosition = '0';
0171     }
0172     double z = qPow(10, (static_cast<qreal>(SKGServices::stringToInt(zoomPosition)) / 30.0));
0173     setZoomFactor(z);
0174     emit zoomChanged(z);
0175 #endif
0176 }
0177 
0178 #if defined(SKG_WEBENGINE) || defined(SKG_WEBKIT)
0179 void SKGWebView::contextMenuEvent(QContextMenuEvent* iEvent)
0180 {
0181     if (iEvent != nullptr) {
0182         auto menu = new QMenu(this);
0183 #ifdef SKG_WEBENGINE
0184         menu->addAction(pageAction(QWebEnginePage::Copy));
0185 #endif
0186 #ifdef SKG_WEBKIT
0187         menu->addAction(pageAction(QWebPage::Copy));
0188 #endif
0189 
0190         QAction* actPrint = menu->addAction(SKGServices::fromTheme(QStringLiteral("printer")), i18nc("Action", "Print…"));
0191         connect(actPrint, &QAction::triggered, this, &SKGWebView::onPrint);
0192 
0193         menu->addAction(KStandardAction::printPreview(this, SLOT(onPrintPreview()), this));
0194 
0195         QAction* actExport = menu->addAction(SKGServices::fromTheme(QStringLiteral("document-export")), i18nc("Noun, user action", "Export…"));
0196         connect(actExport, &QAction::triggered, this, &SKGWebView::onExport);
0197 
0198         menu->popup(this->mapToGlobal(iEvent->pos()));
0199 
0200         iEvent->accept();
0201     }
0202 }
0203 #endif
0204 bool SKGWebView::eventFilter(QObject* iObject, QEvent* iEvent)
0205 {
0206     SKGTRACEINFUNC(10)
0207     if ((iEvent != nullptr) && iEvent->type() == QEvent::Wheel) {
0208         auto* e = dynamic_cast<QWheelEvent*>(iEvent);
0209         if (e != nullptr) {
0210             if ((QApplication::keyboardModifiers() &Qt::ControlModifier) != 0u) {
0211                 int numDegrees = e->angleDelta().y() / 8;
0212                 int numTicks = numDegrees / 15;
0213 
0214                 if (numTicks > 0) {
0215                     onZoomIn();
0216                 } else {
0217                     onZoomOut();
0218                 }
0219                 e->setAccepted(true);
0220                 return true;
0221             }
0222         }
0223     }
0224     return QWidget::eventFilter(iObject, iEvent);
0225 }
0226 
0227 void SKGWebView::onZoomIn()
0228 {
0229     _SKGTRACEINFUNC(10)
0230 #if defined(SKG_WEBENGINE) || defined(SKG_WEBKIT)
0231     int z = qMin(static_cast<int>(qRound(30.0 * log10(zoomFactor()))) + 1, 10);
0232     setZoomFactor(qPow(10, static_cast<qreal>(z) / 30.0));
0233     emit zoomChanged(z);
0234 #endif
0235 }
0236 
0237 void SKGWebView::onZoomOut()
0238 {
0239     _SKGTRACEINFUNC(10)
0240 #if defined(SKG_WEBENGINE) || defined(SKG_WEBKIT)
0241     int z = qMax(static_cast<int>(qRound(30.0 * log10(zoomFactor()))) - 1, -10);
0242     setZoomFactor(qPow(10, static_cast<qreal>(z) / 30.0));
0243     emit zoomChanged(z);
0244 #endif
0245 }
0246 
0247 void SKGWebView::onZoomOriginal()
0248 {
0249     _SKGTRACEINFUNC(10)
0250 #if defined(SKG_WEBENGINE) || defined(SKG_WEBKIT)
0251     setZoomFactor(0);
0252     emit zoomChanged(0);
0253 #endif
0254 }
0255 
0256 void SKGWebView::exportInFile(const QString& iFileName)
0257 {
0258     QString extension = QFileInfo(iFileName).suffix().toUpper();
0259     if (extension == QStringLiteral("ODT")) {
0260 #ifdef SKG_WEBENGINE
0261         page()->toHtml([ = ](const QString & result) {
0262             QTextDocument doc;
0263             QTextDocumentWriter docWriter(iFileName);
0264             doc.setHtml(result);
0265             docWriter.write(&doc);
0266 
0267             emit fileExporter(iFileName);
0268         });
0269 #endif
0270 #ifdef SKG_WEBKIT
0271         QTextDocument doc;
0272         QTextDocumentWriter docWriter(iFileName);
0273         doc.setHtml(page()->mainFrame()->toHtml());
0274         docWriter.write(&doc);
0275 
0276         emit fileExporter(iFileName);
0277 #endif
0278     } else if (extension == QStringLiteral("PDF")) {
0279 #ifdef SKG_WEBENGINE
0280         page()->printToPdf(iFileName);
0281         connect(page(), &QWebEnginePage::pdfPrintingFinished, this, &SKGWebView::fileExporter);
0282 #endif
0283 #ifdef SKG_WEBKIT
0284         QPrinter printer;
0285         printer.setOutputFileName(iFileName);
0286         print(&printer);
0287 
0288         emit fileExporter(iFileName);
0289 #endif
0290     } else if (extension == QStringLiteral("HTML") || extension == QStringLiteral("HTM")) {
0291 #ifdef SKG_WEBENGINE
0292         page()->toHtml([ = ](const QString & result) {
0293             QSaveFile file(iFileName);
0294             if (file.open(QIODevice::WriteOnly)) {
0295                 QTextStream out(&file);
0296                 out << result;
0297 
0298                 // Close file
0299                 file.commit();
0300                 emit fileExporter(iFileName);
0301             }
0302         });
0303 #endif
0304 #ifdef SKG_WEBKIT
0305         QSaveFile file(iFileName);
0306         if (file.open(QIODevice::WriteOnly)) {
0307             QTextStream out(&file);
0308             out << page()->mainFrame()->toHtml();
0309 
0310             // Close file
0311             file.commit();
0312             emit fileExporter(iFileName);
0313         }
0314 #endif
0315     } else {
0316         QImage image(this->size(), QImage::Format_ARGB32);
0317         QPainter painter(&image);
0318         this->render(&painter);
0319         painter.end();
0320         image.save(iFileName);
0321 
0322         emit fileExporter(iFileName);
0323     }
0324 }
0325 
0326 void SKGWebView::onExport()
0327 {
0328     _SKGTRACEINFUNC(10)
0329     QString fileName = SKGMainPanel::getSaveFileName(QStringLiteral("kfiledialog:///IMPEXP"), QStringLiteral("application/pdf text/html application/vnd.oasis.opendocument.text image/png image/jpeg image/gif image/tiff"), this);
0330     if (fileName.isEmpty()) {
0331         return;
0332     }
0333 
0334     exportInFile(fileName);
0335 }
0336 
0337 void SKGWebView::onPrintPreview()
0338 {
0339     SKGTRACEINFUNC(10)
0340     QPointer<QPrintPreviewDialog> dialog = new QPrintPreviewDialog(this);
0341 #ifdef SKG_WEBENGINE
0342     // TODO(SMI): QWebEngine
0343     connect(dialog.data(), &QPrintPreviewDialog::paintRequested, page(), [&](QPrinter * printer) {
0344         page()->print(printer, [](bool) {});
0345     });
0346 #endif
0347 #ifdef SKG_WEBKIT
0348     connect(dialog.data(), &QPrintPreviewDialog::paintRequested, this, &SKGWebView::print);
0349 #endif
0350 
0351     dialog->exec();
0352 }
0353 
0354 void SKGWebView::onPrint()
0355 {
0356     _SKGTRACEINFUNC(10)
0357     QPointer<QPrintDialog> dialog = new QPrintDialog(&m_printer, this);
0358     if (dialog->exec() == QDialog::Accepted) {
0359         QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
0360 #ifdef SKG_WEBENGINE
0361         page()->print(&m_printer, [](bool) {});
0362 #endif
0363 #ifdef SKG_WEBKIT
0364         print(&m_printer);
0365 #endif
0366         QApplication::restoreOverrideCursor();
0367     }
0368 }