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 }