Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 56 additions & 3 deletions desktop-widgets/printer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#include "core/selection.h"
#include "core/statistics.h"
#include "core/qthelper.h"
#include "core/errorhelper.h"
#include "core/xmlparams.h"
#include "profile-widget/profilescene.h"

#include <algorithm>
Expand All @@ -19,6 +21,9 @@
# include <QUrl>
# include <QFile>
# include <qlitehtmlwidget.h>
# include <libxml/HTMLparser.h>
# include <libxslt/transform.h>
# include <libxslt/xsltutils.h>
#else
#include <QtWebKitWidgets>
#include <QWebElementCollection>
Expand Down Expand Up @@ -294,6 +299,57 @@ void Printer::previewOnePage()
#ifdef USE_QLITEHTML
void Printer::Preview(QString content, QPrinter *printer)
{
// Replace dive profile placeholders via XSLT so the transformation is resilient to HTML formatting changes.
auto applyProfileXslt = [](const QString &html, const QString &profileDir) -> QString {
const QByteArray htmlUtf8 = html.toUtf8();
htmlDocPtr doc = htmlReadMemory(htmlUtf8.constData(), htmlUtf8.size(), "preview.html", nullptr,
HTML_PARSE_RECOVER | HTML_PARSE_NODEFDTD | HTML_PARSE_NOERROR | HTML_PARSE_NOWARNING | HTML_PARSE_NONET);
if (!doc) {
report_error("Failed to parse HTML for profile injection");
return html;
}

xsltStylesheetPtr xslt = get_stylesheet("inject-profiles.xslt");
if (!xslt) {
report_error("Failed to load inject-profiles.xslt stylesheet");
xmlFreeDoc(doc);
return html;
}

struct xml_params *params = alloc_xml_params();
// XSLT parameters need to be XPath expressions, so wrap string values in single quotes
QByteArray quotedDir = QString("'%1'").arg(profileDir).toUtf8();
xml_params_add(params, "profile-dir", quotedDir.constData());
xml_params_add(params, "img-height", "'30%'");
xml_params_add(params, "img-width", "'30%'");

xmlDocPtr transformed = xsltApplyStylesheet(xslt, doc, xml_params_get(params));
free_xml_params(params);
xmlFreeDoc(doc);
if (!transformed) {
report_error("Failed to apply profile injection transformation");
xsltFreeStylesheet(xslt);
return html;
}

xmlChar *out = nullptr;
int outLen = 0;
if (xsltSaveResultToString(&out, &outLen, transformed, xslt) != 0 || !out) {
report_error("Failed to serialize transformed HTML");
xmlFreeDoc(transformed);
xsltFreeStylesheet(xslt);
return html;
}

QString result = QString::fromUtf8(reinterpret_cast<char *>(out), outLen);
xmlFree(out);
xmlFreeDoc(transformed);
xsltFreeStylesheet(xslt);
return result;
};

content = applyProfileXslt(content, printDir.path());

QDialog previewer;

previewer.setWindowTitle(tr("Print Preview"));
Expand Down Expand Up @@ -329,9 +385,6 @@ void Printer::Preview(QString content, QPrinter *printer)
// QTextStream in(&file);
// previewWidget.setHtml(in.readAll());

QString repl = QString("<img height=\"30%\" width=\"30%\" src=\"file:///%1/dive_\\1.png\">").arg(printDir.path());
content.replace(QRegularExpression("<div\\s+class=\"diveProfile\"\\s+id=\"dive_([^\"]*)\"\\s*>\\s*</div>"), repl);

previewWidget.setUrl(QUrl("file:///", QUrl::TolerantMode));
previewWidget.setHtml(content);
previewWidget.print(printer);
Expand Down
2 changes: 1 addition & 1 deletion scripts/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,7 @@ for (( i=0 ; i < ${#BUILDS[@]} ; i++ )) ; do
BUILDDIR=${BUILDDIRS[$i]}
echo "build $SUBSURFACE_EXECUTABLE in $BUILDDIR"

if [ "$SUBSURFACE_EXECUTABLE" = "DesktopExecutable" ] && [ "$BUILD_WITH_WEBKIT" = "1" ]; then
if [ "$SUBSURFACE_EXECUTABLE" = "DesktopExecutable" ]; then
EXTRA_OPTS="-DNO_PRINTING=OFF"
else
EXTRA_OPTS="-DNO_PRINTING=ON"
Expand Down
1 change: 1 addition & 0 deletions subsurface.qrc
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
<file>xslt/shearwater.xslt</file>
<file>xslt/DiveLog.xslt</file>
<file>xslt/av1.xslt</file>
<file>xslt/inject-profiles.xslt</file>
<file alias="rate-sac-icon">icons/gas.png</file>
<file alias="depth-mod-icon">icons/mod.png</file>
<file alias="pp-he-icon">icons/he.png</file>
Expand Down
22 changes: 22 additions & 0 deletions xslt/inject-profiles.xslt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="profile-dir"/>
<xsl:param name="img-height">30%</xsl:param>
<xsl:param name="img-width">30%</xsl:param>

<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>

<xsl:template match="div[@class='diveProfile' and starts-with(@id,'dive_')]">
<img>
<xsl:attribute name="height"><xsl:value-of select="$img-height"/></xsl:attribute>
<xsl:attribute name="width"><xsl:value-of select="$img-width"/></xsl:attribute>
<xsl:attribute name="src">
<xsl:value-of select="concat('file:///', $profile-dir, '/dive_', substring-after(@id,'dive_'), '.png')"/>
</xsl:attribute>
</img>
</xsl:template>
</xsl:stylesheet>