Compare commits

...

10 Commits

Author SHA1 Message Date
Dirk Hohndel
a0057c06fb printing: convert to two stage approach
The double connect to onLoadFinished clearly was incorrect, but even with
that removed we still seemed to call the printer before the modified page
finished loading.

Moving the profilesMissing = false setting into the callback also seems
obviously correct, but also wasn't enough to make this work.

So in the end I went the brute force route.
We run the Javascript code to insert the profile images (which is done
in JS to stay compatible with existing templates - yes, this could be
reimplemented differently using Qt primitives - but that would result in
parsing HTML code and that really is what WebEngine is for and the JS
code is known to work...).
And then we write the new HTML out to a file and load that file.
And once THAT file finishes loading (now with all the profiles - if
there were any in the template in the first place), send that to be
printed.

This seems convoluted and silly - but I simply couldn't get a single
step flow to work on openSUSE (which is where this was tested and
implemented).

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2021-11-28 17:43:27 -08:00
Dirk Hohndel
e5915ca4f2 printing: add more debug output
This makes it easier to see what's going on during the printing process.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2021-11-28 17:43:27 -08:00
Dirk Hohndel
47f52cd4d1 printing: use file:// paths for profile images
At least on openSUSE the profile images are otherwise not found.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2021-11-28 17:29:04 -08:00
Dirk Hohndel
38bfb3de16 macOS: correctly bundle QtWebEngineProcess.app
Once again macdeployqt doesn't get things right for us. It doesn't actually
copy this required helper into the bundle. Oh well, more manual magic.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2021-11-26 13:27:23 -08:00
Dirk Hohndel
528559334f build-system: allow building with WebEngine but not WebKit
This appears to be required on openSUSE Tumbleweed where QtWebKit has
disappeared, but QtWebEngine is available.

I'm not sure how to deal with the seemingly independent NO_USERMANUAL and
NO_PRINTING... this solution adds WebEngine if either of those is set.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2021-11-26 12:35:39 -08:00
Dirk Hohndel
042addc30a build-system: test Linux builds against WebEngine
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2021-11-26 12:35:39 -08:00
Dirk Hohndel
f620a2c09d build-system: enable builds against WebEngine in build.sh
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2021-11-26 12:35:39 -08:00
Robert C. Helling
9aced3f49a desktop: don't close edit dialog when save is cancelled
In the edit dialog, when OK is pressed, anotehr modal dialog opens and asks if
the template should be saved.  If the answer is negative, return to the edit
dialog rather than closing it abandoning the changes.

To abandon the changes, there is still the cancel buttton of the edit dialog.

Signed-off-by: Robert C. Helling <helling@atdotde.de>
2021-11-26 12:35:39 -08:00
Robert C. Helling
9583173425 desktop: implement template previewing for WebEngine
This allows the template editor to preview in a QWebEngineView. It also
improves the logic of the buttons (Apply updates the preview but does not force
a save first).

Signed-off-by: Robert C. Helling <helling@atdotde.de>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2021-11-26 12:35:34 -08:00
Robert C. Helling
e7977ee280 desktop: re-add WebEngine support
This reverts commit 643f4a5726 and finishes the task of adding WebEngine as an
alternate backend to be used in printing.

The ultimate goal is to be able to build without QtWebKit (as that is no longer
supported in Qt6). WebKit was used in two places: The user manual and printing.
This patch makes printing work with WebEngine.

The main obstacle is that WebEngine no longer allows accessing HTML elements
from C++ code and rendering the page to a QPainter.

The old version used this to figure out dimensions and page breaks for the
pages and then in the QPainter placed the profile images. With WebEninge, you
need to access the elements using JavaScript which is now used to place the
profile in the html proplerly as an <img> tag. To this end, both html and
profile images are written to a temporary directory on disk.

This image replacement by JavaScript is only necessary to make old templates
still work. It could be replaced by actually putting <img> tags in the
templates (but this would break user edited templates).

