diff --git a/CMakeLists.txt b/CMakeLists.txt index bac09ae8d..fc30aba9c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,6 +51,7 @@ option(NO_USERMANUAL "don't include a viewer for the user manual" OFF) #Options regarding enabling parts of subsurface option(BTSUPPORT "enable support for QtBluetooth (requires Qt5.4 or newer)" ON) option(FTDISUPPORT "enable support for libftdi based serial" OFF) +option(USE_WEBENGINE "Use QWebEngine instead of QWebKit" OFF) # Options regarding What should we build on subsurface option(MAKE_TESTS "Make the tests" ON) diff --git a/cmake/Modules/HandleUserManual.cmake b/cmake/Modules/HandleUserManual.cmake index 226b8ca9e..ba8b66331 100644 --- a/cmake/Modules/HandleUserManual.cmake +++ b/cmake/Modules/HandleUserManual.cmake @@ -2,5 +2,11 @@ if(NO_USERMANUAL) message(STATUS "building without usermanual") add_definitions(-DNO_USERMANUAL) else() - list(APPEND QT_EXTRA_COMPONENTS WebKitWidgets) + if(USE_WEBENGINE) + message(STATUS "building with QWebEngine") + list(APPEND QT_EXTRA_COMPONENTS WebEngineWidgets) + add_definitions(-DUSE_WEBENGINE) + else() + list(APPEND QT_EXTRA_COMPONENTS WebKitWidgets) + endif() endif() diff --git a/desktop-widgets/CMakeLists.txt b/desktop-widgets/CMakeLists.txt index 95c4b1e9a..c20fb2264 100644 --- a/desktop-widgets/CMakeLists.txt +++ b/desktop-widgets/CMakeLists.txt @@ -148,8 +148,6 @@ if(NOT NO_PRINTING) set(SUBSURFACE_INTERFACE ${SUBSURFACE_INTERFACE} printdialog.cpp printdialog.h - printer.cpp - printer.h printoptions.cpp printoptions.h templateedit.cpp @@ -159,6 +157,18 @@ if(NOT NO_PRINTING) ) endif() +if(USE_WEBENGINE) + set(SUBSURFACE_INTERFACE ${SUBSURFACE_INTERFACE} + printerwebengine.cpp + printerwebengine.h + ) +else() + set(SUBSURFACE_INTERFACE ${SUBSURFACE_INTERFACE} + printer.cpp + printer.h + ) +endif() + if (BTSUPPORT) set(SUBSURFACE_INTERFACE ${SUBSURFACE_INTERFACE} btdeviceselectiondialog.cpp diff --git a/desktop-widgets/printdialog.cpp b/desktop-widgets/printdialog.cpp index a4c181c68..5c290398f 100644 --- a/desktop-widgets/printdialog.cpp +++ b/desktop-widgets/printdialog.cpp @@ -1,6 +1,10 @@ // SPDX-License-Identifier: GPL-2.0 #include "printdialog.h" +#ifdef USE_WEBENGINE +#include "printerwebengine.h" +#else #include "printer.h" +#endif #include "core/pref.h" #include "core/dive.h" // for existing_filename @@ -14,6 +18,9 @@ #include #include #include +#ifdef USE_WEBENGINE +#include +#endif #define SETTINGS_GROUP "PrintDialog" @@ -215,13 +222,26 @@ void PrintDialog::printClicked(void) { createPrinterObj(); QPrintDialog printDialog(qprinter, this); +#ifdef USE_WEBENGINE + connect(printer, SIGNAL(progessUpdated(int)), progressBar, SLOT(setValue(int))); + connect(printer, &Printer::jobDone, this, &PrintDialog::printingDone); + printer->print(); +#else if (printDialog.exec() == QDialog::Accepted) { connect(printer, SIGNAL(progessUpdated(int)), progressBar, SLOT(setValue(int))); printer->print(); close(); } +#endif } +#ifdef USE_WEBENGINE +void PrintDialog::printingDone() +{ + close(); +} +#endif + void PrintDialog::onPaintRequested(QPrinter*) { createPrinterObj(); diff --git a/desktop-widgets/printdialog.h b/desktop-widgets/printdialog.h index 7e98f22f6..d67560c5a 100644 --- a/desktop-widgets/printdialog.h +++ b/desktop-widgets/printdialog.h @@ -38,6 +38,13 @@ slots: void printClicked(); void onPaintRequested(QPrinter *); void createPrinterObj(); + +#ifdef USE_WEBENGINE +public +slots: + void printingDone(); +#endif }; + #endif #endif // PRINTDIALOG_H diff --git a/desktop-widgets/printerwebengine.cpp b/desktop-widgets/printerwebengine.cpp new file mode 100644 index 000000000..7f2d54fd8 --- /dev/null +++ b/desktop-widgets/printerwebengine.cpp @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "printerwebengine.h" +#include "mainwindow.h" +#include "templatelayout.h" +#include "core/statistics.h" +#include "core/qthelper.h" +#include "core/settings/qPrefDisplay.h" +#include "profile-widget/profilewidget2.h" + +#include +#include +#include +#include + +extern void exportProfile(const struct dive *dive, const QString filename); + +Printer::Printer(QPaintDevice *paintDevice, const print_options &printOptions, const template_options &templateOptions, PrintMode printMode, bool inPlanner) : + webView(new QWebEngineView), + paintDevice(paintDevice), + printOptions(printOptions), + templateOptions(templateOptions), + printMode(printMode), + inPlanner(inPlanner), + done(0) +{ + connect(webView, &QWebEngineView::loadFinished, this, &Printer::onLoadFinished); + connect(this, &Printer::profilesInserted, this, &Printer::printing); + profilesMissing = true; +} + +Printer::~Printer() +{ + delete webView; +} + +void Printer::onLoadFinished() +{ + if (profilesMissing) { + webView->page()->runJavaScript(" var profiles = document.getElementsByClassName(\"diveProfile\");\ + for (let profile of profiles) { \ + var id = profile.attributes.getNamedItem(\"Id\").value; \ + var img = document.createElement(\"img\"); \ + img.src = id + \".png\"; \ + img.style.height = \"100%\"; \ + img.style.width = \"100%\"; \ + profile.appendChild(img); \ + } \ + ", [this](const QVariant &v) { emit profilesInserted(); }); + + } + profilesMissing = false; + emit(progessUpdated(100)); +} + +void Printer::printing() +{ + QPrintDialog printDialog(&printer, (QWidget *) nullptr); + if (printDialog.exec() == QDialog::Accepted) { + webView->page()->print(&printer, [this](bool ok){ if (ok) emit jobDone(); }); + } + printDialog.close(); +} + +//value: ranges from 0 : 100 and shows the progress of the templating engine +void Printer::templateProgessUpdated(int value) +{ + done = value / 5; //template progess if 1/5 of total work + emit progessUpdated(done); +} + +QString Printer::exportHtml() +{ + // Does anybody actually use this? It will not contian profile images!!! + TemplateLayout t(printOptions, templateOptions); + connect(&t, SIGNAL(progressUpdated(int)), this, SLOT(templateProgessUpdated(int))); + QString html; + + if (printOptions.type == print_options::DIVELIST) + html = t.generate(inPlanner); + else if (printOptions.type == print_options::STATISTICS ) + html = t.generateStatistics(); + + // TODO: write html to file + return html; +} + +void Printer::print() +{ + // we can only print if "PRINT" mode is selected + if (printMode != Printer::PRINT) { + return; + } + int i; + struct dive *dive; + QString fn; + int dives_to_print = 0; + for_each_dive(i, dive) + if (dive->selected || !printOptions.print_selected) + ++dives_to_print; + + for_each_dive (i, dive) { + //TODO check for exporting selected dives only + if (!dive->selected && printOptions.print_selected) + continue; + exportProfile(dive, printDir.filePath(QString("dive_%1.png").arg(dive->id))); + emit(progessUpdated(done + lrint(i * 80.0 / dives_to_print))); + } + + TemplateLayout t(printOptions, templateOptions); + connect(&t, SIGNAL(progressUpdated(int)), this, SLOT(templateProgessUpdated(int))); + int dpi = printer.resolution(); + webView->page()->settings()->setAttribute(QWebEngineSettings::LocalContentCanAccessFileUrls, true); + connect(webView, &QWebEngineView::loadFinished, this, &Printer::onLoadFinished); + + if (printOptions.type == print_options::DIVELIST) { + QFile printFile(printDir.filePath("print.html")); + printFile.open(QIODevice::WriteOnly | QIODevice::Text); + QTextStream out(&printFile); + out << t.generate(inPlanner); + printFile.close(); + webView->load(QUrl::fromLocalFile(printDir.filePath("print.html"))); + } else if (printOptions.type == print_options::STATISTICS ) + webView->setHtml(t.generateStatistics()); + if (printOptions.color_selected && printer.colorMode()) + printer.setColorMode(QPrinter::Color); + else + printer.setColorMode(QPrinter::GrayScale); + printer.setResolution(dpi); +} + +void Printer::previewOnePage() +{ + if (printMode == PREVIEW) { + TemplateLayout t(printOptions, templateOptions); + + pageSize.setHeight(paintDevice->height()); + pageSize.setWidth(paintDevice->width()); + // initialize the border settings + // templateOptions.border_width = std::max(1, pageSize.width() / 1000); + if (printOptions.type == print_options::DIVELIST) + webView->setHtml(t.generate(inPlanner)); + else if (printOptions.type == print_options::STATISTICS ) + webView->setHtml(t.generateStatistics()); + } +} diff --git a/desktop-widgets/printerwebengine.h b/desktop-widgets/printerwebengine.h new file mode 100644 index 000000000..b159a020e --- /dev/null +++ b/desktop-widgets/printerwebengine.h @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0 +#ifndef PRINTER_H +#define PRINTER_H + +#include "printoptions.h" +#include "templateedit.h" +#include +#include + +class ProfileWidget2; +class QPainter; +class QPaintDevice; +class QRect; +class QWebEngineView; + + +class Printer : public QObject { + Q_OBJECT + +public: + QWebEngineView *webView; + enum PrintMode { + PRINT, + PREVIEW + }; + +private: + QPaintDevice *paintDevice; + QPrinter printer; + QTemporaryDir printDir; + const print_options &printOptions; + const template_options &templateOptions; + QSize pageSize; + PrintMode printMode; + bool inPlanner; + int done; + void onLoadFinished(); + bool profilesMissing; + +private slots: + void templateProgessUpdated(int value); + void printing(); + +public: + Printer(QPaintDevice *paintDevice, const print_options &printOptions, const template_options &templateOptions, PrintMode printMode, bool inPlanner); + ~Printer(); + void print(); + void previewOnePage(); + QString exportHtml(); + +signals: + void progessUpdated(int value); + void profilesInserted(); + void jobDone(); +}; + +#endif //PRINTER_H diff --git a/desktop-widgets/usermanual.cpp b/desktop-widgets/usermanual.cpp index a693cef2d..ea5f5912c 100644 --- a/desktop-widgets/usermanual.cpp +++ b/desktop-widgets/usermanual.cpp @@ -35,6 +35,26 @@ void SearchBar::enableButtons(const QString &s) ui.findNext->setEnabled(s.length()); } +#ifdef USE_WEBENGINE +MyQWebEnginePage::MyQWebEnginePage(QObject* parent) : QWebEnginePage(parent) +{ +} + +bool MyQWebEnginePage::acceptNavigationRequest(const QUrl & url, QWebEnginePage::NavigationType type, bool) +{ + if (type == QWebEnginePage::NavigationTypeLinkClicked) + { + QDesktopServices::openUrl(url); + return false; + } + return true; +} + +MyQWebEngineView::MyQWebEngineView(QWidget* parent) +{ +} +#endif + UserManual::UserManual(QWidget *parent) : QDialog(parent) { QShortcut *closeKey = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_W), this); @@ -55,12 +75,19 @@ UserManual::UserManual(QWidget *parent) : QDialog(parent) setWindowTitle(tr("User manual")); setWindowIcon(QIcon(":subsurface-icon")); +#ifdef USE_WEBENGINE + userManual = new MyQWebEngineView(this); + MyQWebEnginePage *page = new MyQWebEnginePage(); + userManual->setPage(page); +#else userManual = new QWebView(this); + userManual->page()->setLinkDelegationPolicy(QWebPage::DelegateExternalLinks); +#endif + QString colorBack = palette().highlight().color().name(QColor::HexRgb); QString colorText = palette().highlightedText().color().name(QColor::HexRgb); userManual->setStyleSheet(QString("QWebView { selection-background-color: %1; selection-color: %2; }") .arg(colorBack).arg(colorText)); - userManual->page()->setLinkDelegationPolicy(QWebPage::DelegateExternalLinks); QString searchPath = getSubsurfaceDataPath("Documentation"); if (searchPath.size()) { // look for localized versions of the manual first @@ -85,7 +112,10 @@ UserManual::UserManual(QWidget *parent) : QDialog(parent) searchBar->hide(); connect(actionShowSearch, SIGNAL(triggered(bool)), searchBar, SLOT(show())); connect(actionHideSearch, SIGNAL(triggered(bool)), searchBar, SLOT(hide())); +#ifndef USE_WEBENGINE connect(userManual, SIGNAL(linkClicked(QUrl)), this, SLOT(linkClickedSlot(QUrl))); +#endif + connect(searchBar, SIGNAL(searchTextChanged(QString)), this, SLOT(searchTextChanged(QString))); connect(searchBar, SIGNAL(searchNext()), this, SLOT(searchNext())); connect(searchBar, SIGNAL(searchPrev()), this, SLOT(searchPrev())); @@ -97,6 +127,14 @@ UserManual::UserManual(QWidget *parent) : QDialog(parent) setLayout(vboxLayout); } +#ifdef USE_WEBENGINE +void UserManual::search(QString text, QWebEnginePage::FindFlags flags = QFlag(0)) +{ + userManual->findText(text, flags, + [this, text](bool found) {searchBar->setStyleSheet(found || text.length() == 0 ? "" : "QLineEdit{background: red;}");}); +} + +#else void UserManual::search(QString text, QWebPage::FindFlags flags = QFlag(0)) { if (userManual->findText(text, QWebPage::FindWrapsAroundDocument | flags) || text.length() == 0) { @@ -105,6 +143,7 @@ void UserManual::search(QString text, QWebPage::FindFlags flags = QFlag(0)) searchBar->setStyleSheet("QLineEdit{background: red;}"); } } +#endif void UserManual::searchTextChanged(const QString& text) { @@ -119,13 +158,21 @@ void UserManual::searchNext() void UserManual::searchPrev() { +#ifdef USE_WEBENGINE + search(mLastText, QWebEnginePage::FindBackward); +#else search(mLastText, QWebPage::FindBackward); +#endif } + +#ifndef USE_WEBENGINE void UserManual::linkClickedSlot(const QUrl& url) { QDesktopServices::openUrl(url); } +#endif + #ifdef Q_OS_MAC void UserManual::showEvent(QShowEvent *e) diff --git a/desktop-widgets/usermanual.h b/desktop-widgets/usermanual.h index bb019f25b..9395ab316 100644 --- a/desktop-widgets/usermanual.h +++ b/desktop-widgets/usermanual.h @@ -2,7 +2,13 @@ #ifndef USERMANUAL_H #define USERMANUAL_H +#ifdef USE_WEBENGINE +#include +#include +#else #include +#endif + #include #include "ui_searchbar.h" @@ -22,6 +28,26 @@ private: Ui::SearchBar ui; }; +#ifdef USE_WEBENGINE +class MyQWebEnginePage : public QWebEnginePage +{ + Q_OBJECT + +public: + MyQWebEnginePage(QObject* parent = 0); + bool acceptNavigationRequest(const QUrl & url, QWebEnginePage::NavigationType type, bool); +}; + +class MyQWebEngineView : public QWebEngineView +{ + Q_OBJECT + +public: + MyQWebEngineView(QWidget* parent = 0); + MyQWebEnginePage* page() const; +}; +#endif + class UserManual : public QDialog { Q_OBJECT @@ -41,11 +67,19 @@ slots: void searchTextChanged(const QString& s); void searchNext(); void searchPrev(); +#ifndef USE_WEBENGINE void linkClickedSlot(const QUrl& url); +#endif private: SearchBar *searchBar; QString mLastText; +#ifdef USE_WEBENGINE + QWebEngineView *userManual; + void search(QString, QWebEnginePage::FindFlags); +#else QWebView *userManual; void search(QString, QWebPage::FindFlags); +#endif }; + #endif // USERMANUAL_H diff --git a/scripts/smtk2ssrf-build.sh b/scripts/smtk2ssrf-build.sh index 7ab5799ba..1fb9b20f2 100755 --- a/scripts/smtk2ssrf-build.sh +++ b/scripts/smtk2ssrf-build.sh @@ -146,6 +146,7 @@ cmake -DBTSUPPORT=OFF \ -DMAKE_TESTS=OFF \ -DNO_DOCS=ON \ -DNO_PRINTING=ON \ + -DUSE_WEBENGINE=OFF \ -DNO_USERMANUAL=ON \ -DSUBSURFACE_TARGET_EXECUTABLE=DesktopExecutable \ build