Merge lp:~verzegnassi-stefano/+junk/new-pdf-plugin into lp:ubuntu-docviewer-app

Proposed by Stefano Verzegnassi
Status: Work in progress
Proposed branch: lp:~verzegnassi-stefano/+junk/new-pdf-plugin
Merge into: lp:ubuntu-docviewer-app
Diff against target: 6278 lines (+3665/-1600) (has conflicts)
51 files modified
po/com.ubuntu.docviewer.pot (+77/-18)
src/app/qml/pdfView/DocumentLockedDialog.qml (+88/-0)
src/app/qml/pdfView/LinkHint.qml (+48/-0)
src/app/qml/pdfView/OpenLinkDialog.qml (+62/-0)
src/app/qml/pdfView/PdfContentsPage.qml (+125/-6)
src/app/qml/pdfView/PdfPresentation.qml (+27/-22)
src/app/qml/pdfView/PdfView.qml (+208/-16)
src/app/qml/pdfView/PdfViewDelegate.qml (+0/-101)
src/app/qml/pdfView/PdfViewGotoDialog.qml (+2/-2)
src/app/qml/pdfView/ZoomSelector.qml (+191/-0)
src/app/qml/ubuntu-docviewer-app.qml (+5/-0)
src/app/renderengine.cpp (+1/-0)
src/app/renderengine.h (+0/-1)
src/app/rendertask.h (+4/-3)
src/plugin/libreofficetoolkit-qml-plugin/lopartsimageresponse.cpp (+1/-1)
src/plugin/libreofficetoolkit-qml-plugin/lorendertask.cpp (+1/-1)
src/plugin/libreofficetoolkit-qml-plugin/lorendertask.h (+2/-2)
src/plugin/libreofficetoolkit-qml-plugin/loview.cpp (+1/-1)
src/plugin/poppler-qml-plugin/CMakeLists.txt (+28/-7)
src/plugin/poppler-qml-plugin/config.h (+13/-0)
src/plugin/poppler-qml-plugin/pagedecoration.cpp (+48/-0)
src/plugin/poppler-qml-plugin/pagedecoration.h (+19/-0)
src/plugin/poppler-qml-plugin/pageoverlay.cpp (+172/-0)
src/plugin/poppler-qml-plugin/pageoverlay.h (+35/-0)
src/plugin/poppler-qml-plugin/pdfdocument.cpp (+259/-161)
src/plugin/poppler-qml-plugin/pdfdocument.h (+91/-59)
src/plugin/poppler-qml-plugin/pdferror.h (+19/-0)
src/plugin/poppler-qml-plugin/pdfimageprovider.cpp (+0/-75)
src/plugin/poppler-qml-plugin/pdfimageprovider.h (+0/-36)
src/plugin/poppler-qml-plugin/pdfimageresponse.cpp (+55/-0)
src/plugin/poppler-qml-plugin/pdfimageresponse.h (+41/-0)
src/plugin/poppler-qml-plugin/pdfitem.cpp (+0/-36)
src/plugin/poppler-qml-plugin/pdfitem.h (+0/-36)
src/plugin/poppler-qml-plugin/pdfrendertask.cpp (+18/-0)
src/plugin/poppler-qml-plugin/pdfrendertask.h (+66/-0)
src/plugin/poppler-qml-plugin/pdftocmodel.cpp (+28/-13)
src/plugin/poppler-qml-plugin/pdftocmodel.h (+11/-6)
src/plugin/poppler-qml-plugin/pdfzoom.cpp (+232/-0)
src/plugin/poppler-qml-plugin/pdfzoom.h (+97/-0)
src/plugin/poppler-qml-plugin/plugin.cpp (+9/-2)
src/plugin/poppler-qml-plugin/qml/Viewer.qml (+186/-0)
src/plugin/poppler-qml-plugin/qmldir (+2/-0)
src/plugin/poppler-qml-plugin/sgtileitem.cpp (+89/-0)
src/plugin/poppler-qml-plugin/sgtileitem.h (+48/-0)
src/plugin/poppler-qml-plugin/touchdetectionarea.cpp (+21/-0)
src/plugin/poppler-qml-plugin/touchdetectionarea.h (+24/-0)
src/plugin/poppler-qml-plugin/twips.h (+98/-0)
src/plugin/poppler-qml-plugin/ucunits.cpp (+241/-0)
src/plugin/poppler-qml-plugin/ucunits.h (+60/-0)
src/plugin/poppler-qml-plugin/verticalview.cpp (+687/-851)
src/plugin/poppler-qml-plugin/verticalview.h (+125/-144)
Text conflict in src/app/qml/pdfView/PdfContentsPage.qml
Text conflict in src/app/qml/pdfView/PdfView.qml
Text conflict in src/app/qml/ubuntu-docviewer-app.qml
To merge this branch: bzr merge lp:~verzegnassi-stefano/+junk/new-pdf-plugin
Reviewer Review Type Date Requested Status
Ubuntu Document Viewer Developers Pending
Review via email: mp+282118@code.launchpad.net
To post a comment you must log in.
240. By Stefano Verzegnassi

* Export Poppler::Error to QML
* Added support for protected PDF documents

241. By Stefano Verzegnassi

Sync with trunk

242. By Stefano Verzegnassi

Sync PDF plugin with latest LOK-plugin changes:
- Pinch to zoom (not tested)
- Double tap to zoom (not tested)
- Use UITK 1.3 ScrollView
- Zoom settings as a separate object
- Use UCUnits for a better scaling strategy/support
- Zoom modes: manual, fit width, fit page and automatic (as gnome-evince)
- Don't remove QImage data in SGTileItem

And probably some other minor change. There's some chance I've introduced some new bug here and there. Anyway that's not yet relevant because of the current status of the plugin.

243. By Stefano Verzegnassi

Use uitk units for rendering the document

244. By Stefano Verzegnassi

* Changed LinkHint style
* OpenLinkDialog: fixed button text

245. By Stefano Verzegnassi

* Fixed an issue with pinch zooming in PDF viewer
* Removed tiled rendering from PdfPageItem
* Create PdfPageItem only for visible indices - stop creating all the pages on initialization
* Fixed VerticalView::positionAtIndex() as consequence of the change above

246. By Stefano Verzegnassi

Added rotation support - pt.1

247. By Stefano Verzegnassi

Added rotation support - pt.2

248. By Stefano Verzegnassi

* Added TODO and FIXME tasks
* Fixed a bug with VerticalView width when rotated

249. By Stefano Verzegnassi

* Fixed PDF link support
* Added touch support for links

250. By Stefano Verzegnassi

Fixed links rotation

251. By Stefano Verzegnassi

disable mouse/touch areas when the flickable is moving + code style

252. By Stefano Verzegnassi

Moved all the logic in VerticalView. Removed PdfPageItem class.

253. By Stefano Verzegnassi

Forgot to remove a last reference to PdfPageItem

254. By Stefano Verzegnassi

Don't show hints on touch gesture

255. By Stefano Verzegnassi

Fixed pdf viewer top margin

256. By Stefano Verzegnassi

[Fix] GoTo links returning wrong coordinates + typo

257. By Stefano Verzegnassi

[Fix] RenderTasks not removed from the queue when the viewport gets cleaned

258. By Stefano Verzegnassi

removed obsolete comments

259. By Stefano Verzegnassi

Pdf rotation as a separate class

260. By Stefano Verzegnassi

* Re-introduced PDF presentation support. Added a QML image provider to the PDF plugin.
* Minor changes to the RenderEngine tasks name.

NB: ImageProvider and paintThumbnail don't work properly yet (i.e. returning an image with a wrong size).

261. By Stefano Verzegnassi

TocModel is now filtered by node level, so we don't get a huge list of entries anymore. Also, this now fits with the UI design specifications.

262. By Stefano Verzegnassi

Change spacing value according to the current zoom value. Workaround for getting zoom properly working on QML.

263. By Stefano Verzegnassi

Fixed broken GoTo dialog

264. By Stefano Verzegnassi

Properly use zoomed spacing where required

Unmerged revisions

264. By Stefano Verzegnassi

Properly use zoomed spacing where required

263. By Stefano Verzegnassi

Fixed broken GoTo dialog

262. By Stefano Verzegnassi

Change spacing value according to the current zoom value. Workaround for getting zoom properly working on QML.

261. By Stefano Verzegnassi

TocModel is now filtered by node level, so we don't get a huge list of entries anymore. Also, this now fits with the UI design specifications.

260. By Stefano Verzegnassi

* Re-introduced PDF presentation support. Added a QML image provider to the PDF plugin.
* Minor changes to the RenderEngine tasks name.

NB: ImageProvider and paintThumbnail don't work properly yet (i.e. returning an image with a wrong size).

259. By Stefano Verzegnassi

Pdf rotation as a separate class

258. By Stefano Verzegnassi

removed obsolete comments

257. By Stefano Verzegnassi

[Fix] RenderTasks not removed from the queue when the viewport gets cleaned

256. By Stefano Verzegnassi

[Fix] GoTo links returning wrong coordinates + typo

255. By Stefano Verzegnassi