In my experiments, the page breaking was done great by html/css, so the
additional magic seems superflous.

What remains to be done:
* remove empty page at the end of printout
* make preview great again (in particlar needed for template editing)

Note: since QtWebEngine currently cannot be built with our toolchain on
Windows, this patch keeps QtWebKit support around by making the QtWebEngine
compile-time conditional via #ifdefs.

[Dirk Hohndel: merged a few commits to make this more logical - the resulting
commit is fairly big, but IMHO preferrable]

Signed-off-by: Robert C. Helling <helling@atdotde.de>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2021-11-26 12:32:10 -08:00
21 changed files with 473 additions and 39 deletions

View File

@ -29,12 +29,13 @@ jobs:
qml-module-qtquick2 qt5-default qt5-qmake qtchooser qtconnectivity5-dev \
qtdeclarative5-dev qtdeclarative5-private-dev qtlocation5-dev \
qtpositioning5-dev qtscript5-dev qttools5-dev qttools5-dev-tools \
qtwebengine5-dev \
qtquickcontrols2-5-dev xvfb libbluetooth-dev libmtp-dev
- name: build Subsurface
run: |
cd ..
bash -x subsurface/scripts/build.sh -desktop -build-with-webkit
bash -x subsurface/scripts/build.sh -desktop -build-with-webkit -print-with-webengine
- name: test desktop build
run: |

View File

@ -33,6 +33,7 @@ jobs:
qml-module-qtquick2 qt5-qmake qtchooser qtconnectivity5-dev \
qtdeclarative5-dev qtdeclarative5-private-dev qtlocation5-dev \
qtpositioning5-dev qtscript5-dev qttools5-dev qttools5-dev-tools \
qtwebengine5-dev \
qtquickcontrols2-5-dev xvfb libbluetooth-dev libmtp-dev
- name: build Subsurface-mobile
@ -60,7 +61,7 @@ jobs:
# now build for the desktop version (including WebKit)
cd ..
bash -e -x subsurface/scripts/build.sh -desktop -build-with-webkit
bash -e -x subsurface/scripts/build.sh -desktop -build-with-webkit -print-with-webengine
- name: test desktop build
run: |

View File

@ -33,6 +33,7 @@ jobs:
qml-module-qtquick2 qt5-qmake qtchooser qtconnectivity5-dev \
qtdeclarative5-dev qtdeclarative5-private-dev qtlocation5-dev \
qtpositioning5-dev qtscript5-dev qttools5-dev qttools5-dev-tools \
qtwebengine5-dev \
qtquickcontrols2-5-dev xvfb libbluetooth-dev libmtp-dev
- name: build Subsurface-mobile
@ -60,7 +61,7 @@ jobs:
# now build for the desktop version (including WebKit)
cd ..
bash -e -x subsurface/scripts/build.sh -desktop -build-with-webkit
bash -e -x subsurface/scripts/build.sh -desktop -build-with-webkit -print-with-webengine
- name: test desktop build
run: |

View File

@ -33,6 +33,7 @@ jobs:
qml-module-qtquick2 qt5-qmake qtchooser qtconnectivity5-dev \
qtdeclarative5-dev qtdeclarative5-private-dev qtlocation5-dev \
qtpositioning5-dev qtscript5-dev qttools5-dev qttools5-dev-tools \
qtwebengine5-dev \
qtquickcontrols2-5-dev xvfb libbluetooth-dev libmtp-dev
- name: build Subsurface-mobile
@ -60,7 +61,7 @@ jobs:
# now build for the desktop version (including WebKit)
cd ..
bash -e -x subsurface/scripts/build.sh -desktop -build-with-webkit
bash -e -x subsurface/scripts/build.sh -desktop -build-with-webkit -print-with-webengine
- name: test desktop build
run: |

View File

@ -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)
@ -189,9 +190,13 @@ if (SUBSURFACE_TARGET_EXECUTABLE MATCHES "DesktopExecutable")
add_definitions(-DNO_PRINTING)
else()
LIST(APPEND QT_EXTRA_COMPONENTS PrintSupport)
# Because Qt5WebKitWidgets isn't a part of the "regular" Qt5, we can't get it the normal way
find_package(Qt5WebKitWidgets REQUIRED)
set(SUBSURFACE_LINK_LIBRARIES ${SUBSURFACE_LINK_LIBRARIES} Qt5::WebKitWidgets)
if(USE_WEBENGINE)
LIST(APPEND QT_EXTRA_COMPONENTS WebEngine)
else()
# Because Qt5WebKitWidgets isn't a part of the "regular" Qt5, we can't get it the normal way
find_package(Qt5WebKitWidgets REQUIRED)
set(SUBSURFACE_LINK_LIBRARIES ${SUBSURFACE_LINK_LIBRARIES} Qt5::WebKitWidgets)
endif()
endif()
elseif (SUBSURFACE_TARGET_EXECUTABLE MATCHES "MobileExecutable")
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
@ -531,6 +536,11 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
install(CODE "execute_process(COMMAND cp -a ${_qt5Core_install_prefix}/qml/QtQml ${CMAKE_BINARY_DIR}/${APP_BUNDLE_DIR}/Contents/Resources/qml)")
install(CODE "execute_process(COMMAND cp -a ${_qt5Core_install_prefix}/qml/QtPositioning ${CMAKE_BINARY_DIR}/${APP_BUNDLE_DIR}/Contents/Resources/qml)")
endif()
# if we build with WebEngine we need to copy the helper which macdeployqt appears to get wrong as well
if(USE_WEBENGINE)
install(CODE "execute_process(COMMAND mkdir -p ${CMAKE_BINARY_DIR}/${APP_BUNDLE_DIR}/Contents/Frameworks/QtWebEngineCore.framework/Helpers)")
install(CODE "execute_process(COMMAND cp -a ${_qt5Core_install_prefix}/lib/QtWebEngineCore.framework/Helpers/QtWebEngineProcess.app ${CMAKE_BINARY_DIR}/${APP_BUNDLE_DIR}/Contents/Frameworks/QtWebEngineCore.framework/Helpers/)")
endif()
elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
if (CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
if(NOT DEFINED OBJCOPY)

View File

@ -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()

View File

@ -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

View File

@ -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 <QSettings>
#include <QMessageBox>
#include <QDialogButtonBox>
#ifdef USE_WEBENGINE
#include <QWebEngineView>
#endif
#define SETTINGS_GROUP "PrintDialog"
@ -110,8 +117,11 @@ PrintDialog::PrintDialog(bool inPlanner, QWidget *parent) :
QPushButton *printButton = new QPushButton(tr("P&rint"));
connect(printButton, SIGNAL(clicked(bool)), this, SLOT(printClicked()));
// To do: Port preview to WebEngine. For the time being: Use OS print preview
#ifndef USE_WEBENGINE
QPushButton *previewButton = new QPushButton(tr("&Preview"));
connect(previewButton, SIGNAL(clicked(bool)), this, SLOT(previewClicked()));
#endif
QPushButton *exportHtmlButton = new QPushButton(tr("Export Html"));
connect(exportHtmlButton, SIGNAL(clicked(bool)), this, SLOT(exportHtmlClicked()));
@ -119,7 +129,9 @@ PrintDialog::PrintDialog(bool inPlanner, QWidget *parent) :
QDialogButtonBox *buttonBox = new QDialogButtonBox;
buttonBox->addButton(QDialogButtonBox::Cancel);
buttonBox->addButton(printButton, QDialogButtonBox::AcceptRole);
#ifndef USE_WEBENGINE
buttonBox->addButton(previewButton, QDialogButtonBox::ActionRole);
#endif
buttonBox->addButton(exportHtmlButton, QDialogButtonBox::AcceptRole);
connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
@ -178,7 +190,7 @@ void PrintDialog::createPrinterObj()
qprinter = new QPrinter;
qprinter->setResolution(printOptions.resolution);
qprinter->setOrientation((QPrinter::Orientation)printOptions.landscape);
printer = new Printer(qprinter, printOptions, templateOptions, Printer::PRINT, inPlanner);
printer = new Printer(qprinter, printOptions, templateOptions, Printer::PRINT, inPlanner, nullptr);
}
}
@ -215,13 +227,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();

View File

@ -38,6 +38,13 @@ slots:
void printClicked();
void onPaintRequested(QPrinter *);
void createPrinterObj();
#ifdef USE_WEBENGINE
public
slots:
void printingDone();
#endif
};
#endif
#endif // PRINTDIALOG_H

View File

@ -14,7 +14,7 @@
#include <QWebElement>
#include "profile-widget/profilewidget2.h"
Printer::Printer(QPaintDevice *paintDevice, const print_options &printOptions, const template_options &templateOptions, PrintMode printMode, bool inPlanner) :
Printer::Printer(QPaintDevice *paintDevice, const print_options &printOptions, const template_options &templateOptions, PrintMode printMode, bool inPlanner, QWidget *parent = nullptr) :
paintDevice(paintDevice),
webView(new QWebView),
printOptions(printOptions),
@ -267,8 +267,6 @@ void Printer::previewOnePage()
pageSize.setHeight(paintDevice->height());
pageSize.setWidth(paintDevice->width());
webView->page()->setViewportSize(pageSize);
// 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 )

View File

@ -38,7 +38,7 @@ private slots:
void templateProgessUpdated(int value);
public:
Printer(QPaintDevice *paintDevice, const print_options &printOptions, const template_options &templateOptions, PrintMode printMode, bool inPlanner);
Printer(QPaintDevice *paintDevice, const print_options &printOptions, const template_options &templateOptions, PrintMode printMode, bool inPlanner, QWidget *parent);
~Printer();
void print();
void previewOnePage();

View File

@ -0,0 +1,193 @@
// 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 <algorithm>
#include <QPainter>
#include <QPrinter>
#include <QtWebEngineWidgets>
extern void exportProfile(const struct dive *dive, const QString filename);
Printer::Printer(QPaintDevice *paintDevice, print_options &printOptions, template_options &templateOptions, PrintMode printMode, bool inPlanner, QWidget *parent = nullptr) :
paintDevice(paintDevice),
printOptions(printOptions),
templateOptions(templateOptions),
printMode(printMode),
inPlanner(inPlanner),
done(0)
{
webView = new QWebEngineView(parent);
connect(webView, &QWebEngineView::loadFinished, this, &Printer::onLoadFinished);
if (printMode == PRINT) {
connect(this, &Printer::profilesInserted, this, &Printer::reopen);
connect(this, &Printer::jobDone, this, &Printer::printFinished);
}
profilesMissing = true;
}
Printer::~Printer()
{
qDebug() << "deleting Printer object";
delete webView;
}
void Printer::onLoadFinished()
{
qDebug() << "onLoadFinished called with profilesMissing" << profilesMissing << "and URL" << webView->url().toString();
if (profilesMissing) {
QString jsText(" var profiles = document.getElementsByClassName(\"diveProfile\");\
for (let profile of profiles) { \
var id = profile.attributes.getNamedItem(\"Id\").value; \
var img = document.createElement(\"img\"); \
img.src = \"TMPPATH\" + id + \".png\"; \
img.style.height = \"100%\"; \
img.style.width = \"100%\"; \
profile.appendChild(img); \
} \
document.documentElement.innerHTML; \
");
QString filePath = QStringLiteral("file://") + printDir.path() + QDir::separator();
jsText.replace("TMPPATH", filePath);
webView->page()->runJavaScript(jsText, [this](const QVariant &v) {
qDebug() << "JS finished";
QFile fd(printDir.filePath("finalprint.html"));
fd.open(QIODevice::WriteOnly | QIODevice::Text);
QTextStream out(&fd);
out << v.toString();
fd.close();
qDebug() << "finalprint.html written";
profilesMissing = false;
emit(progessUpdated(80));
emit profilesInserted();
});
} else {
qDebug() << "load of" << webView->url().toString() << "finished - open printing dialog";
emit(progessUpdated(100));
printing();
}
}
// the Javascript code injecting the profiles has completed, let's reload that page
void Printer::reopen()
{
qDebug() << "opening the finalprint.html file";
webView->load(QUrl::fromLocalFile(printDir.filePath("finalprint.html")));
}
void Printer::printing()
{
QPrintDialog printDialog(&printer, (QWidget *) nullptr);
if (printDialog.exec() == QDialog::Accepted)
webView->page()->print(&printer, [this](bool ok){
if (ok)
emit jobDone();
qDebug() << "printing done with status " << ok ;
qDebug() << "content of" << printDir.path();
qDebug() << QDir(printDir.path()).entryList();
});
qDebug() << "closing the dialog now";
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::updateOptions(print_options &poptions, template_options &toptions)
{
templateOptions = toptions;
printOptions = poptions;
profilesMissing = true;
}
QString Printer::writeTmpTemplate(const QString templtext)
{
QFile fd(printDir.filePath("ssrftmptemplate.html"));
fd.open(QIODevice::WriteOnly | QIODevice::Text);
QTextStream out(&fd);
out << templtext;
fd.close();
return fd.fileName();
}
void Printer::print()
{
// we can only print if "PRINT" mode is selected
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)));
}
profilesMissing = true;
TemplateLayout t(printOptions, templateOptions);
connect(&t, SIGNAL(progressUpdated(int)), this, SLOT(templateProgessUpdated(int)));
int dpi = printer.resolution();
webView->page()->settings()->setAttribute(QWebEngineSettings::LocalContentCanAccessFileUrls, true);
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::printFinished()
{
qDebug() << "received the jobDone signal, closing the dialog; page should have referenced:";
webView->page()->toHtml([](const QString h){
QRegularExpression img("img src=([^ ]+) ");
QRegularExpressionMatchIterator iter = img.globalMatch(h);
while(iter.hasNext()) {
QRegularExpressionMatch match = iter.next();
QString filename = match.captured(1).replace("file://", "");
qDebug() << filename << (QFile(filename).exists() ? "which does" : "which doesn't") << "exist";
}
});
}

View File

@ -0,0 +1,62 @@
// SPDX-License-Identifier: GPL-2.0
#ifndef PRINTER_H
#define PRINTER_H
#include "printoptions.h"
#include <QPrinter>
#include <QTemporaryDir>
class ProfileWidget2;
class QPainter;
class QPaintDevice;
class QRect;
class QWebEngineView;
class Printer : public QObject {
Q_OBJECT
public:
enum PrintMode {
PRINT,
PREVIEW
};
QWebEngineView *webView;
private:
QPaintDevice *paintDevice;
QPrinter printer;
QTemporaryDir printDir;
print_options &printOptions;
template_options &templateOptions;
QSize pageSize;
PrintMode printMode;
bool inPlanner;
int done;
void onLoadFinished();
bool profilesMissing;
private slots:
void templateProgessUpdated(int value);
void printing();
void printFinished();
void reopen();
public:
Printer(QPaintDevice *paintDevice, print_options &printOptions, template_options &templateOptions, PrintMode printMode, bool inPlanner, QWidget *parent);
~Printer();
void print();
void previewOnePage();
QString writeTmpTemplate(const QString templtext);
QString exportHtml();
void updateOptions(print_options &poptions, template_options &toptions);
signals:
void progessUpdated(int value);
void profilesInserted();
void jobDone();
};
#endif //PRINTER_H

View File

@ -1,15 +1,22 @@
// SPDX-License-Identifier: GPL-2.0
#include "templateedit.h"
#include "templatelayout.h"
#ifdef USE_WEBENGINE
#include "printerwebengine.h"
#else
#include "printer.h"
#endif
#include "ui_templateedit.h"
#include <QMessageBox>
#include <QButtonGroup>
#include <QColorDialog>
#include <QDir>
#ifdef USE_WEBENGINE
#include <QWebEngineView>
#endif
TemplateEdit::TemplateEdit(QWidget *parent, const print_options &printOptions, template_options &templateOptions) :
TemplateEdit::TemplateEdit(QWidget *parent, print_options &printOptions, template_options &templateOptions) :
QDialog(parent),
ui(new Ui::TemplateEdit),
printOptions(printOptions),
@ -43,7 +50,20 @@ TemplateEdit::TemplateEdit(QWidget *parent, const print_options &printOptions, t
ui->plainTextEdit->setPlainText(grantlee_template);
editingCustomColors = false;
#ifdef USE_WEBENGINE
QWebEngineView *view;
preview = new Printer(nullptr, printOptions, newTemplateOptions, Printer::PREVIEW, false, this);
view = preview->webView;
int w = ui->label->width();
int h = ui->label->height();
view->resize(w, h);
preview->print();
view->setZoomFactor(0.25);
view->show();
ui->verticalLayout_3->replaceWidget(ui->label, view);
#else
updatePreview();
#endif
}
TemplateEdit::~TemplateEdit()
@ -54,14 +74,16 @@ TemplateEdit::~TemplateEdit()
void TemplateEdit::updatePreview()
{
#ifndef USE_WEBENGINE
// update Qpixmap preview
int width = ui->label->width();
int height = ui->label->height();
QPixmap map(width * 2, height * 2);
map.fill(QColor::fromRgb(255, 255, 255));
Printer printer(&map, printOptions, newTemplateOptions, Printer::PREVIEW, false);
Printer printer(&map, printOptions, newTemplateOptions, Printer::PREVIEW, false, nullptr);
printer.previewOnePage();
ui->label->setPixmap(map.scaled(width, height, Qt::IgnoreAspectRatio));
#endif
// update colors tab
ui->colorLable1->setStyleSheet("QLabel { background-color : \"" + newTemplateOptions.color_palette.color1.name() + "\";}");
@ -158,6 +180,7 @@ void TemplateEdit::saveSettings()
}
if (templateOptions.color_palette_index == CUSTOM)
custom_colors = templateOptions.color_palette;
emit accept();
}
}
}
@ -165,6 +188,7 @@ void TemplateEdit::saveSettings()
void TemplateEdit::on_buttonBox_clicked(QAbstractButton *button)
{
QDialogButtonBox::StandardButton standardButton = ui->buttonBox->standardButton(button);
QString template_file = printOptions.p_template;
switch (standardButton) {
case QDialogButtonBox::Ok:
saveSettings();
@ -172,7 +196,14 @@ void TemplateEdit::on_buttonBox_clicked(QAbstractButton *button)
case QDialogButtonBox::Cancel:
break;
case QDialogButtonBox::Apply:
#ifdef USE_WEBENGINE
printOptions.p_template = preview->writeTmpTemplate(ui->plainTextEdit->toPlainText());
preview->updateOptions(printOptions, templateOptions);
preview->print();
printOptions.p_template = template_file;
#else
saveSettings();
#endif
updatePreview();
break;
default:

View File

@ -4,6 +4,9 @@
#include <QDialog>
#include "printoptions.h"
#ifdef USE_WEBENGINE
#include "printerwebengine.h"
#endif
namespace Ui {
class TemplateEdit;
@ -14,7 +17,7 @@ class TemplateEdit : public QDialog
Q_OBJECT
public:
explicit TemplateEdit(QWidget *parent, const print_options &printOptions, template_options &templateOptions);
explicit TemplateEdit(QWidget *parent, print_options &printOptions, template_options &templateOptions);
~TemplateEdit();
private slots:
void on_fontsize_valueChanged(int font_size);
@ -29,13 +32,15 @@ private:
Ui::TemplateEdit *ui;
QButtonGroup *btnGroup;
bool editingCustomColors;
const print_options &printOptions;
print_options &printOptions;
template_options &templateOptions;
struct template_options newTemplateOptions;
QString grantlee_template;
void saveSettings();
void updatePreview();
#ifdef USE_WEBENGINE
Printer *preview;
#endif
};
#endif // TEMPLATEEDIT_H

View File

@ -571,22 +571,6 @@
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>TemplateEdit</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>

View File

@ -152,7 +152,13 @@ QString TemplateLayout::generateStatistics()
QString TemplateLayout::readTemplate(QString template_name)
{
QFile qfile(getPrintingTemplatePathUser() + QDir::separator() + template_name);
QString filename;
// are we using a temporary file while editing?
if (template_name.contains("ssrftmptemplate.html"))
filename = template_name;
else
filename = getPrintingTemplatePathUser() + QDir::separator() + template_name;
QFile qfile(filename);
if (qfile.open(QFile::ReadOnly | QFile::Text)) {
QTextStream in(&qfile);
return in.readAll();

View File

@ -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)

View File

@ -2,7 +2,13 @@
#ifndef USERMANUAL_H
#define USERMANUAL_H
#ifdef USE_WEBENGINE
#include <QWebEngineView>
#include <QWebEnginePage>
#else
#include <QWebView>
#endif
#include <QDialog>
#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

View File

@ -84,6 +84,12 @@ while [[ $# -gt 0 ]] ; do
shift
BUILD_PREFIX="$1"
;;
-print-with-webengine)
# WebKit is no longer supported in Qt 6
# WebEngine doesn't build with our tools on Windows
# so allow to switch printing between the two flavors
BUILD_WITH_WEBENGINE="1"
;;
-build-with-webkit)
# unless you build Qt from source (or at least webkit from source, you won't have webkit installed
# -build-with-webkit tells the script that in fact we can assume that webkit is present (it usually
@ -126,7 +132,7 @@ while [[ $# -gt 0 ]] ; do
;;
*)
echo "Unknown command line argument $arg"
echo "Usage: build.sh [-no-bt] [-quick] [-build-deps] [-src-dir <SUBSURFACE directory>] [-build-prefix <PREFIX>] [-build-with-webkit] [-mobile] [-desktop] [-downloader] [-both] [-all] [-create-appdir] [-release]"
echo "Usage: build.sh [-no-bt] [-quick] [-build-deps] [-src-dir <SUBSURFACE directory>] [-build-prefix <PREFIX>] [-print-with-webengine] [-build-with-webkit] [-mobile] [-desktop] [-downloader] [-both] [-all] [-create-appdir] [-release]"
exit 1
;;
esac
@ -540,6 +546,11 @@ for (( i=0 ; i < ${#BUILDS[@]} ; i++ )) ; do
else
EXTRA_OPTS="-DNO_USERMANUAL=ON -DNO_PRINTING=ON"
fi
if [ "$SUBSURFACE_EXECUTABLE" = "DesktopExecutable" ] && [ "$BUILD_WITH_WEBENGINE" = "1" ]; then
# if we build with QtWebKit as well then this is a bit redundant, but at least
# it's not wrong
EXTRA_OPTS="-DNO_USERMANUAL=OFF -DNO_PRINTING=OFF -DUSE_WEBENGINE=ON"
fi
cd "$SRC"/${SRC_DIR}

View File

@ -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