Hello all,

As we are approaching gsoc community bonding period so I thought that a
small prototype may be the best way to discuss my thoughts with the
community.
I sent a group of patches with a very small but full working prototype.

- I added Grantlee library to subsurface code base (thanks for the cmake
build environment it made my life much easier as I don't know qmake at all)
- I create a simple Grantlee template that prints two dives per page.
- the TemplateLayout class iterates the selected dives and interface with
Grantlee backend.
- QWebview and QPainter are used to render the html file living in a
QTemporaryFile object.
- finally I added the "print using templates" option in the print dialog.

Note: I tested this on Linux only, so there may be problems on other
platforms.
also many exceptions still need to be handled this is only a fast prototype
for discussion.

So you may test this and tell me what do you think?

-- 
regards,
Gehad
From d274d487dd500d50788517fd42787937c18398cd Mon Sep 17 00:00:00 2001
From: Gehad elrobey <[email protected]>
Date: Wed, 15 Apr 2015 21:00:19 +0200
Subject: [PATCH 1/9] Create two dives per page grantlee template

Signed-off-by: Gehad elrobey <[email protected]>
---
 printing_templates/base.html | 86 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 86 insertions(+)
 create mode 100644 printing_templates/base.html

diff --git a/printing_templates/base.html b/printing_templates/base.html
new file mode 100644
index 0000000..b38cb19
--- /dev/null
+++ b/printing_templates/base.html
@@ -0,0 +1,86 @@
+<html>
+<head>
+<style>
+body {
+    background-color:white;
+    padding:0px;
+    margin:0px;
+}
+
+h1 {
+    font-size: 0.9cm;
+    float:left;
+}
+
+.class1{
+	width:96%;
+	height:50%;
+	margin-left:2%;
+	margin-right:2%;
+	margin-top:0;
+	margin-bottom:0;
+	overflow:hidden;
+	border-width:0px;
+	page-break-inside: avoid;
+}
+
+.table_class{
+	overflow:hidden;
+	max-width:44%;
+	min-width:44%;
+	box-shadow: 5px 5px 5px #888888;
+}
+
+.g{
+	background-color:#CfC7C5;
+	overflow:hidden;
+}
+
+</style>
+</head>
+
+<body>
+{% block main_rows %}
+  {% for dive in dives %}
+		<div class="class1">
+			<div style="height:85%;border-style:solid;padding:0.5%;margin-top:1%;margin-bottom:1%;overflow: hidden;">
+				<div style="width:52%;float:left;">
+					<table class="table_class" border="1" style="margin:1.5%;float:left;">
+						<tr>
+							<td class="g"><h1> Dive No. </h1></td><td><h1> {{ dive.number }} </h1></td>
+						</tr>
+						<tr>
+							<td class="g"><h1> Date </h1></td><td><h1> {{ dive.date }} </h1></td>
+						</tr>
+						<tr>
+							<td class="g"><h1> Location </h1></td><td><h1>{{ dive.location }}</h1></td>
+						</tr>
+						<tr>
+							<td class="g"><h1> Max depth </h1></td><td><h1> {{ dive.depth }} </h1></td>
+						</tr>
+						<tr>
+							<td class="g"><h1> Duration </h1></td><td><h1> {{ dive.duration }} </h1></td>
+						</tr>
+						<tr>
+							<td class="g"><h1> Dive Master </h1></td><td><h1>{{ dive.divemaster }}</h1></td>
+						</tr>
+					</table>
+					<table class="table_class" border="1" style="margin:1.5%;width:47%;float:left;">
+						<tr>
+							<td class="g"><h1> Notes </h1></td>
+						</tr>
+						<tr>
+							<td><h1>-</h1></td>
+						</tr>
+					</table>
+				</div>
+				<div class="diveprofile" style="width:40%;height:50%;margin:1.5%;float:right;border-style:solid;padding:3mm;">
+					<h1>Dive profile area</h1>
+				</div>
+			</div>
+		</div>
+  {% endfor %}
+{% endblock %}
+</body>
+
+</html>
-- 
1.9.1

From 74b123112b68c929a949a2201ed10539451cce50 Mon Sep 17 00:00:00 2001
From: Gehad elrobey <[email protected]>
Date: Sun, 12 Apr 2015 19:19:26 +0200
Subject: [PATCH 2/9] Add Printer class that holds the rendering logic.

Render Html pages into a QWebView then print it using QPainter. the
Printer::print() is called that prepare the HTML file to be rendered by
the QWebView.
Printer::render() will do the rendering task.

Signed-off-by: Gehad elrobey <[email protected]>
---
 CMakeLists.txt       |  1 +
 printer.cpp          | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 printer.h            | 21 +++++++++++++++
 qt-ui/mainwindow.cpp |  3 +++
 subsurface.pro       |  6 +++--
 5 files changed, 101 insertions(+), 2 deletions(-)
 create mode 100644 printer.cpp
 create mode 100644 printer.h

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2f6d713..4d42987 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -195,6 +195,7 @@ SET(SUBSURFACE_CORE_LIB_SRCS
 	configuredivecomputer.cpp
 	configuredivecomputerthreads.cpp
 	divesitehelpers.cpp
+	printer.cpp
 	${PLATFORM_SRC}
 )
 
diff --git a/printer.cpp b/printer.cpp
new file mode 100644
index 0000000..d861057
--- /dev/null
+++ b/printer.cpp
@@ -0,0 +1,72 @@
+#include "printer.h"
+
+#include <QPrintDialog>
+#include <QPrinter>
+#include <QtWebKitWidgets>
+#include <QUrl>
+#include <QPrintDialog>
+#include <QWebElement>
+#include <QWebElementCollection>
+
+#define A4_300DPI_WIDTH 2480
+#define A4_300DPI_HIGHT 3508
+
+QWebView *webView;
+
+void Printer::putFrame(QRect box, QRect viewPort, QPainter *painter)
+{
+	if(!viewPort.contains(box))
+		return;
+
+	int x = box.x() - viewPort.x();
+	int y = box.y() - viewPort.y();
+	int x1 = box.width() + x;
+	int y1 = box.height() + y;
+
+	QRect rec(x, y, box.width(), box.height());
+	painter->fillRect(x, y, box.width(), box.height(), QColor("#CfC7C5"));
+	painter->drawText(rec, Qt::AlignCenter, "Profile Area");
+}
+
+void Printer::render(bool ok)
+{
+	QPrinter printer;
+	printer.setOutputFormat(QPrinter::PdfFormat);
+	printer.setOutputFileName("/home/dive.pdf");
+	printer.setFullPage(true);
+	printer.setOrientation(QPrinter::Portrait);
+	printer.setPaperSize(QPrinter::A4);
+	printer.setPrintRange(QPrinter::AllPages);
+	printer.setResolution(300);
+
+	QPainter painter;
+
+	QSize size(A4_300DPI_WIDTH, A4_300DPI_HIGHT);
+	painter.begin(&printer);
+	painter.setRenderHint(QPainter::Antialiasing);
+	painter.setRenderHint(QPainter::SmoothPixmapTransform);
+
+	webView->page()->setViewportSize(size);
+
+	int Pages = ceil( (float) webView->page()->mainFrame()->contentsSize().rheight() / A4_300DPI_HIGHT);
+	for (int i =0; i < Pages;i++) {
+		QRect viewPort(0, A4_300DPI_HIGHT*i, A4_300DPI_WIDTH, A4_300DPI_HIGHT);
+		webView->page()->mainFrame()->render(&painter, QWebFrame::ContentsLayer);
+		webView->page()->mainFrame()->scroll(0, A4_300DPI_HIGHT);
+		QWebElementCollection collection = webView->page()->mainFrame()->findAllElements(".diveprofile");
+		foreach (QWebElement paraElement, collection) {
+			putFrame(paraElement.geometry(),viewPort, &painter);
+		}
+		if (i < Pages -1)
+			printer.newPage();
+	}
+	painter.end();
+}
+
+void Printer::print()
+{
+	QUrl qurl("file:///tmp/dives.html");
+	webView = new QWebView();
+        webView->load(qurl);
+	connect(webView, SIGNAL(loadFinished(bool)), this, SLOT(render(bool)));
+}
diff --git a/printer.h b/printer.h
new file mode 100644
index 0000000..4c0bc70
--- /dev/null
+++ b/printer.h
@@ -0,0 +1,21 @@
+#ifndef PRINTER_H
+#define PRINTER_H
+#include "QDebug"
+#include <QPainter>
+
+class Printer : public QObject
+{
+	Q_OBJECT
+public:
+	Printer() {
+
+	}
+	void print();
+private:
+	void putFrame(QRect box, QRect viewPort, QPainter *painter);
+private
+slots:
+	void render(bool ok);
+};
+
+#endif //PRINTER_H
diff --git a/qt-ui/mainwindow.cpp b/qt-ui/mainwindow.cpp
index e22f340..8cf1ec3 100644
--- a/qt-ui/mainwindow.cpp
+++ b/qt-ui/mainwindow.cpp
@@ -28,6 +28,7 @@
 #ifndef NO_PRINTING
 #include <QPrintDialog>
 #include "printdialog.h"
+#include "printer.h"
 #endif
 #include "divelogimportdialog.h"
 #include "divelogexportdialog.h"
@@ -431,6 +432,8 @@ void MainWindow::updateLastUsedDir(const QString &dir)
 void MainWindow::on_actionPrint_triggered()
 {
 #ifndef NO_PRINTING
+	Printer *p = new Printer();
+	p->print();
 	PrintDialog dlg(this);
 
 	dlg.exec();
diff --git a/subsurface.pro b/subsurface.pro
index bec7d65..4dda8b8 100644
--- a/subsurface.pro
+++ b/subsurface.pro
@@ -113,7 +113,8 @@ HEADERS = \
 	qt-ui/diveshareexportdialog.h \
 	qt-ui/filtermodels.h \
 	qt-ui/undocommands.h \
-	qt-ui/notificationwidget.h
+	qt-ui/notificationwidget.h \
+	printer.h
 
 android: HEADERS -= \
 	qt-ui/usermanual.h \
@@ -214,7 +215,8 @@ SOURCES =  \
 	qt-ui/filtermodels.cpp \
 	qt-ui/undocommands.cpp \
 	qt-ui/notificationwidget.cpp \
-	ostctools.c
+	ostctools.c \
+	printer.cpp
 
 android: SOURCES += android.cpp
 else: win32: SOURCES += windows.c
-- 
1.9.1

From 465acc71beb2aee5e097289c58688e24c1946e3c Mon Sep 17 00:00:00 2001
From: Gehad elrobey <[email protected]>
Date: Sun, 12 Apr 2015 19:55:08 +0200
Subject: [PATCH 3/9] Integration with subsurface printing dialog

Add option for experimental printing using templates in the existing
printing dialog.

Signed-off-by: Gehad elrobey <[email protected]>
---
 display.h              |  3 ++-
 qt-ui/mainwindow.cpp   |  3 ---
 qt-ui/printlayout.cpp  |  5 +++++
 qt-ui/printoptions.cpp |  9 ++++++++
 qt-ui/printoptions.h   |  1 +
 qt-ui/printoptions.ui  | 59 ++++++++++++++++++++++++++++----------------------
 6 files changed, 50 insertions(+), 30 deletions(-)

diff --git a/display.h b/display.h
index f010144..1946f1f 100644
--- a/display.h
+++ b/display.h
@@ -40,7 +40,8 @@ struct print_options {
 		PRETTY,
 		TABLE,
 		TWOPERPAGE,
-		ONEPERPAGE
+		ONEPERPAGE,
+		TEMPLATEBASED
 	} type;
 	bool print_selected;
 	bool color_selected;
diff --git a/qt-ui/mainwindow.cpp b/qt-ui/mainwindow.cpp
index 8cf1ec3..e22f340 100644
--- a/qt-ui/mainwindow.cpp
+++ b/qt-ui/mainwindow.cpp
@@ -28,7 +28,6 @@
 #ifndef NO_PRINTING
 #include <QPrintDialog>
 #include "printdialog.h"
-#include "printer.h"
 #endif
 #include "divelogimportdialog.h"
 #include "divelogexportdialog.h"
@@ -432,8 +431,6 @@ void MainWindow::updateLastUsedDir(const QString &dir)
 void MainWindow::on_actionPrint_triggered()
 {
 #ifndef NO_PRINTING
-	Printer *p = new Printer();
-	p->print();
 	PrintDialog dlg(this);
 
 	dlg.exec();
diff --git a/qt-ui/printlayout.cpp b/qt-ui/printlayout.cpp
index 4be5fef..bc0e463 100644
--- a/qt-ui/printlayout.cpp
+++ b/qt-ui/printlayout.cpp
@@ -11,6 +11,7 @@
 #include "modeldelegates.h"
 #include "models.h"
 #include "profile/profilewidget2.h"
+#include "printer.h"
 
 PrintLayout::PrintLayout(PrintDialog *dialogPtr, QPrinter *printerPtr, struct print_options *optionsPtr)
 {
@@ -81,6 +82,10 @@ void PrintLayout::print()
 	case print_options::TABLE:
 		printTable();
 		break;
+	case print_options::TEMPLATEBASED:
+		Printer *p = new Printer();
+		p->print();
+		break;
 	}
 }
 
diff --git a/qt-ui/printoptions.cpp b/qt-ui/printoptions.cpp
index d3e148c..dbdcba1 100644
--- a/qt-ui/printoptions.cpp
+++ b/qt-ui/printoptions.cpp
@@ -29,6 +29,9 @@ void PrintOptions::setup(struct print_options *printOpt)
 	case print_options::TABLE:
 		ui.radioTablePrint->setChecked(true);
 		break;
+	case print_options::TEMPLATEBASED:
+		ui.radioTemplateBased->setChecked(true);
+		break;
 	}
 	// general print option checkboxes
 	if (printOptions->color_selected)
@@ -49,6 +52,7 @@ void PrintOptions::setup(struct print_options *printOpt)
 	connect(ui.radioTwoDives, SIGNAL(clicked(bool)), this, SLOT(radioTwoDivesClicked(bool)));
 	connect(ui.radioOneDive, SIGNAL(clicked(bool)), this, SLOT(radioOneDiveClicked(bool)));
 	connect(ui.radioTablePrint, SIGNAL(clicked(bool)), this, SLOT(radioTablePrintClicked(bool)));
+	connect(ui.radioTemplateBased, SIGNAL(clicked(bool)), this, SLOT(radioTemplateBasedClicked(bool)));
 
 	connect(ui.printInColor, SIGNAL(clicked(bool)), this, SLOT(printInColorClicked(bool)));
 	connect(ui.printSelected, SIGNAL(clicked(bool)), this, SLOT(printSelectedClicked(bool)));
@@ -79,6 +83,11 @@ void PrintOptions::radioTablePrintClicked(bool check)
 	printOptions->type = print_options::TABLE;
 }
 
+void PrintOptions::radioTemplateBasedClicked(bool check)
+{
+	printOptions->type = print_options::TEMPLATEBASED;
+}
+
 // general print option checkboxes
 void PrintOptions::printInColorClicked(bool check)
 {
diff --git a/qt-ui/printoptions.h b/qt-ui/printoptions.h
index 658e7ec..a439313 100644
--- a/qt-ui/printoptions.h
+++ b/qt-ui/printoptions.h
@@ -24,6 +24,7 @@ slots:
 	void radioTwoDivesClicked(bool check);
 	void radioOneDiveClicked(bool check);
 	void radioTablePrintClicked(bool check);
+	void radioTemplateBasedClicked(bool check);
 	void printInColorClicked(bool check);
 	void printSelectedClicked(bool check);
 	void notesOnTopClicked(bool check);
diff --git a/qt-ui/printoptions.ui b/qt-ui/printoptions.ui
index 59a48b9..d26a51b 100644
--- a/qt-ui/printoptions.ui
+++ b/qt-ui/printoptions.ui
@@ -29,8 +29,8 @@
       <string>Print type</string>
      </property>
      <layout class="QGridLayout" name="gridLayout">
-      <item row="0" column="0" colspan="2">
-       <widget class="QRadioButton" name="radioSixDives">
+      <item row="4" column="0" colspan="2">
+       <widget class="QRadioButton" name="radioTwoDives">
         <property name="sizePolicy">
          <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
           <horstretch>0</horstretch>
@@ -38,15 +38,12 @@
          </sizepolicy>
         </property>
         <property name="text">
-         <string>&amp;6 dives per page</string>
-        </property>
-        <property name="checked">
-         <bool>true</bool>
+         <string>&amp;2 dives per page</string>
         </property>
        </widget>
       </item>
-      <item row="2" column="0">
-       <widget class="QRadioButton" name="radioOneDive">
+      <item row="1" column="2">
+       <widget class="QRadioButton" name="radioTablePrint">
         <property name="sizePolicy">
          <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
           <horstretch>0</horstretch>
@@ -54,12 +51,25 @@
          </sizepolicy>
         </property>
         <property name="text">
-         <string>&amp;1 dive per page</string>
+         <string>&amp;Table print</string>
         </property>
        </widget>
       </item>
-      <item row="3" column="0" colspan="2">
-       <widget class="QRadioButton" name="radioTwoDives">
+      <item row="3" column="2" rowspan="2">
+       <spacer name="verticalSpacer">
+        <property name="orientation">
+         <enum>Qt::Vertical</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>20</width>
+          <height>40</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item row="1" column="0" colspan="2">
+       <widget class="QRadioButton" name="radioSixDives">
         <property name="sizePolicy">
          <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
           <horstretch>0</horstretch>
@@ -67,12 +77,15 @@
          </sizepolicy>
         </property>
         <property name="text">
-         <string>&amp;2 dives per page</string>
+         <string>&amp;6 dives per page</string>
+        </property>
+        <property name="checked">
+         <bool>true</bool>
         </property>
        </widget>
       </item>
-      <item row="0" column="2">
-       <widget class="QRadioButton" name="radioTablePrint">
+      <item row="3" column="0">
+       <widget class="QRadioButton" name="radioOneDive">
         <property name="sizePolicy">
          <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
           <horstretch>0</horstretch>
@@ -80,22 +93,16 @@
          </sizepolicy>
         </property>
         <property name="text">
-         <string>&amp;Table print</string>
+         <string>&amp;1 dive per page</string>
         </property>
        </widget>
       </item>
-      <item row="2" column="2" rowspan="2">
-       <spacer name="verticalSpacer">
-        <property name="orientation">
-         <enum>Qt::Vertical</enum>
-        </property>
-        <property name="sizeHint" stdset="0">
-         <size>
-          <width>20</width>
-          <height>40</height>
-         </size>
+      <item row="5" column="0" colspan="3">
+       <widget class="QRadioButton" name="radioTemplateBased">
+        <property name="text">
+         <string>Template based print (experimental)</string>
         </property>
-       </spacer>
+       </widget>
       </item>
      </layout>
     </widget>
-- 
1.9.1

From 9fccceab8a13aa57d01be392f59a2478edae5ea6 Mon Sep 17 00:00:00 2001
From: Gehad elrobey <[email protected]>
Date: Mon, 13 Apr 2015 00:32:08 +0200
Subject: [PATCH 4/9] Use the existing QPrinter in printer.cpp

Pass the existing QPrinter object to the printer class, the QPrinter
object is changed to be dynamically allocated as it is used by async
function Printer::render() that runs after printlayout.cpp is closed.
The QPrinter object needs to be freed correctely.

Signed-off-by: Gehad elrobey <[email protected]>
---
 printer.cpp           | 14 +++-----------
 printer.h             | 11 ++++++++++-
 qt-ui/printdialog.cpp | 21 +++++++++++----------
 qt-ui/printdialog.h   |  2 +-
 qt-ui/printlayout.cpp |  2 +-
 5 files changed, 26 insertions(+), 24 deletions(-)

diff --git a/printer.cpp b/printer.cpp
index d861057..6674ac3 100644
--- a/printer.cpp
+++ b/printer.cpp
@@ -30,19 +30,10 @@ void Printer::putFrame(QRect box, QRect viewPort, QPainter *painter)
 
 void Printer::render(bool ok)
 {
-	QPrinter printer;
-	printer.setOutputFormat(QPrinter::PdfFormat);
-	printer.setOutputFileName("/home/dive.pdf");
-	printer.setFullPage(true);
-	printer.setOrientation(QPrinter::Portrait);
-	printer.setPaperSize(QPrinter::A4);
-	printer.setPrintRange(QPrinter::AllPages);
-	printer.setResolution(300);
-
 	QPainter painter;
 
 	QSize size(A4_300DPI_WIDTH, A4_300DPI_HIGHT);
-	painter.begin(&printer);
+	painter.begin(printer);
 	painter.setRenderHint(QPainter::Antialiasing);
 	painter.setRenderHint(QPainter::SmoothPixmapTransform);
 
@@ -58,9 +49,10 @@ void Printer::render(bool ok)
 			putFrame(paraElement.geometry(),viewPort, &painter);
 		}
 		if (i < Pages -1)
-			printer.newPage();
+			printer->newPage();
 	}
 	painter.end();
+	delete printer;
 }
 
 void Printer::print()
diff --git a/printer.h b/printer.h
index 4c0bc70..0f3e582 100644
--- a/printer.h
+++ b/printer.h
@@ -2,16 +2,25 @@
 #define PRINTER_H
 #include "QDebug"
 #include <QPainter>
+#include <QPrinter>
 
 class Printer : public QObject
 {
 	Q_OBJECT
 public:
-	Printer() {
+	Printer(QPrinter *printer) {
+		this->printer = printer;
 
+		//override these settings
+		printer->setFullPage(true);
+		printer->setOrientation(QPrinter::Portrait);
+		printer->setPaperSize(QPrinter::A4);
+		printer->setPrintRange(QPrinter::AllPages);
+		printer->setResolution(300);
 	}
 	void print();
 private:
+	QPrinter *printer;
 	void putFrame(QRect box, QRect viewPort, QPainter *painter);
 private
 slots:
diff --git a/qt-ui/printdialog.cpp b/qt-ui/printdialog.cpp
index fbf71c4..c3f6db0 100644
--- a/qt-ui/printdialog.cpp
+++ b/qt-ui/printdialog.cpp
@@ -17,6 +17,7 @@
 
 PrintDialog::PrintDialog(QWidget *parent, Qt::WindowFlags f) : QDialog(parent, f)
 {
+	printer = new QPrinter();
 	// check if the options were previously stored in the settings; if not use some defaults.
 	QSettings s;
 	bool stored = s.childGroups().contains(SETTINGS_GROUP);
@@ -38,16 +39,16 @@ PrintDialog::PrintDialog(QWidget *parent, Qt::WindowFlags f) : QDialog(parent, f
 		printOptions.margins[1] = s.value("margin_top").toInt();
 		printOptions.margins[2] = s.value("margin_right").toInt();
 		printOptions.margins[3] = s.value("margin_bottom").toInt();
-		printer.setOrientation((QPrinter::Orientation)printOptions.landscape);
+		printer->setOrientation((QPrinter::Orientation)printOptions.landscape);
 #if QT_VERSION >= 0x050300
 		QMarginsF margins;
 		margins.setLeft(printOptions.margins[0]);
 		margins.setTop(printOptions.margins[1]);
 		margins.setRight(printOptions.margins[2]);
 		margins.setBottom(printOptions.margins[3]);
-		printer.setPageMargins(margins, QPageLayout::Millimeter);
+		printer->setPageMargins(margins, QPageLayout::Millimeter);
 #else
-		printer.setPageMargins(
+		printer->setPageMargins(
 			printOptions.margins[0],
 			printOptions.margins[1],
 			printOptions.margins[2],
@@ -58,7 +59,7 @@ PrintDialog::PrintDialog(QWidget *parent, Qt::WindowFlags f) : QDialog(parent, f
 	}
 
 	// create a print layout and pass the printer and options
-	printLayout = new PrintLayout(this, &printer, &printOptions);
+	printLayout = new PrintLayout(this, printer, &printOptions);
 
 	// create a print options object and pass our options struct
 	optionsWidget = new PrintOptions(this, &printOptions);
@@ -116,16 +117,16 @@ void PrintDialog::onFinished()
 	s.setValue("color_selected", printOptions.color_selected);
 	s.setValue("notes_up", printOptions.notes_up);
 #if QT_VERSION >= 0x050300
-	s.setValue("landscape", (bool)printer.pageLayout().orientation());
-	QMarginsF margins = printer.pageLayout().margins(QPageLayout::Millimeter);
+	s.setValue("landscape", (bool)printer->pageLayout().orientation());
+	QMarginsF margins = printer->pageLayout().margins(QPageLayout::Millimeter);
 	s.setValue("margin_left", margins.left());
 	s.setValue("margin_top", margins.top());
 	s.setValue("margin_right", margins.right());
 	s.setValue("margin_bottom", margins.bottom());
 #else
-	s.setValue("landscape", (bool)printer.orientation());
+	s.setValue("landscape", (bool)printer->orientation());
 	qreal left, top, right, bottom;
-	printer.getPageMargins(&left, &top, &right, &bottom, QPrinter::Millimeter);
+	printer->getPageMargins(&left, &top, &right, &bottom, QPrinter::Millimeter);
 	s.setValue("margin_left", (int)left);
 	s.setValue("margin_top", (int)top);
 	s.setValue("margin_right", (int)right);
@@ -135,7 +136,7 @@ void PrintDialog::onFinished()
 
 void PrintDialog::previewClicked(void)
 {
-	QPrintPreviewDialog previewDialog(&printer, this, Qt::Window
+	QPrintPreviewDialog previewDialog(printer, this, Qt::Window
 		| Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint
 		| Qt::WindowTitleHint);
 
@@ -145,7 +146,7 @@ void PrintDialog::previewClicked(void)
 
 void PrintDialog::printClicked(void)
 {
-	QPrintDialog printDialog(&printer, this);
+	QPrintDialog printDialog(printer, this);
 	if (printDialog.exec() == QDialog::Accepted){
 		printLayout->print();
 		close();
diff --git a/qt-ui/printdialog.h b/qt-ui/printdialog.h
index b42102d..5ed56f3 100644
--- a/qt-ui/printdialog.h
+++ b/qt-ui/printdialog.h
@@ -20,7 +20,7 @@ private:
 	PrintOptions *optionsWidget;
 	PrintLayout *printLayout;
 	QProgressBar *progressBar;
-	QPrinter printer;
+	QPrinter *printer;
 	struct print_options printOptions;
 
 private
diff --git a/qt-ui/printlayout.cpp b/qt-ui/printlayout.cpp
index bc0e463..8d1965f 100644
--- a/qt-ui/printlayout.cpp
+++ b/qt-ui/printlayout.cpp
@@ -83,7 +83,7 @@ void PrintLayout::print()
 		printTable();
 		break;
 	case print_options::TEMPLATEBASED:
-		Printer *p = new Printer();
+		Printer *p = new Printer(printer);
 		p->print();
 		break;
 	}
-- 
1.9.1

From 73c01f71b161e49c53722481bb16c6ec9e9d746b Mon Sep 17 00:00:00 2001
From: Gehad elrobey <[email protected]>
Date: Mon, 13 Apr 2015 00:56:21 +0200
Subject: [PATCH 5/9] CMAKE: Require Grantlee library

-find Grantlee package
-configure grantlee_paths.h
-install the printing_templates directory

Include Grantlee package

Signed-off-by: Gehad elrobey <[email protected]>
---
 CMakeLists.txt | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4d42987..8749d3f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -54,10 +54,22 @@ IF(NOT (insource OR insourcedir))
 	add_custom_target(link_marble_data ALL COMMAND rm -f marbledata && ln -s ${${PROJECT_NAME}_SOURCE_DIR}/marbledata ${${PROJECT_NAME}_BINARY_DIR}/marbledata)
 ENDIF()
 
+#setup Grantlee
+
+find_package(Grantlee5)
+
+get_property(Grantlee_PLUGIN_DIR TARGET Grantlee5::defaulttags PROPERTY LOCATION)
+GET_FILENAME_COMPONENT(Grantlee_PLUGIN_DIR ${Grantlee_PLUGIN_DIR} PATH)
+GET_FILENAME_COMPONENT(Grantlee_PLUGIN_DIR ${Grantlee_PLUGIN_DIR} PATH)
+GET_FILENAME_COMPONENT(Grantlee_PLUGIN_DIR ${Grantlee_PLUGIN_DIR} PATH)
+
+configure_file(grantlee_paths.h.cmake ${PROJECT_BINARY_DIR}/grantlee_paths.h)
+
+
 #configure Qt.
 
 FIND_PACKAGE(Qt5 REQUIRED COMPONENTS Core Concurrent Widgets Network WebKitWidgets PrintSupport Svg Test LinguistTools)
-SET(QT_LIBRARIES Qt5::Core Qt5::Concurrent Qt5::Widgets Qt5::Network Qt5::WebKitWidgets Qt5::PrintSupport Qt5::Svg)
+SET(QT_LIBRARIES Qt5::Core Qt5::Concurrent Qt5::Widgets Qt5::Network Qt5::WebKitWidgets Qt5::PrintSupport Qt5::Svg Grantlee5::Templates)
 SET(QT_TEST_LIBRARIES ${QT_LIBRARIES} Qt5::Test)
 
 # Generate the ssrf-config.h every 'make'
@@ -387,6 +399,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
 	install(DIRECTORY Documentation/images DESTINATION ${RESOURCEDIR}/share/Documentation)
 	install(FILES ${DOCFILES} DESTINATION ${RESOURCEDIR}/share/Documentation)
 	install(DIRECTORY theme DESTINATION ${RESOURCEDIR})
+	install(DIRECTORY printing_templates DESTINATION ${RESOURCEDIR})
 	install(FILES ${TRANSLATIONS} DESTINATION ${RESOURCEDIR}/translations)
 	install(FILES ${QTTRANSLATIONS} DESTINATION ${RESOURCEDIR}/translations)
 	install(FILES ${CMAKE_SOURCE_DIR}/gpl-2.0.txt DESTINATION ${RESOURCEDIR})
@@ -407,6 +420,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
 	install(DIRECTORY Documentation/images DESTINATION ${WINDOWSSTAGING}/Documentation)
 	install(FILES ${DOCFILES} DESTINATION ${WINDOWSSTAGING}/Documentation)
 	install(DIRECTORY theme DESTINATION ${WINDOWSSTAGING})
+	install(DIRECTORY printing_templates DESTINATION ${WINDOWSSTAGING})
 	install(FILES ${TRANSLATIONS} DESTINATION ${WINDOWSSTAGING}/translations)
 	install(FILES ${QTTRANSLATIONS} DESTINATION ${WINDOWSSTAGING}/translations)
 	install(FILES ${CMAKE_SOURCE_DIR}/gpl-2.0.txt ${CMAKE_SOURCE_DIR}/packaging/windows/subsurface.ico DESTINATION ${WINDOWSSTAGING})
@@ -493,6 +507,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
 	install(DIRECTORY Documentation/images DESTINATION share/subsurface/Documentation)
 	install(FILES ${DOCFILES} DESTINATION share/subsurface/Documentation)
 	install(DIRECTORY theme DESTINATION share/subsurface)
+	install(DIRECTORY printing_templates DESTINATION share/subsurface)
 	install(FILES ${TRANSLATIONS} DESTINATION share/subsurface/translations)
 	install(TARGETS ${SUBSURFACE_TARGET} DESTINATION bin)
 	IF(DEFINED LIBMARBLEDEVEL)
-- 
1.9.1

From cb901cc6dcace5dee06923dc8ed52aa2286252af Mon Sep 17 00:00:00 2001
From: Gehad elrobey <[email protected]>
Date: Tue, 14 Apr 2015 15:15:37 +0200
Subject: [PATCH 6/9] Add TemplateLayout class

This is the main class to hold Grantlee engine logic.
TemplateLayout::generate() loads QT5Grantlee and initialize the
templates then returns a QTemporaryFile that contains the rendered HTML
by Grantlee library.

Also the class holds Dive class which holds the logic that passes the
data to the templates. A better way to interface the data with Grantlee
can be found instead of copying the data into the memory.

Signed-off-by: Gehad elrobey <[email protected]>
---
 CMakeLists.txt     |  1 +
 printer.cpp        | 33 +++++++------------
 printer.h          |  8 ++---
 templatelayout.cpp | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 templatelayout.h   | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 195 insertions(+), 26 deletions(-)
 create mode 100644 templatelayout.cpp
 create mode 100644 templatelayout.h

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8749d3f..6b9cf54 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -208,6 +208,7 @@ SET(SUBSURFACE_CORE_LIB_SRCS
 	configuredivecomputerthreads.cpp
 	divesitehelpers.cpp
 	printer.cpp
+	templatelayout.cpp
 	${PLATFORM_SRC}
 )
 
diff --git a/printer.cpp b/printer.cpp
index 6674ac3..5e60712 100644
--- a/printer.cpp
+++ b/printer.cpp
@@ -1,7 +1,8 @@
 #include "printer.h"
+#include "templatelayout.h"
 
 #include <QPrintDialog>
-#include <QPrinter>
+#include <QPainter>
 #include <QtWebKitWidgets>
 #include <QUrl>
 #include <QPrintDialog>
@@ -13,23 +14,13 @@
 
 QWebView *webView;
 
-void Printer::putFrame(QRect box, QRect viewPort, QPainter *painter)
+void Printer::render(bool ok)
 {
-	if(!viewPort.contains(box))
+	if (!ok) {
+		//handle the error
 		return;
+	}
 
-	int x = box.x() - viewPort.x();
-	int y = box.y() - viewPort.y();
-	int x1 = box.width() + x;
-	int y1 = box.height() + y;
-
-	QRect rec(x, y, box.width(), box.height());
-	painter->fillRect(x, y, box.width(), box.height(), QColor("#CfC7C5"));
-	painter->drawText(rec, Qt::AlignCenter, "Profile Area");
-}
-
-void Printer::render(bool ok)
-{
 	QPainter painter;
 
 	QSize size(A4_300DPI_WIDTH, A4_300DPI_HIGHT);
@@ -44,21 +35,19 @@ void Printer::render(bool ok)
 		QRect viewPort(0, A4_300DPI_HIGHT*i, A4_300DPI_WIDTH, A4_300DPI_HIGHT);
 		webView->page()->mainFrame()->render(&painter, QWebFrame::ContentsLayer);
 		webView->page()->mainFrame()->scroll(0, A4_300DPI_HIGHT);
-		QWebElementCollection collection = webView->page()->mainFrame()->findAllElements(".diveprofile");
-		foreach (QWebElement paraElement, collection) {
-			putFrame(paraElement.geometry(),viewPort, &painter);
-		}
 		if (i < Pages -1)
 			printer->newPage();
 	}
 	painter.end();
-	delete printer;
+
+	//TODO delete the printer object
 }
 
 void Printer::print()
 {
-	QUrl qurl("file:///tmp/dives.html");
+	TemplateLayout *t = new TemplateLayout();
 	webView = new QWebView();
-        webView->load(qurl);
+        webView->load(t->generate());
 	connect(webView, SIGNAL(loadFinished(bool)), this, SLOT(render(bool)));
+	delete t;
 }
diff --git a/printer.h b/printer.h
index 0f3e582..583fb35 100644
--- a/printer.h
+++ b/printer.h
@@ -1,7 +1,6 @@
 #ifndef PRINTER_H
 #define PRINTER_H
-#include "QDebug"
-#include <QPainter>
+
 #include <QPrinter>
 
 class Printer : public QObject
@@ -11,17 +10,18 @@ public:
 	Printer(QPrinter *printer) {
 		this->printer = printer;
 
-		//override these settings
+		//override these settings for now.
 		printer->setFullPage(true);
 		printer->setOrientation(QPrinter::Portrait);
 		printer->setPaperSize(QPrinter::A4);
 		printer->setPrintRange(QPrinter::AllPages);
 		printer->setResolution(300);
 	}
+	~Printer(){ }
 	void print();
 private:
 	QPrinter *printer;
-	void putFrame(QRect box, QRect viewPort, QPainter *painter);
+
 private
 slots:
 	void render(bool ok);
diff --git a/templatelayout.cpp b/templatelayout.cpp
new file mode 100644
index 0000000..e01c896
--- /dev/null
+++ b/templatelayout.cpp
@@ -0,0 +1,93 @@
+#include <string>
+
+#include "templatelayout.h"
+#include "grantlee_paths.h"
+#include "helpers.h"
+
+QTemporaryFile *TemplateLayout::generate()
+{
+	QTemporaryFile *file;
+	m_engine = new Grantlee::Engine(this);
+
+	QSharedPointer<Grantlee::FileSystemTemplateLoader> m_templateLoader =
+		QSharedPointer<Grantlee::FileSystemTemplateLoader>(new Grantlee::FileSystemTemplateLoader());
+	m_templateLoader->setTemplateDirs(QStringList() << getSubsurfaceDataPath("printing_templates"));
+	m_engine->setPluginPaths( QStringList() << GRANTLEE_PLUGIN_PATH );
+	m_engine->addTemplateLoader(m_templateLoader);
+
+	QVariantHash mapping;
+	QVariantList diveList;
+
+	struct dive *dive;
+	int i;
+	QObject *d;
+	for_each_dive (i, dive) {
+		//TODO check for exporting selected dives only
+		if (!dive->selected)
+			continue;
+		d = new Dive(dive, this);
+		diveList.append(QVariant::fromValue(d));
+	}
+
+	mapping.insert("dives", diveList);
+
+	Grantlee::Context c(mapping);
+
+	Grantlee::Template t = m_engine->loadByName("base.html");
+	if (!t || t->error()) {
+		qDebug() << "Can't to load template";
+		return file;
+	}
+
+	file = new QTemporaryFile(QDir::tempPath() + QDir::separator() + "subsurface_XXXXXX.html");
+	if (!file->open()){
+		qDebug() << "Can't write here.";
+		return file;
+	}
+
+	QString content = t->render(&c);
+
+	if (t->error()) {
+		qDebug() << "Can't render template";
+		return file;
+	}
+	file->write(content.toLocal8Bit());
+	file->close();
+	return file;
+}
+
+void Dive::put_divemaster()
+{
+	if (!dive->divemaster)
+		m_divemaster = "";
+	else
+		m_divemaster = dive->divemaster;
+}
+
+void Dive::put_time()
+{
+	struct tm tm;
+	utc_mkdate(dive->when, &tm);
+	char b[100];
+	sprintf(b, "%04u-%02u-%02u", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
+	m_date = QString::fromUtf8(b);
+}
+
+void Dive::put_location()
+{
+	m_location = QString::fromUtf8(get_dive_location(dive));
+}
+
+void Dive::put_depth()
+{
+	char b[100];
+	sprintf(b, "%0.2f m", dive->dc.maxdepth.mm/1000.0);
+	m_depth = QString::fromUtf8(b);
+}
+
+void Dive::put_duration()
+{
+	char b[100];
+	sprintf(b, "%u:%02u min", FRACTION(dive->dc.duration.seconds, 60));
+	m_duration = QString::fromUtf8(b);
+}
diff --git a/templatelayout.h b/templatelayout.h
new file mode 100644
index 0000000..55205e4
--- /dev/null
+++ b/templatelayout.h
@@ -0,0 +1,86 @@
+#ifndef TEMPLATELAYOUT
+#define TEMPLATELAYOUT
+
+#include <QUrl>
+#include <QTemporaryFile>
+
+#include <grantlee_templates.h>
+#include "mainwindow.h"
+
+class TemplateLayout : public QObject {
+	Q_OBJECT
+public:
+	TemplateLayout() {};
+	~TemplateLayout(){
+		delete m_engine;
+	};
+	QTemporaryFile *generate();
+private:
+	Grantlee::Engine *m_engine;
+};
+
+//I think I am wasting time copying the object into memory.
+//May be there is a better way to genrate the objects.
+class Dive : public QObject {
+	Q_OBJECT
+	Q_PROPERTY(int number READ number)
+	Q_PROPERTY(QString divemaster READ divemaster)
+	Q_PROPERTY(QString date READ date)
+	Q_PROPERTY(QString location READ location)
+	Q_PROPERTY(QString depth READ depth)
+	Q_PROPERTY(QString duration READ duration)
+
+private:
+	QString m_divemaster;
+	QString m_date;
+	QString m_location;
+	QString m_depth;
+	QString m_duration;
+	int m_number;
+	struct dive *dive;
+	void put_divemaster();
+	void put_time();
+	void put_location();
+	void put_depth();
+	void put_duration();
+
+public:
+	Dive(struct dive *dive, QObject *parent = 0)
+	    : QObject(parent), dive(dive)
+	{
+		m_number = dive->number;
+		put_divemaster();
+		put_time();
+		put_location();
+		put_depth();
+		put_duration();
+	}
+	~Dive(){ }
+
+	QString divemaster()
+	{
+		return m_divemaster;
+	}
+	QString date()
+	{
+		return m_date;
+	}
+	QString location()
+	{
+		return m_location;
+	}
+	QString depth()
+	{
+		return m_depth;
+	}
+	QString duration()
+	{
+		return m_duration;
+	}
+	int number()
+	{
+		return m_number;
+	}
+};
+
+#endif
-- 
1.9.1

From 462b2205e44025437e959e112278155288447d9a Mon Sep 17 00:00:00 2001
From: Gehad elrobey <[email protected]>
Date: Wed, 15 Apr 2015 20:58:46 +0200
Subject: [PATCH 7/9] Handle QTemporaryFile generated by template.

Signed-off-by: Gehad elrobey <[email protected]>
---
 printer.cpp | 15 ++++++++++-----
 printer.h   | 10 ++++++++--
 2 files changed, 18 insertions(+), 7 deletions(-)

diff --git a/printer.cpp b/printer.cpp
index 5e60712..88445c8 100644
--- a/printer.cpp
+++ b/printer.cpp
@@ -4,6 +4,7 @@
 #include <QPrintDialog>
 #include <QPainter>
 #include <QtWebKitWidgets>
+#include <QTemporaryFile>
 #include <QUrl>
 #include <QPrintDialog>
 #include <QWebElement>
@@ -12,17 +13,15 @@
 #define A4_300DPI_WIDTH 2480
 #define A4_300DPI_HIGHT 3508
 
-QWebView *webView;
-
 void Printer::render(bool ok)
 {
 	if (!ok) {
 		//handle the error
+		qDebug() << "Error rendering the page";
 		return;
 	}
 
 	QPainter painter;
-
 	QSize size(A4_300DPI_WIDTH, A4_300DPI_HIGHT);
 	painter.begin(printer);
 	painter.setRenderHint(QPainter::Antialiasing);
@@ -41,13 +40,19 @@ void Printer::render(bool ok)
 	painter.end();
 
 	//TODO delete the printer object
+	// a Signal must be emited here
+	delete tempFile;
 }
 
 void Printer::print()
 {
 	TemplateLayout *t = new TemplateLayout();
 	webView = new QWebView();
-        webView->load(t->generate());
-	connect(webView, SIGNAL(loadFinished(bool)), this, SLOT(render(bool)));
+	tempFile = t->generate();
+	if (tempFile) {
+		QUrl url("file:///" + tempFile->fileName());
+		webView->load(url);
+		connect(webView, SIGNAL(loadFinished(bool)), this, SLOT(render(bool)));
+	}
 	delete t;
 }
diff --git a/printer.h b/printer.h
index 583fb35..2df26e5 100644
--- a/printer.h
+++ b/printer.h
@@ -2,10 +2,18 @@
 #define PRINTER_H
 
 #include <QPrinter>
+#include <QTemporaryFile>
+#include <QWebView>
 
 class Printer : public QObject
 {
 	Q_OBJECT
+
+private:
+	QPrinter *printer;
+	QTemporaryFile *tempFile;
+	QWebView *webView;
+
 public:
 	Printer(QPrinter *printer) {
 		this->printer = printer;
@@ -19,8 +27,6 @@ public:
 	}
 	~Printer(){ }
 	void print();
-private:
-	QPrinter *printer;
 
 private
 slots:
-- 
1.9.1

From 412928c10e53b98b77d504ea0aee9ddfdb291dcf Mon Sep 17 00:00:00 2001
From: Gehad elrobey <[email protected]>
Date: Wed, 15 Apr 2015 20:59:51 +0200
Subject: [PATCH 8/9] Add dyanmic paths to Grantlee plugins

Signed-off-by: Gehad elrobey <[email protected]>
---
 grantlee_paths.h.cmake | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 grantlee_paths.h.cmake

diff --git a/grantlee_paths.h.cmake b/grantlee_paths.h.cmake
new file mode 100644
index 0000000..00006d2
--- /dev/null
+++ b/grantlee_paths.h.cmake
@@ -0,0 +1 @@
+#define GRANTLEE_PLUGIN_PATH "@Grantlee_PLUGIN_DIR@"
-- 
1.9.1

From e631a263d04bda5476cb4699935ecb93cd835c40 Mon Sep 17 00:00:00 2001
From: Gehad elrobey <[email protected]>
Date: Wed, 15 Apr 2015 21:11:53 +0200
Subject: [PATCH 9/9] Organize Imports

Signed-off-by: Gehad elrobey <[email protected]>
---
 printer.cpp      | 7 +------
 templatelayout.h | 2 +-
 2 files changed, 2 insertions(+), 7 deletions(-)

diff --git a/printer.cpp b/printer.cpp
index 88445c8..7907a56 100644
--- a/printer.cpp
+++ b/printer.cpp
@@ -1,14 +1,9 @@
 #include "printer.h"
 #include "templatelayout.h"
 
-#include <QPrintDialog>
-#include <QPainter>
 #include <QtWebKitWidgets>
-#include <QTemporaryFile>
+#include <QPainter>
 #include <QUrl>
-#include <QPrintDialog>
-#include <QWebElement>
-#include <QWebElementCollection>
 
 #define A4_300DPI_WIDTH 2480
 #define A4_300DPI_HIGHT 3508
diff --git a/templatelayout.h b/templatelayout.h
index 55205e4..7e8c2ce 100644
--- a/templatelayout.h
+++ b/templatelayout.h
@@ -1,8 +1,8 @@
 #ifndef TEMPLATELAYOUT
 #define TEMPLATELAYOUT
 
-#include <QUrl>
 #include <QTemporaryFile>
+#include <QUrl>
 
 #include <grantlee_templates.h>
 #include "mainwindow.h"
-- 
1.9.1

_______________________________________________
subsurface mailing list
[email protected]
http://lists.subsurface-divelog.org/cgi-bin/mailman/listinfo/subsurface

Reply via email to