Fixed pdf viewer top margin

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'po/com.ubuntu.docviewer.pot'
2--- po/com.ubuntu.docviewer.pot 2016-02-05 22:42:13 +0000
3+++ po/com.ubuntu.docviewer.pot 2016-04-22 10:31:39 +0000
4@@ -8,13 +8,13 @@
5 msgstr ""
6 "Project-Id-Version: \n"
7 "Report-Msgid-Bugs-To: \n"
8-"POT-Creation-Date: 2016-02-05 23:40+0100\n"
9+"POT-Creation-Date: 2016-04-07 00:46+0200\n"
10 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
11 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
12 "Language-Team: LANGUAGE <LL@li.org>\n"
13 "Language: \n"
14 "MIME-Version: 1.0\n"
15-"Content-Type: text/plain; charset=CHARSET\n"
16+"Content-Type: text/plain; charset=UTF-8\n"
17 "Content-Transfer-Encoding: 8bit\n"
18 "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
19
20@@ -42,7 +42,7 @@
21
22 #: ../src/app/qml/common/DetailsPage.qml:26
23 #: ../src/app/qml/loView/LOViewDefaultHeader.qml:107
24-#: ../src/app/qml/pdfView/PdfView.qml:235
25+#: ../src/app/qml/pdfView/PdfView.qml:317
26 #: ../src/app/qml/textView/TextViewDefaultHeader.qml:69
27 msgid "Details"
28 msgstr ""
29@@ -117,7 +117,9 @@
30 #: ../src/app/qml/documentPage/DeleteFileDialog.qml:55
31 #: ../src/app/qml/documentPage/DocumentPagePickModeHeader.qml:28
32 #: ../src/app/qml/loView/LOViewGotoDialog.qml:55
33-#: ../src/app/qml/pdfView/PdfView.qml:180
34+#: ../src/app/qml/pdfView/DocumentLockedDialog.qml:61
35+#: ../src/app/qml/pdfView/OpenLinkDialog.qml:39
36+#: ../src/app/qml/pdfView/PdfView.qml:261
37 #: ../src/app/qml/pdfView/PdfViewGotoDialog.qml:51
38 msgid "Cancel"
39 msgstr ""
40@@ -216,7 +218,7 @@
41 msgstr ""
42
43 #: ../src/app/qml/documentPage/DocumentPage.qml:23
44-#: /tmp/lok-qml-async-imageprovider-build/po/com.ubuntu.docviewer.desktop.in.in.h:3
45+#: /tmp/temp-new-pdf-plugin-build/po/com.ubuntu.docviewer.desktop.in.in.h:3
46 msgid "Documents"
47 msgstr ""
48
49@@ -228,15 +230,15 @@
50 msgid "Sorting settings..."
51 msgstr ""
52
53-#: ../src/app/qml/documentPage/DocumentPagePickModeHeader.qml:41
54+#: ../src/app/qml/documentPage/DocumentPagePickModeHeader.qml:44
55 msgid "Switch to single column list"
56 msgstr ""
57
58-#: ../src/app/qml/documentPage/DocumentPagePickModeHeader.qml:41
59+#: ../src/app/qml/documentPage/DocumentPagePickModeHeader.qml:44
60 msgid "Switch to grid"
61 msgstr ""
62
63-#: ../src/app/qml/documentPage/DocumentPagePickModeHeader.qml:49
64+#: ../src/app/qml/documentPage/DocumentPagePickModeHeader.qml:52
65 msgid "Pick"
66 msgstr ""
67
68@@ -343,13 +345,13 @@
69 msgstr ""
70
71 #: ../src/app/qml/loView/LOViewDefaultHeader.qml:100
72-#: ../src/app/qml/pdfView/PdfView.qml:228
73+#: ../src/app/qml/pdfView/PdfView.qml:310
74 #: ../src/app/qml/textView/TextViewDefaultHeader.qml:63
75 msgid "Disable night mode"
76 msgstr ""
77
78 #: ../src/app/qml/loView/LOViewDefaultHeader.qml:100
79-#: ../src/app/qml/pdfView/PdfView.qml:228
80+#: ../src/app/qml/pdfView/PdfView.qml:310
81 #: ../src/app/qml/textView/TextViewDefaultHeader.qml:63
82 msgid "Enable night mode"
83 msgstr ""
84@@ -400,6 +402,7 @@
85 msgstr ""
86
87 #: ../src/app/qml/loView/ZoomSelector.qml:122
88+#: ../src/app/qml/pdfView/ZoomSelector.qml:119
89 msgid "Fit width"
90 msgstr ""
91
92@@ -408,35 +411,87 @@
93 msgstr ""
94
95 #: ../src/app/qml/loView/ZoomSelector.qml:124
96+#: ../src/app/qml/pdfView/ZoomSelector.qml:121
97 msgid "Automatic"
98 msgstr ""
99
100+#: ../src/app/qml/pdfView/DocumentLockedDialog.qml:25
101+msgid "Document is locked"
102+msgstr ""
103+
104+#: ../src/app/qml/pdfView/DocumentLockedDialog.qml:26
105+msgid "Please insert a password in order to unlock this document"
106+msgstr ""
107+
108+#: ../src/app/qml/pdfView/DocumentLockedDialog.qml:48
109+msgid "Entered password is not valid"
110+msgstr ""
111+
112+#: ../src/app/qml/pdfView/DocumentLockedDialog.qml:67
113+msgid "Unlock"
114+msgstr ""
115+
116+#: ../src/app/qml/pdfView/LinkHint.qml:36
117+#, qt-format
118+msgid "Open link externally: %1"
119+msgstr ""
120+
121+#: ../src/app/qml/pdfView/LinkHint.qml:37
122+#: ../src/app/qml/pdfView/OpenLinkDialog.qml:28
123+#, qt-format
124+msgid "Go to page %1"
125+msgstr ""
126+
127+#: ../src/app/qml/pdfView/OpenLinkDialog.qml:28
128+msgid "Open link externally"
129+msgstr ""
130+
131+#: ../src/app/qml/pdfView/OpenLinkDialog.qml:29
132+msgid "Are you sure?"
133+msgstr ""
134+
135+#: ../src/app/qml/pdfView/OpenLinkDialog.qml:45
136+msgid "Open"
137+msgstr ""
138+
139+#: ../src/app/qml/pdfView/OpenLinkDialog.qml:45
140+msgid "Go to destination"
141+msgstr ""
142+
143 #. TRANSLATORS: "Contents" refers to the "Table of Contents" of a PDF document.
144 #: ../src/app/qml/pdfView/PdfContentsPage.qml:31
145-#: ../src/app/qml/pdfView/PdfView.qml:153
146+#: ../src/app/qml/pdfView/PdfView.qml:230
147 msgid "Contents"
148 msgstr ""
149
150 #. TRANSLATORS: the first argument (%1) refers to the page currently shown on the screen,
151 #. while the second one (%2) refers to the total pages count.
152 #: ../src/app/qml/pdfView/PdfPresentation.qml:51
153-#: ../src/app/qml/pdfView/PdfView.qml:56
154+#: ../src/app/qml/pdfView/PdfView.qml:49
155 #, qt-format
156 msgid "Page %1 of %2"
157 msgstr ""
158
159-#: ../src/app/qml/pdfView/PdfView.qml:203
160+#: ../src/app/qml/pdfView/PdfView.qml:284
161 msgid "Search"
162 msgstr ""
163
164-#: ../src/app/qml/pdfView/PdfView.qml:213
165+#: ../src/app/qml/pdfView/PdfView.qml:294
166 msgid "Go to page..."
167 msgstr ""
168
169-#: ../src/app/qml/pdfView/PdfView.qml:221
170+#: ../src/app/qml/pdfView/PdfView.qml:303
171 msgid "Presentation"
172 msgstr ""
173
174+#: ../src/app/qml/pdfView/PdfView.qml:324
175+msgid "Rotate 90° right"
176+msgstr ""
177+
178+#: ../src/app/qml/pdfView/PdfView.qml:341
179+msgid "Rotate 90° left"
180+msgstr ""
181+
182 #: ../src/app/qml/pdfView/PdfViewGotoDialog.qml:26
183 msgid "Go to page"
184 msgstr ""
185@@ -446,7 +501,11 @@
186 msgid "Choose a page between 1 and %1"
187 msgstr ""
188
189-#: ../src/app/qml/ubuntu-docviewer-app.qml:114
190+#: ../src/app/qml/pdfView/ZoomSelector.qml:120
191+msgid "Fit page"
192+msgstr ""
193+
194+#: ../src/app/qml/ubuntu-docviewer-app.qml:117
195 msgid "File does not exist."
196 msgstr ""
197
198@@ -464,10 +523,10 @@
199 msgid "copy %1"
200 msgstr ""
201
202-#: /tmp/lok-qml-async-imageprovider-build/po/com.ubuntu.docviewer.desktop.in.in.h:1
203+#: /tmp/temp-new-pdf-plugin-build/po/com.ubuntu.docviewer.desktop.in.in.h:1
204 msgid "Document Viewer"
205 msgstr ""
206
207-#: /tmp/lok-qml-async-imageprovider-build/po/com.ubuntu.docviewer.desktop.in.in.h:2
208+#: /tmp/temp-new-pdf-plugin-build/po/com.ubuntu.docviewer.desktop.in.in.h:2
209 msgid "documents;viewer;pdf;reader;"
210 msgstr ""
211
212=== added file 'src/app/qml/pdfView/DocumentLockedDialog.qml'
213--- src/app/qml/pdfView/DocumentLockedDialog.qml 1970-01-01 00:00:00 +0000
214+++ src/app/qml/pdfView/DocumentLockedDialog.qml 2016-04-22 10:31:39 +0000
215@@ -0,0 +1,88 @@
216+/*
217+ * Copyright (C) 2016 Stefano Verzegnassi
218+ *
219+ * This program is free software; you can redistribute it and/or modify
220+ * it under the terms of the GNU General Public License as published by
221+ * the Free Software Foundation; version 3.
222+ *
223+ * This program is distributed in the hope that it will be useful,
224+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
225+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
226+ * GNU General Public License for more details.
227+ *
228+ * You should have received a copy of the GNU General Public License
229+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
230+ */
231+
232+import QtQuick 2.4
233+import Ubuntu.Components 1.3
234+import Ubuntu.Components.Popups 1.3
235+import QtQuick.Layouts 1.1
236+
237+Dialog {
238+ id: unlockDialog
239+
240+ title: i18n.tr("Document is locked")
241+ text: i18n.tr("Please insert a password in order to unlock this document")
242+
243+ TextField {
244+ id: passwordField
245+ width: parent.width
246+
247+ hasClearButton: true
248+
249+ Keys.onReturnPressed: tryUnlock()
250+ onAccepted: tryUnlock()
251+
252+ Component.onCompleted: forceActiveFocus()
253+
254+ onTextChanged: {
255+ if (text.length === 0) {
256+ errorLabel.visible = false
257+ }
258+ }
259+ }
260+
261+ Label {
262+ id: errorLabel
263+ text: i18n.tr("Entered password is not valid")
264+ color: UbuntuColors.red
265+ visible: false
266+ }
267+
268+ RowLayout {
269+ anchors {
270+ left: parent.left
271+ right: parent.right
272+ margins: units.gu(-1)
273+ }
274+
275+ Button {
276+ text: i18n.tr("Cancel")
277+ onClicked: close()
278+ Layout.fillWidth: true
279+ }
280+
281+ Button {
282+ text: i18n.tr("Unlock")
283+ color: UbuntuColors.green
284+ Layout.fillWidth: true
285+
286+ onClicked: goToPage()
287+ }
288+ }
289+
290+ function close() {
291+ PopupUtils.close(unlockDialog)
292+ }
293+
294+ function tryUnlock() {
295+ var result = pdfView.unlock(passwordField.text, passwordField.text)
296+
297+ if (result) {
298+ close()
299+ } else {
300+ errorLabel.visible = true
301+ }
302+ }
303+}
304
305=== added file 'src/app/qml/pdfView/LinkHint.qml'
306--- src/app/qml/pdfView/LinkHint.qml 1970-01-01 00:00:00 +0000
307+++ src/app/qml/pdfView/LinkHint.qml 2016-04-22 10:31:39 +0000
308@@ -0,0 +1,48 @@
309+/*
310+ * Copyright (C) 2016 Stefano Verzegnassi
311+ *
312+ * This program is free software; you can redistribute it and/or modify
313+ * it under the terms of the GNU General Public License as published by
314+ * the Free Software Foundation; version 3.
315+ *
316+ * This program is distributed in the hope that it will be useful,
317+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
318+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
319+ * GNU General Public License for more details.
320+ *
321+ * You should have received a copy of the GNU General Public License
322+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
323+ */
324+
325+import QtQuick 2.4
326+import Ubuntu.Components 1.3
327+
328+UbuntuShape {
329+ id: rootItem
330+
331+ property var linkInfo
332+
333+ height: hintText.paintedHeight + units.gu(1)
334+ width: hintText.paintedWidth + units.gu(2)
335+
336+ // TODO: Is .raised okay? https://developer.ubuntu.com/en/apps/qml/tutorials/ubuntu-ui-toolkit-palette/
337+ color: theme.palette.normal.raised
338+ aspect: UbuntuShape.DropShadow
339+
340+ Label {
341+ id: hintText
342+ anchors.centerIn: parent
343+
344+ // TODO: Is .raisedText okay? https://developer.ubuntu.com/en/apps/qml/tutorials/ubuntu-ui-toolkit-palette/
345+ color: theme.palette.normal.raisedText
346+ textSize: Label.Small
347+ text: linkInfo.url ? i18n.tr("Open «%1»").arg(linkInfo.url)
348+ : i18n.tr("Go to page %1").arg(linkInfo.pageIndex + 1)
349+ }
350+
351+ Timer {
352+ interval: 2000
353+ running: true
354+ onTriggered: rootItem.destroy()
355+ }
356+}
357
358=== added file 'src/app/qml/pdfView/OpenLinkDialog.qml'
359--- src/app/qml/pdfView/OpenLinkDialog.qml 1970-01-01 00:00:00 +0000
360+++ src/app/qml/pdfView/OpenLinkDialog.qml 2016-04-22 10:31:39 +0000
361@@ -0,0 +1,62 @@
362+/*
363+ * Copyright (C) 2015, 2016 Stefano Verzegnassi
364+ *
365+ * This program is free software; you can redistribute it and/or modify
366+ * it under the terms of the GNU General Public License as published by
367+ * the Free Software Foundation; version 3.
368+ *
369+ * This program is distributed in the hope that it will be useful,
370+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
371+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
372+ * GNU General Public License for more details.
373+ *
374+ * You should have received a copy of the GNU General Public License
375+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
376+ */
377+
378+import QtQuick 2.4
379+import Ubuntu.Components 1.3
380+import Ubuntu.Components.Popups 1.3
381+import QtQuick.Layouts 1.1
382+
383+Dialog {
384+ id: openLinkDialog
385+ objectName:"PdfViewGotoDialog"
386+
387+ property var linkInfo
388+
389+ title: linkInfo.url ? i18n.tr("Open link externally") : i18n.tr("Go to page %1").arg(linkInfo.pageIndex + 1)
390+ text: i18n.tr("Are you sure?")
391+
392+ RowLayout {
393+ anchors {
394+ left: parent.left
395+ right: parent.right
396+ margins: units.gu(-1)
397+ }
398+
399+ Button {
400+ text: i18n.tr("Cancel")
401+ onClicked: PopupUtils.close(openLinkDialog)
402+ Layout.fillWidth: true
403+ }
404+
405+ Button {
406+ text: linkInfo.url ? i18n.tr("Open") : i18n.tr("Go")
407+ color: UbuntuColors.green
408+ Layout.fillWidth: true
409+
410+ onClicked: openLink()
411+ }
412+ }
413+
414+ function openLink() {
415+ if (linkInfo.url) {
416+ Qt.openUrlExternally(linkInfo.url)
417+ } else {
418+ pdfView.positionAtIndex(linkInfo.pageIndex, linkInfo.top, linkInfo.left)
419+ }
420+
421+ PopupUtils.close(openLinkDialog)
422+ }
423+}
424
425=== modified file 'src/app/qml/pdfView/PdfContentsPage.qml'
426--- src/app/qml/pdfView/PdfContentsPage.qml 2016-03-22 19:31:22 +0000
427+++ src/app/qml/pdfView/PdfContentsPage.qml 2016-04-22 10:31:39 +0000
428@@ -17,27 +17,33 @@
429
430 import QtQuick 2.4
431 import Ubuntu.Components 1.3
432-import QtQuick.Layouts 1.1
433+
434+import "../common"
435
436 Page {
437 id: pdfContents
438 objectName: "pdfcontents"
439
440+ property var tocModel: pdfView.document.tocModel
441+
442 // this property will have to be removed when bug #1341671 will be fixed.
443 property string testProperty: "for page name issue"
444
445 header: PageHeader {
446 // TRANSLATORS: "Contents" refers to the "Table of Contents" of a PDF document.
447- title: i18n.tr("Contents")
448+ title: sortedModel.parentNode == -1
449+ ? i18n.tr("Contents")
450+ : tocModel.get(sortedModel.parentNode).title
451 flickable: view
452 }
453
454+ // FIXME
455 onActiveChanged: {
456 // Find out the current page position in the ToC index
457- for (var i=0; i<poppler.tocModel.count; i++) {
458- if (i+1 < poppler.tocModel.count) {
459- if (pdfView.currentPageIndex >= poppler.tocModel.get(i).pageIndex &&
460- pdfView.currentPageIndex < poppler.tocModel.get(i+1).pageIndex) {
461+ for (var i=0; i<tocModel.count; i++) {
462+ if (i+1 < tocModel.count) {
463+ if (pdfView.currentPageIndex >= tocModel.get(i).pageIndex &&
464+ pdfView.currentPageIndex < tocModel.get(i+1).pageIndex) {
465 break;
466 }
467 }
468@@ -52,6 +58,7 @@
469
470 ScrollView {
471 anchors.fill: parent
472+<<<<<<< TREE
473
474 ListView {
475 id: view
476@@ -115,6 +122,118 @@
477 color: __isCurrentIndex ? theme.palette.selected.backgroundText
478 : theme.palette.normal.backgroundText
479 }
480+=======
481+
482+ ListView {
483+ id: view
484+ objectName: "view"
485+ anchors.fill: parent
486+ clip: true
487+
488+ model: SortFilterModel {
489+ id: sortedModel
490+
491+ property int parentNode: -1
492+
493+ model: tocModel
494+ filter.property: "parentNodeIndex"
495+ filter.pattern: new RegExp(parentNode)
496+ }
497+
498+ // Count changes when we change the current parent node.
499+ onCountChanged: view.positionViewAtBeginning()
500+
501+ header: ListItem {
502+ visible: sortedModel.parentNode > -1
503+ height: visible ? units.gu(6) : 0
504+ onClicked: sortedModel.parentNode = -1
505+
506+ ListItemLayout {
507+ anchors.centerIn: parent
508+ title.text: i18n.tr("Back to parent node")
509+
510+ Icon {
511+ SlotsLayout.position: SlotsLayout.Leading
512+ width: units.gu(2); height: width
513+ name: "go-previous"
514+ }
515+ }
516+ }
517+
518+ delegate: ListItem {
519+ id: delegate
520+ objectName: "delegate" + index
521+
522+ onClicked: {
523+ pdfView.positionAtIndex(model.pageIndex);
524+ contentsBottomEdge.collapse();
525+ }
526+
527+ // Highlighted property of ListItem is read-only. In order to
528+ // provide an highlight for the current page, we need to duplicate
529+ // the overlay.
530+ Rectangle {
531+ anchors.fill: parent
532+ color: Qt.rgba(0, 0, 0, 0.05)
533+ visible: view.currentIndex == model.index
534+ }
535+
536+ ListItemLayout {
537+ id: listItemLayout
538+ objectName: "listItemLayout" + index
539+ anchors.fill: parent
540+
541+ Label {
542+ objectName: "pageindex"
543+ SlotsLayout.position: SlotsLayout.Leading
544+ text: model.pageIndex + 1
545+ }
546+
547+ title {
548+ text: model.title
549+ elide: Text.ElideRight
550+ }
551+
552+ Icon {
553+ SlotsLayout.position: SlotsLayout.Trailing
554+ width: units.gu(2); height: width
555+ name: "tick"
556+ color: UbuntuColors.green
557+ visible: view.currentIndex == model.index
558+ }
559+
560+ AbstractButton {
561+ SlotsLayout.position: SlotsLayout.Last
562+ width: units.gu(4); height: units.gu(8)
563+ opacity: model.hasChildNodes ? 1.0 : 0.0
564+
565+ // We use 'nodeIndex' because model.index from SortFilterModel is not
566+ // the one provided in the Toc model
567+ onClicked: sortedModel.parentNode = model.nodeIndex
568+
569+ Rectangle {
570+ anchors.fill: parent
571+ anchors.rightMargin: units.gu(-2)
572+ color: theme.palette.highlighted.background
573+ visible: parent.pressed
574+ }
575+
576+ VerticalDivider {
577+ anchors {
578+ left: parent.left
579+ top: parent.top
580+ bottom: parent.bottom
581+ }
582+ }
583+
584+ Icon {
585+ anchors.centerIn: parent
586+ anchors.horizontalCenterOffset: units.gu(1)
587+ width: units.gu(2); height: width
588+ name: "go-next"
589+ }
590+ }
591+>>>>>>> MERGE-SOURCE
592 }
593 }
594 }
595
596=== modified file 'src/app/qml/pdfView/PdfPresentation.qml'
597--- src/app/qml/pdfView/PdfPresentation.qml 2016-03-26 18:44:53 +0000
598+++ src/app/qml/pdfView/PdfPresentation.qml 2016-04-22 10:31:39 +0000
599@@ -17,14 +17,12 @@
600 import QtQuick 2.4
601 import Ubuntu.Components 1.3
602 import DocumentViewer 1.0
603-import DocumentViewer.PDF 1.0 as PDF
604+import DocumentViewer.PDF 2.0 as PDF
605
606 Page {
607- id: pdfPage
608+ id: pdfPres
609 property var poppler
610 property bool isPresentationMode: true
611- anchors.fill: parent
612- title: DocumentViewer.getFileBaseNameFromPath(poppler.path)
613 focus: true
614
615 header: PageHeader {
616@@ -41,15 +39,15 @@
617 title {
618 font.weight: Font.DemiBold
619 textSize: Label.Large
620- text: pdfPage.title
621- color: pdfPage.header.__styleInstance.foregroundColor
622+ text: DocumentViewer.getFileBaseNameFromPath(file.path)
623+ color: pdfPres.header.__styleInstance.foregroundColor
624 }
625 subtitle {
626 textSize: Label.Medium
627 // TRANSLATORS: the first argument (%1) refers to the page currently shown on the screen,
628 // while the second one (%2) refers to the total pages count.
629- text: i18n.tr("Page %1 of %2").arg(pdfView.currentIndex + 1).arg(pdfView.count)
630- color: pdfPage.header.__styleInstance.foregroundColor
631+ text: i18n.tr("Page %1 of %2").arg(view.currentIndex + 1).arg(poppler.pagesCount)
632+ color: pdfPres.header.__styleInstance.foregroundColor
633 }
634 }
635
636@@ -61,7 +59,7 @@
637 }
638
639 ListView {
640- id: pdfView
641+ id: view
642 anchors.fill: parent
643 focus: true
644
645@@ -73,25 +71,32 @@
646 boundsBehavior: Flickable.StopAtBounds
647 cacheBuffer: width
648
649- model: poppler
650- delegate: PdfViewDelegate {
651- presentationMode: true
652- width: pdfPage.width
653- height: pdfPage.height
654+ model: poppler.pagesCount
655+ delegate: Rectangle {
656+ width: pdfPres.width
657+ height: pdfPres.height
658 color: "black"
659- Component.onDestruction: window.releaseResources()
660+
661+ Image {
662+ anchors.fill: parent
663+ source: "image://poppler/page/" + model.index + "/" + poppler.rotation
664+ sourceSize.width: pdfPres.width
665+ sourceSize.height: pdfPres.height
666+ fillMode: Image.PreserveAspectFit //Image.Pad
667+ cache: false
668+ }
669 }
670- Component.onCompleted: pdfPage.forceActiveFocus()
671+ Component.onCompleted: pdfPres.forceActiveFocus()
672
673 MouseArea {
674 anchors.fill: parent
675- onDoubleClicked: pdfPage.header.visible = !pdfPage.header.visible
676+ onDoubleClicked: pdfPres.header.visible = !pdfPres.header.visible
677
678 // Hide mouse curson when there's no on-going mouse event
679 hoverEnabled: true
680 // Flickable can steal mouse handling from MouseArea,
681 // so check for any on-going dragging too
682- cursorShape: (showCursorTimer.running || pdfView.dragging) ? Qt.ArrowCursor : Qt.BlankCursor
683+ cursorShape: (showCursorTimer.running || view.dragging) ? Qt.ArrowCursor : Qt.BlankCursor
684 onPositionChanged: {
685 showCursorTimer.restart()
686 }
687@@ -104,15 +109,15 @@
688
689 Keys.onPressed: {
690 if (event.key == Qt.Key_Escape) { pageStack.pop(); return; }
691- if (event.key == Qt.Key_Home) { pdfView.positionViewAtBeginning(); return; }
692- if (event.key == Qt.Key_End) { pdfView.positionViewAtEnd(); return; }
693+ if (event.key == Qt.Key_Home) { view.positionViewAtBeginning(); return; }
694+ if (event.key == Qt.Key_End) { view.positionViewAtEnd(); return; }
695
696 if (event.key == Qt.Key_Right || event.key == Qt.Key_PageDown) {
697- pdfView.incrementCurrentIndex();
698+ view.incrementCurrentIndex();
699 return;
700 }
701 if (event.key == Qt.Key_Left || event.key == Qt.Key_PageUp) {
702- pdfView.decrementCurrentIndex();
703+ view.decrementCurrentIndex();
704 return;
705 }
706 }
707
708=== modified file 'src/app/qml/pdfView/PdfView.qml'
709--- src/app/qml/pdfView/PdfView.qml 2016-03-26 18:44:53 +0000
710+++ src/app/qml/pdfView/PdfView.qml 2016-04-22 10:31:39 +0000
711@@ -17,13 +17,14 @@
712 import QtQuick 2.4
713 import Ubuntu.Components 1.3
714 import Ubuntu.Components.Popups 1.3
715-import QtQuick.Layouts 1.1
716+import DocumentViewer.PDF 2.0 as PDF
717 import DocumentViewer 1.0
718-import DocumentViewer.PDF 1.0 as PDF
719
720 import "../common"
721 import "../common/utils.js" as Utils
722
723+// FIXME: After a resizing of the window, keep the current page visible.
724+
725 Page {
726 id: pdfPage
727 title: DocumentViewer.getFileBaseNameFromPath(file.path)
728@@ -31,19 +32,15 @@
729 header: PageHeader {
730 flickable: pdfView
731
732+<<<<<<< TREE
733 trailingActionBar.actions: [ goToPage, startPresentation, nightModeToggle, fileDetails ]
734+=======
735+ trailingActionBar.actions: [ goToPage, startPresentation, nightModeToggle, fileDetails, rotateRight, rotateLeft ]
736+>>>>>>> MERGE-SOURCE
737
738 contents: ListItemLayout {
739 anchors.centerIn: parent
740
741- ActivityIndicator {
742- SlotsLayout.position: SlotsLayout.Leading
743- SlotsLayout.overrideVerticalPositioning: true
744- y: (parent.height - height) * 0.5
745- running: pdfView.currentPageItem.status == Image.Loading || poppler.isLoading
746- visible: running
747- }
748-
749 title {
750 font.weight: Font.DemiBold
751 text: pdfPage.title
752@@ -53,7 +50,13 @@
753 textSize: Label.Small
754 // TRANSLATORS: the first argument (%1) refers to the page currently shown on the screen,
755 // while the second one (%2) refers to the total pages count.
756- text: i18n.tr("Page %1 of %2").arg(pdfView.currentPageIndex + 1).arg(pdfView.count)
757+ text: i18n.tr("Page %1 of %2").arg(pdfView.currentPageIndex + 1).arg(pdfView.pagesCount)
758+ }
759+
760+ ZoomSelector {
761+ SlotsLayout.position: SlotsLayout.Trailing
762+ view: pdfView
763+ visible: DocumentViewer.desktopMode || mainView.wideWindow
764 }
765 }
766 }
767@@ -62,6 +65,7 @@
768 // Component.onDestruction: mainView.nightModeEnabled = false
769
770 Keys.onPressed: {
771+<<<<<<< TREE
772 if (event.key == Qt.Key_F5) { pageStack.push(Qt.resolvedUrl("./PdfPresentation.qml"), {'poppler': poppler}); }
773 }
774 Rectangle {
775@@ -136,6 +140,152 @@
776 }
777 }
778
779+=======
780+ if (event.key == Qt.Key_F5) { pageStack.push(Qt.resolvedUrl("PdfPresentation.qml"), {'poppler': pdfView}); }
781+ }
782+
783+
784+ ScalingPinchArea {
785+ id: pinchArea
786+ objectName: "pinchArea"
787+ anchors.fill: parent
788+
789+ clip: true
790+
791+ enabled: !pdfView.moving
792+
793+ targetFlickable: pdfView
794+ onTotalScaleChanged: targetFlickable.updateContentSize(totalScale)
795+
796+ maximumZoom: pdfView.zoomSettings.maximumZoom
797+ minimumZoom: {
798+ if (DocumentViewer.desktopMode || mainView.wideWindow)
799+ return pdfView.zoomSettings.minimumZoom
800+
801+
802+ return pdfView.zoomSettings.valueAutomaticZoom
803+ }
804+
805+ Binding {
806+ when: !pinchArea.pinch.active
807+ target: pinchArea
808+ property: "zoomValue"
809+ value: pdfView.zoomSettings.zoomFactor
810+ }
811+
812+ Rectangle {
813+ // Since UITK 1.3, the MainView background is white.
814+ // We need to set a different color, otherwise pages
815+ // boundaries are not visible.
816+ anchors.fill: parent
817+ color: "#f5f5f5"
818+ }
819+
820+ ScrollView {
821+ anchors.fill: parent
822+
823+ PDF.Viewer {
824+ id: pdfView
825+ objectName: "pdfView"
826+ anchors.fill: parent
827+
828+ function updateContentSize(tgtScale) {
829+ zoomSettings.zoomFactor = tgtScale
830+ }
831+
832+ renderHints: PDF.Document.Antialiasing | PDF.Document.TextAntialiasing
833+
834+ linkHighlightColor: UbuntuColors.orange
835+
836+ spacing: units.gu(4)
837+
838+ documentPath: file.path
839+ clip: false
840+
841+ Component.onCompleted: {
842+ // WORKAROUND: Fix for wrong grid unit size
843+ flickDeceleration = 1500 * units.gridUnit / 8
844+ maximumFlickVelocity = 2500 * units.gridUnit / 8
845+
846+ var t = pdfView.document.documentInfo(PDF.Document.Title);
847+ if (t) {
848+ pdfPage.title = t
849+ }
850+ }
851+
852+ onErrorChanged: {
853+ // TODO: Error management
854+ console.log(pdfView.error)
855+
856+ switch(pdfView.error) {
857+ case PDF.Error.DocumentLocked:
858+ PopupUtils.open(Qt.resolvedUrl("DocumentLockedDialog.qml"), pdfPage)
859+ break;
860+ }
861+ }
862+
863+ // FIXME: TODO: Not the best management for this. See if/how it can be improved.
864+ property var hint
865+ onLinkHovered: {
866+ if (!hint) {
867+ var hintComponent = Qt.createComponent("LinkHint.qml");
868+ hint = hintComponent.createObject(pdfView, { "x": mouseX, "y": mouseY - units.gu(3), "linkInfo": linkInfo })
869+ }
870+ }
871+ onIsLinkHoveredChanged: {
872+ if (!isLinkHovered && hint)
873+ hint.destroy()
874+ }
875+
876+ onLinkClicked: {
877+ if (!isTouch) {
878+ if (linkInfo.url) {
879+ Qt.openUrlExternally(linkInfo.url)
880+ } else {
881+ pdfView.positionAtIndex(linkInfo.pageIndex, linkInfo.top, linkInfo.left)
882+ }
883+ }
884+ }
885+
886+ onLinkPressAndHold: {
887+ if (isTouch) {
888+ PopupUtils.open(Qt.resolvedUrl("OpenLinkDialog.qml"), pdfPage, { linkInfo: linkInfo })
889+ }
890+ }
891+
892+ ScalingMouseArea {
893+ id: mouseArea
894+ anchors.fill: parent
895+ enabled: !pdfView.moving
896+
897+ targetFlickable: pdfView
898+ onTotalScaleChanged: targetFlickable.updateContentSize(totalScale)
899+
900+ thresholdZoom: minimumZoom + (maximumZoom - minimumZoom) * 0.75
901+ maximumZoom: {
902+ if (DocumentViewer.desktopMode || mainView.wideWindow)
903+ return 3.0
904+
905+ return minimumZoom * 3
906+ }
907+ minimumZoom: {
908+ if (DocumentViewer.desktopMode || mainView.wideWindow)
909+ return pdfView.zoomSettings.minimumZoom
910+
911+
912+ return pdfView.zoomSettings.valueAutomaticZoom
913+ }
914+
915+ Binding {
916+ target: mouseArea
917+ property: "zoomValue"
918+ value: pdfView.zoomSettings.zoomFactor
919+ }
920+ }
921+ }
922+ }
923+ }
924+>>>>>>> MERGE-SOURCE
925
926 BottomEdge {
927 id: contentsBottomEdge
928@@ -166,7 +316,7 @@
929 children: contentsBottomEdge._realPage
930 }
931
932- enabled: poppler.tocModel.count > 0
933+ enabled: pdfView.document.tocModel.count > 0
934 visible: enabled
935
936 onCollapseCompleted: {
937@@ -192,21 +342,29 @@
938 PdfContentsPage {
939 width: contentsBottomEdge.width
940 height: contentsBottomEdge.height
941- enabled: contentsBottomEdge.status === BottomEdge.Committed
942- active: contentsBottomEdge.status === BottomEdge.Committed
943- visible: contentsBottomEdge.status !== BottomEdge.Hidden
944+ enabled: contentsBottomEdge.status == BottomEdge.Committed
945+ active: contentsBottomEdge.status == BottomEdge.Committed
946+ visible: contentsBottomEdge.status != BottomEdge.Hidden
947 }
948 }
949 }
950
951 /*** ACTIONS ***/
952+<<<<<<< TREE
953
954 Action {
955+=======
956+ Action {
957+>>>>>>> MERGE-SOURCE
958 id: goToPage
959 objectName:"gotopage"
960 iconName: "browser-tabs"
961 text: i18n.tr("Go to page...")
962+<<<<<<< TREE
963 onTriggered: PopupUtils.open(Qt.resolvedUrl("PdfViewGotoDialog.qml"), pdfPage)
964+=======
965+ onTriggered: PopupUtils.open(Qt.resolvedUrl("PdfViewGotoDialog.qml"))
966+>>>>>>> MERGE-SOURCE
967 }
968
969 Action {
970@@ -214,7 +372,7 @@
971 objectName:"presentationmode"
972 iconName: "slideshow"
973 text: i18n.tr("Presentation")
974- onTriggered: pageStack.push(Qt.resolvedUrl("./PdfPresentation.qml"), {'poppler': poppler})
975+ onTriggered: pageStack.push(Qt.resolvedUrl("PdfPresentation.qml"), { poppler: pdfView })
976 }
977
978 Action {
979@@ -231,4 +389,38 @@
980 iconName: "info"
981 onTriggered: pageStack.push(Qt.resolvedUrl("../common/DetailsPage.qml"))
982 }
983+
984+ Action {
985+ id: rotateRight
986+ text: i18n.tr("Rotate 90° right")
987+ iconName: "rotate-right"
988+ onTriggered: {
989+ var r = pdfView.rotation
990+ r += 1
991+
992+ if (r > 3)
993+ r = 0
994+ else if (r < 0)
995+ r = 3
996+
997+ pdfView.rotation = r
998+ }
999+ }
1000+
1001+ Action {
1002+ id: rotateLeft
1003+ text: i18n.tr("Rotate 90° left")
1004+ iconName: "rotate-left"
1005+ onTriggered: {
1006+ var r = pdfView.rotation
1007+ r -= 1
1008+
1009+ if (r > 3)
1010+ r = 0
1011+ else if (r < 0)
1012+ r = 3
1013+
1014+ pdfView.rotation = r
1015+ }
1016+ }
1017 }
1018
1019=== removed file 'src/app/qml/pdfView/PdfViewDelegate.qml'
1020--- src/app/qml/pdfView/PdfViewDelegate.qml 2016-01-29 12:23:24 +0000
1021+++ src/app/qml/pdfView/PdfViewDelegate.qml 1970-01-01 00:00:00 +0000
1022@@ -1,101 +0,0 @@
1023-/*
1024- * Copyright (C) 2013-2015 Canonical, Ltd.
1025- *
1026- * This program is free software; you can redistribute it and/or modify
1027- * it under the terms of the GNU General Public License as published by
1028- * the Free Software Foundation; version 3.
1029- *
1030- * This program is distributed in the hope that it will be useful,
1031- * but WITHOUT ANY WARRANTY; without even the implied warranty of
1032- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1033- * GNU General Public License for more details.
1034- *
1035- * You should have received a copy of the GNU General Public License
1036- * along with this program. If not, see <http://www.gnu.org/licenses/>.
1037- */
1038-import QtQuick 2.4
1039-import Ubuntu.Components 1.3
1040-
1041-Rectangle {
1042- id: pdfPage
1043-
1044- property int index: model.index
1045- property bool _previewFetched: false
1046- property bool presentationMode: false
1047-
1048- property alias status: pageImg.status
1049-
1050- width: parent.width
1051- height: width * (model.height / model.width)
1052- color: "#E6E6E6"
1053-
1054- // Preview page rendering. Used as placeholder while zooming the page.
1055- // We generate the low resolution preview from the texture of the PDF page,
1056- // so that we can keep page rendering as fast as possible.
1057- ShaderEffectSource {
1058- id: previewImg
1059- anchors.fill: parent
1060-
1061- // We cannot change its opacity or visibility, otherwise the texture will be refreshed,
1062- // even if live is false.
1063- live: false
1064- textureSize: Qt.size(256, 256 * (model.height / model.width))
1065- }
1066-
1067- Image {
1068- id: pageImg
1069- anchors.fill: parent
1070-
1071- cache: false
1072- source: "image://poppler" + (index % poppler.providersNumber) + "/page/" + index;
1073- sourceSize.width: pdfPage.width
1074- fillMode: Image.PreserveAspectFit
1075-
1076- onStatusChanged: {
1077- if (presentationMode)
1078- return;
1079-
1080- // This is supposed to run the first time PdfViewDelegate gets the page rendering.
1081- if (!_previewFetched) {
1082- if (status == Image.Ready) {
1083- previewImg.sourceItem = pageImg
1084- // Re-assign sourceItem property, so the texture is not updated when Image status changes.
1085- previewImg.sourceItem = pdfPage
1086- }
1087- }
1088- }
1089-
1090- // Request a new page rendering. The order, which pages are requested with, depends on the distance from the currentPage
1091- Timer {
1092- id: _zoomTimer
1093- interval: {
1094- var diff = Math.abs(pdfView.currentPageIndex - model.index)
1095- var prov = poppler.providersNumber * 0.5
1096-
1097- if (diff < prov)
1098- return 0
1099- else
1100- return (diff - prov) * 10
1101- }
1102-
1103- onTriggered: {
1104- pageImg.sourceSize.width = pdfPage.width;
1105- }
1106- }
1107- }
1108-
1109- // Page rendering depends on the width of PdfViewDelegate.
1110- // Because of this, we have multiple callings to ImageProvider while zooming.
1111- // Just avoid it.
1112- Connections {
1113- target: !presentationMode ? pinchy : null
1114-
1115- onPinchStarted: _zoomTimer.stop();
1116- onPinchUpdated: {
1117- // This ensures that page image is not reloaded when the maximumScale or minimumScale has already been reached.
1118- if ( !(_zoomHelper.scale >= 2.5 && pinch.scale > 1.0) && !(_zoomHelper.scale <= 1.0 && pinch.scale < 1.0) )
1119- pageImg.sourceSize.width = 0;
1120- }
1121- onPinchFinished: _zoomTimer.restart();
1122- }
1123-}
1124
1125=== modified file 'src/app/qml/pdfView/PdfViewGotoDialog.qml'
1126--- src/app/qml/pdfView/PdfViewGotoDialog.qml 2016-03-26 18:44:53 +0000
1127+++ src/app/qml/pdfView/PdfViewGotoDialog.qml 2016-04-22 10:31:39 +0000
1128@@ -24,7 +24,7 @@
1129 objectName:"PdfViewGotoDialog"
1130
1131 title: i18n.tr("Go to page")
1132- text: i18n.tr("Choose a page between 1 and %1").arg(pdfView.count)
1133+ text: i18n.tr("Choose a page between 1 and %1").arg(pdfView.pagesCount)
1134
1135 TextField {
1136 id: goToPageTextField
1137@@ -34,7 +34,7 @@
1138
1139 hasClearButton: true
1140 inputMethodHints: Qt.ImhFormattedNumbersOnly
1141- validator: IntValidator{ bottom: 1; top: pdfView.count }
1142+ validator: IntValidator{ bottom: 1; top: pdfView.pagesCount }
1143
1144 onAccepted: goToPage()
1145 Component.onCompleted: forceActiveFocus()
1146
1147=== added file 'src/app/qml/pdfView/ZoomSelector.qml'
1148--- src/app/qml/pdfView/ZoomSelector.qml 1970-01-01 00:00:00 +0000
1149+++ src/app/qml/pdfView/ZoomSelector.qml 2016-04-22 10:31:39 +0000
1150@@ -0,0 +1,191 @@
1151+/*
1152+ * Copyright (C) 2015 Stefano Verzegnassi
1153+ *
1154+ * This program is free software; you can redistribute it and/or modify
1155+ * it under the terms of the GNU General Public License as published by
1156+ * the Free Software Foundation; version 3.
1157+ *
1158+ * This program is distributed in the hope that it will be useful,
1159+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1160+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1161+ * GNU General Public License for more details.
1162+ *
1163+ * You should have received a copy of the GNU General Public License
1164+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1165+ */
1166+
1167+import QtQuick 2.4
1168+import Ubuntu.Components 1.3
1169+import QtQuick.Layouts 1.1
1170+import DocumentViewer.PDF 2.0 as PDF
1171+
1172+import "../common"
1173+
1174+TextFieldWithButton {
1175+ id: textField
1176+ anchors.verticalCenter: parent.verticalCenter
1177+ width: units.gu(12)
1178+
1179+ property var view
1180+
1181+ hasClearButton: true
1182+ inputMethodHints: Qt.ImhFormattedNumbersOnly
1183+ validator: IntValidator { bottom: 50; top: 400 }
1184+
1185+ onAccepted: {
1186+ textField.view.setZoom(parseInt(text) / 100)
1187+ focus = false
1188+ }
1189+
1190+ onHighlightedChanged: {
1191+ if (highlighted) {
1192+ text = parseInt(textField.view.zoomSettings.zoomFactor * 100)
1193+ } else text = ""
1194+ }
1195+
1196+ Label {
1197+ anchors.centerIn: parent
1198+ visible: !textField.highlighted
1199+ text: "%1%".arg(parseInt(textField.view.zoomSettings.zoomFactor*100))
1200+ }
1201+
1202+ popover: TextFieldButtonPopover {
1203+ id: zoomSelectorDialogue
1204+
1205+ /************************************
1206+ * Zoom in - Zoom out controls *
1207+ ************************************/
1208+
1209+ RowLayout {
1210+ anchors { left: parent.left; right: parent.right }
1211+ height: units.gu(4)
1212+ spacing: units.gu(1)
1213+
1214+ ListItem {
1215+ divider.visible: false
1216+ Layout.fillHeight: true
1217+ Layout.fillWidth: true
1218+
1219+ onClicked: textField.view.setZoom(textField.view.zoomSettings.zoomFactor + 0.1)
1220+
1221+ Icon {
1222+ width: units.gu(2); height: width
1223+ anchors.centerIn: parent
1224+ name: "zoom-in"
1225+ }
1226+ }
1227+
1228+ VerticalDivider {
1229+ Layout.fillHeight: true
1230+ Layout.preferredWidth: units.dp(2)
1231+ }
1232+
1233+ ListItem {
1234+ divider.visible: false
1235+ Layout.fillHeight: true
1236+ Layout.fillWidth: true
1237+
1238+ onClicked: textField.view.setZoom(textField.view.zoomSettings.zoomFactor - 0.1)
1239+
1240+ Icon {
1241+ width: units.gu(2); height: width
1242+ anchors.centerIn: parent
1243+ name: "zoom-out"
1244+ }
1245+ }
1246+ } // RowLayout
1247+
1248+ HorizontalDivider { anchors { left: parent.left; right: parent.right } }
1249+
1250+ /************************************
1251+ * Zoom modes controls *
1252+ ************************************/
1253+
1254+ Repeater {
1255+ id: zoomModesRepeater
1256+
1257+ function delegate_onClicked(mode) {
1258+ if (mode === PDF.Zoom.FitWidth)
1259+ textField.view.adjustZoomToWidth()
1260+
1261+ if (mode === PDF.Zoom.FitPage)
1262+ textField.view.adjustZoomToPage()
1263+
1264+ if (mode === PDF.Zoom.Automatic)
1265+ textField.view.adjustAutomaticZoom()
1266+ }
1267+
1268+ model: [
1269+ { text: i18n.tr("Fit width"), mode: PDF.Zoom.FitWidth },
1270+ { text: i18n.tr("Fit page"), mode: PDF.Zoom.FitPage },
1271+ { text: i18n.tr("Automatic"), mode: PDF.Zoom.Automatic }
1272+ ]
1273+
1274+ ListItem {
1275+ height: units.gu(4)
1276+ divider.visible: false
1277+
1278+ onClicked: {
1279+ zoomSelectorDialogue.close()
1280+ zoomModesRepeater.delegate_onClicked(modelData.mode)
1281+ }
1282+
1283+ /* UITK 1.3 specs: Two slot layout (A-B) */
1284+ ListItemLayout {
1285+ anchors.centerIn: parent
1286+
1287+ /* UITK 1.3 specs: Slot A */
1288+ title.text: modelData.text
1289+
1290+ /* UITK 1.3 specs: Slot B */
1291+ Icon {
1292+ SlotsLayout.position: SlotsLayout.Last
1293+ width: units.gu(2); height: width
1294+ name: "tick"
1295+ color: UbuntuColors.green
1296+ visible: textField.view.zoomSettings.zoomMode == modelData.mode
1297+ }
1298+ }
1299+ } // ListItem
1300+ }
1301+
1302+ HorizontalDivider { visible: zoomModesRepeater.visible; anchors { left: parent.left; right: parent.right } }
1303+
1304+ /************************************
1305+ * Default zoom values controls *
1306+ ************************************/
1307+
1308+ Repeater {
1309+ model: [
1310+ { text: "50%", value: 0.50 },
1311+ { text: "70%", value: 0.70 },
1312+ { text: "85%", value: 0.85 },
1313+ { text: "100%", value: 1.00 },
1314+ { text: "125%", value: 1.25 },
1315+ { text: "150%", value: 1.50 },
1316+ { text: "175%", value: 1.75 },
1317+ { text: "200%", value: 2.00 },
1318+ { text: "300%", value: 3.00 },
1319+ { text: "400%", value: 4.00 }
1320+ ]
1321+
1322+ ListItem {
1323+ divider.visible: false
1324+ height: units.gu(4)
1325+
1326+ onClicked: {
1327+ textField.view.setZoom(modelData.value)
1328+ zoomSelectorDialogue.close()
1329+ }
1330+
1331+ Label {
1332+ text: modelData.text
1333+ anchors {
1334+ left: parent.left; leftMargin: units.gu(1)
1335+ verticalCenter: parent.verticalCenter
1336+ }
1337+ }
1338+ }
1339+ } // Repeater
1340+ } // zoomSelectorDialogue
1341+} // textField
1342
1343=== modified file 'src/app/qml/ubuntu-docviewer-app.qml'
1344--- src/app/qml/ubuntu-docviewer-app.qml 2016-04-05 09:33:28 +0000
1345+++ src/app/qml/ubuntu-docviewer-app.qml 2016-04-22 10:31:39 +0000
1346@@ -115,9 +115,14 @@
1347 }
1348
1349 Component.onCompleted: {
1350+<<<<<<< TREE
1351 // WORKAROUND: Mouse detection is not included in the SDK yet
1352 QuickUtils.mouseAttached = true
1353
1354+=======
1355+ QuickUtils.mouseAttached = true;
1356+
1357+>>>>>>> MERGE-SOURCE
1358 pageStack.push(Qt.resolvedUrl("documentPage/DocumentPage.qml"));
1359
1360 // Open the document, if one has been specified.
1361
1362=== modified file 'src/app/renderengine.cpp'
1363--- src/app/renderengine.cpp 2016-01-17 20:33:06 +0000
1364+++ src/app/renderengine.cpp 2016-04-22 10:31:39 +0000
1365@@ -18,6 +18,7 @@
1366
1367 void RenderEngine::enqueueTask(AbstractRenderTask *task)
1368 {
1369+ dequeueTask(task->id()); // TODO Rethink.
1370 m_queue.enqueue(task);
1371 doNextTask();
1372 }
1373
1374=== modified file 'src/app/renderengine.h'
1375--- src/app/renderengine.h 2016-01-17 16:17:02 +0000
1376+++ src/app/renderengine.h 2016-04-22 10:31:39 +0000
1377@@ -27,7 +27,6 @@
1378 void dequeueTask(int id);
1379
1380 public:
1381-
1382 static RenderEngine* instance() {
1383 if(!s_instance)
1384 s_instance = new RenderEngine();
1385
1386=== modified file 'src/app/rendertask.h'
1387--- src/app/rendertask.h 2016-01-17 16:25:30 +0000
1388+++ src/app/rendertask.h 2016-04-22 10:31:39 +0000
1389@@ -13,9 +13,10 @@
1390 enum RenderTaskType
1391 {
1392 RttUnknown = 0x0,
1393- RttTile = 0x1,
1394- RttImpressThumbnail = 0x2,
1395- RttPdfPage = 0x3
1396+ RttLibreofficeTile = 0x1,
1397+ RttLibreofficeThumbnail = 0x2,
1398+ RttPdfTile = 0x3,
1399+ RttPdfThumbnail = 0x4
1400 };
1401
1402 class AbstractRenderTask
1403
1404=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/lopartsimageresponse.cpp'
1405--- src/plugin/libreofficetoolkit-qml-plugin/lopartsimageresponse.cpp 2016-01-24 20:27:40 +0000
1406+++ src/plugin/libreofficetoolkit-qml-plugin/lopartsimageresponse.cpp 2016-04-22 10:31:39 +0000
1407@@ -32,7 +32,7 @@
1408
1409 connect(RenderEngine::instance(), &RenderEngine::taskRenderFinished,
1410 this, [&](AbstractRenderTask *task, QImage img) {
1411- if (m_taskId == task->id() && task->type() == RttImpressThumbnail) {
1412+ if (m_taskId == task->id() && task->type() == RttLibreofficeThumbnail) {
1413 m_image = img;
1414 Q_EMIT finished();
1415 }
1416
1417=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/lorendertask.cpp'
1418--- src/plugin/libreofficetoolkit-qml-plugin/lorendertask.cpp 2016-01-17 17:42:34 +0000
1419+++ src/plugin/libreofficetoolkit-qml-plugin/lorendertask.cpp 2016-04-22 10:31:39 +0000
1420@@ -3,7 +3,7 @@
1421 bool LoRenderTask::canBeRunInParallel(AbstractRenderTask* prevTask)
1422 {
1423 Q_ASSERT(prevTask != nullptr);
1424- if (prevTask->type() == RttTile || prevTask->type() == RttImpressThumbnail) {
1425+ if (prevTask->type() == RttLibreofficeTile || prevTask->type() == RttLibreofficeThumbnail) {
1426 LoRenderTask* loTask = static_cast<LoRenderTask*>(prevTask);
1427
1428 // Another document or the same part in the same document can be run parallel.
1429
1430=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/lorendertask.h'
1431--- src/plugin/libreofficetoolkit-qml-plugin/lorendertask.h 2016-01-17 17:42:34 +0000
1432+++ src/plugin/libreofficetoolkit-qml-plugin/lorendertask.h 2016-04-22 10:31:39 +0000
1433@@ -30,7 +30,7 @@
1434 class TileRenderTask : public LoRenderTask
1435 {
1436 public:
1437- virtual RenderTaskType type() { return RttTile; }
1438+ virtual RenderTaskType type() { return RttLibreofficeTile; }
1439 virtual QImage doWork();
1440
1441 QRect area() { return m_area; }
1442@@ -45,7 +45,7 @@
1443 class ThumbnailRenderTask : public LoRenderTask
1444 {
1445 public:
1446- virtual RenderTaskType type() { return RttImpressThumbnail; }
1447+ virtual RenderTaskType type() { return RttLibreofficeThumbnail; }
1448 virtual QImage doWork();
1449
1450 QSize size() const { return m_size; }
1451
1452=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/loview.cpp'
1453--- src/plugin/libreofficetoolkit-qml-plugin/loview.cpp 2016-02-05 22:42:13 +0000
1454+++ src/plugin/libreofficetoolkit-qml-plugin/loview.cpp 2016-04-22 10:31:39 +0000
1455@@ -343,7 +343,7 @@
1456
1457 void LOView::slotTaskRenderFinished(AbstractRenderTask* task, QImage img)
1458 {
1459- if (task->type() == RttTile) {
1460+ if (task->type() == RttLibreofficeTile) {
1461 int id = task->id();
1462
1463 for (auto i = m_tiles.begin(); i != m_tiles.end(); ++i) {
1464
1465=== modified file 'src/plugin/poppler-qml-plugin/CMakeLists.txt'
1466--- src/plugin/poppler-qml-plugin/CMakeLists.txt 2015-10-21 13:16:12 +0000
1467+++ src/plugin/poppler-qml-plugin/CMakeLists.txt 2016-04-22 10:31:39 +0000
1468@@ -8,24 +8,43 @@
1469 find_package(Qt5Concurrent)
1470
1471 include_directories(
1472- ${CMAKE_CURRENT_SOURCE_DIR}
1473- ${CMAKE_CURRENT_BINARY_DIR}
1474- ${Qt5Quick_PRIVATE_INCLUDE_DIRS}
1475- ${Qt5Qml_PRIVATE_INCLUDE_DIRS}
1476-)
1477+ ${CMAKE_CURRENT_SOURCE_DIR}
1478+ ${CMAKE_CURRENT_BINARY_DIR}
1479+)
1480+
1481+file(GLOB_RECURSE QML_SRCS
1482+ qml/*.qml
1483+ qml/*.js
1484+)
1485+
1486
1487 #add the sources to compile
1488 set(popplerqmlplugin_SRCS
1489 plugin.cpp
1490 pdfdocument.cpp
1491- pdfimageprovider.cpp
1492- pdfitem.cpp
1493 verticalview.cpp
1494 pdftocmodel.cpp
1495+ pdfrendertask.cpp
1496+ sgtileitem.cpp
1497+ pagedecoration.cpp
1498+ pageoverlay.cpp
1499+ pdfzoom.cpp
1500+ ucunits.cpp
1501+ touchdetectionarea.cpp
1502+ pdfimageprovider.cpp
1503+ pdfimageresponse.cpp
1504+ ${QML_SRCS}
1505+)
1506+
1507+set(popplerqmlplugin_HDRS
1508+ pdferror.h
1509+ twips.h
1510+ config.h
1511 )
1512
1513 add_library(popplerqmlplugin MODULE
1514 ${popplerqmlplugin_SRCS}
1515+ ${popplerqmlplugin_HDRS}
1516 )
1517
1518 target_link_libraries(popplerqmlplugin poppler-qt5)
1519@@ -38,9 +57,11 @@
1520 COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/../${PLUGIN_DIR}
1521 COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/qmldir ${CMAKE_CURRENT_BINARY_DIR}/../${PLUGIN_DIR}
1522 COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:popplerqmlplugin> ${CMAKE_CURRENT_BINARY_DIR}/../${PLUGIN_DIR}
1523+ COMMAND ${CMAKE_COMMAND} -E copy ${QML_SRCS} ${CMAKE_CURRENT_BINARY_DIR}/../${PLUGIN_DIR}
1524 )
1525 endif(NOT "${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}")
1526
1527 # Install plugin file
1528 install(TARGETS popplerqmlplugin DESTINATION ${QT_IMPORTS_DIR}/${PLUGIN_DIR})
1529 install(FILES qmldir DESTINATION ${QT_IMPORTS_DIR}/${PLUGIN_DIR})
1530+install(FILES ${QML_SRCS} DESTINATION ${QT_IMPORTS_DIR}/${PLUGIN_DIR})
1531
1532=== added file 'src/plugin/poppler-qml-plugin/config.h'
1533--- src/plugin/poppler-qml-plugin/config.h 1970-01-01 00:00:00 +0000
1534+++ src/plugin/poppler-qml-plugin/config.h 2016-04-22 10:31:39 +0000
1535@@ -0,0 +1,13 @@
1536+#ifndef CONFIG_H
1537+#define CONFIG_H
1538+
1539+// Uncomment it if you want to see tiles boundaries
1540+//#define DEBUG_SHOW_TILE_BORDER
1541+
1542+// Uncomment for benchmarking tile rendering performance
1543+//#define DEBUG_TILE_BENCHMARK
1544+
1545+// Uncomment if you want more verbose application output
1546+//#define DEBUG_VERBOSE
1547+
1548+#endif // CONFIG_H
1549
1550=== added file 'src/plugin/poppler-qml-plugin/pagedecoration.cpp'
1551--- src/plugin/poppler-qml-plugin/pagedecoration.cpp 1970-01-01 00:00:00 +0000
1552+++ src/plugin/poppler-qml-plugin/pagedecoration.cpp 2016-04-22 10:31:39 +0000
1553@@ -0,0 +1,48 @@
1554+#include "pagedecoration.h"
1555+
1556+#include <QDebug>
1557+#include <QSGSimpleRectNode>
1558+
1559+#define PAGEDECORATION_BORDER_WIDTH 1
1560+
1561+PageDecoration::PageDecoration(QQuickItem *parent)
1562+ : QQuickItem(parent)
1563+{
1564+ setFlag(ItemHasContents, true);
1565+}
1566+
1567+PageDecoration::~PageDecoration()
1568+{ }
1569+
1570+QSGNode *PageDecoration::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *)
1571+{
1572+ QSGSimpleRectNode* node = static_cast<QSGSimpleRectNode*>(oldNode);
1573+ QQuickWindow* wnd = window();
1574+
1575+ QRectF outterRect = boundingRect().adjusted(
1576+ PAGEDECORATION_BORDER_WIDTH * -1,
1577+ PAGEDECORATION_BORDER_WIDTH * -1,
1578+ PAGEDECORATION_BORDER_WIDTH,
1579+ PAGEDECORATION_BORDER_WIDTH);
1580+
1581+ if (!node && wnd) {
1582+ node = new QSGSimpleRectNode();
1583+ node->setColor(QColor::fromRgb(0, 0, 0, 12));
1584+
1585+ auto whitePaperNode = new QSGSimpleRectNode();
1586+ whitePaperNode->setColor(Qt::white);
1587+ whitePaperNode->setRect(boundingRect());
1588+
1589+ node->appendChildNode(whitePaperNode);
1590+ }
1591+
1592+ node->setRect(outterRect);
1593+
1594+ return node;
1595+}
1596+
1597+void PageDecoration::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
1598+{
1599+ QQuickItem::geometryChanged(newGeometry, oldGeometry);
1600+ update();
1601+}
1602
1603=== added file 'src/plugin/poppler-qml-plugin/pagedecoration.h'
1604--- src/plugin/poppler-qml-plugin/pagedecoration.h 1970-01-01 00:00:00 +0000
1605+++ src/plugin/poppler-qml-plugin/pagedecoration.h 2016-04-22 10:31:39 +0000
1606@@ -0,0 +1,19 @@
1607+#ifndef PAGEDECORATION_H
1608+#define PAGEDECORATION_H
1609+
1610+#include <QQuickItem>
1611+
1612+class PageDecoration: public QQuickItem
1613+{
1614+ Q_OBJECT
1615+
1616+public:
1617+ PageDecoration(QQuickItem *parent);
1618+ ~PageDecoration();
1619+
1620+protected:
1621+ virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
1622+ virtual void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry);
1623+
1624+};
1625+#endif // PAGEDECORATION_H
1626
1627=== added file 'src/plugin/poppler-qml-plugin/pageoverlay.cpp'
1628--- src/plugin/poppler-qml-plugin/pageoverlay.cpp 1970-01-01 00:00:00 +0000
1629+++ src/plugin/poppler-qml-plugin/pageoverlay.cpp 2016-04-22 10:31:39 +0000
1630@@ -0,0 +1,172 @@
1631+#include "pageoverlay.h"
1632+#include "pdfdocument.h"
1633+#include "verticalview.h"
1634+
1635+#include <QDebug>
1636+
1637+// scenegraph painting
1638+#include <QSGNode>
1639+#include <QSGSimpleRectNode>
1640+
1641+// mouse cursor
1642+//#include <QCursor>
1643+
1644+// Poppler Qt5
1645+#include <poppler/qt5/poppler-qt5.h>
1646+
1647+PageOverlay::PageOverlay(VerticalView *view, int pageIndex, QQuickItem *parent)
1648+ : QQuickItem(parent)
1649+ , m_view(view)
1650+ , m_pageIndex(pageIndex)
1651+{
1652+ setFlag(ItemHasContents, true);
1653+ //setAcceptHoverEvents(true);
1654+
1655+ connect(m_view, &VerticalView::showLinkHighlightChanged, this, &PageOverlay::update);
1656+ connect(m_view, &VerticalView::linkHighlightColorChanged, this, &PageOverlay::update);
1657+}
1658+
1659+PageOverlay::~PageOverlay()
1660+{ }
1661+
1662+QSGNode *PageOverlay::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *)
1663+{
1664+ QSGNode* node = static_cast<QSGNode*>(oldNode);
1665+ QQuickWindow* wnd = window();
1666+
1667+ if (!node && wnd) {
1668+ node = new QSGNode();
1669+ }
1670+
1671+ if (m_view->showLinkHighlight() && boundingRect().isValid()) {
1672+ QList<Poppler::Link *> links = m_view->document()->pageLinks(m_pageIndex);
1673+
1674+ Q_FOREACH(Poppler::Link *link, links) {
1675+ if (link->linkType() == Poppler::Link::Goto ||
1676+ link->linkType() == Poppler::Link::Browse) {
1677+
1678+ bool rotatedBy90 = (m_view->rotation() == PdfRotation::Rotate90 ||
1679+ m_view->rotation() == PdfRotation::Rotate270);
1680+
1681+ QRectF linkRect;
1682+ int x1 = (!rotatedBy90 ? width() : height()) * link->linkArea().left();
1683+ int y1 = (!rotatedBy90 ? height() : width()) * link->linkArea().top();
1684+ int x2 = (!rotatedBy90 ? width() : height()) * link->linkArea().right();
1685+ int y2 = (!rotatedBy90 ? height() : width()) * link->linkArea().bottom();
1686+ int w = this->width();
1687+ int h = this->height();
1688+
1689+ switch (m_view->rotation()) {
1690+ case PdfRotation::Rotate0:
1691+ linkRect.setLeft ( x1 );
1692+ linkRect.setTop ( y1 );
1693+ linkRect.setRight ( x2 );
1694+ linkRect.setBottom ( y2 );
1695+ break;
1696+ case PdfRotation::Rotate90:
1697+ linkRect.setLeft ( w - y2 );
1698+ linkRect.setTop ( x1 );
1699+ linkRect.setRight ( w - y1 );
1700+ linkRect.setBottom ( x2 );
1701+ break;
1702+ case PdfRotation::Rotate180:
1703+ linkRect.setLeft ( w - x2 );
1704+ linkRect.setTop ( h - y2 );
1705+ linkRect.setRight ( w - x1 );
1706+ linkRect.setBottom ( h - y1 );
1707+ break;
1708+ case PdfRotation::Rotate270:
1709+ linkRect.setLeft ( y1 );
1710+ linkRect.setTop ( h - x2 );
1711+ linkRect.setRight ( y2 );
1712+ linkRect.setBottom ( h - x1 );
1713+ break;
1714+ }
1715+
1716+ auto linkNode = new QSGSimpleRectNode();
1717+
1718+ const QColor &linkColor = m_view->linkHighlightColor();
1719+ linkNode->setColor(QColor::fromRgb(linkColor.red(), linkColor.green(), linkColor.blue(), 8));
1720+ linkNode->setRect(linkRect);
1721+
1722+ drawLinkBorders(linkNode);
1723+
1724+ node->appendChildNode(linkNode);
1725+ }
1726+ }
1727+ }
1728+
1729+ return node;
1730+}
1731+
1732+void PageOverlay::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
1733+{
1734+ QQuickItem::geometryChanged(newGeometry, oldGeometry);
1735+ update();
1736+}
1737+
1738+/*
1739+ * QML MouseArea overwrite any attempt to set this from C++
1740+ * Disable this code and do it through QML (see Viewer.qml).
1741+ * TODO: Check performance of the QML code that handles this.
1742+ *
1743+void PageOverlay::hoverMoveEvent(QHoverEvent *event)
1744+{
1745+ // We only handle what's strictly necessary for changing the cursor aspect.
1746+ // Any other mouse event is handled directly through QML.
1747+ const QPointF &curPos = event->posF();
1748+
1749+ QList<Poppler::Link *> links = m_view->document()->pageLinks(m_pageIndex);
1750+ Q_FOREACH (Poppler::Link *link, links) {
1751+ QRectF linkRect(link->linkArea().x() * this->width(),
1752+ link->linkArea().y() * this->height(),
1753+ link->linkArea().width() * this->width(),
1754+ link->linkArea().height() * this->height());
1755+
1756+ if (linkRect.contains(curPos)) {
1757+ setCursor(QCursor(Qt::PointingHandCursor));
1758+ return;
1759+ }
1760+ }
1761+
1762+ // Not hovering a link. Restore default cursor.
1763+ unsetCursor();
1764+}
1765+*/
1766+
1767+void PageOverlay::drawLinkBorders(QSGSimpleRectNode *parentNode)
1768+{
1769+ auto node = parentNode;
1770+
1771+ auto linkBorderGeometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 8);
1772+ linkBorderGeometry->setDrawingMode(GL_LINES);
1773+ linkBorderGeometry->setLineWidth(1);
1774+
1775+ QSGGeometry::Point2D* vertex = linkBorderGeometry->vertexDataAsPoint2D();
1776+ vertex[0].set(node->rect().left(), node->rect().top());
1777+ vertex[1].set(node->rect().left(), node->rect().bottom());
1778+
1779+ vertex[2].set(node->rect().right(), node->rect().top());
1780+ vertex[3].set(node->rect().right(), node->rect().bottom());
1781+
1782+ vertex[4].set(vertex[0].x, vertex[0].y);
1783+ vertex[5].set(vertex[2].x, vertex[2].y);
1784+
1785+ vertex[6].set(vertex[1].x, vertex[1].y);
1786+ vertex[7].set(vertex[3].x, vertex[3].y);
1787+
1788+ auto linkBorderMaterial = new QSGFlatColorMaterial;
1789+
1790+ const QColor &linkColor = m_view->linkHighlightColor();
1791+ linkBorderMaterial->setColor(QColor::fromRgb(linkColor.red(), linkColor.green(), linkColor.blue(), 64));
1792+
1793+ auto linkBorderNode = new QSGGeometryNode;
1794+
1795+ linkBorderNode->setGeometry(linkBorderGeometry);
1796+ linkBorderNode->setFlag(QSGNode::OwnsGeometry);
1797+
1798+ linkBorderNode->setMaterial(linkBorderMaterial);
1799+ linkBorderNode->setFlag(QSGNode::OwnsMaterial);
1800+
1801+ node->appendChildNode(linkBorderNode);
1802+}
1803
1804=== added file 'src/plugin/poppler-qml-plugin/pageoverlay.h'
1805--- src/plugin/poppler-qml-plugin/pageoverlay.h 1970-01-01 00:00:00 +0000
1806+++ src/plugin/poppler-qml-plugin/pageoverlay.h 2016-04-22 10:31:39 +0000
1807@@ -0,0 +1,35 @@
1808+#ifndef PAGEOVERLAY_H
1809+#define PAGEOVERLAY_H
1810+
1811+#include <QQuickItem>
1812+
1813+class VerticalView;
1814+class QSGSimpleRectNode;
1815+
1816+class PageOverlay: public QQuickItem
1817+{
1818+ Q_OBJECT
1819+
1820+public:
1821+ PageOverlay(VerticalView *view, int pageIndex, QQuickItem *parent);
1822+ ~PageOverlay();
1823+
1824+ bool showLinkHighlight() const;
1825+ void setShowLinkHighlight(bool show);
1826+
1827+ QColor linkHighlightColor() const;
1828+ void setLinkHightlightColor(const QColor &color);
1829+
1830+protected:
1831+ virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
1832+ virtual void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry);
1833+ //virtual void hoverMoveEvent(QHoverEvent * event);
1834+
1835+private:
1836+ void drawLinkBorders(QSGSimpleRectNode *parentNode);
1837+
1838+private:
1839+ VerticalView* m_view;
1840+ int m_pageIndex;
1841+};
1842+#endif // PAGEOVERLAY_H
1843
1844=== modified file 'src/plugin/poppler-qml-plugin/pdfdocument.cpp'
1845--- src/plugin/poppler-qml-plugin/pdfdocument.cpp 2015-07-14 15:43:11 +0000
1846+++ src/plugin/poppler-qml-plugin/pdfdocument.cpp 2016-04-22 10:31:39 +0000
1847@@ -1,24 +1,5 @@
1848-/*
1849- * Copyright (C) 2013-2015 Canonical, Ltd.
1850- *
1851- * This program is free software: you can redistribute it and/or modify it
1852- * under the terms of the GNU General Public License version 3, as published
1853- * by the Free Software Foundation.
1854- *
1855- * This program is distributed in the hope that it will be useful, but
1856- * WITHOUT ANY WARRANTY; without even the implied warranties of
1857- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1858- * PURPOSE. See the GNU General Public License for more details.
1859- *
1860- * You should have received a copy of the GNU General Public License along
1861- * with this program. If not, see <http://www.gnu.org/licenses/>.
1862- *
1863- * Authors: Anthony Granger <grangeranthony@gmail.com>
1864- * Stefano Verzegnassi <stefano92.100@gmail.com>
1865- */
1866-
1867 #include "pdfdocument.h"
1868-#include "pdfimageprovider.h"
1869+#include "twips.h"
1870
1871 #include <poppler/qt5/poppler-qt5.h>
1872 #include <QDebug>
1873@@ -27,47 +8,18 @@
1874
1875 #include <QtConcurrent/QtConcurrent>
1876
1877-PdfDocument::PdfDocument(QAbstractListModel *parent):
1878- QAbstractListModel(parent)
1879- , m_path("")
1880- , m_providersNumber(1)
1881+// TODO: Add QQuickAsyncImageProvider for thumbnails
1882+
1883+PdfDocument::PdfDocument():
1884+ m_path("")
1885 , m_tocModel(nullptr)
1886-{
1887- qRegisterMetaType<PdfPagesList>("PdfPagesList");
1888-}
1889-
1890-QHash<int, QByteArray> PdfDocument::roleNames() const
1891-{
1892- QHash<int, QByteArray> roles;
1893- roles[WidthRole] = "width";
1894- roles[HeightRole] = "height";
1895- return roles;
1896-}
1897-
1898-int PdfDocument::rowCount(const QModelIndex & parent) const
1899-{
1900- Q_UNUSED(parent)
1901- return m_pages.count();
1902-}
1903-
1904-QVariant PdfDocument::data(const QModelIndex & index, int role) const
1905-{
1906- if (index.row() < 0 || index.row() > m_pages.count())
1907- return QVariant();
1908-
1909- const PdfItem &pdfItem = m_pages.at(index.row());
1910-
1911- switch (role) {
1912- case WidthRole:
1913- return pdfItem.width();
1914- case HeightRole:
1915- return pdfItem.height();
1916- default:
1917- return 0;
1918- }
1919-}
1920-
1921-void PdfDocument::setPath(QString &pathName)
1922+ , m_error(PopplerError::NoError)
1923+ , m_renderHints(0)
1924+{
1925+ connect(this, &PdfDocument::renderHintsChanged, this, &PdfDocument::updateRenderHints);
1926+}
1927+
1928+void PdfDocument::setPath(const QString &pathName)
1929 {
1930 if (pathName.isEmpty())
1931 return;
1932@@ -75,131 +27,277 @@
1933 m_path = pathName;
1934 Q_EMIT pathChanged();
1935
1936- if (!loadDocument(m_path))
1937- return;
1938-
1939- // Init toc model
1940- m_tocModel = new PdfTocModel;
1941- m_tocModel->setDocument(m_document);
1942- Q_EMIT tocModelChanged();
1943-
1944- loadPages();
1945- loadProvider();
1946-}
1947-
1948-bool PdfDocument::loadDocument(QString &pathName)
1949-{
1950- qDebug() << "Loading document...";
1951-
1952- if (pathName.isEmpty()) {
1953- qDebug() << "Can't load the document, path is empty.";
1954- return false;
1955- }
1956-
1957- m_document = Poppler::Document::load(pathName);
1958-
1959- if (!m_document || m_document->isLocked()) {
1960- qDebug() << "ERROR : Can't open the document located at " + pathName;
1961- Q_EMIT error("Can't open the document located at " + pathName);
1962-
1963- delete m_document;
1964- return false;
1965- }
1966-
1967- qDebug() << "Document loaded successfully !";
1968-
1969- m_document->setRenderHint(Poppler::Document::Antialiasing, true);
1970- m_document->setRenderHint(Poppler::Document::TextAntialiasing, true);
1971-
1972- return true;
1973+ loadDocument();
1974+}
1975+
1976+bool PdfDocument::isLocked()
1977+{
1978+ if (!m_popDocument)
1979+ return true;
1980+
1981+ return m_popDocument.data()->isLocked();
1982+}
1983+
1984+int PdfDocument::pageCount()
1985+{
1986+ if (!m_popDocument)
1987+ return 0;
1988+
1989+ return m_popDocument.data()->numPages();
1990 }
1991
1992 QDateTime PdfDocument::getDocumentDate(QString data)
1993 {
1994- if (!m_document)
1995+ if (!m_popDocument)
1996 return QDateTime();
1997
1998 if (data == "CreationDate" || data == "ModDate")
1999- return m_document->date(data);
2000+ return m_popDocument->date(data);
2001 else
2002 return QDateTime();
2003 }
2004
2005 QString PdfDocument::getDocumentInfo(QString data)
2006 {
2007- if (!m_document)
2008+ if (!m_popDocument)
2009 return QString("");
2010
2011 if (data == "Title" || data == "Subject" || data == "Author" || data == "Creator" || data == "Producer")
2012- return m_document->info(data);
2013+ return m_popDocument->info(data);
2014 else
2015 return QString("");
2016 }
2017
2018-bool PdfDocument::loadPages()
2019-{
2020- qDebug() << "Populating model...";
2021-
2022- m_pages.clear();
2023-
2024- if (!m_document)
2025- return false;
2026-
2027- Poppler::Document* document = m_document;
2028- QtConcurrent::run( [=] {
2029- PdfPagesList pages;
2030-
2031- for( int i = 0; i < document->numPages(); ++i )
2032- pages.append(document->page(i));
2033-
2034- QMetaObject::invokeMethod(this, "_q_populate", Qt::QueuedConnection, Q_ARG(PdfPagesList, pages));
2035- });
2036+QVariant PdfDocument::documentInfo(PdfDocument::DocumentInfo info)
2037+{
2038+ if (!m_popDocument)
2039+ return QVariant();
2040+
2041+ switch (info) {
2042+ case Title:
2043+ return m_popDocument->info("Title");
2044+ case Subject:
2045+ return m_popDocument->info("Subject");
2046+ case Author:
2047+ return m_popDocument->info("Author");
2048+ case Creator:
2049+ return m_popDocument->info("Creator");
2050+ case Producer:
2051+ return m_popDocument->info("Producer");
2052+ case CreationDate:
2053+ return m_popDocument->date("CreationDate");
2054+ case ModifiedDate:
2055+ return m_popDocument->date("ModDate");
2056+ default:
2057+ return QVariant();
2058+ }
2059+}
2060+
2061+bool PdfDocument::unlock(const QString &ownerPassword, const QString &userPassword)
2062+{
2063+ bool result = false;
2064+
2065+ m_popDocument.data()->unlock(ownerPassword.toLatin1(), userPassword.toLatin1());
2066+
2067+ // It seems that Poppler::Document::unlock() returns true even with the wrong password :/
2068+ result = !isLocked();
2069+
2070+ if (result) {
2071+ completeIntialization();
2072+ }
2073+
2074+ return result;
2075+}
2076+
2077+QObject *PdfDocument::tocModel() const
2078+{
2079+ return m_tocModel;
2080+}
2081+
2082+QSize PdfDocument::pageSize(int index) const
2083+{
2084+ QSize s;
2085+
2086+ if (m_popDocument) {
2087+ Poppler::Page* page = m_popDocument.data()->page(index);
2088+
2089+ s = page->pageSize();
2090+
2091+ delete page;
2092+ }
2093+
2094+ return s;
2095+}
2096+
2097+PopplerError::Error PdfDocument::error() const
2098+{
2099+ return m_error;
2100+}
2101+
2102+PdfDocument::RenderHints PdfDocument::renderHints() const
2103+{
2104+ return m_renderHints;
2105+}
2106+
2107+void PdfDocument::setRenderHints(const RenderHints hints)
2108+{
2109+ if (m_renderHints == hints)
2110+ return;
2111+
2112+ m_renderHints = hints;
2113+ Q_EMIT renderHintsChanged();
2114+}
2115+
2116+void PdfDocument::updateRenderHints()
2117+{
2118+ if (!m_popDocument)
2119+ return;
2120+
2121+ Poppler::Document* doc = m_popDocument.data();
2122+
2123+ doc->setRenderHint(Poppler::Document::RenderHint::Antialiasing, m_renderHints & PdfDocument::Antialiasing);
2124+ doc->setRenderHint(Poppler::Document::RenderHint::TextAntialiasing, m_renderHints & PdfDocument::TextAntialiasing);
2125+ doc->setRenderHint(Poppler::Document::RenderHint::TextHinting, m_renderHints & PdfDocument::TextHinting);
2126+ doc->setRenderHint(Poppler::Document::RenderHint::TextSlightHinting, m_renderHints & PdfDocument::TextSlightHinting);
2127+ doc->setRenderHint(Poppler::Document::RenderHint::OverprintPreview, m_renderHints & PdfDocument::OverprintPreview);
2128+ doc->setRenderHint(Poppler::Document::RenderHint::ThinLineSolid, m_renderHints & PdfDocument::ThinLineSolid);
2129+ doc->setRenderHint(Poppler::Document::RenderHint::ThinLineShape, m_renderHints & PdfDocument::ThinLineShape);
2130+}
2131+
2132+QImage PdfDocument::paintTile(int pageIndex, const qreal &zoom, QRect rect, PdfRotation::Rotation rotate) const
2133+{
2134+ QImage result;
2135+
2136+ if (m_popDocument) {
2137+ if (pageIndex >= 0 || pageIndex < m_popDocument.data()->numPages()) {
2138+ Poppler::Page* page = m_popDocument.data()->page(pageIndex);
2139+
2140+ result = page->renderToImage(
2141+ DEFAULT_DPI * Twips::getUnitsRatio() * zoom,
2142+ DEFAULT_DPI * Twips::getUnitsRatio() * zoom,
2143+ rect.x(), rect.y(), rect.width(), rect.height(),
2144+ Poppler::Page::Rotation(rotate));
2145+
2146+ delete page;
2147+ }
2148+ }
2149+
2150+ return result;
2151+}
2152+
2153+//FIXME: Not perfect!
2154+QImage PdfDocument::paintThumbnail(int pageIndex, const QSize &size, PdfRotation::Rotation rotate) const
2155+{
2156+ QImage result;
2157+
2158+ if (m_popDocument) {
2159+ if (pageIndex >= 0 || pageIndex < m_popDocument.data()->numPages()) {
2160+ Poppler::Page* page = m_popDocument.data()->page(pageIndex);
2161+
2162+ QSize resultSize;
2163+ QSize pageSize = page->pageSize();
2164+
2165+ if (pageSize.width() > pageSize.height()) {
2166+ resultSize.setWidth(size.width());
2167+ resultSize.setHeight(size.width() * pageSize.height() / pageSize.width());
2168+ } else {
2169+ resultSize.setHeight(size.height());
2170+ resultSize.setWidth(size.height() * pageSize.width() / pageSize.height());
2171+ }
2172+
2173+ result = page->renderToImage(
2174+ resultSize.width() / (pageSize.width() / 72),
2175+ resultSize.height() / (pageSize.height() / 72),
2176+ -1, -1, -1, -1,
2177+ Poppler::Page::Rotation(rotate));
2178+
2179+ delete page;
2180+ }
2181+ }
2182+
2183+ return result;
2184+}
2185+
2186+QList<Poppler::Link *> PdfDocument::pageLinks(int pageIndex) const
2187+{
2188+ QList<Poppler::Link *> result;
2189+
2190+ if (!m_links.empty())
2191+ result = m_links.value(pageIndex);
2192+
2193+ return result;
2194+}
2195+
2196+bool PdfDocument::loadDocument()
2197+{
2198+ qDebug() << "Loading document...";
2199+
2200+ if (m_path.isEmpty()) {
2201+ qDebug() << "Can't load the document, path is empty.";
2202+ setError(PopplerError::FileNotFound);
2203+ return false;
2204+ }
2205+
2206+ Poppler::Document* doc = Poppler::Document::load(m_path);
2207+ m_popDocument = QSharedPointer<Poppler::Document>(doc);
2208+
2209+ if (!doc || doc->isLocked()) {
2210+ qDebug() << "ERROR : Can't open the document located at " + m_path;
2211+ setError(PopplerError::DocumentLocked);
2212+
2213+ return false;
2214+ }
2215+
2216+ setError(PopplerError::NoError);
2217+ qDebug() << "Document loaded successfully !";
2218+
2219+ completeIntialization();
2220
2221 return true;
2222-}
2223-
2224-void PdfDocument::_q_populate(PdfPagesList pagesList)
2225-{
2226- qDebug() << "Number of pages:" << pagesList.count();
2227-
2228- Q_FOREACH (Poppler::Page *page, pagesList) {
2229- beginInsertRows(QModelIndex(), rowCount(), rowCount());
2230- m_pages << page;
2231- endInsertRows();
2232- }
2233-
2234- qDebug() << "Model has been successfully populated!";
2235- Q_EMIT pagesLoaded();
2236-}
2237-
2238-void PdfDocument::loadProvider()
2239-{
2240- // WORKAROUND: QQuickImageProvider should create multiple threads to load more images at the same time.
2241- // [QTBUG-37998] QQuickImageProvider can block its separate thread with ForceAsynchronousImageLoading
2242- // Link: https://bugreports.qt.io/browse/QTBUG-37988
2243-
2244- // WORKAROUND: ARM SoCs can disable some of their cores when the load is not particulary high.
2245- // This causes a wrong value for the "newProvidersNumber" variable.
2246- // We hard-code its value to 4 (which is the number of available core on all the supported devices).
2247-// int newProvidersNumber = QThread::idealThreadCount();
2248- int newProvidersNumber = 4;
2249-
2250- if (newProvidersNumber != m_providersNumber) {
2251- m_providersNumber = newProvidersNumber;
2252- Q_EMIT providersNumberChanged();
2253- }
2254-
2255- qDebug() << "Ideal number of image providers is:" << m_providersNumber;
2256-
2257- qDebug() << "Loading image provider(s)...";
2258- QQmlEngine *engine = QQmlEngine::contextForObject(this)->engine();
2259-
2260- for (int i=0; i<m_providersNumber; i++)
2261- engine->addImageProvider(QLatin1String("poppler" + QByteArray::number(i)), new PdfImageProvider(m_document));
2262-
2263- qDebug() << "Image provider(s) loaded successfully !";
2264+
2265+}
2266+
2267+void PdfDocument::setError(const PopplerError::Error &error)
2268+{
2269+ if (m_error == error)
2270+ return;
2271+
2272+ m_error = error;
2273+ Q_EMIT errorChanged();
2274+}
2275+
2276+void PdfDocument::completeIntialization()
2277+{
2278+ updateRenderHints();
2279+
2280+ // Init toc model
2281+ m_tocModel = new PdfTocModel;
2282+ m_tocModel->setDocument(m_popDocument);
2283+ Q_EMIT tocModelChanged();
2284+
2285+ Q_EMIT pageCountChanged();
2286+
2287+ // WORKAROUND: Getting links from pages seems a bit trivial and causes SIGFAULTs.
2288+ // Do it once at document initialization and cache them for any future request.
2289+ for (int i=0; i<m_popDocument->numPages(); ++i) {
2290+ Poppler::Page* page = m_popDocument->page(i);
2291+
2292+ QList<Poppler::Link *> l = page->links();
2293+ m_links.insert(i, l);
2294+
2295+ delete page;
2296+ }
2297 }
2298
2299 PdfDocument::~PdfDocument()
2300 {
2301+ Q_FOREACH(QList<Poppler::Link *> list, m_links)
2302+ qDeleteAll(list);
2303+
2304+ delete m_tocModel;
2305+}
2306+
2307+QString PdfDocument::path() const
2308+{
2309+ return m_path;
2310 }
2311
2312=== modified file 'src/plugin/poppler-qml-plugin/pdfdocument.h'
2313--- src/plugin/poppler-qml-plugin/pdfdocument.h 2015-02-04 19:19:21 +0000
2314+++ src/plugin/poppler-qml-plugin/pdfdocument.h 2016-04-22 10:31:39 +0000
2315@@ -1,85 +1,117 @@
2316-/*
2317- * Copyright (C) 2013-2015 Canonical, Ltd.
2318- *
2319- * This program is free software: you can redistribute it and/or modify it
2320- * under the terms of the GNU General Public License version 3, as published
2321- * by the Free Software Foundation.
2322- *
2323- * This program is distributed in the hope that it will be useful, but
2324- * WITHOUT ANY WARRANTY; without even the implied warranties of
2325- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2326- * PURPOSE. See the GNU General Public License for more details.
2327- *
2328- * You should have received a copy of the GNU General Public License along
2329- * with this program. If not, see <http://www.gnu.org/licenses/>.
2330- *
2331- * Author: Anthony Granger <grangeranthony@gmail.com>
2332- * Stefano Verzegnassi <stefano92.100@gmail.com>
2333- */
2334-
2335 #ifndef PDFDOCUMENT_H
2336 #define PDFDOCUMENT_H
2337
2338-#include <QAbstractListModel>
2339+#include <QObject>
2340+#include <QSharedPointer>
2341 #include <poppler/qt5/poppler-qt5.h>
2342-#include "pdfitem.h"
2343+
2344+#include "../../app/renderengine.h"
2345 #include "pdftocmodel.h"
2346-
2347-typedef QList<Poppler::Page*> PdfPagesList;
2348-
2349-class PdfDocument : public QAbstractListModel
2350+#include "pdferror.h"
2351+
2352+class PdfRotation : public QObject
2353+{
2354+ Q_OBJECT
2355+ Q_ENUMS(Rotation)
2356+
2357+public:
2358+ enum Rotation {
2359+ Rotate0 = Poppler::Page::Rotate0,
2360+ Rotate90 = Poppler::Page::Rotate90,
2361+ Rotate180 = Poppler::Page::Rotate180,
2362+ Rotate270 = Poppler::Page::Rotate270,
2363+ };
2364+};
2365+
2366+class PdfDocument : public QObject
2367 {
2368 Q_OBJECT
2369 Q_DISABLE_COPY(PdfDocument)
2370+ Q_ENUMS(DocumentInfo)
2371+ Q_ENUMS(RenderHint)
2372+ Q_FLAGS(RenderHints)
2373 Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged)
2374- Q_PROPERTY(int providersNumber READ providersNumber NOTIFY providersNumberChanged)
2375+ Q_PROPERTY(int pageCount READ pageCount NOTIFY pageCountChanged)
2376 Q_PROPERTY(QObject* tocModel READ tocModel NOTIFY tocModelChanged)
2377+ Q_PROPERTY(PopplerError::Error error READ error NOTIFY errorChanged)
2378+ Q_PROPERTY(RenderHints renderHints READ renderHints WRITE setRenderHints NOTIFY renderHintsChanged)
2379
2380 public:
2381- enum Roles {
2382- WidthRole = Qt::UserRole + 1,
2383- HeightRole
2384- };
2385-
2386- explicit PdfDocument(QAbstractListModel *parent = 0);
2387- virtual ~PdfDocument();
2388-
2389- QString path() const { return m_path; }
2390- void setPath(QString &pathName);
2391-
2392- int providersNumber() const { return m_providersNumber; }
2393-
2394- QHash<int, QByteArray> roleNames() const;
2395-
2396- int rowCount(const QModelIndex & parent = QModelIndex()) const;
2397- QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
2398+ explicit PdfDocument();
2399+ ~PdfDocument();
2400+
2401+ enum DocumentInfo {
2402+ Title,
2403+ Subject,
2404+ Author,
2405+ Creator,
2406+ Producer,
2407+ CreationDate,
2408+ ModifiedDate
2409+ };
2410+
2411+ enum RenderHint {
2412+ Antialiasing = 0x00000001,
2413+ TextAntialiasing = 0x00000002,
2414+ TextHinting = 0x00000004,
2415+ TextSlightHinting = 0x00000008,
2416+ OverprintPreview = 0x00000010,
2417+ ThinLineSolid = 0x00000020,
2418+ ThinLineShape = 0x00000040
2419+ };
2420+ Q_DECLARE_FLAGS(RenderHints, RenderHint)
2421+
2422+ QString path() const;
2423+ void setPath(const QString &pathName);
2424+
2425+ bool isLocked();
2426+
2427+ int pageCount();
2428+
2429+ QImage paintTile(int pageIndex, const qreal &zoom, QRect rect, PdfRotation::Rotation rotate = PdfRotation::Rotate0) const;
2430+ QImage paintThumbnail(int pageIndex, const QSize &size, PdfRotation::Rotation rotate = PdfRotation::Rotate0) const;
2431+
2432+ QList<Poppler::Link *> pageLinks(int pageIndex) const;
2433
2434 Q_INVOKABLE QDateTime getDocumentDate(QString data);
2435 Q_INVOKABLE QString getDocumentInfo(QString data);
2436-
2437- QObject *tocModel() const { return m_tocModel; }
2438+ Q_INVOKABLE QVariant documentInfo(DocumentInfo info);
2439+
2440+ Q_INVOKABLE bool unlock(const QString &ownerPassword, const QString &userPassword);
2441+
2442+ QObject *tocModel() const;
2443+
2444+ QSize pageSize(int index) const;
2445+
2446+ PopplerError::Error error() const;
2447+
2448+ RenderHints renderHints() const;
2449+ void setRenderHints(const RenderHints hints);
2450
2451 Q_SIGNALS:
2452 void pathChanged();
2453- void error(const QString& errorMessage);
2454- void pagesLoaded();
2455- void providersNumberChanged();
2456+ void pageCountChanged();
2457 void tocModelChanged();
2458-
2459-private slots:
2460- void _q_populate(PdfPagesList pagesList);
2461+ void errorChanged();
2462+ void renderHintsChanged();
2463+
2464+private Q_SLOTS:
2465+ void updateRenderHints();
2466+
2467+private:
2468+ bool loadDocument();
2469+ void setError(const PopplerError::Error &error);
2470+ void completeIntialization();
2471
2472 private:
2473 QString m_path;
2474- int m_providersNumber;
2475-
2476- bool loadDocument(QString &pathNAme);
2477- void loadProvider();
2478- bool loadPages();
2479-
2480- Poppler::Document *m_document;
2481- QList<PdfItem> m_pages;
2482 PdfTocModel* m_tocModel;
2483+ PopplerError::Error m_error;
2484+ RenderHints m_renderHints;
2485+
2486+ QHash<int, QList<Poppler::Link *>> m_links;
2487+
2488+ QSharedPointer<Poppler::Document> m_popDocument;
2489 };
2490
2491 #endif // PDFDOCUMENT_H
2492
2493=== added file 'src/plugin/poppler-qml-plugin/pdferror.h'
2494--- src/plugin/poppler-qml-plugin/pdferror.h 1970-01-01 00:00:00 +0000
2495+++ src/plugin/poppler-qml-plugin/pdferror.h 2016-04-22 10:31:39 +0000
2496@@ -0,0 +1,19 @@
2497+#ifndef PDFERROR_H
2498+#define PDFERROR_H
2499+
2500+#include <QObject>
2501+
2502+class PopplerError : public QObject
2503+{
2504+ Q_OBJECT
2505+ Q_ENUMS(Error)
2506+
2507+public:
2508+ enum Error {
2509+ NoError = 0,
2510+ FileNotFound = 1,
2511+ DocumentLocked = 2
2512+ };
2513+};
2514+
2515+#endif // PDFERROR_H
2516
2517=== added file 'src/plugin/poppler-qml-plugin/pdfimageprovider.cpp'
2518--- src/plugin/poppler-qml-plugin/pdfimageprovider.cpp 1970-01-01 00:00:00 +0000
2519+++ src/plugin/poppler-qml-plugin/pdfimageprovider.cpp 2016-04-22 10:31:39 +0000
2520@@ -0,0 +1,60 @@
2521+/*
2522+ * Copyright (C) 2015, 2016 Stefano Verzegnassi
2523+ *
2524+ * This program is free software: you can redistribute it and/or modify it
2525+ * under the terms of the GNU General Public License version 3, as published
2526+ * by the Free Software Foundation.
2527+ *
2528+ * This program is distributed in the hope that it will be useful, but
2529+ * WITHOUT ANY WARRANTY; without even the implied warranties of
2530+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2531+ * PURPOSE. See the GNU General Public License for more details.
2532+ *
2533+ * You should have received a copy of the GNU General Public License along
2534+ * with this program. If not, see <http://www.gnu.org/licenses/>.
2535+ */
2536+
2537+#include "pdfimageprovider.h"
2538+#include "pdfimageresponse.h"
2539+
2540+#include "pdfdocument.h"
2541+
2542+#include "../../app/renderengine.h"
2543+#include "pdfrendertask.h"
2544+
2545+#include <QDebug>
2546+
2547+PdfImageProvider::PdfImageProvider(const QSharedPointer<PdfDocument>& d)
2548+ : QQuickAsyncImageProvider()
2549+ , m_document(d)
2550+{ }
2551+
2552+QQuickImageResponse *PdfImageProvider::requestImageResponse(const QString & id, const QSize & requestedSize)
2553+{
2554+ QString type = id.section("/", 0, 0);
2555+ int part = id.section("/", 1, 1).toInt();
2556+ int rotation = id.section("/", 2, 2).toInt();
2557+ bool isValid = bool(!requestedSize.isNull() && type == "page");
2558+
2559+ auto response = new PdfImageResponse(isValid);
2560+
2561+ if (isValid) {
2562+ int taskId = RenderEngine::getNextId();
2563+ response->setTaskId(taskId);
2564+ RenderEngine::instance()->enqueueTask(createTask(part, rotation, requestedSize, taskId));
2565+ }
2566+
2567+ return response;
2568+}
2569+
2570+PdfThumbnailRenderTask* PdfImageProvider::createTask(int pageIndex, int rotation, const QSize &size, int id) const
2571+{
2572+ auto task = new PdfThumbnailRenderTask();
2573+ task->setId(id);
2574+ task->setPage(pageIndex);
2575+ task->setDocument(m_document);
2576+ task->setRotation(rotation);
2577+ task->setSize(size.isEmpty() ? QSize(256, 256) : size);
2578+
2579+ return task;
2580+}
2581
2582=== removed file 'src/plugin/poppler-qml-plugin/pdfimageprovider.cpp'
2583--- src/plugin/poppler-qml-plugin/pdfimageprovider.cpp 2015-02-03 18:50:36 +0000
2584+++ src/plugin/poppler-qml-plugin/pdfimageprovider.cpp 1970-01-01 00:00:00 +0000
2585@@ -1,75 +0,0 @@
2586-/*
2587- * Copyright (C) 2013-2015 Canonical, Ltd.
2588- *
2589- * This program is free software: you can redistribute it and/or modify it
2590- * under the terms of the GNU General Public License version 3, as published
2591- * by the Free Software Foundation.
2592- *
2593- * This program is distributed in the hope that it will be useful, but
2594- * WITHOUT ANY WARRANTY; without even the implied warranties of
2595- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2596- * PURPOSE. See the GNU General Public License for more details.
2597- *
2598- * You should have received a copy of the GNU General Public License along
2599- * with this program. If not, see <http://www.gnu.org/licenses/>.
2600- *
2601- * Author: Anthony Granger <grangeranthony@gmail.com>
2602- * Stefano Verzegnassi <stefano92.100@gmail.com
2603- */
2604-
2605-#include <poppler/qt5/poppler-qt5.h>
2606-#include <QQuickImageProvider>
2607-#include <QDebug>
2608-
2609-#include "pdfimageprovider.h"
2610-
2611-PdfImageProvider::PdfImageProvider(Poppler::Document *pdfDocument)
2612- : QQuickImageProvider(QQuickImageProvider::Image, QQuickImageProvider::ForceAsynchronousImageLoading)
2613-{
2614- this->document = pdfDocument;
2615-}
2616-
2617-QImage PdfImageProvider::requestImage(const QString & id, QSize * size, const QSize & requestedSize)
2618-{
2619- Q_UNUSED(size)
2620-
2621- // If the requestedSize.width is 0, avoid Poppler rendering
2622- // FIXME: Actually it works correctly, but an error is anyway shown in the application output.
2623- if (requestedSize.width() > 0) {
2624- QString type = id.section("/", 0, 0);
2625- QImage result;
2626- QSizeF pageSize;
2627- QSizeF pageSizePhys;
2628- float res = 0;
2629- Poppler::Page *page;
2630-
2631- if (type == "page")
2632- {
2633- int numPage = id.section("/", 1, 1).toInt();
2634-
2635- // Useful for debugging, keep commented unless you need it.
2636- // qDebug() << "Page" << numPage + 1 << "requested";
2637-
2638- page = document->page(numPage);
2639-
2640- pageSize = page->pageSizeF();
2641- pageSizePhys.setWidth(pageSize.width() / 72);
2642- res = requestedSize.width() / pageSizePhys.width();
2643-
2644- // Useful for debugging, keep commented unless you need it.
2645- /*
2646- qDebug() << "Requested size :" << requestedSize.width() << ";" << requestedSize.height();
2647- qDebug() << "Size :" << pageSizePhys.width() << ";" << pageSizePhys.height();
2648- qDebug() << "Resolution :" << res;
2649- */
2650-
2651- // Render the page to QImage
2652- result = page->renderToImage(res, res);
2653- }
2654-
2655- return result;
2656- }
2657-
2658- // Requested size is 0, so return a null image.
2659- return QImage();
2660-}
2661
2662=== added file 'src/plugin/poppler-qml-plugin/pdfimageprovider.h'
2663--- src/plugin/poppler-qml-plugin/pdfimageprovider.h 1970-01-01 00:00:00 +0000
2664+++ src/plugin/poppler-qml-plugin/pdfimageprovider.h 2016-04-22 10:31:39 +0000
2665@@ -0,0 +1,41 @@
2666+/*
2667+ * Copyright (C) 2015, 2016 Stefano Verzegnassi
2668+ *
2669+ * This program is free software: you can redistribute it and/or modify it
2670+ * under the terms of the GNU General Public License version 3, as published
2671+ * by the Free Software Foundation.
2672+ *
2673+ * This program is distributed in the hope that it will be useful, but
2674+ * WITHOUT ANY WARRANTY; without even the implied warranties of
2675+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2676+ * PURPOSE. See the GNU General Public License for more details.
2677+ *
2678+ * You should have received a copy of the GNU General Public License along
2679+ * with this program. If not, see <http://www.gnu.org/licenses/>.
2680+ *
2681+ */
2682+
2683+#ifndef PDFIMAGEPROVIDER_H
2684+#define PDFIMAGEPROVIDER_H
2685+
2686+// For QQuickAsyncImageProvider
2687+#include <qquickimageprovider.h>
2688+#include <QSharedPointer>
2689+
2690+class PdfDocument;
2691+class PdfThumbnailRenderTask;
2692+
2693+class PdfImageProvider : public QQuickAsyncImageProvider
2694+{
2695+public:
2696+ PdfImageProvider(const QSharedPointer<PdfDocument>& d);
2697+ QQuickImageResponse* requestImageResponse(const QString & id, const QSize & requestedSize);
2698+
2699+private:
2700+ PdfThumbnailRenderTask* createTask(int pageIndex, int rotation, const QSize &size, int id) const;
2701+
2702+private:
2703+ QSharedPointer<PdfDocument> m_document;
2704+};
2705+
2706+#endif // PDFIMAGEPROVIDER_H
2707
2708=== removed file 'src/plugin/poppler-qml-plugin/pdfimageprovider.h'
2709--- src/plugin/poppler-qml-plugin/pdfimageprovider.h 2015-01-30 18:05:22 +0000
2710+++ src/plugin/poppler-qml-plugin/pdfimageprovider.h 1970-01-01 00:00:00 +0000
2711@@ -1,36 +0,0 @@
2712-/*
2713- * Copyright (C) 2013-2015 Canonical, Ltd.
2714- *
2715- * This program is free software: you can redistribute it and/or modify it
2716- * under the terms of the GNU General Public License version 3, as published
2717- * by the Free Software Foundation.
2718- *
2719- * This program is distributed in the hope that it will be useful, but
2720- * WITHOUT ANY WARRANTY; without even the implied warranties of
2721- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2722- * PURPOSE. See the GNU General Public License for more details.
2723- *
2724- * You should have received a copy of the GNU General Public License along
2725- * with this program. If not, see <http://www.gnu.org/licenses/>.
2726- *
2727- * Author: Anthony Granger <grangeranthony@gmail.com>
2728- * Stefano Verzegnassi <stefano92.100@gmail.com>
2729- */
2730-
2731-#ifndef PDFIMAGEPROVIDER_H
2732-#define PDFIMAGEPROVIDER_H
2733-
2734-#include <QQuickImageProvider>
2735-#include <poppler/qt5/poppler-qt5.h>
2736-
2737-class PdfImageProvider : public QQuickImageProvider
2738-{
2739-public:
2740- PdfImageProvider(Poppler::Document *pdfDocument);
2741- QImage requestImage(const QString & id, QSize * size, const QSize & requestedSize);
2742-
2743-private:
2744- Poppler::Document *document;
2745-};
2746-
2747-#endif // PDFIMAGEPROVIDER_H
2748
2749=== added file 'src/plugin/poppler-qml-plugin/pdfimageresponse.cpp'
2750--- src/plugin/poppler-qml-plugin/pdfimageresponse.cpp 1970-01-01 00:00:00 +0000
2751+++ src/plugin/poppler-qml-plugin/pdfimageresponse.cpp 2016-04-22 10:31:39 +0000
2752@@ -0,0 +1,55 @@
2753+/*
2754+ * Copyright (C) 2015 Roman Shchekin
2755+ * Copyright (C) 2015, 2016 Stefano Verzegnassi
2756+ *
2757+ * This program is free software: you can redistribute it and/or modify it
2758+ * under the terms of the GNU General Public License version 3, as published
2759+ * by the Free Software Foundation.
2760+ *
2761+ * This program is distributed in the hope that it will be useful, but
2762+ * WITHOUT ANY WARRANTY; without even the implied warranties of
2763+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2764+ * PURPOSE. See the GNU General Public License for more details.
2765+ *
2766+ * You should have received a copy of the GNU General Public License along
2767+ * with this program. If not, see <http://www.gnu.org/licenses/>.
2768+ */
2769+
2770+#include "pdfimageresponse.h"
2771+#include "pdfdocument.h"
2772+
2773+#include "../../app/renderengine.h"
2774+
2775+PdfImageResponse::PdfImageResponse(bool isRequestValid)
2776+ : m_taskId(0)
2777+{
2778+ if (!isRequestValid) {
2779+ m_errorString = "Requested size or id are not valid.";
2780+
2781+ QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection);
2782+ return;
2783+ }
2784+
2785+ connect(RenderEngine::instance(), &RenderEngine::taskRenderFinished,
2786+ this, [&](AbstractRenderTask *task, QImage img)
2787+ {
2788+ if (m_taskId == task->id() && task->type() == RttPdfThumbnail) {
2789+ m_image = img;
2790+ Q_EMIT finished();
2791+ }
2792+ }, Qt::BlockingQueuedConnection);
2793+}
2794+
2795+PdfImageResponse::~PdfImageResponse()
2796+{
2797+ disconnect(this);
2798+
2799+ QMetaObject::invokeMethod(RenderEngine::instance(), "dequeueTask",
2800+ Qt::QueuedConnection,
2801+ Q_ARG(int, m_taskId));
2802+}
2803+
2804+QQuickTextureFactory * PdfImageResponse::textureFactory() const
2805+{
2806+ return QQuickTextureFactory::textureFactoryForImage(m_image);
2807+}
2808
2809=== added file 'src/plugin/poppler-qml-plugin/pdfimageresponse.h'
2810--- src/plugin/poppler-qml-plugin/pdfimageresponse.h 1970-01-01 00:00:00 +0000
2811+++ src/plugin/poppler-qml-plugin/pdfimageresponse.h 2016-04-22 10:31:39 +0000
2812@@ -0,0 +1,41 @@
2813+/*
2814+ * Copyright (C) 2015, 2016 Stefano Verzegnassi
2815+ *
2816+ * This program is free software: you can redistribute it and/or modify it
2817+ * under the terms of the GNU General Public License version 3, as published
2818+ * by the Free Software Foundation.
2819+ *
2820+ * This program is distributed in the hope that it will be useful, but
2821+ * WITHOUT ANY WARRANTY; without even the implied warranties of
2822+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2823+ * PURPOSE. See the GNU General Public License for more details.
2824+ *
2825+ * You should have received a copy of the GNU General Public License along
2826+ * with this program. If not, see <http://www.gnu.org/licenses/>.
2827+ *
2828+ */
2829+
2830+#ifndef PDFIMAGERESPONSE_H
2831+#define PDFIMAGERESPONSE_H
2832+
2833+// For QQuickImageResponse
2834+#include <qquickimageprovider.h>
2835+
2836+class PdfImageResponse : public QQuickImageResponse
2837+{
2838+public:
2839+ PdfImageResponse(bool isRequestValid);
2840+ ~PdfImageResponse();
2841+
2842+ void setTaskId(const int id) { m_taskId = id; }
2843+ QString errorString() const override { return m_errorString; }
2844+ QQuickTextureFactory * textureFactory() const override;
2845+
2846+private:
2847+ QString m_errorString;
2848+ QImage m_image;
2849+ int m_taskId;
2850+};
2851+
2852+
2853+#endif // PDFIMAGERESPONSE_H
2854
2855=== removed file 'src/plugin/poppler-qml-plugin/pdfitem.cpp'
2856--- src/plugin/poppler-qml-plugin/pdfitem.cpp 2015-01-30 18:10:21 +0000
2857+++ src/plugin/poppler-qml-plugin/pdfitem.cpp 1970-01-01 00:00:00 +0000
2858@@ -1,36 +0,0 @@
2859-/*
2860- * Copyright (C) 2014-2015 Canonical, Ltd.
2861- *
2862- * This program is free software: you can redistribute it and/or modify it
2863- * under the terms of the GNU General Public License version 3, as published
2864- * by the Free Software Foundation.
2865- *
2866- * This program is distributed in the hope that it will be useful, but
2867- * WITHOUT ANY WARRANTY; without even the implied warranties of
2868- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2869- * PURPOSE. See the GNU General Public License for more details.
2870- *
2871- * You should have received a copy of the GNU General Public License along
2872- * with this program. If not, see <http://www.gnu.org/licenses/>.
2873- *
2874- * Author: Stefano Verzegnassi <stefano92.100@gmail.com>
2875- */
2876-
2877-#include "pdfitem.h"
2878-#include <poppler/qt5/poppler-qt5.h>
2879-
2880-PdfItem::PdfItem(Poppler::Page *page)
2881-{
2882- m_width = page->pageSize().width();
2883- m_height = page->pageSize().height();
2884-}
2885-
2886-int PdfItem::width() const
2887-{
2888- return m_width;
2889-}
2890-
2891-int PdfItem::height() const
2892-{
2893- return m_height;
2894-}
2895
2896=== removed file 'src/plugin/poppler-qml-plugin/pdfitem.h'
2897--- src/plugin/poppler-qml-plugin/pdfitem.h 2015-01-30 18:10:21 +0000
2898+++ src/plugin/poppler-qml-plugin/pdfitem.h 1970-01-01 00:00:00 +0000
2899@@ -1,36 +0,0 @@
2900-/*
2901- * Copyright (C) 2014-2015 Canonical, Ltd.
2902- *
2903- * This program is free software: you can redistribute it and/or modify it
2904- * under the terms of the GNU General Public License version 3, as published
2905- * by the Free Software Foundation.
2906- *
2907- * This program is distributed in the hope that it will be useful, but
2908- * WITHOUT ANY WARRANTY; without even the implied warranties of
2909- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2910- * PURPOSE. See the GNU General Public License for more details.
2911- *
2912- * You should have received a copy of the GNU General Public License along
2913- * with this program. If not, see <http://www.gnu.org/licenses/>.
2914- *
2915- * Author: Stefano Verzegnassi <stefano92.100@gmail.com>
2916- */
2917-
2918-#ifndef PDFITEM_H
2919-#define PDFITEM_H
2920-
2921-#include <poppler/qt5/poppler-qt5.h>
2922-
2923-class PdfItem
2924-{
2925-public:
2926- PdfItem(Poppler::Page *page);
2927- int width() const;
2928- int height() const;
2929-
2930-private:
2931- int m_width;
2932- int m_height;
2933-};
2934-
2935-#endif // PDFITEM_H
2936
2937=== added file 'src/plugin/poppler-qml-plugin/pdfrendertask.cpp'
2938--- src/plugin/poppler-qml-plugin/pdfrendertask.cpp 1970-01-01 00:00:00 +0000
2939+++ src/plugin/poppler-qml-plugin/pdfrendertask.cpp 2016-04-22 10:31:39 +0000
2940@@ -0,0 +1,18 @@
2941+#include "pdfrendertask.h"
2942+
2943+bool PdfRenderTask::canBeRunInParallel(AbstractRenderTask* prevTask)
2944+{
2945+ Q_ASSERT(prevTask != nullptr);
2946+ return true;
2947+}
2948+
2949+QImage PdfTileRenderTask::doWork()
2950+{
2951+ return m_document.data()->paintTile(m_page, m_zoom, m_area, PdfRotation::Rotation(m_rotation));
2952+}
2953+
2954+QImage PdfThumbnailRenderTask::doWork()
2955+{
2956+ return m_document.data()->paintThumbnail(m_page, m_size, PdfRotation::Rotation(m_rotation));
2957+}
2958+
2959
2960=== added file 'src/plugin/poppler-qml-plugin/pdfrendertask.h'
2961--- src/plugin/poppler-qml-plugin/pdfrendertask.h 1970-01-01 00:00:00 +0000
2962+++ src/plugin/poppler-qml-plugin/pdfrendertask.h 2016-04-22 10:31:39 +0000
2963@@ -0,0 +1,66 @@
2964+#ifndef LORENDERTASK_H
2965+#define LORENDERTASK_H
2966+
2967+#include <QObject>
2968+#include <QDebug>
2969+#include <QImage>
2970+#include <QSharedPointer>
2971+#include <QHash>
2972+#include <QQueue>
2973+#include <QAtomicInt>
2974+
2975+#include "../../app/rendertask.h"
2976+#include <QSharedPointer>
2977+#include "pdfdocument.h"
2978+
2979+class PdfRenderTask : public AbstractRenderTask
2980+{
2981+public:
2982+ virtual bool canBeRunInParallel(AbstractRenderTask* prevTask);
2983+ virtual void prepare() { }
2984+
2985+ int rotation() { return m_rotation; }
2986+ void setRotation(int r) { m_rotation = r; }
2987+
2988+ int page() { return m_page; }
2989+ void setPage(int p) { m_page = p; }
2990+
2991+ QSharedPointer<PdfDocument> document() { return m_document; }
2992+ void setDocument(QSharedPointer<PdfDocument> d) { m_document = d; }
2993+
2994+protected:
2995+ int m_page;
2996+ int m_rotation;
2997+ QSharedPointer<PdfDocument> m_document;
2998+};
2999+
3000+
3001+class PdfTileRenderTask : public PdfRenderTask
3002+{
3003+public:
3004+ virtual RenderTaskType type() { return RttPdfTile; }
3005+ virtual QImage doWork();
3006+
3007+ QRect area() { return m_area; }
3008+ void setArea(const QRect& a) { m_area = a; }
3009+ qreal zoom() { return m_zoom; }
3010+ void setZoom(qreal z) { m_zoom = z; }
3011+protected:
3012+ QRect m_area;
3013+ qreal m_zoom;
3014+};
3015+
3016+class PdfThumbnailRenderTask : public PdfRenderTask
3017+{
3018+public:
3019+ virtual RenderTaskType type() { return RttPdfThumbnail; }
3020+ virtual QImage doWork();
3021+
3022+ QSize size() const { return m_size; }
3023+ void setSize(const QSize & s) { m_size = s; }
3024+protected:
3025+ QSize m_size;
3026+};
3027+
3028+
3029+#endif // LORENDERTASK_H
3030
3031=== modified file 'src/plugin/poppler-qml-plugin/pdftocmodel.cpp'
3032--- src/plugin/poppler-qml-plugin/pdftocmodel.cpp 2015-04-16 12:58:29 +0000
3033+++ src/plugin/poppler-qml-plugin/pdftocmodel.cpp 2016-04-22 10:31:39 +0000
3034@@ -1,5 +1,5 @@
3035 /*
3036- * Copyright (C) 2015
3037+ * Copyright (C) 2015, 2016
3038 * Stefano Verzegnassi <verzegnassi.stefano@gmail.com>
3039 *
3040 * This program is free software: you can redistribute it and/or modify it
3041@@ -26,16 +26,12 @@
3042
3043 PdfTocModel::PdfTocModel(QAbstractListModel *parent):
3044 QAbstractListModel(parent)
3045-{
3046- connect(this, SIGNAL(documentChanged()), this, SLOT(fillModel()));
3047-}
3048+{ }
3049
3050-void PdfTocModel::setDocument(Poppler::Document *document)
3051+void PdfTocModel::setDocument(const QSharedPointer<Poppler::Document>& document)
3052 {
3053- if (document != m_document) {
3054- m_document = document;
3055- Q_EMIT documentChanged();
3056- }
3057+ m_document = document;
3058+ fillModel();
3059 }
3060
3061 QHash<int, QByteArray> PdfTocModel::roleNames() const
3062@@ -43,6 +39,9 @@
3063 QHash<int, QByteArray> roles;
3064 roles[TitleRole] = "title";
3065 roles[PageIndexRole] = "pageIndex";
3066+ roles[NodeIndexRole] = "nodeIndex";
3067+ roles[ParentNodeIndexRole] = "parentNodeIndex";
3068+ roles[HasChildNodesRole] = "hasChildNodes";
3069 roles[LevelRole] = "level";
3070 return roles;
3071 }
3072@@ -65,6 +64,12 @@
3073 return tocEntry.title;
3074 case PageIndexRole:
3075 return tocEntry.pageIndex;
3076+ case NodeIndexRole:
3077+ return tocEntry.nodeIndex;
3078+ case ParentNodeIndexRole:
3079+ return tocEntry.parentNodeIndex;
3080+ case HasChildNodesRole:
3081+ return tocEntry.hasChildNodes;
3082 case LevelRole:
3083 return tocEntry.level;
3084 default:
3085@@ -84,6 +89,8 @@
3086 QVariantMap map;
3087 map["title"] = item.title;
3088 map["pageIndex"] = item.pageIndex;
3089+ map["nodeIndex"] = item.nodeIndex;
3090+ map["parentNodeIndex"] = item.parentNodeIndex;
3091 map["level"] = item.level;
3092
3093 return map;
3094@@ -91,7 +98,10 @@
3095
3096 void PdfTocModel::fillModel() {
3097 if (m_entries.count() != 0) {
3098+ beginResetModel();
3099 m_entries.clear();
3100+ endResetModel();
3101+
3102 Q_EMIT countChanged();
3103 }
3104
3105@@ -104,13 +114,16 @@
3106 }
3107 }
3108
3109-void PdfTocModel::recursiveGetEntries(QDomNode node, int nodeLevel)
3110+void PdfTocModel::recursiveGetEntries(QDomNode node, int nodeLevel, int parentNodeIndex)
3111 {
3112 while(!node.isNull()) {
3113 QDomNode child = node.firstChild();
3114
3115 TocEntry entry;
3116 entry.title = node.toElement().tagName();
3117+ entry.nodeIndex = m_entries.count();
3118+ entry.parentNodeIndex = parentNodeIndex;
3119+ entry.hasChildNodes = node.hasChildNodes();
3120 entry.level = nodeLevel;
3121
3122 QString dest = node.toElement().attribute("Destination");
3123@@ -125,11 +138,14 @@
3124 }
3125 }
3126
3127+ beginInsertRows(QModelIndex(), rowCount(), rowCount());
3128 m_entries.append(entry);
3129+ endInsertRows();
3130+
3131 Q_EMIT countChanged();
3132
3133 // Look for children entries
3134- recursiveGetEntries(child, nodeLevel + 1);
3135+ recursiveGetEntries(child, nodeLevel + 1, m_entries.count() - 1);
3136
3137 // Go to the next entry at the same level.
3138 node = node.nextSibling();
3139@@ -137,5 +153,4 @@
3140 }
3141
3142 PdfTocModel::~PdfTocModel()
3143-{
3144-}
3145+{ }
3146
3147=== modified file 'src/plugin/poppler-qml-plugin/pdftocmodel.h'
3148--- src/plugin/poppler-qml-plugin/pdftocmodel.h 2015-04-08 14:11:02 +0000
3149+++ src/plugin/poppler-qml-plugin/pdftocmodel.h 2016-04-22 10:31:39 +0000
3150@@ -1,5 +1,5 @@
3151 /*
3152- * Copyright (C) 2015
3153+ * Copyright (C) 2015, 2016
3154 * Stefano Verzegnassi <verzegnassi.stefano@gmail.com>
3155 *
3156 * This program is free software: you can redistribute it and/or modify it
3157@@ -20,6 +20,7 @@
3158 #define PDFTOCMODEL_H
3159
3160 #include <QAbstractListModel>
3161+#include <QSharedPointer>
3162 #include <poppler/qt5/poppler-qt5.h>
3163 #include <QDomNode>
3164
3165@@ -28,6 +29,9 @@
3166 public:
3167 QString title;
3168 int pageIndex = 0;
3169+ int nodeIndex = 0;
3170+ int parentNodeIndex = 0;
3171+ bool hasChildNodes = false;
3172 int level = 0;
3173 };
3174
3175@@ -41,13 +45,16 @@
3176 enum Roles {
3177 TitleRole = Qt::UserRole + 1,
3178 PageIndexRole,
3179+ NodeIndexRole,
3180+ ParentNodeIndexRole,
3181+ HasChildNodesRole,
3182 LevelRole
3183 };
3184
3185 explicit PdfTocModel(QAbstractListModel *parent = 0);
3186 virtual ~PdfTocModel();
3187
3188- void setDocument(Poppler::Document* document);
3189+ void setDocument(const QSharedPointer<Poppler::Document>& document);
3190
3191 QHash<int, QByteArray> roleNames() const;
3192
3193@@ -57,18 +64,16 @@
3194 Q_INVOKABLE QVariantMap get(int index) const;
3195
3196 Q_SIGNALS:
3197- void documentChanged();
3198 void countChanged();
3199
3200 private slots:
3201 void fillModel();
3202
3203 private:
3204- Poppler::Document* m_document;
3205+ QSharedPointer<Poppler::Document> m_document;
3206 QList<TocEntry> m_entries;
3207
3208- void recursiveGetEntries(QDomNode node, int nodeLevel);
3209-
3210+ void recursiveGetEntries(QDomNode node, int nodeLevel, int parentNodeIndex = -1);
3211 };
3212
3213 #endif // PDFTOCMODEL_H
3214
3215=== added file 'src/plugin/poppler-qml-plugin/pdfzoom.cpp'
3216--- src/plugin/poppler-qml-plugin/pdfzoom.cpp 1970-01-01 00:00:00 +0000
3217+++ src/plugin/poppler-qml-plugin/pdfzoom.cpp 2016-04-22 10:31:39 +0000
3218@@ -0,0 +1,232 @@
3219+/*
3220+ * Copyright (C) 2016 Stefano Verzegnassi
3221+ *
3222+ * This program is free software; you can redistribute it and/or modify
3223+ * it under the terms of the GNU General Public License as published by
3224+ * the Free Software Foundation; version 3.
3225+ *
3226+ * This program is distributed in the hope that it will be useful,
3227+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3228+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3229+ * GNU General Public License for more details.
3230+ *
3231+ * You should have received a copy of the GNU General Public License
3232+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3233+ */
3234+
3235+#include "pdfzoom.h"
3236+#include "verticalview.h"
3237+#include "pdfdocument.h"
3238+#include "twips.h"
3239+
3240+static qreal getZoomToFitWidth(const qreal &width, int documentWidth)
3241+{
3242+ return qreal(width / Twips::convertPointsToPixels(documentWidth, 1.0));
3243+}
3244+
3245+static qreal getZoomToFitHeight(const qreal &height, int documentHeight)
3246+{
3247+ return qreal(height / Twips::convertPointsToPixels(documentHeight, 1.0));
3248+}
3249+
3250+PdfZoom::PdfZoom(VerticalView *view)
3251+ : QObject(view)
3252+ , m_view(view)
3253+ , m_zoomMode(ZoomMode::Manual)
3254+ , m_zoomFactor(1.0)
3255+ , m_minimumZoom(0.25)
3256+ , m_maximumZoom(4.0)
3257+{ }
3258+
3259+PdfZoom::~PdfZoom()
3260+{ }
3261+
3262+PdfZoom::ZoomMode PdfZoom::zoomMode() const
3263+{
3264+ return m_zoomMode;
3265+}
3266+
3267+void PdfZoom::setZoomMode(const PdfZoom::ZoomMode zoomMode)
3268+{
3269+ if (m_zoomMode == zoomMode)
3270+ return;
3271+
3272+ m_zoomMode = zoomMode;
3273+ Q_EMIT zoomModeChanged();
3274+}
3275+
3276+void PdfZoom::updateZoomValues()
3277+{
3278+ int maxWidth = 0;
3279+ int maxHeight = 0;
3280+ for (int i=0; i<m_view->document()->pageCount(); ++i) {
3281+ int w, h;
3282+ if (m_view->rotation() == PdfRotation::Rotate0 || m_view->rotation() == PdfRotation::Rotate180) {
3283+ h = m_view->document()->pageSize(i).height();
3284+ w = m_view->document()->pageSize(i).width();
3285+ } else {
3286+ w = m_view->document()->pageSize(i).height();
3287+ h = m_view->document()->pageSize(i).width();
3288+ }
3289+
3290+ if (h > maxHeight)
3291+ maxHeight = h;
3292+
3293+ if (w > maxWidth)
3294+ maxWidth = w;
3295+ }
3296+
3297+ // Maximum zoom value to fit the width of the flickable
3298+ m_valueFitWidthZoom = getZoomToFitWidth(m_view->parentFlickable()->width(), maxWidth);
3299+
3300+ // Maximum zoom value that ensures that each page is fully visible in the view (without any
3301+ // need for scrolling)
3302+ m_valueFitPageZoom = qMin(getZoomToFitHeight(m_view->parentFlickable()->height(), maxHeight),
3303+ m_valueFitWidthZoom);
3304+
3305+ // Like ZoomMode::FitWidth, but its maximum value is limited to a 1.0x factor
3306+ m_valueAutomaticZoom = qMin(1.0, m_valueFitWidthZoom);
3307+
3308+ Q_EMIT valueFitWidthZoomChanged();
3309+ Q_EMIT valueFitPageZoomChanged();
3310+ Q_EMIT valueAutomaticZoomChanged();
3311+}
3312+
3313+qreal PdfZoom::zoomFactor() const
3314+{
3315+ return m_zoomFactor;
3316+}
3317+
3318+void PdfZoom::setZoomFactor(const qreal zoom)
3319+{
3320+ if (m_zoomFactor == zoom || zoom < m_minimumZoom || zoom > m_maximumZoom)
3321+ return;
3322+
3323+ m_zoomFactor = zoom;
3324+
3325+ if (m_zoomFactor != m_valueFitWidthZoom
3326+ && m_zoomFactor != m_valueFitPageZoom
3327+ && m_zoomFactor != m_valueAutomaticZoom)
3328+ setZoomMode(PdfZoom::Manual);
3329+
3330+ Q_EMIT zoomFactorChanged();
3331+}
3332+
3333+qreal PdfZoom::minimumZoom() const
3334+{
3335+ return m_minimumZoom;
3336+}
3337+
3338+/*
3339+void PdfZoom::setMinimumZoom(const qreal newValue)
3340+{
3341+ if (m_minimumZoom == newValue)
3342+ return;
3343+
3344+ m_minimumZoom = newValue;
3345+ Q_EMIT minimumZoomChanged();
3346+}
3347+*/
3348+
3349+qreal PdfZoom::maximumZoom() const
3350+{
3351+ return m_maximumZoom;
3352+}
3353+
3354+/*
3355+void PdfZoom::setMaximumZoom(const qreal newValue)
3356+{
3357+ if (m_maximumZoom == newValue)
3358+ return;
3359+
3360+ m_maximumZoom = newValue;
3361+ Q_EMIT maximumZoomChanged();
3362+}
3363+*/
3364+
3365+qreal PdfZoom::valueFitWidthZoom() const
3366+{
3367+ return m_valueFitWidthZoom;
3368+}
3369+
3370+qreal PdfZoom::valueFitPageZoom() const
3371+{
3372+ return m_valueFitPageZoom;
3373+}
3374+
3375+qreal PdfZoom::valueAutomaticZoom() const
3376+{
3377+ return m_valueAutomaticZoom;
3378+}
3379+
3380+bool PdfZoom::adjustZoomToWidth(bool changeMode)
3381+{
3382+ if (!m_view->document())
3383+ return false;
3384+
3385+ if (changeMode)
3386+ setZoomMode(PdfZoom::FitWidth);
3387+
3388+ int maxWidth = 0;
3389+ for (int i=0; i<m_view->document()->pageCount(); ++i) {
3390+ int w = m_view->document()->pageSize(i).width();
3391+ if (w > maxWidth)
3392+ maxWidth = w;
3393+ }
3394+
3395+ updateZoomValues();
3396+
3397+ if (m_zoomFactor != m_valueFitWidthZoom) {
3398+ setZoomFactor(m_valueFitWidthZoom);
3399+
3400+ qDebug() << Q_FUNC_INFO << "- value:" << m_zoomFactor << "- changeMode:" << changeMode;
3401+ return true;
3402+ }
3403+
3404+ return false;
3405+}
3406+
3407+bool PdfZoom::adjustZoomToPage(bool changeMode)
3408+{
3409+ if (!m_view->document())
3410+ return false;
3411+
3412+ if (changeMode)
3413+ setZoomMode(PdfZoom::FitPage);
3414+
3415+ updateZoomValues();
3416+
3417+ if (m_zoomFactor != m_valueFitPageZoom) {
3418+ setZoomFactor(m_valueFitPageZoom);
3419+
3420+ qDebug() << Q_FUNC_INFO << "- value:" << m_zoomFactor << "- changeMode:" << changeMode;
3421+ return true;
3422+ }
3423+
3424+ return false;
3425+}
3426+
3427+bool PdfZoom::adjustAutomaticZoom(bool changeMode)
3428+{
3429+ if (!m_view->document())
3430+ return false;
3431+
3432+ if (changeMode)
3433+ setZoomMode(PdfZoom::Automatic);
3434+
3435+ updateZoomValues();
3436+
3437+ if (m_zoomFactor != m_valueAutomaticZoom) {
3438+ setZoomFactor(m_valueAutomaticZoom);
3439+
3440+ qDebug() << Q_FUNC_INFO << "- value:" << m_zoomFactor << "- changeMode:" << changeMode;
3441+ return true;
3442+ }
3443+
3444+ return false;
3445+}
3446+
3447+void PdfZoom::init()
3448+{
3449+ setZoomMode(ZoomMode::Automatic);
3450+}
3451
3452=== added file 'src/plugin/poppler-qml-plugin/pdfzoom.h'
3453--- src/plugin/poppler-qml-plugin/pdfzoom.h 1970-01-01 00:00:00 +0000
3454+++ src/plugin/poppler-qml-plugin/pdfzoom.h 2016-04-22 10:31:39 +0000
3455@@ -0,0 +1,97 @@
3456+/*
3457+ * Copyright (C) 2016 Stefano Verzegnassi
3458+ *
3459+ * This program is free software; you can redistribute it and/or modify
3460+ * it under the terms of the GNU General Public License as published by
3461+ * the Free Software Foundation; version 3.
3462+ *
3463+ * This program is distributed in the hope that it will be useful,
3464+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3465+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3466+ * GNU General Public License for more details.
3467+ *
3468+ * You should have received a copy of the GNU General Public License
3469+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3470+ */
3471+
3472+#ifndef PDFZOOM_H
3473+#define PDFZOOM_H
3474+
3475+#include <QObject>
3476+#include <QSharedPointer>
3477+
3478+class VerticalView;
3479+
3480+class PdfZoom : public QObject
3481+{
3482+ Q_OBJECT
3483+ Q_ENUMS(ZoomMode)
3484+ Q_PROPERTY(ZoomMode zoomMode READ zoomMode NOTIFY zoomModeChanged)
3485+ Q_PROPERTY(qreal zoomFactor READ zoomFactor WRITE setZoomFactor NOTIFY zoomFactorChanged)
3486+ Q_PROPERTY(qreal minimumZoom READ minimumZoom CONSTANT) //WRITE setMinimumZoom NOTIFY minimumZoomChanged)
3487+ Q_PROPERTY(qreal maximumZoom READ maximumZoom CONSTANT) //WRITE setMaximumZoom NOTIFY maximumZoomChanged)
3488+ Q_PROPERTY(qreal valueFitWidthZoom READ valueFitWidthZoom NOTIFY valueFitWidthZoomChanged)
3489+ Q_PROPERTY(qreal valueFitPageZoom READ valueFitPageZoom NOTIFY valueFitPageZoomChanged)
3490+ Q_PROPERTY(qreal valueAutomaticZoom READ valueAutomaticZoom NOTIFY valueAutomaticZoomChanged)
3491+
3492+public:
3493+ PdfZoom(VerticalView *view);
3494+ ~PdfZoom();
3495+
3496+ enum ZoomMode {
3497+ Manual = 0x0,
3498+ FitWidth = 0x1,
3499+ FitPage = 0x2,
3500+ Automatic = 0x4
3501+ };
3502+
3503+ ZoomMode zoomMode() const;
3504+ qreal zoomFactor() const;
3505+ void setZoomFactor(const qreal zoom);
3506+
3507+ qreal minimumZoom() const;
3508+// void setMinimumZoom(const qreal newValue);
3509+
3510+ qreal maximumZoom() const;
3511+// void setMaximumZoom(const qreal newValue);
3512+
3513+ qreal valueFitWidthZoom() const;
3514+ qreal valueFitPageZoom() const;
3515+ qreal valueAutomaticZoom() const;
3516+
3517+ bool adjustZoomToWidth(bool changeMode = true);
3518+ bool adjustZoomToPage(bool changeMode = true);
3519+ bool adjustAutomaticZoom(bool changeMode = true);
3520+
3521+ void init();
3522+
3523+Q_SIGNALS:
3524+ void zoomModeChanged();
3525+ void zoomModesAvailableChanged();
3526+ void zoomFactorChanged();
3527+// void minimumZoomChanged();
3528+// void maximumZoomChanged();
3529+ void valueFitWidthZoomChanged();
3530+ void valueFitPageZoomChanged();
3531+ void valueAutomaticZoomChanged();
3532+
3533+private:
3534+ VerticalView* m_view;
3535+
3536+ ZoomMode m_zoomMode;
3537+
3538+ qreal m_zoomFactor;
3539+
3540+ qreal m_minimumZoom;
3541+ qreal m_maximumZoom;
3542+
3543+ qreal m_valueFitWidthZoom;
3544+ qreal m_valueFitPageZoom;
3545+ qreal m_valueAutomaticZoom;
3546+
3547+private:
3548+ void setZoomMode(const ZoomMode zoomMode);
3549+ void updateZoomValues();
3550+};
3551+
3552+#endif // PDFZOOM_H
3553
3554=== modified file 'src/plugin/poppler-qml-plugin/plugin.cpp'
3555--- src/plugin/poppler-qml-plugin/plugin.cpp 2015-04-15 14:47:28 +0000
3556+++ src/plugin/poppler-qml-plugin/plugin.cpp 2016-04-22 10:31:39 +0000
3557@@ -20,15 +20,22 @@
3558
3559 #include "plugin.h"
3560 #include "pdfdocument.h"
3561+#include "pdfzoom.h"
3562+#include "pdferror.h"
3563 #include "verticalview.h"
3564+#include "touchdetectionarea.h"
3565
3566 void PopplerPlugin::registerTypes(const char *uri)
3567 {
3568 Q_ASSERT(uri == QLatin1String("DocumentViewer.PDF"));
3569
3570 //@uri DocumentViewer.PDF
3571- qmlRegisterType<PdfDocument>(uri, 1, 0, "Document");
3572- qmlRegisterType<VerticalView>(uri, 1, 0, "VerticalView");
3573+ qmlRegisterType<PdfDocument>(uri, 2, 0, "Document");
3574+ qmlRegisterUncreatableType<PdfZoom>(uri, 2, 0, "Zoom", "Not creatable as an object, use only to retrieve error enums (e.g. PDF.Zoom.Manual)");
3575+ qmlRegisterType<VerticalView>(uri, 2, 0, "VerticalView");
3576+ qmlRegisterType<TouchDetectionArea>(uri, 2, 0, "TouchDetectionArea");
3577+ qmlRegisterUncreatableType<PopplerError>(uri, 2, 0, "Error", "Not creatable as an object, use only to retrieve error enums (e.g. PDF.Error.FileNotFound)");
3578+ qmlRegisterUncreatableType<PdfRotation>(uri, 2, 0, "Rotation", "Not creatable as an object, use only to set rotation (e.g. PDF.Rotation.Rotate180)");
3579 }
3580
3581 void PopplerPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
3582
3583=== added directory 'src/plugin/poppler-qml-plugin/qml'
3584=== added file 'src/plugin/poppler-qml-plugin/qml/Viewer.qml'
3585--- src/plugin/poppler-qml-plugin/qml/Viewer.qml 1970-01-01 00:00:00 +0000
3586+++ src/plugin/poppler-qml-plugin/qml/Viewer.qml 2016-04-22 10:31:39 +0000
3587@@ -0,0 +1,186 @@
3588+import QtQuick 2.4
3589+import DocumentViewer.PDF 2.0 as PDF
3590+
3591+Flickable {
3592+ id: rootFlickable
3593+
3594+ property alias document: view.document
3595+ property alias zoomSettings: view.zoomSettings
3596+ property alias cacheBuffer: view.cacheBuffer
3597+ property alias error: view.error
3598+ property alias currentPageIndex: view.currentPageIndex
3599+ property alias pagesCount: view.pagesCount
3600+ property alias spacing: view.spacing
3601+ property alias renderHints: view.renderHints
3602+ property alias showLinkHighlight: view.showLinkHighlight
3603+ property alias linkHighlightColor: view.linkHighlightColor
3604+ property alias rotation: view.rotation
3605+
3606+ property string documentPath: ""
3607+
3608+ property bool isLinkHovered: false
3609+ signal linkHovered(var linkInfo, var mouseX, var mouseY) // mouseX and mouseY are relative to rootFlickable
3610+ signal linkClicked(var isTouch, var linkInfo)
3611+ signal linkDoubleClicked(var isTouch, var linkInfo)
3612+ signal linkPressAndHold(var isTouch, var linkInfo)
3613+
3614+ function adjustZoomToWidth()
3615+ {
3616+ var oldZoom = view.zoomSettings.zoomFactor
3617+ view.adjustZoomToWidth()
3618+
3619+ var zoomScale = view.zoomSettings.zoomFactor / oldZoom
3620+ rootFlickable.contentX *= zoomScale
3621+ rootFlickable.contentY *= zoomScale
3622+ }
3623+
3624+ function adjustZoomToPage()
3625+ {
3626+ var oldZoom = view.zoomSettings.zoomFactor
3627+ view.adjustZoomToPage()
3628+
3629+ var zoomScale = view.zoomSettings.zoomFactor / oldZoom
3630+ rootFlickable.contentX *= zoomScale
3631+ rootFlickable.contentY *= zoomScale
3632+ }
3633+
3634+ function adjustAutomaticZoom()
3635+ {
3636+ var oldZoom = view.zoomSettings.zoomFactor
3637+ view.adjustAutomaticZoom()
3638+
3639+ var zoomScale = view.zoomSettings.zoomFactor / oldZoom
3640+ rootFlickable.contentX *= zoomScale
3641+ rootFlickable.contentY *= zoomScale
3642+ }
3643+
3644+ function setZoom(newValue)
3645+ {
3646+ var zoomScale = newValue / view.zoomSettings.zoomFactor;
3647+ view.zoomSettings.zoomFactor = newValue;
3648+
3649+ rootFlickable.contentX *= zoomScale;
3650+ rootFlickable.contentY *= zoomScale;
3651+ }
3652+
3653+ function moveView(axis, diff)
3654+ {
3655+ if (axis == "vertical") {
3656+ var maxContentY = Math.max(0, rootFlickable.contentHeight - rootFlickable.height)
3657+ rootFlickable.contentY = Math.max(0, Math.min(rootFlickable.contentY + diff, maxContentY ))
3658+ } else {
3659+ var maxContentX = Math.max(0, rootFlickable.contentWidth - rootFlickable.width)
3660+ rootFlickable.contentX = Math.max(0, Math.min(rootFlickable.contentX + diff, maxContentX ))
3661+ }
3662+ }
3663+
3664+ function positionAtBeginning() {
3665+ view.positionAtBeginning()
3666+ }
3667+
3668+ function positionAtIndex(index, top, left) {
3669+ if (typeof(top) === "undefined") top = 0
3670+ if (typeof(left) === "undefined") left = 0
3671+
3672+ view.positionAtIndex(index, top, left)
3673+ }
3674+
3675+ function positionAtEnd() {
3676+ view.positionAtEnd()
3677+ }
3678+
3679+ function unlock(ownerPassword, userPassword) {
3680+ return view.unlock(ownerPassword, userPassword)
3681+ }
3682+
3683+ onDocumentPathChanged: {
3684+ if (documentPath)
3685+ view.initializeDocument(documentPath)
3686+ }
3687+
3688+ // zoomFactor is not used here to set contentSize, since it's all managed
3689+ // internally, in the LibreOffice.View component.
3690+ contentHeight: Math.max(rootFlickable.height, view.height)
3691+ contentWidth: Math.max(rootFlickable.width, view.width)
3692+
3693+ boundsBehavior: Flickable.StopAtBounds
3694+
3695+ PDF.VerticalView {
3696+ id: view
3697+
3698+ x: Math.max(0, (rootFlickable.width - view.width) * 0.5)
3699+ y: Math.max(0, (rootFlickable.height - view.height) * 0.5)
3700+
3701+ parentFlickable: rootFlickable
3702+ }
3703+
3704+ MouseArea {
3705+ anchors.fill: parent
3706+ // Explicitely set rootFlickable as parent, otherwise it's rootFlickable.contentItem
3707+ parent: rootFlickable
3708+ enabled: !rootFlickable.moving
3709+
3710+ acceptedButtons: Qt.LeftButton
3711+
3712+ hoverEnabled: true
3713+ onPositionChanged: {
3714+ var linkInfo = view.linkAtPosition(rootFlickable.contentX + mouse.x - view.x,
3715+ rootFlickable.contentY + mouse.y - view.y);
3716+
3717+ // Don't emit linkHovered() if it's a touch event.
3718+ // Hover boxes are a mouse-related thing.
3719+ if (touchArea.touchPressed)
3720+ return
3721+
3722+ if (linkInfo.pageIndex || linkInfo.url) {
3723+ cursorShape = Qt.PointingHandCursor
3724+ rootFlickable.linkHovered(linkInfo, mouse.x, mouse.y)
3725+ rootFlickable.isLinkHovered = true
3726+ } else {
3727+ cursorShape = Qt.ArrowCursor
3728+ rootFlickable.isLinkHovered = false
3729+ }
3730+ }
3731+
3732+ onClicked: {
3733+ var isTouch = touchArea.touchPressed
3734+ var linkInfo = view.linkAtPosition(rootFlickable.contentX + mouse.x - view.x,
3735+ rootFlickable.contentY + mouse.y - view.y);
3736+
3737+ if (linkInfo.pageIndex || linkInfo.url) {
3738+ rootFlickable.linkClicked(isTouch, linkInfo)
3739+ }
3740+ }
3741+
3742+ onDoubleClicked: {
3743+ var isTouch = touchArea.touchPressed
3744+ var linkInfo = view.linkAtPosition(rootFlickable.contentX + mouse.x - view.x,
3745+ rootFlickable.contentY + mouse.y - view.y);
3746+
3747+ if (linkInfo.pageIndex || linkInfo.url) {
3748+ rootFlickable.linkDoubleClicked(isTouch, linkInfo)
3749+ }
3750+ }
3751+
3752+ onPressAndHold: {
3753+ var isTouch = touchArea.touchPressed
3754+ var linkInfo = view.linkAtPosition(rootFlickable.contentX + mouse.x - view.x,
3755+ rootFlickable.contentY + mouse.y - view.y);
3756+
3757+ if (linkInfo.pageIndex || linkInfo.url) {
3758+ rootFlickable.linkPressAndHold(isTouch, linkInfo)
3759+ }
3760+ }
3761+
3762+ // QML MultiPointTouchArea does not propagate events to its parent items. That
3763+ // would have led to a more complex logic.
3764+ // However, events returned by QML MouseArea signals don't inherit QEvent, so
3765+ // we can not check for the type event.
3766+ // We need to create our own component then.
3767+ PDF.TouchDetectionArea {
3768+ id: touchArea
3769+ anchors.fill: parent
3770+ enabled: !rootFlickable.moving
3771+ }
3772+ }
3773+}
3774
3775=== modified file 'src/plugin/poppler-qml-plugin/qmldir'
3776--- src/plugin/poppler-qml-plugin/qmldir 2015-04-15 14:47:28 +0000
3777+++ src/plugin/poppler-qml-plugin/qmldir 2016-04-22 10:31:39 +0000
3778@@ -1,2 +1,4 @@
3779 module DocumentViewer.PDF
3780 plugin popplerqmlplugin
3781+
3782+Viewer 2.0 Viewer.qml
3783
3784=== added file 'src/plugin/poppler-qml-plugin/sgtileitem.cpp'
3785--- src/plugin/poppler-qml-plugin/sgtileitem.cpp 1970-01-01 00:00:00 +0000
3786+++ src/plugin/poppler-qml-plugin/sgtileitem.cpp 2016-04-22 10:31:39 +0000
3787@@ -0,0 +1,89 @@
3788+#include "sgtileitem.h"
3789+#include "pdfdocument.h"
3790+
3791+#include <QQuickWindow>
3792+#include <QSGSimpleTextureNode>
3793+
3794+#ifdef DEBUG_SHOW_TILE_BORDER
3795+#include <QSGGeometryNode>
3796+#include <QSGFlatColorMaterial>
3797+#endif
3798+
3799+SGTileItem::SGTileItem(const QRect& area, qreal zoom, int id, QQuickItem *parent)
3800+ : QQuickItem(parent)
3801+ , m_area(area)
3802+ , m_zoomFactor(zoom)
3803+ , m_id (id)
3804+{
3805+ setFlag(ItemHasContents, true);
3806+
3807+ setX(m_area.x());
3808+ setY(m_area.y());
3809+ setWidth(m_area.width());
3810+ setHeight(m_area.height());
3811+}
3812+
3813+SGTileItem::~SGTileItem()
3814+{ }
3815+
3816+QSGNode *SGTileItem::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *)
3817+{
3818+ QSGSimpleTextureNode* node = static_cast<QSGSimpleTextureNode*>(oldNode);
3819+ QQuickWindow* wnd = window();
3820+
3821+ if (!node && wnd && !m_data.isNull()) {
3822+ auto texture = wnd->createTextureFromImage(m_data);
3823+ node = new QSGSimpleTextureNode();
3824+ node->setTexture(texture);
3825+ node->setOwnsTexture(true);
3826+
3827+ node->setRect(QRect(0, 0, width(), height()));
3828+
3829+#ifdef DEBUG_SHOW_TILE_BORDER
3830+ drawTileBorders(node);
3831+#endif
3832+ }
3833+
3834+ return node;
3835+}
3836+
3837+void SGTileItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
3838+{
3839+ QQuickItem::geometryChanged(newGeometry, oldGeometry);
3840+}
3841+
3842+#ifdef DEBUG_SHOW_TILE_BORDER
3843+void SGTileItem::drawTileBorders(QSGSimpleTextureNode* parentNode)
3844+{
3845+ auto node = parentNode;
3846+ auto tileBorderGeometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 8);
3847+ tileBorderGeometry->setDrawingMode(GL_LINES);
3848+ tileBorderGeometry->setLineWidth(4);
3849+
3850+ QSGGeometry::Point2D* vertex = tileBorderGeometry->vertexDataAsPoint2D();
3851+ vertex[0].set(node->rect().left(), node->rect().top());
3852+ vertex[1].set(node->rect().left(), node->rect().bottom());
3853+
3854+ vertex[2].set(node->rect().right(), node->rect().top());
3855+ vertex[3].set(node->rect().right(), node->rect().bottom());
3856+
3857+ vertex[4].set(vertex[0].x, vertex[0].y);
3858+ vertex[5].set(vertex[2].x, vertex[2].y);
3859+
3860+ vertex[6].set(vertex[1].x, vertex[1].y);
3861+ vertex[7].set(vertex[3].x, vertex[3].y);
3862+
3863+ auto tileBorderMaterial = new QSGFlatColorMaterial;
3864+ tileBorderMaterial->setColor(Qt::red);
3865+
3866+ auto tileBorderNode = new QSGGeometryNode;
3867+
3868+ tileBorderNode->setGeometry(tileBorderGeometry);
3869+ tileBorderNode->setFlag(QSGNode::OwnsGeometry);
3870+
3871+ tileBorderNode->setMaterial(tileBorderMaterial);
3872+ tileBorderNode->setFlag(QSGNode::OwnsMaterial);
3873+
3874+ node->appendChildNode(tileBorderNode);
3875+}
3876+#endif
3877
3878=== added file 'src/plugin/poppler-qml-plugin/sgtileitem.h'
3879--- src/plugin/poppler-qml-plugin/sgtileitem.h 1970-01-01 00:00:00 +0000
3880+++ src/plugin/poppler-qml-plugin/sgtileitem.h 2016-04-22 10:31:39 +0000
3881@@ -0,0 +1,48 @@
3882+#ifndef SGTILEITEM_H
3883+#define SGTILEITEM_H
3884+
3885+#include <QQuickItem>
3886+#include <QImage>
3887+
3888+class PdfDocument;
3889+
3890+//#ifdef DEBUG_SHOW_TILE_BORDER
3891+class QSGSimpleTextureNode;
3892+//#endif
3893+
3894+class SGTileItem : public QQuickItem
3895+{
3896+ Q_OBJECT
3897+public:
3898+ SGTileItem(const QRect& area, qreal zoom, int id, QQuickItem *parent = 0);
3899+ ~SGTileItem();
3900+
3901+ inline const QRect& area() { return m_area; }
3902+ inline void setArea(const QRect& rect) { m_area = rect; }
3903+
3904+ inline const qreal& zoomFactor() const { return m_zoomFactor; }
3905+ inline void setZoomFactor(const qreal &zoom) { m_zoomFactor = zoom; }
3906+
3907+ inline int id() { return m_id; }
3908+ inline void setId(int id) { m_id = id; }
3909+
3910+ inline QImage data() { return m_data; }
3911+ inline void setData(QImage data) { m_data = data; update(); }
3912+
3913+protected:
3914+ virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
3915+ virtual void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry);
3916+
3917+private:
3918+#ifdef DEBUG_SHOW_TILE_BORDER
3919+ void drawTileBorders(QSGSimpleTextureNode *parentNode);
3920+#endif
3921+
3922+private:
3923+ QRect m_area;
3924+ qreal m_zoomFactor;
3925+ QImage m_data;
3926+ int m_id;
3927+};
3928+
3929+#endif // SGTILEITEM_H
3930
3931=== added file 'src/plugin/poppler-qml-plugin/touchdetectionarea.cpp'
3932--- src/plugin/poppler-qml-plugin/touchdetectionarea.cpp 1970-01-01 00:00:00 +0000
3933+++ src/plugin/poppler-qml-plugin/touchdetectionarea.cpp 2016-04-22 10:31:39 +0000
3934@@ -0,0 +1,21 @@
3935+#include "touchdetectionarea.h"
3936+
3937+#include <QDebug>
3938+
3939+TouchDetectionArea::TouchDetectionArea(QQuickItem *parent)
3940+ : QQuickItem(parent)
3941+ , m_touchPressed(false)
3942+{ }
3943+
3944+void TouchDetectionArea::touchEvent(QTouchEvent *event)
3945+{
3946+ if (event->type() == QEvent::TouchBegin) {
3947+ m_touchPressed = true;
3948+ Q_EMIT touchPressedChanged();
3949+ } else if (event->type() == QEvent::TouchEnd) {
3950+ m_touchPressed = false;
3951+ Q_EMIT touchPressedChanged();
3952+ }
3953+
3954+ event->ignore();
3955+}
3956
3957=== added file 'src/plugin/poppler-qml-plugin/touchdetectionarea.h'
3958--- src/plugin/poppler-qml-plugin/touchdetectionarea.h 1970-01-01 00:00:00 +0000
3959+++ src/plugin/poppler-qml-plugin/touchdetectionarea.h 2016-04-22 10:31:39 +0000
3960@@ -0,0 +1,24 @@
3961+#ifndef TOUCHDETECTIONAREA_H
3962+#define TOUCHDETECTIONAREA_H
3963+
3964+#include <QQuickItem>
3965+
3966+class TouchDetectionArea : public QQuickItem
3967+{
3968+ Q_OBJECT
3969+ Q_PROPERTY(bool touchPressed READ touchPressed NOTIFY touchPressedChanged)
3970+public:
3971+ TouchDetectionArea(QQuickItem *parent = 0);
3972+ bool touchPressed() const { return m_touchPressed; }
3973+
3974+Q_SIGNALS:
3975+ void touchPressedChanged();
3976+
3977+protected:
3978+ virtual void touchEvent(QTouchEvent *event);
3979+
3980+private:
3981+ bool m_touchPressed;
3982+};
3983+
3984+#endif // TOUCHDETECTIONAREA_H
3985
3986=== added file 'src/plugin/poppler-qml-plugin/twips.h'
3987--- src/plugin/poppler-qml-plugin/twips.h 1970-01-01 00:00:00 +0000
3988+++ src/plugin/poppler-qml-plugin/twips.h 2016-04-22 10:31:39 +0000
3989@@ -0,0 +1,98 @@
3990+/*
3991+ * Copyright (C) 2015, 2016 Stefano Verzegnassi
3992+ * Copyright (C) 2015 Roman Shchekin
3993+ *
3994+ * This program is free software: you can redistribute it and/or modify it
3995+ * under the terms of the GNU General Public License version 3, as published
3996+ * by the Free Software Foundation.
3997+ *
3998+ * This program is distributed in the hope that it will be useful, but
3999+ * WITHOUT ANY WARRANTY; without even the implied warranties of
4000+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
4001+ * PURPOSE. See the GNU General Public License for more details.
4002+ *
4003+ * You should have received a copy of the GNU General Public License along
4004+ * with this program. If not, see <http://www.gnu.org/licenses/>.
4005+ *
4006+ */
4007+
4008+#ifndef TWIPS_H
4009+#define TWIPS_H
4010+
4011+#include <QtGlobal>
4012+#include <QtWidgets/QApplication>
4013+#include <QScreen>
4014+
4015+#include "ucunits.h"
4016+
4017+#define DEFAULT_DPI 96
4018+#define DEFAULT_GRID_UNIT_PX 8
4019+
4020+class Twips
4021+{
4022+public:
4023+ enum ConvertionMode {
4024+ UseDPI = 0,
4025+ UseUnits = 1
4026+ };
4027+
4028+ static inline int convertPointsToPixels(int points, qreal zoom = 1.0,
4029+ ConvertionMode mode = ConvertionMode::UseUnits)
4030+ {
4031+ return convertTwipsToPixels(points * 20, zoom, mode);
4032+ }
4033+
4034+ static inline int convertPixelsToPoints(int pixels, qreal zoom = 1.0,
4035+ ConvertionMode mode = ConvertionMode::UseUnits)
4036+ {
4037+ return convertPixelsToTwips(pixels / 20, zoom, mode);
4038+ }
4039+
4040+ static inline int convertTwipsToPixels(int twips, qreal zoom = 1.0,
4041+ ConvertionMode mode = ConvertionMode::UseUnits)
4042+ {
4043+ if (mode == ConvertionMode::UseUnits) {
4044+ qreal ratio = getUnitsRatio();
4045+ return int(twips / 1440.0 * (DEFAULT_DPI * ratio) * zoom);
4046+ } else {
4047+ qreal dpi = getLogicalDotsPerInch();
4048+ return int(twips / 1440.0 * (dpi ? dpi : DEFAULT_DPI) * zoom);
4049+ }
4050+ }
4051+
4052+ static inline int convertPixelsToTwips(int pixels, qreal zoom = 1.0,
4053+ ConvertionMode mode = ConvertionMode::UseUnits)
4054+ {
4055+ if (mode == ConvertionMode::UseUnits) {
4056+ qreal ratio = getUnitsRatio();
4057+ return int(pixels * 1440.0 / (DEFAULT_DPI * ratio) / zoom);
4058+ } else {
4059+ qreal dpi = getLogicalDotsPerInch();
4060+ return int(pixels * 1440.0 / (dpi ? dpi : DEFAULT_DPI) / zoom);
4061+ }
4062+ }
4063+
4064+ static inline qreal getLogicalDotsPerInch()
4065+ {
4066+ static qreal value = 0;
4067+ if (!value) {
4068+ QList<QScreen*> screens = QGuiApplication::screens();
4069+ if (screens.size()) {
4070+ QScreen *screen = screens.at(0);
4071+ // Subscribe for changing signal (just to make caching rock-solid).
4072+ QObject::connect(screen, &QScreen::logicalDotsPerInchChanged,
4073+ [] (const qreal newValue) { value = newValue; } );
4074+ value = screen->logicalDotsPerInch();
4075+ }
4076+ }
4077+
4078+ return value;
4079+ }
4080+
4081+ static inline qreal getUnitsRatio()
4082+ {
4083+ return UCUnits::instance().gridUnit() / DEFAULT_GRID_UNIT_PX;
4084+ }
4085+};
4086+
4087+#endif // TWIPS_H
4088
4089=== added file 'src/plugin/poppler-qml-plugin/ucunits.cpp'
4090--- src/plugin/poppler-qml-plugin/ucunits.cpp 1970-01-01 00:00:00 +0000
4091+++ src/plugin/poppler-qml-plugin/ucunits.cpp 2016-04-22 10:31:39 +0000
4092@@ -0,0 +1,241 @@
4093+/*
4094+ * Copyright 2012 Canonical Ltd.
4095+ *
4096+ * This program is free software; you can redistribute it and/or modify
4097+ * it under the terms of the GNU Lesser General Public License as published by
4098+ * the Free Software Foundation; version 3.
4099+ *
4100+ * This program is distributed in the hope that it will be useful,
4101+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4102+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4103+ * GNU Lesser General Public License for more details.
4104+ *
4105+ * You should have received a copy of the GNU Lesser General Public License
4106+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4107+ *
4108+ * Author: Florian Boucault <florian.boucault@canonical.com>
4109+ */
4110+
4111+#include "ucunits.h"
4112+
4113+#include <QtQml/QQmlContext>
4114+#include <QtQml/QQmlFile>
4115+#include <QtCore/QFileInfo>
4116+#include <QtCore/QDir>
4117+#include <QtCore/QRegularExpression>
4118+#include <QtCore/qmath.h>
4119+#include <QtGui/QGuiApplication>
4120+#include <QtGui/QScreen>
4121+
4122+#define ENV_GRID_UNIT_PX "GRID_UNIT_PX"
4123+#define DEFAULT_GRID_UNIT_PX 8
4124+
4125+static float getenvFloat(const char* name, float defaultValue)
4126+{
4127+ QByteArray stringValue = qgetenv(name);
4128+ bool ok;
4129+ float value = stringValue.toFloat(&ok);
4130+ return ok ? value : defaultValue;
4131+}
4132+
4133+
4134+/*!
4135+ \qmltype Units
4136+ \instantiates UCUnits
4137+ \inqmlmodule Ubuntu.Components 1.1
4138+ \ingroup resolution-independence
4139+ \brief Units of measurement for sizes, spacing, margin, etc.
4140+
4141+ Units provides facilities for measuring UI elements in a variety
4142+ of units other than just pixels.
4143+
4144+ A global instance of Units is exposed as the \b{units} context property.
4145+ Example usage:
4146+
4147+ \qml
4148+ import QtQuick 2.4
4149+ import Ubuntu.Components 1.2
4150+
4151+ Item {
4152+ width: units.gu(2)
4153+ height: units.gu(5)
4154+ }
4155+ \endqml
4156+
4157+ \sa {Resolution Independence}
4158+*/
4159+
4160+/*
4161+ * Note on the interaction between GRID_UNIT_PX and QT_DEVICE_PIXEL_RATIO
4162+ *
4163+ * In Qt5.4 there is a single means to scale the UI: the QT_DEVICE_PIXEL_RATIO environment
4164+ * variable. This accepts only integer values, thus allowing a x2 or x3 scaling of any
4165+ * Qt-based UI, that includes QWidget as well as any QML UI.
4166+ *
4167+ * Setting QT_DEVICE_PIXEL_RATIO=2 implies one density-independent pixel corresponds to 2
4168+ * physical pixels. Developers describe their UI in terms of density-independent pixels.
4169+ * Qt scales accordingly.
4170+ *
4171+ * The Ubuntu UI Toolkit has solved the scaling problem with the GRID_UNIT_PX variable.
4172+ * It offers more flexibility, but only scales QML applications written to use the UITK
4173+ * (since it uses this Units class) as it is built on top of QML.
4174+ *
4175+ * There are additional areas in Qt where QT_DEVICE_PIXEL_RATIO causes correct scaling which
4176+ * GRID_UNIT_PX cannot, for example:
4177+ * 1. cacheBuffer for ListView/GridViews - specified in density-independent pixels
4178+ * 2. gesture recognition matches what is on screen better, as it is density-independent
4179+ * pixel aware
4180+ *
4181+ * In order to get the best of both worlds, Ubuntu will set both GRID_UNIT_PX and
4182+ * QT_DEVICE_PIXEL_RATIO. Thus all Qt apps will scale reasonably well, with UITK-based apps
4183+ * scaling perfectly for any desired scale (i.e. non-integer scales).
4184+ *
4185+ * However UITK developers can just use this Units class as usual, and will be almost totally
4186+ * isolated from Qt's own scaling concept.
4187+ */
4188+
4189+UCUnits::UCUnits(QObject *parent) :
4190+ QObject(parent),
4191+ m_devicePixelRatio(qGuiApp->devicePixelRatio())
4192+{
4193+ // If GRID_UNIT_PX set, always use it. If not, 1GU := DEFAULT_GRID_UNIT_PX * m_devicePixelRatio
4194+ if (qEnvironmentVariableIsSet(ENV_GRID_UNIT_PX)) {
4195+ m_gridUnit = getenvFloat(ENV_GRID_UNIT_PX, DEFAULT_GRID_UNIT_PX);
4196+ } else {
4197+ m_gridUnit = DEFAULT_GRID_UNIT_PX * m_devicePixelRatio;
4198+ }
4199+}
4200+
4201+/*!
4202+ \qmlproperty real Units::gridUnit
4203+
4204+ The number of pixels 1 grid unit corresponds to.
4205+*/
4206+float UCUnits::gridUnit()
4207+{
4208+ return m_gridUnit;
4209+}
4210+
4211+void UCUnits::setGridUnit(float gridUnit)
4212+{
4213+ m_gridUnit = gridUnit;
4214+ Q_EMIT gridUnitChanged();
4215+}
4216+
4217+/*!
4218+ \qmlmethod real Units::dp(real value)
4219+
4220+ Returns the number of pixels \a value density independent pixels correspond to.
4221+*/
4222+// Density-independent pixels (and not physical pixels) because Qt sizes in terms of density-independent pixels.
4223+float UCUnits::dp(float value)
4224+{
4225+ const float ratio = m_gridUnit / DEFAULT_GRID_UNIT_PX;
4226+ if (value <= 2.0) {
4227+ // for values under 2dp, return only multiples of the value
4228+ return qRound(value * qFloor(ratio)) / m_devicePixelRatio;
4229+ } else {
4230+ return qRound(value * ratio) / m_devicePixelRatio;
4231+ }
4232+}
4233+
4234+/*!
4235+ \qmlmethod real Units::gu(real value)
4236+
4237+ Returns the number of pixels \a value grid units correspond to.
4238+*/
4239+// Density-independent pixels (and not physical pixels) because Qt sizes in terms of density-independent pixels.
4240+
4241+float UCUnits::gu(float value)
4242+{
4243+ return qRound(value * m_gridUnit) / m_devicePixelRatio;
4244+}
4245+
4246+QString UCUnits::resolveResource(const QUrl& url)
4247+{
4248+ if (url.isEmpty()) {
4249+ return QString();
4250+ }
4251+
4252+ QString path = QQmlFile::urlToLocalFileOrQrc(url);
4253+
4254+ if (path.isEmpty()) {
4255+ return QString();
4256+ }
4257+
4258+ QFileInfo fileInfo(path);
4259+ if (fileInfo.exists() && !fileInfo.isFile()) {
4260+ return QString();
4261+ }
4262+
4263+ QString prefix = fileInfo.dir().absolutePath() + QDir::separator() + fileInfo.baseName();
4264+ QString suffix = "." + fileInfo.completeSuffix();
4265+
4266+ /* Use file with expected grid unit suffix if it exists.
4267+ For example, if m_gridUnit = 10, look for resource@10.png.
4268+ */
4269+
4270+ path = prefix + suffixForGridUnit(m_gridUnit) + suffix;
4271+ if (QFile::exists(path)) {
4272+ return QString("1") + "/" + path;
4273+ }
4274+
4275+ /* No file with expected grid unit suffix exists.
4276+ List all the files of the form fileBaseName@[0-9]*.fileSuffix and select
4277+ the most appropriate one privileging downscaling high resolution assets
4278+ over upscaling low resolution assets.
4279+
4280+ The most appropriate file has a grid unit suffix greater than the target
4281+ grid unit (m_gridUnit) yet as small as possible.
4282+ If no file with a grid unit suffix greater than the target grid unit
4283+ exists, then select one with a grid unit suffix as close as possible to
4284+ the target grid unit.
4285+
4286+ For example, if m_gridUnit = 10 and the available files are
4287+ resource@9.png, resource@14.png and resource@18.png, the most appropriate
4288+ file would be resource@14.png since it is above 10 and smaller
4289+ than resource@18.png.
4290+ */
4291+ QStringList nameFilters;
4292+ nameFilters << fileInfo.baseName() + "@[0-9]*" + suffix;
4293+ QStringList files = fileInfo.dir().entryList(nameFilters, QDir::Files);
4294+
4295+ if (!files.empty()) {
4296+ float selectedGridUnitSuffix = gridUnitSuffixFromFileName(files.first());
4297+
4298+ Q_FOREACH (const QString& fileName, files) {
4299+ float gridUnitSuffix = gridUnitSuffixFromFileName(fileName);
4300+ if ((selectedGridUnitSuffix >= m_gridUnit && gridUnitSuffix >= m_gridUnit && gridUnitSuffix < selectedGridUnitSuffix)
4301+ || (selectedGridUnitSuffix < m_gridUnit && gridUnitSuffix > selectedGridUnitSuffix)) {
4302+ selectedGridUnitSuffix = gridUnitSuffix;
4303+ }
4304+ }
4305+
4306+ path = prefix + suffixForGridUnit(selectedGridUnitSuffix) + suffix;
4307+ float scaleFactor = m_gridUnit / selectedGridUnitSuffix;
4308+ return QString::number(scaleFactor) + "/" + path;
4309+ }
4310+
4311+ path = prefix + suffix;
4312+ if (QFile::exists(path)) {
4313+ return QString("1") + "/" + path;
4314+ }
4315+
4316+ return QString();
4317+}
4318+
4319+QString UCUnits::suffixForGridUnit(float gridUnit)
4320+{
4321+ return "@" + QString::number(gridUnit);
4322+}
4323+
4324+float UCUnits::gridUnitSuffixFromFileName(const QString& fileName)
4325+{
4326+ QRegularExpression re("^.*@([0-9]*).*$");
4327+ QRegularExpressionMatch match = re.match(fileName);
4328+ if (match.hasMatch()) {
4329+ return match.captured(1).toFloat();
4330+ } else {
4331+ return 0;
4332+ }
4333+}
4334
4335=== added file 'src/plugin/poppler-qml-plugin/ucunits.h'
4336--- src/plugin/poppler-qml-plugin/ucunits.h 1970-01-01 00:00:00 +0000
4337+++ src/plugin/poppler-qml-plugin/ucunits.h 2016-04-22 10:31:39 +0000
4338@@ -0,0 +1,60 @@
4339+/*
4340+ * Copyright 2012 Canonical Ltd.
4341+ *
4342+ * This program is free software; you can redistribute it and/or modify
4343+ * it under the terms of the GNU Lesser General Public License as published by
4344+ * the Free Software Foundation; version 3.
4345+ *
4346+ * This program is distributed in the hope that it will be useful,
4347+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4348+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4349+ * GNU Lesser General Public License for more details.
4350+ *
4351+ * You should have received a copy of the GNU Lesser General Public License
4352+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4353+ *
4354+ * Author: Florian Boucault <florian.boucault@canonical.com>
4355+ */
4356+
4357+#ifndef UBUNTU_COMPONENTS_UNITS_H
4358+#define UBUNTU_COMPONENTS_UNITS_H
4359+
4360+#include <QObject>
4361+#include <QtCore/QHash>
4362+#include <QtCore/QUrl>
4363+
4364+class UCUnits : public QObject
4365+{
4366+ Q_OBJECT
4367+ Q_PROPERTY(float gridUnit READ gridUnit WRITE setGridUnit NOTIFY gridUnitChanged)
4368+
4369+public:
4370+ static UCUnits& instance() {
4371+ static UCUnits instance;
4372+ return instance;
4373+ }
4374+
4375+ explicit UCUnits(QObject *parent = 0);
4376+ Q_INVOKABLE float dp(float value);
4377+ Q_INVOKABLE float gu(float value);
4378+ QString resolveResource(const QUrl& url);
4379+
4380+ // getters
4381+ float gridUnit();
4382+
4383+ // setters
4384+ void setGridUnit(float gridUnit);
4385+
4386+Q_SIGNALS:
4387+ void gridUnitChanged();
4388+
4389+protected:
4390+ QString suffixForGridUnit(float gridUnit);
4391+ float gridUnitSuffixFromFileName(const QString &fileName);
4392+
4393+private:
4394+ float m_devicePixelRatio;
4395+ float m_gridUnit;
4396+};
4397+
4398+#endif // UBUNTU_COMPONENTS_UNITS_H
4399
4400=== modified file 'src/plugin/poppler-qml-plugin/verticalview.cpp'
4401--- src/plugin/poppler-qml-plugin/verticalview.cpp 2015-04-26 14:39:20 +0000
4402+++ src/plugin/poppler-qml-plugin/verticalview.cpp 2016-04-22 10:31:39 +0000
4403@@ -1,187 +1,117 @@
4404-/*
4405- * Copyright (C) 2013-2015 Canonical, Ltd.
4406- *
4407- * This program is free software; you can redistribute it and/or modify
4408- * it under the terms of the GNU General Public License as published by
4409- * the Free Software Foundation; version 3.
4410- *
4411- * This program is distributed in the hope that it will be useful,
4412- * but WITHOUT ANY WARRANTY; without even the implied warranty of
4413- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4414- * GNU General Public License for more details.
4415- *
4416- * You should have received a copy of the GNU General Public License
4417- * along with this program. If not, see <http://www.gnu.org/licenses/>.
4418- */
4419-
4420-/*
4421- * Some documentation on how this thing works:
4422- *
4423- * A flickable has two very important concepts that define the top and
4424- * height of the flickable area.
4425- * The top is returned in minYExtent()
4426- * The height is set using setContentHeight()
4427- * By changing those two values we can make the list grow up or down
4428- * as needed. e.g. if we are in the middle of the list
4429- * and something that is above the viewport grows, since we do not
4430- * want to change the viewport because of that we just adjust the
4431- * minYExtent so that the list grows up.
4432- *
4433- * The implementation on the list relies on the delegateModel doing
4434- * most of the instantiation work. You call createItem() when you
4435- * need to create an item asking for it async or not. If returns null
4436- * it means the item will be created async and the model will call the
4437- * itemCreated slot with the item.
4438- *
4439- * updatePolish is the central point of dispatch for the work of the
4440- * class. It is called by the scene graph just before drawing the class.
4441- * In it we:
4442- * * Make sure all items are positioned correctly
4443- * * Add/Remove items if needed
4444- * * Update the content height if it was dirty
4445- *
4446- * m_visibleItems contains all the items we have created at the moment.
4447- * Actually not all of them are visible since it includes the ones
4448- * in the cache area we create asynchronously to help performance.
4449- * The first item in m_visibleItems has the m_firstVisibleIndex in
4450- * the model. If you actually want to know what is the first
4451- * item in the viewport you have to find the first non culled element
4452- * in m_visibleItems
4453- *
4454- * The first item of m_visibleItems is the one that defines the
4455- * positions of all the rest of items (see updatePolish()) and
4456- * this is why sometimes we move it even if it's not the item
4457- * that has triggered the function (i.e. in itemGeometryChanged())
4458- *
4459- * m_visibleItems is a list of ListItem. Each ListItem
4460- * will contain a item and potentially a sectionItem. The sectionItem
4461- * is only there when the list is using sectionDelegate+sectionProperty
4462- * and this is the first item of the section. Each ListItem is vertically
4463- * layouted with the sectionItem first and then the item.
4464- *
4465- * Note that minYExtent and height are not always totally accurate, since
4466- * we don't have the items created we can't guess their heights
4467- * so we can only guarantee the values are correct when the first/last
4468- * items of the list are visible, otherwise we just live with good enough
4469- * values that make the list scrollable
4470- *
4471- * There are a few things that are not really implemented or tested properly
4472- * which we don't use at the moment like changing the model, etc.
4473- * The known missing features are marked with TODOs along the code.
4474- */
4475-
4476 #include "verticalview.h"
4477-
4478-#include <QCoreApplication>
4479-#include <QDebug>
4480-#include <qqmlinfo.h>
4481-#include <qqmlengine.h>
4482-#pragma GCC diagnostic push
4483-#pragma GCC diagnostic ignored "-pedantic"
4484-#include <private/qqmldelegatemodel_p.h>
4485-#include <private/qqmlglobal_p.h>
4486-#include <private/qquickitem_p.h>
4487-#include <private/qquickanimation_p.h>
4488-#pragma GCC diagnostic pop
4489-
4490-qreal VerticalView::ListItem::height() const
4491-{
4492- return m_item->height();
4493-}
4494-
4495-qreal VerticalView::ListItem::y() const
4496-{
4497- return m_item->y();
4498-}
4499-
4500-void VerticalView::ListItem::setY(qreal newY)
4501-{
4502- m_item->setY(newY);
4503-}
4504-
4505-bool VerticalView::ListItem::culled() const
4506-{
4507- return QQuickItemPrivate::get(m_item)->culled;
4508-}
4509-
4510-void VerticalView::ListItem::setCulled(bool culled)
4511-{
4512- QQuickItemPrivate::get(m_item)->setCulled(culled);
4513-}
4514-
4515-VerticalView::VerticalView()
4516- : m_delegateModel(nullptr)
4517- , m_asyncRequestedIndex(-1)
4518- , m_delegateValidated(false)
4519- , m_firstVisibleIndex(-1)
4520- , m_currentPageIndex(-1)
4521- , m_minYExtent(0)
4522- , m_contentHeightDirty(false)
4523- , m_previousContentY(0)
4524- , m_inLayout(false)
4525- , m_cacheBuffer(0)
4526- , m_spacing(0)
4527-{
4528- connect(this, SIGNAL(heightChanged()), this, SLOT(_q_heightChanged()));
4529- connect(this, SIGNAL(contentYChanged()), this, SLOT(_q_updateCurrentPageIndex()));
4530-
4531- setFlickableDirection(QQuickFlickable::HorizontalAndVerticalFlick);
4532+//#include "pdfdocument.h"
4533+#include "pdfzoom.h"
4534+#include "twips.h"
4535+#include "sgtileitem.h"
4536+#include "pagedecoration.h"
4537+#include "pageoverlay.h"
4538+
4539+#include "config.h"
4540+
4541+#include <QImage>
4542+#include <QtCore/qmath.h>
4543+
4544+// FIXME: Sometimes layout is not created when a document is opened
4545+// TODO: Check if everything works as expected when zooming
4546+
4547+#define UPDATE_TIMER_MSECS 20
4548+
4549+VerticalView::VerticalView(QQuickItem *parent)
4550+ : QQuickItem(parent)
4551+ , m_parentFlickable(nullptr)
4552+ , m_document(nullptr)
4553+ , m_zoomSettings(new PdfZoom(this))
4554+ , m_cacheBuffer(200)
4555+ , m_spacing(12)
4556+ , m_rotation(PdfRotation::Rotate0)
4557+ , m_currentPageIndex(-1)
4558+ , m_visibleArea(0, 0, 0, 0)
4559+ , m_bufferArea(0, 0, 0, 0)
4560+ , m_renderHints(0)
4561+ , m_showLinkHighlight(true)
4562+ , m_linkHighlightColor(Qt::red)
4563+ , m_error(PopplerError::NoError)
4564+ , m_hasZoomChanged(false)
4565+ , m_hasRotationChanged(false)
4566+ , m_hasFlickableBeenScrolled(false)
4567+ , m_hasFlickableBeenResized(false)
4568+ , m_hasRenderHintsChanged(false)
4569+{
4570+ // Connect signals
4571+ connect(this, &VerticalView::documentChanged, this, &VerticalView::updateLayout);
4572+ connect(this, &VerticalView::parentFlickableChanged, this, &VerticalView::updateLayout);
4573+ connect(this, &VerticalView::cacheBufferChanged, this, &VerticalView::updateLayout);
4574+ connect(this, &VerticalView::spacingChanged, this, &VerticalView::updateLayout);
4575+ connect(this, &VerticalView::renderHintsChanged, this, &VerticalView::onRenderHintsChanged);
4576+
4577+ connect(RenderEngine::instance(), &RenderEngine::taskRenderFinished,
4578+ this, &VerticalView::slotTaskRenderFinished);
4579+
4580+ connect(&m_updateTimer, &QTimer::timeout, this, &VerticalView::updateLayout);
4581+
4582+ connect(m_zoomSettings, &PdfZoom::zoomFactorChanged, [&]() {
4583+ m_hasZoomChanged = true;
4584+ updateLayout();
4585+ });
4586+
4587+ connect(this, &VerticalView::rotationChanged, [&]() {
4588+ m_hasRotationChanged = true;
4589+ updateLayout();
4590+ });
4591 }
4592
4593 VerticalView::~VerticalView()
4594 {
4595-}
4596-
4597-QAbstractItemModel *VerticalView::model() const
4598-{
4599- return m_delegateModel ? m_delegateModel->model().value<QAbstractItemModel *>() : nullptr;
4600-}
4601-
4602-void VerticalView::setModel(QAbstractItemModel *model)
4603-{
4604- if (model != this->model()) {
4605- if (!m_delegateModel) {
4606- createDelegateModel();
4607- } else {
4608- disconnect(m_delegateModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)), this, SLOT(_q_modelUpdated(QQmlChangeSet,bool)));
4609- }
4610- m_delegateModel->setModel(QVariant::fromValue<QAbstractItemModel *>(model));
4611- connect(m_delegateModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)), this, SLOT(_q_modelUpdated(QQmlChangeSet,bool)));
4612- Q_EMIT modelChanged();
4613- polish();
4614- // TODO?
4615-// Q_EMIT contentHeightChanged();
4616-// Q_EMIT contentYChanged();
4617- }
4618-}
4619-
4620-QQmlComponent *VerticalView::delegate() const
4621-{
4622- return m_delegateModel ? m_delegateModel->delegate() : nullptr;
4623-}
4624-
4625-void VerticalView::setDelegate(QQmlComponent *delegate)
4626-{
4627- if (delegate != this->delegate()) {
4628- if (!m_delegateModel) {
4629- createDelegateModel();
4630- }
4631-
4632- // Cleanup the existing items
4633- Q_FOREACH(ListItem *item, m_visibleItems)
4634- releaseItem(item);
4635- m_visibleItems.clear();
4636- m_firstVisibleIndex = -1;
4637- adjustMinYExtent();
4638- setContentY(0);
4639-
4640- m_delegateModel->setDelegate(delegate);
4641-
4642- Q_EMIT delegateChanged();
4643- m_delegateValidated = false;
4644- m_contentHeightDirty = true;
4645- polish();
4646- }
4647+ disconnect(RenderEngine::instance(), &RenderEngine::taskRenderFinished,
4648+ this, &VerticalView::slotTaskRenderFinished);
4649+
4650+ qDeleteAll(m_decorations);
4651+ qDeleteAll(m_overlays);
4652+ qDeleteAll(m_pages);
4653+}
4654+
4655+// Returns the parent QML Flickable
4656+QQuickItem* VerticalView::parentFlickable() const
4657+{
4658+ return m_parentFlickable;
4659+}
4660+
4661+// Set the parent QML Flickable
4662+void VerticalView::setParentFlickable(QQuickItem *flickable)
4663+{
4664+ if (m_parentFlickable == flickable)
4665+ return;
4666+
4667+ if (m_parentFlickable)
4668+ m_parentFlickable->disconnect(this);
4669+
4670+ m_parentFlickable = flickable;
4671+
4672+ connect(m_parentFlickable, &QQuickItem::widthChanged, this, &VerticalView::onFlickableSizeChanged);
4673+ connect(m_parentFlickable, &QQuickItem::heightChanged, this, &VerticalView::onFlickableSizeChanged);
4674+
4675+ connect(m_parentFlickable, SIGNAL(contentXChanged()), this, SLOT(onFlickableScrolled()));
4676+ connect(m_parentFlickable, SIGNAL(contentYChanged()), this, SLOT(onFlickableScrolled()));
4677+
4678+ Q_EMIT parentFlickableChanged();
4679+}
4680+
4681+PdfDocument* VerticalView::document() const
4682+{
4683+ return m_document.data();
4684+}
4685+
4686+PdfZoom *VerticalView::zoomSettings() const
4687+{
4688+ return m_zoomSettings;
4689+}
4690+void VerticalView::setCurrentPageIndex(int currentPageIndex)
4691+{
4692+ if (m_currentPageIndex == currentPageIndex)
4693+ return;
4694+
4695+ m_currentPageIndex = currentPageIndex;
4696+ Q_EMIT currentPageIndexChanged();
4697 }
4698
4699 int VerticalView::cacheBuffer() const
4700@@ -191,43 +121,25 @@
4701
4702 void VerticalView::setCacheBuffer(int cacheBuffer)
4703 {
4704- if (cacheBuffer < 0) {
4705- qmlInfo(this) << "Cannot set a negative cache buffer";
4706+ if (m_cacheBuffer == cacheBuffer)
4707 return;
4708- }
4709
4710- if (cacheBuffer != m_cacheBuffer) {
4711- m_cacheBuffer = cacheBuffer;
4712- Q_EMIT cacheBufferChanged();
4713- polish();
4714- }
4715+ m_cacheBuffer = cacheBuffer;
4716+ Q_EMIT cacheBufferChanged();
4717 }
4718
4719-qreal VerticalView::spacing() const
4720+int VerticalView::spacing() const
4721 {
4722 return m_spacing;
4723 }
4724
4725-void VerticalView::setSpacing(qreal spacing)
4726+void VerticalView::setSpacing(int spacing)
4727 {
4728- if (spacing < 0) {
4729- qmlInfo(this) << "Cannot set a negative spacing";
4730+ if (m_spacing == spacing)
4731 return;
4732- }
4733-
4734- if (spacing != m_spacing) {
4735- m_spacing = spacing;
4736- Q_EMIT spacingChanged();
4737- polish();
4738- }
4739-}
4740-
4741-int VerticalView::count() const
4742-{
4743- if (m_delegateModel)
4744- return m_delegateModel->count();
4745- else
4746- return 0;
4747+
4748+ m_spacing = spacing;
4749+ Q_EMIT spacingChanged();
4750 }
4751
4752 int VerticalView::currentPageIndex() const
4753@@ -235,659 +147,583 @@
4754 return m_currentPageIndex;
4755 }
4756
4757-QQuickItem *VerticalView::currentPageItem() const
4758-{
4759- return itemAt(m_currentPageIndex);
4760-}
4761-
4762-void VerticalView::_q_updateCurrentPageIndex()
4763-{
4764- if (!m_visibleItems.isEmpty()) {
4765- qreal pos = this->contentY() + (this->height() * 0.5);
4766-
4767- int oldCurrentPageIndex = m_currentPageIndex;
4768- int i = 0;
4769-
4770- Q_FOREACH(ListItem * item, m_visibleItems) {
4771- if (item->y() < pos && item->y() + item->height() > pos)
4772- break;
4773-
4774- i++;
4775- }
4776-
4777- // If spacing is set, there may be no page on posY position,
4778- // and the Q_FOREACH loop keep on running until the end.
4779- if (i != m_visibleItems.length())
4780- m_currentPageIndex = m_firstVisibleIndex + i;
4781-
4782- if (m_currentPageIndex != oldCurrentPageIndex) {
4783- Q_EMIT currentPageIndexChanged();
4784- Q_EMIT currentPageItemChanged();
4785- }
4786-
4787+int VerticalView::pagesCount() const
4788+{
4789+ if (!m_document || m_document.data()->isLocked())
4790+ return 0;
4791+
4792+ return m_document.data()->pageCount();
4793+}
4794+
4795+PdfRotation::Rotation VerticalView::rotation() const
4796+{
4797+ return m_rotation;
4798+}
4799+
4800+void VerticalView::setRotation(PdfRotation::Rotation rotation)
4801+{
4802+ if (m_rotation == rotation)
4803+ return;
4804+
4805+ m_rotation = rotation;
4806+ Q_EMIT rotationChanged();
4807+}
4808+
4809+PopplerError::Error VerticalView::error() const
4810+{
4811+ return m_error;
4812+}
4813+
4814+PdfDocument::RenderHints VerticalView::renderHints() const
4815+{
4816+ return m_renderHints;
4817+}
4818+
4819+void VerticalView::setRenderHints(const PdfDocument::RenderHints hints)
4820+{
4821+ if (m_renderHints == hints)
4822+ return;
4823+
4824+ m_renderHints = hints;
4825+ Q_EMIT renderHintsChanged();
4826+}
4827+
4828+bool VerticalView::showLinkHighlight() const
4829+{
4830+ return m_showLinkHighlight;
4831+}
4832+
4833+void VerticalView::setShowLinkHighlight(bool show)
4834+{
4835+ if (m_showLinkHighlight == show)
4836+ return;
4837+
4838+ m_showLinkHighlight = show;
4839+ Q_EMIT showLinkHighlightChanged();
4840+}
4841+
4842+QColor VerticalView::linkHighlightColor() const
4843+{
4844+ return m_linkHighlightColor;
4845+}
4846+
4847+void VerticalView::setLinkHighlightColor(const QColor &color)
4848+{
4849+ if (m_linkHighlightColor == color)
4850+ return;
4851+
4852+ m_linkHighlightColor = color;
4853+ Q_EMIT linkHighlightColorChanged();
4854+}
4855+
4856+void VerticalView::setError(const PopplerError::Error &error)
4857+{
4858+ if (m_error == error)
4859+ return;
4860+
4861+ m_error = error;
4862+ Q_EMIT errorChanged();
4863+}
4864+
4865+void VerticalView::initializeDocument(const QString &path)
4866+{
4867+ if (m_document)
4868+ m_document->disconnect(this);
4869+
4870+ setError(PopplerError::NoError);
4871+
4872+ m_document = QSharedPointer<PdfDocument>(new PdfDocument());
4873+ m_document->setPath(path);
4874+
4875+ /* A lot of things happens when we set the path property in
4876+ * m_document. Need to check if an error has been emitted. */
4877+ setError(m_document->error());
4878+
4879+ if (m_error != PopplerError::NoError && m_error != PopplerError::DocumentLocked) {
4880+ m_document.clear();
4881+
4882+ // Stop doing anything below.
4883+ return;
4884 }
4885+
4886+ m_document.data()->setRenderHints(m_renderHints);
4887+
4888+ // --------------------------------------------------
4889+ QQmlEngine *engine = QQmlEngine::contextForObject(this)->engine();
4890+ if (engine->imageProvider("poppler"))
4891+ engine->removeImageProvider("poppler");
4892+
4893+ m_imageProvider = new PdfImageProvider(m_document);
4894+ engine->addImageProvider("poppler", m_imageProvider);
4895+ // --------------------------------------------------
4896+
4897+ Q_EMIT documentChanged();
4898+
4899+ // Init zoom settings
4900+ m_zoomSettings->init();
4901+}
4902+
4903+bool VerticalView::adjustZoomToWidth()
4904+{
4905+ if (!m_zoomSettings)
4906+ return false;
4907+
4908+ bool result;
4909+
4910+ result = m_zoomSettings->adjustZoomToWidth();
4911+ m_hasZoomChanged = result;
4912+
4913+ return result;
4914+}
4915+
4916+bool VerticalView::adjustZoomToPage()
4917+{
4918+ if (!m_zoomSettings)
4919+ return false;
4920+
4921+ bool result;
4922+
4923+ result = m_zoomSettings->adjustZoomToPage();
4924+ m_hasZoomChanged = result;
4925+
4926+ return result;
4927+}
4928+
4929+bool VerticalView::adjustAutomaticZoom()
4930+{
4931+ if (!m_zoomSettings)
4932+ return false;
4933+
4934+ bool result;
4935+
4936+ result = m_zoomSettings->adjustAutomaticZoom();
4937+ m_hasZoomChanged = result;
4938+
4939+ return result;
4940 }
4941
4942 void VerticalView::positionAtBeginning()
4943 {
4944- if (m_delegateModel->count() <= 0)
4945- return;
4946-
4947- if (m_firstVisibleIndex != 0) {
4948- // TODO This could be optimized by trying to reuse the interesection
4949- // of items that may end up intersecting between the existing
4950- // m_visibleItems and the items we are creating in the next loop
4951- Q_FOREACH(ListItem *item, m_visibleItems)
4952- releaseItem(item);
4953- m_visibleItems.clear();
4954- m_firstVisibleIndex = -1;
4955-
4956- // Create the item 0, it will be already correctly positioned at createItem()
4957- ListItem *item = createItem(0, false);
4958- // Create the subsequent items
4959- int modelIndex = 1;
4960- qreal pos = item->y() + item->height();
4961- const qreal bufferTo = height() + m_cacheBuffer;
4962- while (modelIndex < m_delegateModel->count() && pos <= bufferTo) {
4963- if (!(item = createItem(modelIndex, false)))
4964+ m_parentFlickable->setProperty("contentY", 0);
4965+}
4966+
4967+void VerticalView::positionAtIndex(int index, qreal top, qreal left)
4968+{
4969+ SGTileItem* page = m_pages.value(index);
4970+
4971+ if (!page) {
4972+ PdfDocument* doc = m_document.data();
4973+
4974+ const qreal &zoomFactor = m_zoomSettings->zoomFactor();
4975+ qreal totalHeight = 0;
4976+
4977+ for (int j=0; j < doc->pageCount(); ++j) {
4978+ const QSize &s = doc->pageSize(j);
4979+ QRect pageRect;
4980+
4981+ if (m_rotation == PdfRotation::Rotate0 || m_rotation == PdfRotation::Rotate180) {
4982+ pageRect = QRect(
4983+ (this->width() - Twips::convertPointsToPixels(s.width(), zoomFactor)) * 0.5,
4984+ totalHeight,
4985+ Twips::convertPointsToPixels(s.width(), zoomFactor),
4986+ Twips::convertPointsToPixels(s.height(), zoomFactor)
4987+ );
4988+ } else {
4989+ pageRect = QRect(
4990+ (this->width() - Twips::convertPointsToPixels(s.height(), zoomFactor)) * 0.5,
4991+ totalHeight,
4992+ Twips::convertPointsToPixels(s.height(), zoomFactor),
4993+ Twips::convertPointsToPixels(s.width(), zoomFactor)
4994+ );
4995+ }
4996+
4997+ if (j == index) {
4998+ page = createPage(j, pageRect);
4999 break;
5000- pos += item->height();
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches