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
=== modified file 'po/com.ubuntu.docviewer.pot'
--- po/com.ubuntu.docviewer.pot 2016-02-05 22:42:13 +0000
+++ po/com.ubuntu.docviewer.pot 2016-04-22 10:31:39 +0000
@@ -8,13 +8,13 @@
8msgstr ""8msgstr ""
9"Project-Id-Version: \n"9"Project-Id-Version: \n"
10"Report-Msgid-Bugs-To: \n"10"Report-Msgid-Bugs-To: \n"
11"POT-Creation-Date: 2016-02-05 23:40+0100\n"11"POT-Creation-Date: 2016-04-07 00:46+0200\n"
12"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"12"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"13"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14"Language-Team: LANGUAGE <LL@li.org>\n"14"Language-Team: LANGUAGE <LL@li.org>\n"
15"Language: \n"15"Language: \n"
16"MIME-Version: 1.0\n"16"MIME-Version: 1.0\n"
17"Content-Type: text/plain; charset=CHARSET\n"17"Content-Type: text/plain; charset=UTF-8\n"
18"Content-Transfer-Encoding: 8bit\n"18"Content-Transfer-Encoding: 8bit\n"
19"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"19"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
2020
@@ -42,7 +42,7 @@
4242
43#: ../src/app/qml/common/DetailsPage.qml:2643#: ../src/app/qml/common/DetailsPage.qml:26
44#: ../src/app/qml/loView/LOViewDefaultHeader.qml:10744#: ../src/app/qml/loView/LOViewDefaultHeader.qml:107
45#: ../src/app/qml/pdfView/PdfView.qml:23545#: ../src/app/qml/pdfView/PdfView.qml:317
46#: ../src/app/qml/textView/TextViewDefaultHeader.qml:6946#: ../src/app/qml/textView/TextViewDefaultHeader.qml:69
47msgid "Details"47msgid "Details"
48msgstr ""48msgstr ""
@@ -117,7 +117,9 @@
117#: ../src/app/qml/documentPage/DeleteFileDialog.qml:55117#: ../src/app/qml/documentPage/DeleteFileDialog.qml:55
118#: ../src/app/qml/documentPage/DocumentPagePickModeHeader.qml:28118#: ../src/app/qml/documentPage/DocumentPagePickModeHeader.qml:28
119#: ../src/app/qml/loView/LOViewGotoDialog.qml:55119#: ../src/app/qml/loView/LOViewGotoDialog.qml:55
120#: ../src/app/qml/pdfView/PdfView.qml:180120#: ../src/app/qml/pdfView/DocumentLockedDialog.qml:61
121#: ../src/app/qml/pdfView/OpenLinkDialog.qml:39
122#: ../src/app/qml/pdfView/PdfView.qml:261
121#: ../src/app/qml/pdfView/PdfViewGotoDialog.qml:51123#: ../src/app/qml/pdfView/PdfViewGotoDialog.qml:51
122msgid "Cancel"124msgid "Cancel"
123msgstr ""125msgstr ""
@@ -216,7 +218,7 @@
216msgstr ""218msgstr ""
217219
218#: ../src/app/qml/documentPage/DocumentPage.qml:23220#: ../src/app/qml/documentPage/DocumentPage.qml:23
219#: /tmp/lok-qml-async-imageprovider-build/po/com.ubuntu.docviewer.desktop.in.in.h:3221#: /tmp/temp-new-pdf-plugin-build/po/com.ubuntu.docviewer.desktop.in.in.h:3
220msgid "Documents"222msgid "Documents"
221msgstr ""223msgstr ""
222224
@@ -228,15 +230,15 @@
228msgid "Sorting settings..."230msgid "Sorting settings..."
229msgstr ""231msgstr ""
230232
231#: ../src/app/qml/documentPage/DocumentPagePickModeHeader.qml:41233#: ../src/app/qml/documentPage/DocumentPagePickModeHeader.qml:44
232msgid "Switch to single column list"234msgid "Switch to single column list"
233msgstr ""235msgstr ""
234236
235#: ../src/app/qml/documentPage/DocumentPagePickModeHeader.qml:41237#: ../src/app/qml/documentPage/DocumentPagePickModeHeader.qml:44
236msgid "Switch to grid"238msgid "Switch to grid"
237msgstr ""239msgstr ""
238240
239#: ../src/app/qml/documentPage/DocumentPagePickModeHeader.qml:49241#: ../src/app/qml/documentPage/DocumentPagePickModeHeader.qml:52
240msgid "Pick"242msgid "Pick"
241msgstr ""243msgstr ""
242244
@@ -343,13 +345,13 @@
343msgstr ""345msgstr ""
344346
345#: ../src/app/qml/loView/LOViewDefaultHeader.qml:100347#: ../src/app/qml/loView/LOViewDefaultHeader.qml:100
346#: ../src/app/qml/pdfView/PdfView.qml:228348#: ../src/app/qml/pdfView/PdfView.qml:310
347#: ../src/app/qml/textView/TextViewDefaultHeader.qml:63349#: ../src/app/qml/textView/TextViewDefaultHeader.qml:63
348msgid "Disable night mode"350msgid "Disable night mode"
349msgstr ""351msgstr ""
350352
351#: ../src/app/qml/loView/LOViewDefaultHeader.qml:100353#: ../src/app/qml/loView/LOViewDefaultHeader.qml:100
352#: ../src/app/qml/pdfView/PdfView.qml:228354#: ../src/app/qml/pdfView/PdfView.qml:310
353#: ../src/app/qml/textView/TextViewDefaultHeader.qml:63355#: ../src/app/qml/textView/TextViewDefaultHeader.qml:63
354msgid "Enable night mode"356msgid "Enable night mode"
355msgstr ""357msgstr ""
@@ -400,6 +402,7 @@
400msgstr ""402msgstr ""
401403
402#: ../src/app/qml/loView/ZoomSelector.qml:122404#: ../src/app/qml/loView/ZoomSelector.qml:122
405#: ../src/app/qml/pdfView/ZoomSelector.qml:119
403msgid "Fit width"406msgid "Fit width"
404msgstr ""407msgstr ""
405408
@@ -408,35 +411,87 @@
408msgstr ""411msgstr ""
409412
410#: ../src/app/qml/loView/ZoomSelector.qml:124413#: ../src/app/qml/loView/ZoomSelector.qml:124
414#: ../src/app/qml/pdfView/ZoomSelector.qml:121
411msgid "Automatic"415msgid "Automatic"
412msgstr ""416msgstr ""
413417
418#: ../src/app/qml/pdfView/DocumentLockedDialog.qml:25
419msgid "Document is locked"
420msgstr ""
421
422#: ../src/app/qml/pdfView/DocumentLockedDialog.qml:26
423msgid "Please insert a password in order to unlock this document"
424msgstr ""
425
426#: ../src/app/qml/pdfView/DocumentLockedDialog.qml:48
427msgid "Entered password is not valid"
428msgstr ""
429
430#: ../src/app/qml/pdfView/DocumentLockedDialog.qml:67
431msgid "Unlock"
432msgstr ""
433
434#: ../src/app/qml/pdfView/LinkHint.qml:36
435#, qt-format
436msgid "Open link externally: %1"
437msgstr ""
438
439#: ../src/app/qml/pdfView/LinkHint.qml:37
440#: ../src/app/qml/pdfView/OpenLinkDialog.qml:28
441#, qt-format
442msgid "Go to page %1"
443msgstr ""
444
445#: ../src/app/qml/pdfView/OpenLinkDialog.qml:28
446msgid "Open link externally"
447msgstr ""
448
449#: ../src/app/qml/pdfView/OpenLinkDialog.qml:29
450msgid "Are you sure?"
451msgstr ""
452
453#: ../src/app/qml/pdfView/OpenLinkDialog.qml:45
454msgid "Open"
455msgstr ""
456
457#: ../src/app/qml/pdfView/OpenLinkDialog.qml:45
458msgid "Go to destination"
459msgstr ""
460
414#. TRANSLATORS: "Contents" refers to the "Table of Contents" of a PDF document.461#. TRANSLATORS: "Contents" refers to the "Table of Contents" of a PDF document.
415#: ../src/app/qml/pdfView/PdfContentsPage.qml:31462#: ../src/app/qml/pdfView/PdfContentsPage.qml:31
416#: ../src/app/qml/pdfView/PdfView.qml:153463#: ../src/app/qml/pdfView/PdfView.qml:230
417msgid "Contents"464msgid "Contents"
418msgstr ""465msgstr ""
419466
420#. TRANSLATORS: the first argument (%1) refers to the page currently shown on the screen,467#. TRANSLATORS: the first argument (%1) refers to the page currently shown on the screen,
421#. while the second one (%2) refers to the total pages count.468#. while the second one (%2) refers to the total pages count.
422#: ../src/app/qml/pdfView/PdfPresentation.qml:51469#: ../src/app/qml/pdfView/PdfPresentation.qml:51
423#: ../src/app/qml/pdfView/PdfView.qml:56470#: ../src/app/qml/pdfView/PdfView.qml:49
424#, qt-format471#, qt-format
425msgid "Page %1 of %2"472msgid "Page %1 of %2"
426msgstr ""473msgstr ""
427474
428#: ../src/app/qml/pdfView/PdfView.qml:203475#: ../src/app/qml/pdfView/PdfView.qml:284
429msgid "Search"476msgid "Search"
430msgstr ""477msgstr ""
431478
432#: ../src/app/qml/pdfView/PdfView.qml:213479#: ../src/app/qml/pdfView/PdfView.qml:294
433msgid "Go to page..."480msgid "Go to page..."
434msgstr ""481msgstr ""
435482
436#: ../src/app/qml/pdfView/PdfView.qml:221483#: ../src/app/qml/pdfView/PdfView.qml:303
437msgid "Presentation"484msgid "Presentation"
438msgstr ""485msgstr ""
439486
487#: ../src/app/qml/pdfView/PdfView.qml:324
488msgid "Rotate 90° right"
489msgstr ""
490
491#: ../src/app/qml/pdfView/PdfView.qml:341
492msgid "Rotate 90° left"
493msgstr ""
494
440#: ../src/app/qml/pdfView/PdfViewGotoDialog.qml:26495#: ../src/app/qml/pdfView/PdfViewGotoDialog.qml:26
441msgid "Go to page"496msgid "Go to page"
442msgstr ""497msgstr ""
@@ -446,7 +501,11 @@
446msgid "Choose a page between 1 and %1"501msgid "Choose a page between 1 and %1"
447msgstr ""502msgstr ""
448503
449#: ../src/app/qml/ubuntu-docviewer-app.qml:114504#: ../src/app/qml/pdfView/ZoomSelector.qml:120
505msgid "Fit page"
506msgstr ""
507
508#: ../src/app/qml/ubuntu-docviewer-app.qml:117
450msgid "File does not exist."509msgid "File does not exist."
451msgstr ""510msgstr ""
452511
@@ -464,10 +523,10 @@
464msgid "copy %1"523msgid "copy %1"
465msgstr ""524msgstr ""
466525
467#: /tmp/lok-qml-async-imageprovider-build/po/com.ubuntu.docviewer.desktop.in.in.h:1526#: /tmp/temp-new-pdf-plugin-build/po/com.ubuntu.docviewer.desktop.in.in.h:1
468msgid "Document Viewer"527msgid "Document Viewer"
469msgstr ""528msgstr ""
470529
471#: /tmp/lok-qml-async-imageprovider-build/po/com.ubuntu.docviewer.desktop.in.in.h:2530#: /tmp/temp-new-pdf-plugin-build/po/com.ubuntu.docviewer.desktop.in.in.h:2
472msgid "documents;viewer;pdf;reader;"531msgid "documents;viewer;pdf;reader;"
473msgstr ""532msgstr ""
474533
=== added file 'src/app/qml/pdfView/DocumentLockedDialog.qml'
--- src/app/qml/pdfView/DocumentLockedDialog.qml 1970-01-01 00:00:00 +0000
+++ src/app/qml/pdfView/DocumentLockedDialog.qml 2016-04-22 10:31:39 +0000
@@ -0,0 +1,88 @@
1/*
2 * Copyright (C) 2016 Stefano Verzegnassi
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.4
18import Ubuntu.Components 1.3
19import Ubuntu.Components.Popups 1.3
20import QtQuick.Layouts 1.1
21
22Dialog {
23 id: unlockDialog
24
25 title: i18n.tr("Document is locked")
26 text: i18n.tr("Please insert a password in order to unlock this document")
27
28 TextField {
29 id: passwordField
30 width: parent.width
31
32 hasClearButton: true
33
34 Keys.onReturnPressed: tryUnlock()
35 onAccepted: tryUnlock()
36
37 Component.onCompleted: forceActiveFocus()
38
39 onTextChanged: {
40 if (text.length === 0) {
41 errorLabel.visible = false
42 }
43 }
44 }
45
46 Label {
47 id: errorLabel
48 text: i18n.tr("Entered password is not valid")
49 color: UbuntuColors.red
50 visible: false
51 }
52
53 RowLayout {
54 anchors {
55 left: parent.left
56 right: parent.right
57 margins: units.gu(-1)
58 }
59
60 Button {
61 text: i18n.tr("Cancel")
62 onClicked: close()
63 Layout.fillWidth: true
64 }
65
66 Button {
67 text: i18n.tr("Unlock")
68 color: UbuntuColors.green
69 Layout.fillWidth: true
70
71 onClicked: goToPage()
72 }
73 }
74
75 function close() {
76 PopupUtils.close(unlockDialog)
77 }
78
79 function tryUnlock() {
80 var result = pdfView.unlock(passwordField.text, passwordField.text)
81
82 if (result) {
83 close()
84 } else {
85 errorLabel.visible = true
86 }
87 }
88}
089
=== added file 'src/app/qml/pdfView/LinkHint.qml'
--- src/app/qml/pdfView/LinkHint.qml 1970-01-01 00:00:00 +0000
+++ src/app/qml/pdfView/LinkHint.qml 2016-04-22 10:31:39 +0000
@@ -0,0 +1,48 @@
1/*
2 * Copyright (C) 2016 Stefano Verzegnassi
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.4
18import Ubuntu.Components 1.3
19
20UbuntuShape {
21 id: rootItem
22
23 property var linkInfo
24
25 height: hintText.paintedHeight + units.gu(1)
26 width: hintText.paintedWidth + units.gu(2)
27
28 // TODO: Is .raised okay? https://developer.ubuntu.com/en/apps/qml/tutorials/ubuntu-ui-toolkit-palette/
29 color: theme.palette.normal.raised
30 aspect: UbuntuShape.DropShadow
31
32 Label {
33 id: hintText
34 anchors.centerIn: parent
35
36 // TODO: Is .raisedText okay? https://developer.ubuntu.com/en/apps/qml/tutorials/ubuntu-ui-toolkit-palette/
37 color: theme.palette.normal.raisedText
38 textSize: Label.Small
39 text: linkInfo.url ? i18n.tr("Open «%1»").arg(linkInfo.url)
40 : i18n.tr("Go to page %1").arg(linkInfo.pageIndex + 1)
41 }
42
43 Timer {
44 interval: 2000
45 running: true
46 onTriggered: rootItem.destroy()
47 }
48}
049
=== added file 'src/app/qml/pdfView/OpenLinkDialog.qml'
--- src/app/qml/pdfView/OpenLinkDialog.qml 1970-01-01 00:00:00 +0000
+++ src/app/qml/pdfView/OpenLinkDialog.qml 2016-04-22 10:31:39 +0000
@@ -0,0 +1,62 @@
1/*
2 * Copyright (C) 2015, 2016 Stefano Verzegnassi
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.4
18import Ubuntu.Components 1.3
19import Ubuntu.Components.Popups 1.3
20import QtQuick.Layouts 1.1
21
22Dialog {
23 id: openLinkDialog
24 objectName:"PdfViewGotoDialog"
25
26 property var linkInfo
27
28 title: linkInfo.url ? i18n.tr("Open link externally") : i18n.tr("Go to page %1").arg(linkInfo.pageIndex + 1)
29 text: i18n.tr("Are you sure?")
30
31 RowLayout {
32 anchors {
33 left: parent.left
34 right: parent.right
35 margins: units.gu(-1)
36 }
37
38 Button {
39 text: i18n.tr("Cancel")
40 onClicked: PopupUtils.close(openLinkDialog)
41 Layout.fillWidth: true
42 }
43
44 Button {
45 text: linkInfo.url ? i18n.tr("Open") : i18n.tr("Go")
46 color: UbuntuColors.green
47 Layout.fillWidth: true
48
49 onClicked: openLink()
50 }
51 }
52
53 function openLink() {
54 if (linkInfo.url) {
55 Qt.openUrlExternally(linkInfo.url)
56 } else {
57 pdfView.positionAtIndex(linkInfo.pageIndex, linkInfo.top, linkInfo.left)
58 }
59
60 PopupUtils.close(openLinkDialog)
61 }
62}
063
=== modified file 'src/app/qml/pdfView/PdfContentsPage.qml'
--- src/app/qml/pdfView/PdfContentsPage.qml 2016-03-22 19:31:22 +0000
+++ src/app/qml/pdfView/PdfContentsPage.qml 2016-04-22 10:31:39 +0000
@@ -17,27 +17,33 @@
1717
18import QtQuick 2.418import QtQuick 2.4
19import Ubuntu.Components 1.319import Ubuntu.Components 1.3
20import QtQuick.Layouts 1.120
21import "../common"
2122
22Page {23Page {
23 id: pdfContents24 id: pdfContents
24 objectName: "pdfcontents"25 objectName: "pdfcontents"
2526
27 property var tocModel: pdfView.document.tocModel
28
26 // this property will have to be removed when bug #1341671 will be fixed.29 // this property will have to be removed when bug #1341671 will be fixed.
27 property string testProperty: "for page name issue"30 property string testProperty: "for page name issue"
2831
29 header: PageHeader {32 header: PageHeader {
30 // TRANSLATORS: "Contents" refers to the "Table of Contents" of a PDF document.33 // TRANSLATORS: "Contents" refers to the "Table of Contents" of a PDF document.
31 title: i18n.tr("Contents")34 title: sortedModel.parentNode == -1
35 ? i18n.tr("Contents")
36 : tocModel.get(sortedModel.parentNode).title
32 flickable: view37 flickable: view
33 }38 }
3439
40 // FIXME
35 onActiveChanged: {41 onActiveChanged: {
36 // Find out the current page position in the ToC index42 // Find out the current page position in the ToC index
37 for (var i=0; i<poppler.tocModel.count; i++) {43 for (var i=0; i<tocModel.count; i++) {
38 if (i+1 < poppler.tocModel.count) {44 if (i+1 < tocModel.count) {
39 if (pdfView.currentPageIndex >= poppler.tocModel.get(i).pageIndex &&45 if (pdfView.currentPageIndex >= tocModel.get(i).pageIndex &&
40 pdfView.currentPageIndex < poppler.tocModel.get(i+1).pageIndex) {46 pdfView.currentPageIndex < tocModel.get(i+1).pageIndex) {
41 break;47 break;
42 }48 }
43 }49 }
@@ -52,6 +58,7 @@
5258
53 ScrollView {59 ScrollView {
54 anchors.fill: parent60 anchors.fill: parent
61<<<<<<< TREE
5562
56 ListView {63 ListView {
57 id: view64 id: view
@@ -115,6 +122,118 @@
115 color: __isCurrentIndex ? theme.palette.selected.backgroundText122 color: __isCurrentIndex ? theme.palette.selected.backgroundText
116 : theme.palette.normal.backgroundText123 : theme.palette.normal.backgroundText
117 }124 }
125=======
126
127 ListView {
128 id: view
129 objectName: "view"
130 anchors.fill: parent
131 clip: true
132
133 model: SortFilterModel {
134 id: sortedModel
135
136 property int parentNode: -1
137
138 model: tocModel
139 filter.property: "parentNodeIndex"
140 filter.pattern: new RegExp(parentNode)
141 }
142
143 // Count changes when we change the current parent node.
144 onCountChanged: view.positionViewAtBeginning()
145
146 header: ListItem {
147 visible: sortedModel.parentNode > -1
148 height: visible ? units.gu(6) : 0
149 onClicked: sortedModel.parentNode = -1
150
151 ListItemLayout {
152 anchors.centerIn: parent
153 title.text: i18n.tr("Back to parent node")
154
155 Icon {
156 SlotsLayout.position: SlotsLayout.Leading
157 width: units.gu(2); height: width
158 name: "go-previous"
159 }
160 }
161 }
162
163 delegate: ListItem {
164 id: delegate
165 objectName: "delegate" + index
166
167 onClicked: {
168 pdfView.positionAtIndex(model.pageIndex);
169 contentsBottomEdge.collapse();
170 }
171
172 // Highlighted property of ListItem is read-only. In order to
173 // provide an highlight for the current page, we need to duplicate
174 // the overlay.
175 Rectangle {
176 anchors.fill: parent
177 color: Qt.rgba(0, 0, 0, 0.05)
178 visible: view.currentIndex == model.index
179 }
180
181 ListItemLayout {
182 id: listItemLayout
183 objectName: "listItemLayout" + index
184 anchors.fill: parent
185
186 Label {
187 objectName: "pageindex"
188 SlotsLayout.position: SlotsLayout.Leading
189 text: model.pageIndex + 1
190 }
191
192 title {
193 text: model.title
194 elide: Text.ElideRight
195 }
196
197 Icon {
198 SlotsLayout.position: SlotsLayout.Trailing
199 width: units.gu(2); height: width
200 name: "tick"
201 color: UbuntuColors.green
202 visible: view.currentIndex == model.index
203 }
204
205 AbstractButton {
206 SlotsLayout.position: SlotsLayout.Last
207 width: units.gu(4); height: units.gu(8)
208 opacity: model.hasChildNodes ? 1.0 : 0.0
209
210 // We use 'nodeIndex' because model.index from SortFilterModel is not
211 // the one provided in the Toc model
212 onClicked: sortedModel.parentNode = model.nodeIndex
213
214 Rectangle {
215 anchors.fill: parent
216 anchors.rightMargin: units.gu(-2)
217 color: theme.palette.highlighted.background
218 visible: parent.pressed
219 }
220
221 VerticalDivider {
222 anchors {
223 left: parent.left
224 top: parent.top
225 bottom: parent.bottom
226 }
227 }
228
229 Icon {
230 anchors.centerIn: parent
231 anchors.horizontalCenterOffset: units.gu(1)
232 width: units.gu(2); height: width
233 name: "go-next"
234 }
235 }
236>>>>>>> MERGE-SOURCE
118 }237 }
119 }238 }
120 }239 }
121240
=== modified file 'src/app/qml/pdfView/PdfPresentation.qml'
--- src/app/qml/pdfView/PdfPresentation.qml 2016-03-26 18:44:53 +0000
+++ src/app/qml/pdfView/PdfPresentation.qml 2016-04-22 10:31:39 +0000
@@ -17,14 +17,12 @@
17import QtQuick 2.417import QtQuick 2.4
18import Ubuntu.Components 1.318import Ubuntu.Components 1.3
19import DocumentViewer 1.019import DocumentViewer 1.0
20import DocumentViewer.PDF 1.0 as PDF20import DocumentViewer.PDF 2.0 as PDF
2121
22Page {22Page {
23 id: pdfPage23 id: pdfPres
24 property var poppler24 property var poppler
25 property bool isPresentationMode: true25 property bool isPresentationMode: true
26 anchors.fill: parent
27 title: DocumentViewer.getFileBaseNameFromPath(poppler.path)
28 focus: true26 focus: true
2927
30 header: PageHeader {28 header: PageHeader {
@@ -41,15 +39,15 @@
41 title {39 title {
42 font.weight: Font.DemiBold40 font.weight: Font.DemiBold
43 textSize: Label.Large41 textSize: Label.Large
44 text: pdfPage.title42 text: DocumentViewer.getFileBaseNameFromPath(file.path)
45 color: pdfPage.header.__styleInstance.foregroundColor43 color: pdfPres.header.__styleInstance.foregroundColor
46 }44 }
47 subtitle {45 subtitle {
48 textSize: Label.Medium46 textSize: Label.Medium
49 // TRANSLATORS: the first argument (%1) refers to the page currently shown on the screen,47 // TRANSLATORS: the first argument (%1) refers to the page currently shown on the screen,
50 // while the second one (%2) refers to the total pages count.48 // while the second one (%2) refers to the total pages count.
51 text: i18n.tr("Page %1 of %2").arg(pdfView.currentIndex + 1).arg(pdfView.count)49 text: i18n.tr("Page %1 of %2").arg(view.currentIndex + 1).arg(poppler.pagesCount)
52 color: pdfPage.header.__styleInstance.foregroundColor50 color: pdfPres.header.__styleInstance.foregroundColor
53 }51 }
54 }52 }
5553
@@ -61,7 +59,7 @@
61 }59 }
6260
63 ListView {61 ListView {
64 id: pdfView62 id: view
65 anchors.fill: parent63 anchors.fill: parent
66 focus: true64 focus: true
6765
@@ -73,25 +71,32 @@
73 boundsBehavior: Flickable.StopAtBounds71 boundsBehavior: Flickable.StopAtBounds
74 cacheBuffer: width72 cacheBuffer: width
7573
76 model: poppler74 model: poppler.pagesCount
77 delegate: PdfViewDelegate {75 delegate: Rectangle {
78 presentationMode: true76 width: pdfPres.width
79 width: pdfPage.width77 height: pdfPres.height
80 height: pdfPage.height
81 color: "black"78 color: "black"
82 Component.onDestruction: window.releaseResources()79
80 Image {
81 anchors.fill: parent
82 source: "image://poppler/page/" + model.index + "/" + poppler.rotation
83 sourceSize.width: pdfPres.width
84 sourceSize.height: pdfPres.height
85 fillMode: Image.PreserveAspectFit //Image.Pad
86 cache: false
87 }
83 }88 }
84 Component.onCompleted: pdfPage.forceActiveFocus()89 Component.onCompleted: pdfPres.forceActiveFocus()
8590
86 MouseArea {91 MouseArea {
87 anchors.fill: parent92 anchors.fill: parent
88 onDoubleClicked: pdfPage.header.visible = !pdfPage.header.visible93 onDoubleClicked: pdfPres.header.visible = !pdfPres.header.visible
8994
90 // Hide mouse curson when there's no on-going mouse event95 // Hide mouse curson when there's no on-going mouse event
91 hoverEnabled: true96 hoverEnabled: true
92 // Flickable can steal mouse handling from MouseArea,97 // Flickable can steal mouse handling from MouseArea,
93 // so check for any on-going dragging too98 // so check for any on-going dragging too
94 cursorShape: (showCursorTimer.running || pdfView.dragging) ? Qt.ArrowCursor : Qt.BlankCursor99 cursorShape: (showCursorTimer.running || view.dragging) ? Qt.ArrowCursor : Qt.BlankCursor
95 onPositionChanged: {100 onPositionChanged: {
96 showCursorTimer.restart()101 showCursorTimer.restart()
97 }102 }
@@ -104,15 +109,15 @@
104109
105 Keys.onPressed: {110 Keys.onPressed: {
106 if (event.key == Qt.Key_Escape) { pageStack.pop(); return; }111 if (event.key == Qt.Key_Escape) { pageStack.pop(); return; }
107 if (event.key == Qt.Key_Home) { pdfView.positionViewAtBeginning(); return; }112 if (event.key == Qt.Key_Home) { view.positionViewAtBeginning(); return; }
108 if (event.key == Qt.Key_End) { pdfView.positionViewAtEnd(); return; }113 if (event.key == Qt.Key_End) { view.positionViewAtEnd(); return; }
109114
110 if (event.key == Qt.Key_Right || event.key == Qt.Key_PageDown) {115 if (event.key == Qt.Key_Right || event.key == Qt.Key_PageDown) {
111 pdfView.incrementCurrentIndex();116 view.incrementCurrentIndex();
112 return;117 return;
113 }118 }
114 if (event.key == Qt.Key_Left || event.key == Qt.Key_PageUp) {119 if (event.key == Qt.Key_Left || event.key == Qt.Key_PageUp) {
115 pdfView.decrementCurrentIndex();120 view.decrementCurrentIndex();
116 return;121 return;
117 }122 }
118 }123 }
119124
=== modified file 'src/app/qml/pdfView/PdfView.qml'
--- src/app/qml/pdfView/PdfView.qml 2016-03-26 18:44:53 +0000
+++ src/app/qml/pdfView/PdfView.qml 2016-04-22 10:31:39 +0000
@@ -17,13 +17,14 @@
17import QtQuick 2.417import QtQuick 2.4
18import Ubuntu.Components 1.318import Ubuntu.Components 1.3
19import Ubuntu.Components.Popups 1.319import Ubuntu.Components.Popups 1.3
20import QtQuick.Layouts 1.120import DocumentViewer.PDF 2.0 as PDF
21import DocumentViewer 1.021import DocumentViewer 1.0
22import DocumentViewer.PDF 1.0 as PDF
2322
24import "../common"23import "../common"
25import "../common/utils.js" as Utils24import "../common/utils.js" as Utils
2625
26// FIXME: After a resizing of the window, keep the current page visible.
27
27Page {28Page {
28 id: pdfPage29 id: pdfPage
29 title: DocumentViewer.getFileBaseNameFromPath(file.path)30 title: DocumentViewer.getFileBaseNameFromPath(file.path)
@@ -31,19 +32,15 @@
31 header: PageHeader {32 header: PageHeader {
32 flickable: pdfView33 flickable: pdfView
3334
35<<<<<<< TREE
34 trailingActionBar.actions: [ goToPage, startPresentation, nightModeToggle, fileDetails ]36 trailingActionBar.actions: [ goToPage, startPresentation, nightModeToggle, fileDetails ]
37=======
38 trailingActionBar.actions: [ goToPage, startPresentation, nightModeToggle, fileDetails, rotateRight, rotateLeft ]
39>>>>>>> MERGE-SOURCE
3540
36 contents: ListItemLayout {41 contents: ListItemLayout {
37 anchors.centerIn: parent42 anchors.centerIn: parent
3843
39 ActivityIndicator {
40 SlotsLayout.position: SlotsLayout.Leading
41 SlotsLayout.overrideVerticalPositioning: true
42 y: (parent.height - height) * 0.5
43 running: pdfView.currentPageItem.status == Image.Loading || poppler.isLoading
44 visible: running
45 }
46
47 title {44 title {
48 font.weight: Font.DemiBold45 font.weight: Font.DemiBold
49 text: pdfPage.title46 text: pdfPage.title
@@ -53,7 +50,13 @@
53 textSize: Label.Small50 textSize: Label.Small
54 // TRANSLATORS: the first argument (%1) refers to the page currently shown on the screen,51 // TRANSLATORS: the first argument (%1) refers to the page currently shown on the screen,
55 // while the second one (%2) refers to the total pages count.52 // while the second one (%2) refers to the total pages count.
56 text: i18n.tr("Page %1 of %2").arg(pdfView.currentPageIndex + 1).arg(pdfView.count)53 text: i18n.tr("Page %1 of %2").arg(pdfView.currentPageIndex + 1).arg(pdfView.pagesCount)
54 }
55
56 ZoomSelector {
57 SlotsLayout.position: SlotsLayout.Trailing
58 view: pdfView
59 visible: DocumentViewer.desktopMode || mainView.wideWindow
57 }60 }
58 }61 }
59 }62 }
@@ -62,6 +65,7 @@
62 // Component.onDestruction: mainView.nightModeEnabled = false65 // Component.onDestruction: mainView.nightModeEnabled = false
6366
64 Keys.onPressed: {67 Keys.onPressed: {
68<<<<<<< TREE
65 if (event.key == Qt.Key_F5) { pageStack.push(Qt.resolvedUrl("./PdfPresentation.qml"), {'poppler': poppler}); }69 if (event.key == Qt.Key_F5) { pageStack.push(Qt.resolvedUrl("./PdfPresentation.qml"), {'poppler': poppler}); }
66 }70 }
67 Rectangle {71 Rectangle {
@@ -136,6 +140,152 @@
136 }140 }
137 }141 }
138142
143=======
144 if (event.key == Qt.Key_F5) { pageStack.push(Qt.resolvedUrl("PdfPresentation.qml"), {'poppler': pdfView}); }
145 }
146
147
148 ScalingPinchArea {
149 id: pinchArea
150 objectName: "pinchArea"
151 anchors.fill: parent
152
153 clip: true
154
155 enabled: !pdfView.moving
156
157 targetFlickable: pdfView
158 onTotalScaleChanged: targetFlickable.updateContentSize(totalScale)
159
160 maximumZoom: pdfView.zoomSettings.maximumZoom
161 minimumZoom: {
162 if (DocumentViewer.desktopMode || mainView.wideWindow)
163 return pdfView.zoomSettings.minimumZoom
164
165
166 return pdfView.zoomSettings.valueAutomaticZoom
167 }
168
169 Binding {
170 when: !pinchArea.pinch.active
171 target: pinchArea
172 property: "zoomValue"
173 value: pdfView.zoomSettings.zoomFactor
174 }
175
176 Rectangle {
177 // Since UITK 1.3, the MainView background is white.
178 // We need to set a different color, otherwise pages
179 // boundaries are not visible.
180 anchors.fill: parent
181 color: "#f5f5f5"
182 }
183
184 ScrollView {
185 anchors.fill: parent
186
187 PDF.Viewer {
188 id: pdfView
189 objectName: "pdfView"
190 anchors.fill: parent
191
192 function updateContentSize(tgtScale) {
193 zoomSettings.zoomFactor = tgtScale
194 }
195
196 renderHints: PDF.Document.Antialiasing | PDF.Document.TextAntialiasing
197
198 linkHighlightColor: UbuntuColors.orange
199
200 spacing: units.gu(4)
201
202 documentPath: file.path
203 clip: false
204
205 Component.onCompleted: {
206 // WORKAROUND: Fix for wrong grid unit size
207 flickDeceleration = 1500 * units.gridUnit / 8
208 maximumFlickVelocity = 2500 * units.gridUnit / 8
209
210 var t = pdfView.document.documentInfo(PDF.Document.Title);
211 if (t) {
212 pdfPage.title = t
213 }
214 }
215
216 onErrorChanged: {
217 // TODO: Error management
218 console.log(pdfView.error)
219
220 switch(pdfView.error) {
221 case PDF.Error.DocumentLocked:
222 PopupUtils.open(Qt.resolvedUrl("DocumentLockedDialog.qml"), pdfPage)
223 break;
224 }
225 }
226
227 // FIXME: TODO: Not the best management for this. See if/how it can be improved.
228 property var hint
229 onLinkHovered: {
230 if (!hint) {
231 var hintComponent = Qt.createComponent("LinkHint.qml");
232 hint = hintComponent.createObject(pdfView, { "x": mouseX, "y": mouseY - units.gu(3), "linkInfo": linkInfo })
233 }
234 }
235 onIsLinkHoveredChanged: {
236 if (!isLinkHovered && hint)
237 hint.destroy()
238 }
239
240 onLinkClicked: {
241 if (!isTouch) {
242 if (linkInfo.url) {
243 Qt.openUrlExternally(linkInfo.url)
244 } else {
245 pdfView.positionAtIndex(linkInfo.pageIndex, linkInfo.top, linkInfo.left)
246 }
247 }
248 }
249
250 onLinkPressAndHold: {
251 if (isTouch) {
252 PopupUtils.open(Qt.resolvedUrl("OpenLinkDialog.qml"), pdfPage, { linkInfo: linkInfo })
253 }
254 }
255
256 ScalingMouseArea {
257 id: mouseArea
258 anchors.fill: parent
259 enabled: !pdfView.moving
260
261 targetFlickable: pdfView
262 onTotalScaleChanged: targetFlickable.updateContentSize(totalScale)
263
264 thresholdZoom: minimumZoom + (maximumZoom - minimumZoom) * 0.75
265 maximumZoom: {
266 if (DocumentViewer.desktopMode || mainView.wideWindow)
267 return 3.0
268
269 return minimumZoom * 3
270 }
271 minimumZoom: {
272 if (DocumentViewer.desktopMode || mainView.wideWindow)
273 return pdfView.zoomSettings.minimumZoom
274
275
276 return pdfView.zoomSettings.valueAutomaticZoom
277 }
278
279 Binding {
280 target: mouseArea
281 property: "zoomValue"
282 value: pdfView.zoomSettings.zoomFactor
283 }
284 }
285 }
286 }
287 }
288>>>>>>> MERGE-SOURCE
139289
140 BottomEdge {290 BottomEdge {
141 id: contentsBottomEdge291 id: contentsBottomEdge
@@ -166,7 +316,7 @@
166 children: contentsBottomEdge._realPage316 children: contentsBottomEdge._realPage
167 }317 }
168318
169 enabled: poppler.tocModel.count > 0319 enabled: pdfView.document.tocModel.count > 0
170 visible: enabled320 visible: enabled
171321
172 onCollapseCompleted: {322 onCollapseCompleted: {
@@ -192,21 +342,29 @@
192 PdfContentsPage {342 PdfContentsPage {
193 width: contentsBottomEdge.width343 width: contentsBottomEdge.width
194 height: contentsBottomEdge.height344 height: contentsBottomEdge.height
195 enabled: contentsBottomEdge.status === BottomEdge.Committed345 enabled: contentsBottomEdge.status == BottomEdge.Committed
196 active: contentsBottomEdge.status === BottomEdge.Committed346 active: contentsBottomEdge.status == BottomEdge.Committed
197 visible: contentsBottomEdge.status !== BottomEdge.Hidden347 visible: contentsBottomEdge.status != BottomEdge.Hidden
198 }348 }
199 }349 }
200 }350 }
201351
202 /*** ACTIONS ***/352 /*** ACTIONS ***/
353<<<<<<< TREE
203354
204 Action {355 Action {
356=======
357 Action {
358>>>>>>> MERGE-SOURCE
205 id: goToPage359 id: goToPage
206 objectName:"gotopage"360 objectName:"gotopage"
207 iconName: "browser-tabs"361 iconName: "browser-tabs"
208 text: i18n.tr("Go to page...")362 text: i18n.tr("Go to page...")
363<<<<<<< TREE
209 onTriggered: PopupUtils.open(Qt.resolvedUrl("PdfViewGotoDialog.qml"), pdfPage)364 onTriggered: PopupUtils.open(Qt.resolvedUrl("PdfViewGotoDialog.qml"), pdfPage)
365=======
366 onTriggered: PopupUtils.open(Qt.resolvedUrl("PdfViewGotoDialog.qml"))
367>>>>>>> MERGE-SOURCE
210 }368 }
211369
212 Action {370 Action {
@@ -214,7 +372,7 @@
214 objectName:"presentationmode"372 objectName:"presentationmode"
215 iconName: "slideshow"373 iconName: "slideshow"
216 text: i18n.tr("Presentation")374 text: i18n.tr("Presentation")
217 onTriggered: pageStack.push(Qt.resolvedUrl("./PdfPresentation.qml"), {'poppler': poppler})375 onTriggered: pageStack.push(Qt.resolvedUrl("PdfPresentation.qml"), { poppler: pdfView })
218 }376 }
219377
220 Action {378 Action {
@@ -231,4 +389,38 @@
231 iconName: "info"389 iconName: "info"
232 onTriggered: pageStack.push(Qt.resolvedUrl("../common/DetailsPage.qml"))390 onTriggered: pageStack.push(Qt.resolvedUrl("../common/DetailsPage.qml"))
233 }391 }
392
393 Action {
394 id: rotateRight
395 text: i18n.tr("Rotate 90° right")
396 iconName: "rotate-right"
397 onTriggered: {
398 var r = pdfView.rotation
399 r += 1
400
401 if (r > 3)
402 r = 0
403 else if (r < 0)
404 r = 3
405
406 pdfView.rotation = r
407 }
408 }
409
410 Action {
411 id: rotateLeft
412 text: i18n.tr("Rotate 90° left")
413 iconName: "rotate-left"
414 onTriggered: {
415 var r = pdfView.rotation
416 r -= 1
417
418 if (r > 3)
419 r = 0
420 else if (r < 0)
421 r = 3
422
423 pdfView.rotation = r
424 }
425 }
234}426}
235427
=== removed file 'src/app/qml/pdfView/PdfViewDelegate.qml'
--- src/app/qml/pdfView/PdfViewDelegate.qml 2016-01-29 12:23:24 +0000
+++ src/app/qml/pdfView/PdfViewDelegate.qml 1970-01-01 00:00:00 +0000
@@ -1,101 +0,0 @@
1/*
2 * Copyright (C) 2013-2015 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16import QtQuick 2.4
17import Ubuntu.Components 1.3
18
19Rectangle {
20 id: pdfPage
21
22 property int index: model.index
23 property bool _previewFetched: false
24 property bool presentationMode: false
25
26 property alias status: pageImg.status
27
28 width: parent.width
29 height: width * (model.height / model.width)
30 color: "#E6E6E6"
31
32 // Preview page rendering. Used as placeholder while zooming the page.
33 // We generate the low resolution preview from the texture of the PDF page,
34 // so that we can keep page rendering as fast as possible.
35 ShaderEffectSource {
36 id: previewImg
37 anchors.fill: parent
38
39 // We cannot change its opacity or visibility, otherwise the texture will be refreshed,
40 // even if live is false.
41 live: false
42 textureSize: Qt.size(256, 256 * (model.height / model.width))
43 }
44
45 Image {
46 id: pageImg
47 anchors.fill: parent
48
49 cache: false
50 source: "image://poppler" + (index % poppler.providersNumber) + "/page/" + index;
51 sourceSize.width: pdfPage.width
52 fillMode: Image.PreserveAspectFit
53
54 onStatusChanged: {
55 if (presentationMode)
56 return;
57
58 // This is supposed to run the first time PdfViewDelegate gets the page rendering.
59 if (!_previewFetched) {
60 if (status == Image.Ready) {
61 previewImg.sourceItem = pageImg
62 // Re-assign sourceItem property, so the texture is not updated when Image status changes.
63 previewImg.sourceItem = pdfPage
64 }
65 }
66 }
67
68 // Request a new page rendering. The order, which pages are requested with, depends on the distance from the currentPage
69 Timer {
70 id: _zoomTimer
71 interval: {
72 var diff = Math.abs(pdfView.currentPageIndex - model.index)
73 var prov = poppler.providersNumber * 0.5
74
75 if (diff < prov)
76 return 0
77 else
78 return (diff - prov) * 10
79 }
80
81 onTriggered: {
82 pageImg.sourceSize.width = pdfPage.width;
83 }
84 }
85 }
86
87 // Page rendering depends on the width of PdfViewDelegate.
88 // Because of this, we have multiple callings to ImageProvider while zooming.
89 // Just avoid it.
90 Connections {
91 target: !presentationMode ? pinchy : null
92
93 onPinchStarted: _zoomTimer.stop();
94 onPinchUpdated: {
95 // This ensures that page image is not reloaded when the maximumScale or minimumScale has already been reached.
96 if ( !(_zoomHelper.scale >= 2.5 && pinch.scale > 1.0) && !(_zoomHelper.scale <= 1.0 && pinch.scale < 1.0) )
97 pageImg.sourceSize.width = 0;
98 }
99 onPinchFinished: _zoomTimer.restart();
100 }
101}
1020
=== modified file 'src/app/qml/pdfView/PdfViewGotoDialog.qml'
--- src/app/qml/pdfView/PdfViewGotoDialog.qml 2016-03-26 18:44:53 +0000
+++ src/app/qml/pdfView/PdfViewGotoDialog.qml 2016-04-22 10:31:39 +0000
@@ -24,7 +24,7 @@
24 objectName:"PdfViewGotoDialog"24 objectName:"PdfViewGotoDialog"
2525
26 title: i18n.tr("Go to page")26 title: i18n.tr("Go to page")
27 text: i18n.tr("Choose a page between 1 and %1").arg(pdfView.count)27 text: i18n.tr("Choose a page between 1 and %1").arg(pdfView.pagesCount)
2828
29 TextField {29 TextField {
30 id: goToPageTextField30 id: goToPageTextField
@@ -34,7 +34,7 @@
3434
35 hasClearButton: true35 hasClearButton: true
36 inputMethodHints: Qt.ImhFormattedNumbersOnly36 inputMethodHints: Qt.ImhFormattedNumbersOnly
37 validator: IntValidator{ bottom: 1; top: pdfView.count }37 validator: IntValidator{ bottom: 1; top: pdfView.pagesCount }
3838
39 onAccepted: goToPage()39 onAccepted: goToPage()
40 Component.onCompleted: forceActiveFocus()40 Component.onCompleted: forceActiveFocus()
4141
=== added file 'src/app/qml/pdfView/ZoomSelector.qml'
--- src/app/qml/pdfView/ZoomSelector.qml 1970-01-01 00:00:00 +0000
+++ src/app/qml/pdfView/ZoomSelector.qml 2016-04-22 10:31:39 +0000
@@ -0,0 +1,191 @@
1/*
2 * Copyright (C) 2015 Stefano Verzegnassi
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.4
18import Ubuntu.Components 1.3
19import QtQuick.Layouts 1.1
20import DocumentViewer.PDF 2.0 as PDF
21
22import "../common"
23
24TextFieldWithButton {
25 id: textField
26 anchors.verticalCenter: parent.verticalCenter
27 width: units.gu(12)
28
29 property var view
30
31 hasClearButton: true
32 inputMethodHints: Qt.ImhFormattedNumbersOnly
33 validator: IntValidator { bottom: 50; top: 400 }
34
35 onAccepted: {
36 textField.view.setZoom(parseInt(text) / 100)
37 focus = false
38 }
39
40 onHighlightedChanged: {
41 if (highlighted) {
42 text = parseInt(textField.view.zoomSettings.zoomFactor * 100)
43 } else text = ""
44 }
45
46 Label {
47 anchors.centerIn: parent
48 visible: !textField.highlighted
49 text: "%1%".arg(parseInt(textField.view.zoomSettings.zoomFactor*100))
50 }
51
52 popover: TextFieldButtonPopover {
53 id: zoomSelectorDialogue
54
55 /************************************
56 * Zoom in - Zoom out controls *
57 ************************************/
58
59 RowLayout {
60 anchors { left: parent.left; right: parent.right }
61 height: units.gu(4)
62 spacing: units.gu(1)
63
64 ListItem {
65 divider.visible: false
66 Layout.fillHeight: true
67 Layout.fillWidth: true
68
69 onClicked: textField.view.setZoom(textField.view.zoomSettings.zoomFactor + 0.1)
70
71 Icon {
72 width: units.gu(2); height: width
73 anchors.centerIn: parent
74 name: "zoom-in"
75 }
76 }
77
78 VerticalDivider {
79 Layout.fillHeight: true
80 Layout.preferredWidth: units.dp(2)
81 }
82
83 ListItem {
84 divider.visible: false
85 Layout.fillHeight: true
86 Layout.fillWidth: true
87
88 onClicked: textField.view.setZoom(textField.view.zoomSettings.zoomFactor - 0.1)
89
90 Icon {
91 width: units.gu(2); height: width
92 anchors.centerIn: parent
93 name: "zoom-out"
94 }
95 }
96 } // RowLayout
97
98 HorizontalDivider { anchors { left: parent.left; right: parent.right } }
99
100 /************************************
101 * Zoom modes controls *
102 ************************************/
103
104 Repeater {
105 id: zoomModesRepeater
106
107 function delegate_onClicked(mode) {
108 if (mode === PDF.Zoom.FitWidth)
109 textField.view.adjustZoomToWidth()
110
111 if (mode === PDF.Zoom.FitPage)
112 textField.view.adjustZoomToPage()
113
114 if (mode === PDF.Zoom.Automatic)
115 textField.view.adjustAutomaticZoom()
116 }
117
118 model: [
119 { text: i18n.tr("Fit width"), mode: PDF.Zoom.FitWidth },
120 { text: i18n.tr("Fit page"), mode: PDF.Zoom.FitPage },
121 { text: i18n.tr("Automatic"), mode: PDF.Zoom.Automatic }
122 ]
123
124 ListItem {
125 height: units.gu(4)
126 divider.visible: false
127
128 onClicked: {
129 zoomSelectorDialogue.close()
130 zoomModesRepeater.delegate_onClicked(modelData.mode)
131 }
132
133 /* UITK 1.3 specs: Two slot layout (A-B) */
134 ListItemLayout {
135 anchors.centerIn: parent
136
137 /* UITK 1.3 specs: Slot A */
138 title.text: modelData.text
139
140 /* UITK 1.3 specs: Slot B */
141 Icon {
142 SlotsLayout.position: SlotsLayout.Last
143 width: units.gu(2); height: width
144 name: "tick"
145 color: UbuntuColors.green
146 visible: textField.view.zoomSettings.zoomMode == modelData.mode
147 }
148 }
149 } // ListItem
150 }
151
152 HorizontalDivider { visible: zoomModesRepeater.visible; anchors { left: parent.left; right: parent.right } }
153
154 /************************************
155 * Default zoom values controls *
156 ************************************/
157
158 Repeater {
159 model: [
160 { text: "50%", value: 0.50 },
161 { text: "70%", value: 0.70 },
162 { text: "85%", value: 0.85 },
163 { text: "100%", value: 1.00 },
164 { text: "125%", value: 1.25 },
165 { text: "150%", value: 1.50 },
166 { text: "175%", value: 1.75 },
167 { text: "200%", value: 2.00 },
168 { text: "300%", value: 3.00 },
169 { text: "400%", value: 4.00 }
170 ]
171
172 ListItem {
173 divider.visible: false
174 height: units.gu(4)
175
176 onClicked: {
177 textField.view.setZoom(modelData.value)
178 zoomSelectorDialogue.close()
179 }
180
181 Label {
182 text: modelData.text
183 anchors {
184 left: parent.left; leftMargin: units.gu(1)
185 verticalCenter: parent.verticalCenter
186 }
187 }
188 }
189 } // Repeater
190 } // zoomSelectorDialogue
191} // textField
0192
=== modified file 'src/app/qml/ubuntu-docviewer-app.qml'
--- src/app/qml/ubuntu-docviewer-app.qml 2016-04-05 09:33:28 +0000
+++ src/app/qml/ubuntu-docviewer-app.qml 2016-04-22 10:31:39 +0000
@@ -115,9 +115,14 @@
115 }115 }
116116
117 Component.onCompleted: {117 Component.onCompleted: {
118<<<<<<< TREE
118 // WORKAROUND: Mouse detection is not included in the SDK yet119 // WORKAROUND: Mouse detection is not included in the SDK yet
119 QuickUtils.mouseAttached = true120 QuickUtils.mouseAttached = true
120121
122=======
123 QuickUtils.mouseAttached = true;
124
125>>>>>>> MERGE-SOURCE
121 pageStack.push(Qt.resolvedUrl("documentPage/DocumentPage.qml"));126 pageStack.push(Qt.resolvedUrl("documentPage/DocumentPage.qml"));
122127
123 // Open the document, if one has been specified.128 // Open the document, if one has been specified.
124129
=== modified file 'src/app/renderengine.cpp'
--- src/app/renderengine.cpp 2016-01-17 20:33:06 +0000
+++ src/app/renderengine.cpp 2016-04-22 10:31:39 +0000
@@ -18,6 +18,7 @@
1818
19void RenderEngine::enqueueTask(AbstractRenderTask *task)19void RenderEngine::enqueueTask(AbstractRenderTask *task)
20{20{
21 dequeueTask(task->id()); // TODO Rethink.
21 m_queue.enqueue(task);22 m_queue.enqueue(task);
22 doNextTask();23 doNextTask();
23}24}
2425
=== modified file 'src/app/renderengine.h'
--- src/app/renderengine.h 2016-01-17 16:17:02 +0000
+++ src/app/renderengine.h 2016-04-22 10:31:39 +0000
@@ -27,7 +27,6 @@
27 void dequeueTask(int id);27 void dequeueTask(int id);
2828
29public:29public:
30
31 static RenderEngine* instance() {30 static RenderEngine* instance() {
32 if(!s_instance)31 if(!s_instance)
33 s_instance = new RenderEngine();32 s_instance = new RenderEngine();
3433
=== modified file 'src/app/rendertask.h'
--- src/app/rendertask.h 2016-01-17 16:25:30 +0000
+++ src/app/rendertask.h 2016-04-22 10:31:39 +0000
@@ -13,9 +13,10 @@
13enum RenderTaskType13enum RenderTaskType
14{14{
15 RttUnknown = 0x0,15 RttUnknown = 0x0,
16 RttTile = 0x1,16 RttLibreofficeTile = 0x1,
17 RttImpressThumbnail = 0x2,17 RttLibreofficeThumbnail = 0x2,
18 RttPdfPage = 0x318 RttPdfTile = 0x3,
19 RttPdfThumbnail = 0x4
19};20};
2021
21class AbstractRenderTask22class AbstractRenderTask
2223
=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/lopartsimageresponse.cpp'
--- src/plugin/libreofficetoolkit-qml-plugin/lopartsimageresponse.cpp 2016-01-24 20:27:40 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/lopartsimageresponse.cpp 2016-04-22 10:31:39 +0000
@@ -32,7 +32,7 @@
3232
33 connect(RenderEngine::instance(), &RenderEngine::taskRenderFinished,33 connect(RenderEngine::instance(), &RenderEngine::taskRenderFinished,
34 this, [&](AbstractRenderTask *task, QImage img) {34 this, [&](AbstractRenderTask *task, QImage img) {
35 if (m_taskId == task->id() && task->type() == RttImpressThumbnail) {35 if (m_taskId == task->id() && task->type() == RttLibreofficeThumbnail) {
36 m_image = img;36 m_image = img;
37 Q_EMIT finished();37 Q_EMIT finished();
38 }38 }
3939
=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/lorendertask.cpp'
--- src/plugin/libreofficetoolkit-qml-plugin/lorendertask.cpp 2016-01-17 17:42:34 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/lorendertask.cpp 2016-04-22 10:31:39 +0000
@@ -3,7 +3,7 @@
3bool LoRenderTask::canBeRunInParallel(AbstractRenderTask* prevTask)3bool LoRenderTask::canBeRunInParallel(AbstractRenderTask* prevTask)
4{4{
5 Q_ASSERT(prevTask != nullptr);5 Q_ASSERT(prevTask != nullptr);
6 if (prevTask->type() == RttTile || prevTask->type() == RttImpressThumbnail) {6 if (prevTask->type() == RttLibreofficeTile || prevTask->type() == RttLibreofficeThumbnail) {
7 LoRenderTask* loTask = static_cast<LoRenderTask*>(prevTask);7 LoRenderTask* loTask = static_cast<LoRenderTask*>(prevTask);
88
9 // Another document or the same part in the same document can be run parallel.9 // Another document or the same part in the same document can be run parallel.
1010
=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/lorendertask.h'
--- src/plugin/libreofficetoolkit-qml-plugin/lorendertask.h 2016-01-17 17:42:34 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/lorendertask.h 2016-04-22 10:31:39 +0000
@@ -30,7 +30,7 @@
30class TileRenderTask : public LoRenderTask30class TileRenderTask : public LoRenderTask
31{31{
32public:32public:
33 virtual RenderTaskType type() { return RttTile; }33 virtual RenderTaskType type() { return RttLibreofficeTile; }
34 virtual QImage doWork();34 virtual QImage doWork();
3535
36 QRect area() { return m_area; }36 QRect area() { return m_area; }
@@ -45,7 +45,7 @@
45class ThumbnailRenderTask : public LoRenderTask45class ThumbnailRenderTask : public LoRenderTask
46{46{
47public:47public:
48 virtual RenderTaskType type() { return RttImpressThumbnail; }48 virtual RenderTaskType type() { return RttLibreofficeThumbnail; }
49 virtual QImage doWork();49 virtual QImage doWork();
5050
51 QSize size() const { return m_size; }51 QSize size() const { return m_size; }
5252
=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/loview.cpp'
--- src/plugin/libreofficetoolkit-qml-plugin/loview.cpp 2016-02-05 22:42:13 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/loview.cpp 2016-04-22 10:31:39 +0000
@@ -343,7 +343,7 @@
343343
344void LOView::slotTaskRenderFinished(AbstractRenderTask* task, QImage img)344void LOView::slotTaskRenderFinished(AbstractRenderTask* task, QImage img)
345{345{
346 if (task->type() == RttTile) {346 if (task->type() == RttLibreofficeTile) {
347 int id = task->id();347 int id = task->id();
348348
349 for (auto i = m_tiles.begin(); i != m_tiles.end(); ++i) {349 for (auto i = m_tiles.begin(); i != m_tiles.end(); ++i) {
350350
=== modified file 'src/plugin/poppler-qml-plugin/CMakeLists.txt'
--- src/plugin/poppler-qml-plugin/CMakeLists.txt 2015-10-21 13:16:12 +0000
+++ src/plugin/poppler-qml-plugin/CMakeLists.txt 2016-04-22 10:31:39 +0000
@@ -8,24 +8,43 @@
8find_package(Qt5Concurrent)8find_package(Qt5Concurrent)
99
10include_directories(10include_directories(
11 ${CMAKE_CURRENT_SOURCE_DIR}11 ${CMAKE_CURRENT_SOURCE_DIR}
12 ${CMAKE_CURRENT_BINARY_DIR}12 ${CMAKE_CURRENT_BINARY_DIR}
13 ${Qt5Quick_PRIVATE_INCLUDE_DIRS}13)
14 ${Qt5Qml_PRIVATE_INCLUDE_DIRS}14
15)15file(GLOB_RECURSE QML_SRCS
16 qml/*.qml
17 qml/*.js
18)
19
1620
17#add the sources to compile21#add the sources to compile
18set(popplerqmlplugin_SRCS22set(popplerqmlplugin_SRCS
19 plugin.cpp23 plugin.cpp
20 pdfdocument.cpp24 pdfdocument.cpp
21 pdfimageprovider.cpp
22 pdfitem.cpp
23 verticalview.cpp25 verticalview.cpp
24 pdftocmodel.cpp26 pdftocmodel.cpp
27 pdfrendertask.cpp
28 sgtileitem.cpp
29 pagedecoration.cpp
30 pageoverlay.cpp
31 pdfzoom.cpp
32 ucunits.cpp
33 touchdetectionarea.cpp
34 pdfimageprovider.cpp
35 pdfimageresponse.cpp
36 ${QML_SRCS}
37)
38
39set(popplerqmlplugin_HDRS
40 pdferror.h
41 twips.h
42 config.h
25)43)
2644
27add_library(popplerqmlplugin MODULE45add_library(popplerqmlplugin MODULE
28 ${popplerqmlplugin_SRCS}46 ${popplerqmlplugin_SRCS}
47 ${popplerqmlplugin_HDRS}
29)48)
3049
31target_link_libraries(popplerqmlplugin poppler-qt5)50target_link_libraries(popplerqmlplugin poppler-qt5)
@@ -38,9 +57,11 @@
38 COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/../${PLUGIN_DIR}57 COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/../${PLUGIN_DIR}
39 COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/qmldir ${CMAKE_CURRENT_BINARY_DIR}/../${PLUGIN_DIR}58 COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/qmldir ${CMAKE_CURRENT_BINARY_DIR}/../${PLUGIN_DIR}
40 COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:popplerqmlplugin> ${CMAKE_CURRENT_BINARY_DIR}/../${PLUGIN_DIR}59 COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:popplerqmlplugin> ${CMAKE_CURRENT_BINARY_DIR}/../${PLUGIN_DIR}
60 COMMAND ${CMAKE_COMMAND} -E copy ${QML_SRCS} ${CMAKE_CURRENT_BINARY_DIR}/../${PLUGIN_DIR}
41)61)
42endif(NOT "${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}")62endif(NOT "${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}")
4363
44# Install plugin file64# Install plugin file
45install(TARGETS popplerqmlplugin DESTINATION ${QT_IMPORTS_DIR}/${PLUGIN_DIR})65install(TARGETS popplerqmlplugin DESTINATION ${QT_IMPORTS_DIR}/${PLUGIN_DIR})
46install(FILES qmldir DESTINATION ${QT_IMPORTS_DIR}/${PLUGIN_DIR})66install(FILES qmldir DESTINATION ${QT_IMPORTS_DIR}/${PLUGIN_DIR})
67install(FILES ${QML_SRCS} DESTINATION ${QT_IMPORTS_DIR}/${PLUGIN_DIR})
4768
=== added file 'src/plugin/poppler-qml-plugin/config.h'
--- src/plugin/poppler-qml-plugin/config.h 1970-01-01 00:00:00 +0000
+++ src/plugin/poppler-qml-plugin/config.h 2016-04-22 10:31:39 +0000
@@ -0,0 +1,13 @@
1#ifndef CONFIG_H
2#define CONFIG_H
3
4// Uncomment it if you want to see tiles boundaries
5//#define DEBUG_SHOW_TILE_BORDER
6
7// Uncomment for benchmarking tile rendering performance
8//#define DEBUG_TILE_BENCHMARK
9
10// Uncomment if you want more verbose application output
11//#define DEBUG_VERBOSE
12
13#endif // CONFIG_H
014
=== added file 'src/plugin/poppler-qml-plugin/pagedecoration.cpp'
--- src/plugin/poppler-qml-plugin/pagedecoration.cpp 1970-01-01 00:00:00 +0000
+++ src/plugin/poppler-qml-plugin/pagedecoration.cpp 2016-04-22 10:31:39 +0000
@@ -0,0 +1,48 @@
1#include "pagedecoration.h"
2
3#include <QDebug>
4#include <QSGSimpleRectNode>
5
6#define PAGEDECORATION_BORDER_WIDTH 1
7
8PageDecoration::PageDecoration(QQuickItem *parent)
9 : QQuickItem(parent)
10{
11 setFlag(ItemHasContents, true);
12}
13
14PageDecoration::~PageDecoration()
15{ }
16
17QSGNode *PageDecoration::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *)
18{
19 QSGSimpleRectNode* node = static_cast<QSGSimpleRectNode*>(oldNode);
20 QQuickWindow* wnd = window();
21
22 QRectF outterRect = boundingRect().adjusted(
23 PAGEDECORATION_BORDER_WIDTH * -1,
24 PAGEDECORATION_BORDER_WIDTH * -1,
25 PAGEDECORATION_BORDER_WIDTH,
26 PAGEDECORATION_BORDER_WIDTH);
27
28 if (!node && wnd) {
29 node = new QSGSimpleRectNode();
30 node->setColor(QColor::fromRgb(0, 0, 0, 12));
31
32 auto whitePaperNode = new QSGSimpleRectNode();
33 whitePaperNode->setColor(Qt::white);
34 whitePaperNode->setRect(boundingRect());
35
36 node->appendChildNode(whitePaperNode);
37 }
38
39 node->setRect(outterRect);
40
41 return node;
42}
43
44void PageDecoration::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
45{
46 QQuickItem::geometryChanged(newGeometry, oldGeometry);
47 update();
48}
049
=== added file 'src/plugin/poppler-qml-plugin/pagedecoration.h'
--- src/plugin/poppler-qml-plugin/pagedecoration.h 1970-01-01 00:00:00 +0000
+++ src/plugin/poppler-qml-plugin/pagedecoration.h 2016-04-22 10:31:39 +0000
@@ -0,0 +1,19 @@
1#ifndef PAGEDECORATION_H
2#define PAGEDECORATION_H
3
4#include <QQuickItem>
5
6class PageDecoration: public QQuickItem
7{
8 Q_OBJECT
9
10public:
11 PageDecoration(QQuickItem *parent);
12 ~PageDecoration();
13
14protected:
15 virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
16 virtual void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry);
17
18};
19#endif // PAGEDECORATION_H
020
=== added file 'src/plugin/poppler-qml-plugin/pageoverlay.cpp'
--- src/plugin/poppler-qml-plugin/pageoverlay.cpp 1970-01-01 00:00:00 +0000
+++ src/plugin/poppler-qml-plugin/pageoverlay.cpp 2016-04-22 10:31:39 +0000
@@ -0,0 +1,172 @@
1#include "pageoverlay.h"
2#include "pdfdocument.h"
3#include "verticalview.h"
4
5#include <QDebug>
6
7// scenegraph painting
8#include <QSGNode>
9#include <QSGSimpleRectNode>
10
11// mouse cursor
12//#include <QCursor>
13
14// Poppler Qt5
15#include <poppler/qt5/poppler-qt5.h>
16
17PageOverlay::PageOverlay(VerticalView *view, int pageIndex, QQuickItem *parent)
18 : QQuickItem(parent)
19 , m_view(view)
20 , m_pageIndex(pageIndex)
21{
22 setFlag(ItemHasContents, true);
23 //setAcceptHoverEvents(true);
24
25 connect(m_view, &VerticalView::showLinkHighlightChanged, this, &PageOverlay::update);
26 connect(m_view, &VerticalView::linkHighlightColorChanged, this, &PageOverlay::update);
27}
28
29PageOverlay::~PageOverlay()
30{ }
31
32QSGNode *PageOverlay::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *)
33{
34 QSGNode* node = static_cast<QSGNode*>(oldNode);
35 QQuickWindow* wnd = window();
36
37 if (!node && wnd) {
38 node = new QSGNode();
39 }
40
41 if (m_view->showLinkHighlight() && boundingRect().isValid()) {
42 QList<Poppler::Link *> links = m_view->document()->pageLinks(m_pageIndex);
43
44 Q_FOREACH(Poppler::Link *link, links) {
45 if (link->linkType() == Poppler::Link::Goto ||
46 link->linkType() == Poppler::Link::Browse) {
47
48 bool rotatedBy90 = (m_view->rotation() == PdfRotation::Rotate90 ||
49 m_view->rotation() == PdfRotation::Rotate270);
50
51 QRectF linkRect;
52 int x1 = (!rotatedBy90 ? width() : height()) * link->linkArea().left();
53 int y1 = (!rotatedBy90 ? height() : width()) * link->linkArea().top();
54 int x2 = (!rotatedBy90 ? width() : height()) * link->linkArea().right();
55 int y2 = (!rotatedBy90 ? height() : width()) * link->linkArea().bottom();
56 int w = this->width();
57 int h = this->height();
58
59 switch (m_view->rotation()) {
60 case PdfRotation::Rotate0:
61 linkRect.setLeft ( x1 );
62 linkRect.setTop ( y1 );
63 linkRect.setRight ( x2 );
64 linkRect.setBottom ( y2 );
65 break;
66 case PdfRotation::Rotate90:
67 linkRect.setLeft ( w - y2 );
68 linkRect.setTop ( x1 );
69 linkRect.setRight ( w - y1 );
70 linkRect.setBottom ( x2 );
71 break;
72 case PdfRotation::Rotate180:
73 linkRect.setLeft ( w - x2 );
74 linkRect.setTop ( h - y2 );
75 linkRect.setRight ( w - x1 );
76 linkRect.setBottom ( h - y1 );
77 break;
78 case PdfRotation::Rotate270:
79 linkRect.setLeft ( y1 );
80 linkRect.setTop ( h - x2 );
81 linkRect.setRight ( y2 );
82 linkRect.setBottom ( h - x1 );
83 break;
84 }
85
86 auto linkNode = new QSGSimpleRectNode();
87
88 const QColor &linkColor = m_view->linkHighlightColor();
89 linkNode->setColor(QColor::fromRgb(linkColor.red(), linkColor.green(), linkColor.blue(), 8));
90 linkNode->setRect(linkRect);
91
92 drawLinkBorders(linkNode);
93
94 node->appendChildNode(linkNode);
95 }
96 }
97 }
98
99 return node;
100}
101
102void PageOverlay::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
103{
104 QQuickItem::geometryChanged(newGeometry, oldGeometry);
105 update();
106}
107
108/*
109 * QML MouseArea overwrite any attempt to set this from C++
110 * Disable this code and do it through QML (see Viewer.qml).
111 * TODO: Check performance of the QML code that handles this.
112 *
113void PageOverlay::hoverMoveEvent(QHoverEvent *event)
114{
115 // We only handle what's strictly necessary for changing the cursor aspect.
116 // Any other mouse event is handled directly through QML.
117 const QPointF &curPos = event->posF();
118
119 QList<Poppler::Link *> links = m_view->document()->pageLinks(m_pageIndex);
120 Q_FOREACH (Poppler::Link *link, links) {
121 QRectF linkRect(link->linkArea().x() * this->width(),
122 link->linkArea().y() * this->height(),
123 link->linkArea().width() * this->width(),
124 link->linkArea().height() * this->height());
125
126 if (linkRect.contains(curPos)) {
127 setCursor(QCursor(Qt::PointingHandCursor));
128 return;
129 }
130 }
131
132 // Not hovering a link. Restore default cursor.
133 unsetCursor();
134}
135*/
136
137void PageOverlay::drawLinkBorders(QSGSimpleRectNode *parentNode)
138{
139 auto node = parentNode;
140
141 auto linkBorderGeometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 8);
142 linkBorderGeometry->setDrawingMode(GL_LINES);
143 linkBorderGeometry->setLineWidth(1);
144
145 QSGGeometry::Point2D* vertex = linkBorderGeometry->vertexDataAsPoint2D();
146 vertex[0].set(node->rect().left(), node->rect().top());
147 vertex[1].set(node->rect().left(), node->rect().bottom());
148
149 vertex[2].set(node->rect().right(), node->rect().top());
150 vertex[3].set(node->rect().right(), node->rect().bottom());
151
152 vertex[4].set(vertex[0].x, vertex[0].y);
153 vertex[5].set(vertex[2].x, vertex[2].y);
154
155 vertex[6].set(vertex[1].x, vertex[1].y);
156 vertex[7].set(vertex[3].x, vertex[3].y);
157
158 auto linkBorderMaterial = new QSGFlatColorMaterial;
159
160 const QColor &linkColor = m_view->linkHighlightColor();
161 linkBorderMaterial->setColor(QColor::fromRgb(linkColor.red(), linkColor.green(), linkColor.blue(), 64));
162
163 auto linkBorderNode = new QSGGeometryNode;
164
165 linkBorderNode->setGeometry(linkBorderGeometry);
166 linkBorderNode->setFlag(QSGNode::OwnsGeometry);
167
168 linkBorderNode->setMaterial(linkBorderMaterial);
169 linkBorderNode->setFlag(QSGNode::OwnsMaterial);
170
171 node->appendChildNode(linkBorderNode);
172}
0173
=== added file 'src/plugin/poppler-qml-plugin/pageoverlay.h'
--- src/plugin/poppler-qml-plugin/pageoverlay.h 1970-01-01 00:00:00 +0000
+++ src/plugin/poppler-qml-plugin/pageoverlay.h 2016-04-22 10:31:39 +0000
@@ -0,0 +1,35 @@
1#ifndef PAGEOVERLAY_H
2#define PAGEOVERLAY_H
3
4#include <QQuickItem>
5
6class VerticalView;
7class QSGSimpleRectNode;
8
9class PageOverlay: public QQuickItem
10{
11 Q_OBJECT
12
13public:
14 PageOverlay(VerticalView *view, int pageIndex, QQuickItem *parent);
15 ~PageOverlay();
16
17 bool showLinkHighlight() const;
18 void setShowLinkHighlight(bool show);
19
20 QColor linkHighlightColor() const;
21 void setLinkHightlightColor(const QColor &color);
22
23protected:
24 virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
25 virtual void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry);
26 //virtual void hoverMoveEvent(QHoverEvent * event);
27
28private:
29 void drawLinkBorders(QSGSimpleRectNode *parentNode);
30
31private:
32 VerticalView* m_view;
33 int m_pageIndex;
34};
35#endif // PAGEOVERLAY_H
036
=== modified file 'src/plugin/poppler-qml-plugin/pdfdocument.cpp'
--- src/plugin/poppler-qml-plugin/pdfdocument.cpp 2015-07-14 15:43:11 +0000
+++ src/plugin/poppler-qml-plugin/pdfdocument.cpp 2016-04-22 10:31:39 +0000
@@ -1,24 +1,5 @@
1/*
2 * Copyright (C) 2013-2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors: Anthony Granger <grangeranthony@gmail.com>
17 * Stefano Verzegnassi <stefano92.100@gmail.com>
18 */
19
20#include "pdfdocument.h"1#include "pdfdocument.h"
21#include "pdfimageprovider.h"2#include "twips.h"
223
23#include <poppler/qt5/poppler-qt5.h>4#include <poppler/qt5/poppler-qt5.h>
24#include <QDebug>5#include <QDebug>
@@ -27,47 +8,18 @@
278
28#include <QtConcurrent/QtConcurrent>9#include <QtConcurrent/QtConcurrent>
2910
30PdfDocument::PdfDocument(QAbstractListModel *parent):11// TODO: Add QQuickAsyncImageProvider for thumbnails
31 QAbstractListModel(parent)12
32 , m_path("")13PdfDocument::PdfDocument():
33 , m_providersNumber(1)14 m_path("")
34 , m_tocModel(nullptr)15 , m_tocModel(nullptr)
35{16 , m_error(PopplerError::NoError)
36 qRegisterMetaType<PdfPagesList>("PdfPagesList");17 , m_renderHints(0)
37}18{
3819 connect(this, &PdfDocument::renderHintsChanged, this, &PdfDocument::updateRenderHints);
39QHash<int, QByteArray> PdfDocument::roleNames() const20}
40{21
41 QHash<int, QByteArray> roles;22void PdfDocument::setPath(const QString &pathName)
42 roles[WidthRole] = "width";
43 roles[HeightRole] = "height";
44 return roles;
45}
46
47int PdfDocument::rowCount(const QModelIndex & parent) const
48{
49 Q_UNUSED(parent)
50 return m_pages.count();
51}
52
53QVariant PdfDocument::data(const QModelIndex & index, int role) const
54{
55 if (index.row() < 0 || index.row() > m_pages.count())
56 return QVariant();
57
58 const PdfItem &pdfItem = m_pages.at(index.row());
59
60 switch (role) {
61 case WidthRole:
62 return pdfItem.width();
63 case HeightRole:
64 return pdfItem.height();
65 default:
66 return 0;
67 }
68}
69
70void PdfDocument::setPath(QString &pathName)
71{23{
72 if (pathName.isEmpty())24 if (pathName.isEmpty())
73 return;25 return;
@@ -75,131 +27,277 @@
75 m_path = pathName;27 m_path = pathName;
76 Q_EMIT pathChanged();28 Q_EMIT pathChanged();
7729
78 if (!loadDocument(m_path))30 loadDocument();
79 return;31}
8032
81 // Init toc model33bool PdfDocument::isLocked()
82 m_tocModel = new PdfTocModel;34{
83 m_tocModel->setDocument(m_document);35 if (!m_popDocument)
84 Q_EMIT tocModelChanged();36 return true;
8537
86 loadPages();38 return m_popDocument.data()->isLocked();
87 loadProvider();39}
88}40
8941int PdfDocument::pageCount()
90bool PdfDocument::loadDocument(QString &pathName)42{
91{43 if (!m_popDocument)
92 qDebug() << "Loading document...";44 return 0;
9345
94 if (pathName.isEmpty()) {46 return m_popDocument.data()->numPages();
95 qDebug() << "Can't load the document, path is empty.";
96 return false;
97 }
98
99 m_document = Poppler::Document::load(pathName);
100
101 if (!m_document || m_document->isLocked()) {
102 qDebug() << "ERROR : Can't open the document located at " + pathName;
103 Q_EMIT error("Can't open the document located at " + pathName);
104
105 delete m_document;
106 return false;
107 }
108
109 qDebug() << "Document loaded successfully !";
110
111 m_document->setRenderHint(Poppler::Document::Antialiasing, true);
112 m_document->setRenderHint(Poppler::Document::TextAntialiasing, true);
113
114 return true;
115}47}
11648
117QDateTime PdfDocument::getDocumentDate(QString data)49QDateTime PdfDocument::getDocumentDate(QString data)
118{50{
119 if (!m_document)51 if (!m_popDocument)
120 return QDateTime();52 return QDateTime();
12153
122 if (data == "CreationDate" || data == "ModDate")54 if (data == "CreationDate" || data == "ModDate")
123 return m_document->date(data);55 return m_popDocument->date(data);
124 else56 else
125 return QDateTime();57 return QDateTime();
126}58}
12759
128QString PdfDocument::getDocumentInfo(QString data)60QString PdfDocument::getDocumentInfo(QString data)
129{61{
130 if (!m_document)62 if (!m_popDocument)
131 return QString("");63 return QString("");
13264
133 if (data == "Title" || data == "Subject" || data == "Author" || data == "Creator" || data == "Producer")65 if (data == "Title" || data == "Subject" || data == "Author" || data == "Creator" || data == "Producer")
134 return m_document->info(data);66 return m_popDocument->info(data);
135 else67 else
136 return QString("");68 return QString("");
137}69}
13870
139bool PdfDocument::loadPages()71QVariant PdfDocument::documentInfo(PdfDocument::DocumentInfo info)
140{72{
141 qDebug() << "Populating model...";73 if (!m_popDocument)
14274 return QVariant();
143 m_pages.clear();75
14476 switch (info) {
145 if (!m_document)77 case Title:
146 return false;78 return m_popDocument->info("Title");
14779 case Subject:
148 Poppler::Document* document = m_document;80 return m_popDocument->info("Subject");
149 QtConcurrent::run( [=] {81 case Author:
150 PdfPagesList pages;82 return m_popDocument->info("Author");
15183 case Creator:
152 for( int i = 0; i < document->numPages(); ++i )84 return m_popDocument->info("Creator");
153 pages.append(document->page(i));85 case Producer:
15486 return m_popDocument->info("Producer");
155 QMetaObject::invokeMethod(this, "_q_populate", Qt::QueuedConnection, Q_ARG(PdfPagesList, pages));87 case CreationDate:
156 });88 return m_popDocument->date("CreationDate");
89 case ModifiedDate:
90 return m_popDocument->date("ModDate");
91 default:
92 return QVariant();
93 }
94}
95
96bool PdfDocument::unlock(const QString &ownerPassword, const QString &userPassword)
97{
98 bool result = false;
99
100 m_popDocument.data()->unlock(ownerPassword.toLatin1(), userPassword.toLatin1());
101
102 // It seems that Poppler::Document::unlock() returns true even with the wrong password :/
103 result = !isLocked();
104
105 if (result) {
106 completeIntialization();
107 }
108
109 return result;
110}
111
112QObject *PdfDocument::tocModel() const
113{
114 return m_tocModel;
115}
116
117QSize PdfDocument::pageSize(int index) const
118{
119 QSize s;
120
121 if (m_popDocument) {
122 Poppler::Page* page = m_popDocument.data()->page(index);
123
124 s = page->pageSize();
125
126 delete page;
127 }
128
129 return s;
130}
131
132PopplerError::Error PdfDocument::error() const
133{
134 return m_error;
135}
136
137PdfDocument::RenderHints PdfDocument::renderHints() const
138{
139 return m_renderHints;
140}
141
142void PdfDocument::setRenderHints(const RenderHints hints)
143{
144 if (m_renderHints == hints)
145 return;
146
147 m_renderHints = hints;
148 Q_EMIT renderHintsChanged();
149}
150
151void PdfDocument::updateRenderHints()
152{
153 if (!m_popDocument)
154 return;
155
156 Poppler::Document* doc = m_popDocument.data();
157
158 doc->setRenderHint(Poppler::Document::RenderHint::Antialiasing, m_renderHints & PdfDocument::Antialiasing);
159 doc->setRenderHint(Poppler::Document::RenderHint::TextAntialiasing, m_renderHints & PdfDocument::TextAntialiasing);
160 doc->setRenderHint(Poppler::Document::RenderHint::TextHinting, m_renderHints & PdfDocument::TextHinting);
161 doc->setRenderHint(Poppler::Document::RenderHint::TextSlightHinting, m_renderHints & PdfDocument::TextSlightHinting);
162 doc->setRenderHint(Poppler::Document::RenderHint::OverprintPreview, m_renderHints & PdfDocument::OverprintPreview);
163 doc->setRenderHint(Poppler::Document::RenderHint::ThinLineSolid, m_renderHints & PdfDocument::ThinLineSolid);
164 doc->setRenderHint(Poppler::Document::RenderHint::ThinLineShape, m_renderHints & PdfDocument::ThinLineShape);
165}
166
167QImage PdfDocument::paintTile(int pageIndex, const qreal &zoom, QRect rect, PdfRotation::Rotation rotate) const
168{
169 QImage result;
170
171 if (m_popDocument) {
172 if (pageIndex >= 0 || pageIndex < m_popDocument.data()->numPages()) {
173 Poppler::Page* page = m_popDocument.data()->page(pageIndex);
174
175 result = page->renderToImage(
176 DEFAULT_DPI * Twips::getUnitsRatio() * zoom,
177 DEFAULT_DPI * Twips::getUnitsRatio() * zoom,
178 rect.x(), rect.y(), rect.width(), rect.height(),
179 Poppler::Page::Rotation(rotate));
180
181 delete page;
182 }
183 }
184
185 return result;
186}
187
188//FIXME: Not perfect!
189QImage PdfDocument::paintThumbnail(int pageIndex, const QSize &size, PdfRotation::Rotation rotate) const
190{
191 QImage result;
192
193 if (m_popDocument) {
194 if (pageIndex >= 0 || pageIndex < m_popDocument.data()->numPages()) {
195 Poppler::Page* page = m_popDocument.data()->page(pageIndex);
196
197 QSize resultSize;
198 QSize pageSize = page->pageSize();
199
200 if (pageSize.width() > pageSize.height()) {
201 resultSize.setWidth(size.width());
202 resultSize.setHeight(size.width() * pageSize.height() / pageSize.width());
203 } else {
204 resultSize.setHeight(size.height());
205 resultSize.setWidth(size.height() * pageSize.width() / pageSize.height());
206 }
207
208 result = page->renderToImage(
209 resultSize.width() / (pageSize.width() / 72),
210 resultSize.height() / (pageSize.height() / 72),
211 -1, -1, -1, -1,
212 Poppler::Page::Rotation(rotate));
213
214 delete page;
215 }
216 }
217
218 return result;
219}
220
221QList<Poppler::Link *> PdfDocument::pageLinks(int pageIndex) const
222{
223 QList<Poppler::Link *> result;
224
225 if (!m_links.empty())
226 result = m_links.value(pageIndex);
227
228 return result;
229}
230
231bool PdfDocument::loadDocument()
232{
233 qDebug() << "Loading document...";
234
235 if (m_path.isEmpty()) {
236 qDebug() << "Can't load the document, path is empty.";
237 setError(PopplerError::FileNotFound);
238 return false;
239 }
240
241 Poppler::Document* doc = Poppler::Document::load(m_path);
242 m_popDocument = QSharedPointer<Poppler::Document>(doc);
243
244 if (!doc || doc->isLocked()) {
245 qDebug() << "ERROR : Can't open the document located at " + m_path;
246 setError(PopplerError::DocumentLocked);
247
248 return false;
249 }
250
251 setError(PopplerError::NoError);
252 qDebug() << "Document loaded successfully !";
253
254 completeIntialization();
157255
158 return true;256 return true;
159}257
160258}
161void PdfDocument::_q_populate(PdfPagesList pagesList)259
162{260void PdfDocument::setError(const PopplerError::Error &error)
163 qDebug() << "Number of pages:" << pagesList.count();261{
164262 if (m_error == error)
165 Q_FOREACH (Poppler::Page *page, pagesList) {263 return;
166 beginInsertRows(QModelIndex(), rowCount(), rowCount());264
167 m_pages << page;265 m_error = error;
168 endInsertRows();266 Q_EMIT errorChanged();
169 }267}
170268
171 qDebug() << "Model has been successfully populated!";269void PdfDocument::completeIntialization()
172 Q_EMIT pagesLoaded();270{
173}271 updateRenderHints();
174272
175void PdfDocument::loadProvider()273 // Init toc model
176{274 m_tocModel = new PdfTocModel;
177 // WORKAROUND: QQuickImageProvider should create multiple threads to load more images at the same time.275 m_tocModel->setDocument(m_popDocument);
178 // [QTBUG-37998] QQuickImageProvider can block its separate thread with ForceAsynchronousImageLoading276 Q_EMIT tocModelChanged();
179 // Link: https://bugreports.qt.io/browse/QTBUG-37988277
180278 Q_EMIT pageCountChanged();
181 // WORKAROUND: ARM SoCs can disable some of their cores when the load is not particulary high.279
182 // This causes a wrong value for the "newProvidersNumber" variable.280 // WORKAROUND: Getting links from pages seems a bit trivial and causes SIGFAULTs.
183 // We hard-code its value to 4 (which is the number of available core on all the supported devices).281 // Do it once at document initialization and cache them for any future request.
184// int newProvidersNumber = QThread::idealThreadCount();282 for (int i=0; i<m_popDocument->numPages(); ++i) {
185 int newProvidersNumber = 4;283 Poppler::Page* page = m_popDocument->page(i);
186284
187 if (newProvidersNumber != m_providersNumber) {285 QList<Poppler::Link *> l = page->links();
188 m_providersNumber = newProvidersNumber;286 m_links.insert(i, l);
189 Q_EMIT providersNumberChanged();287
190 }288 delete page;
191289 }
192 qDebug() << "Ideal number of image providers is:" << m_providersNumber;
193
194 qDebug() << "Loading image provider(s)...";
195 QQmlEngine *engine = QQmlEngine::contextForObject(this)->engine();
196
197 for (int i=0; i<m_providersNumber; i++)
198 engine->addImageProvider(QLatin1String("poppler" + QByteArray::number(i)), new PdfImageProvider(m_document));
199
200 qDebug() << "Image provider(s) loaded successfully !";
201}290}
202291
203PdfDocument::~PdfDocument()292PdfDocument::~PdfDocument()
204{293{
294 Q_FOREACH(QList<Poppler::Link *> list, m_links)
295 qDeleteAll(list);
296
297 delete m_tocModel;
298}
299
300QString PdfDocument::path() const
301{
302 return m_path;
205}303}
206304
=== modified file 'src/plugin/poppler-qml-plugin/pdfdocument.h'
--- src/plugin/poppler-qml-plugin/pdfdocument.h 2015-02-04 19:19:21 +0000
+++ src/plugin/poppler-qml-plugin/pdfdocument.h 2016-04-22 10:31:39 +0000
@@ -1,85 +1,117 @@
1/*
2 * Copyright (C) 2013-2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Author: Anthony Granger <grangeranthony@gmail.com>
17 * Stefano Verzegnassi <stefano92.100@gmail.com>
18 */
19
20#ifndef PDFDOCUMENT_H1#ifndef PDFDOCUMENT_H
21#define PDFDOCUMENT_H2#define PDFDOCUMENT_H
223
23#include <QAbstractListModel>4#include <QObject>
5#include <QSharedPointer>
24#include <poppler/qt5/poppler-qt5.h>6#include <poppler/qt5/poppler-qt5.h>
25#include "pdfitem.h"7
8#include "../../app/renderengine.h"
26#include "pdftocmodel.h"9#include "pdftocmodel.h"
2710#include "pdferror.h"
28typedef QList<Poppler::Page*> PdfPagesList;11
2912class PdfRotation : public QObject
30class PdfDocument : public QAbstractListModel13{
14 Q_OBJECT
15 Q_ENUMS(Rotation)
16
17public:
18 enum Rotation {
19 Rotate0 = Poppler::Page::Rotate0,
20 Rotate90 = Poppler::Page::Rotate90,
21 Rotate180 = Poppler::Page::Rotate180,
22 Rotate270 = Poppler::Page::Rotate270,
23 };
24};
25
26class PdfDocument : public QObject
31{27{
32 Q_OBJECT28 Q_OBJECT
33 Q_DISABLE_COPY(PdfDocument)29 Q_DISABLE_COPY(PdfDocument)
30 Q_ENUMS(DocumentInfo)
31 Q_ENUMS(RenderHint)
32 Q_FLAGS(RenderHints)
34 Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged)33 Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged)
35 Q_PROPERTY(int providersNumber READ providersNumber NOTIFY providersNumberChanged)34 Q_PROPERTY(int pageCount READ pageCount NOTIFY pageCountChanged)
36 Q_PROPERTY(QObject* tocModel READ tocModel NOTIFY tocModelChanged)35 Q_PROPERTY(QObject* tocModel READ tocModel NOTIFY tocModelChanged)
36 Q_PROPERTY(PopplerError::Error error READ error NOTIFY errorChanged)
37 Q_PROPERTY(RenderHints renderHints READ renderHints WRITE setRenderHints NOTIFY renderHintsChanged)
3738
38public:39public:
39 enum Roles {40 explicit PdfDocument();
40 WidthRole = Qt::UserRole + 1,41 ~PdfDocument();
41 HeightRole42
42 };43 enum DocumentInfo {
4344 Title,
44 explicit PdfDocument(QAbstractListModel *parent = 0);45 Subject,
45 virtual ~PdfDocument();46 Author,
4647 Creator,
47 QString path() const { return m_path; }48 Producer,
48 void setPath(QString &pathName);49 CreationDate,
4950 ModifiedDate
50 int providersNumber() const { return m_providersNumber; }51 };
5152
52 QHash<int, QByteArray> roleNames() const;53 enum RenderHint {
5354 Antialiasing = 0x00000001,
54 int rowCount(const QModelIndex & parent = QModelIndex()) const;55 TextAntialiasing = 0x00000002,
55 QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;56 TextHinting = 0x00000004,
57 TextSlightHinting = 0x00000008,
58 OverprintPreview = 0x00000010,
59 ThinLineSolid = 0x00000020,
60 ThinLineShape = 0x00000040
61 };
62 Q_DECLARE_FLAGS(RenderHints, RenderHint)
63
64 QString path() const;
65 void setPath(const QString &pathName);
66
67 bool isLocked();
68
69 int pageCount();
70
71 QImage paintTile(int pageIndex, const qreal &zoom, QRect rect, PdfRotation::Rotation rotate = PdfRotation::Rotate0) const;
72 QImage paintThumbnail(int pageIndex, const QSize &size, PdfRotation::Rotation rotate = PdfRotation::Rotate0) const;
73
74 QList<Poppler::Link *> pageLinks(int pageIndex) const;
5675
57 Q_INVOKABLE QDateTime getDocumentDate(QString data);76 Q_INVOKABLE QDateTime getDocumentDate(QString data);
58 Q_INVOKABLE QString getDocumentInfo(QString data);77 Q_INVOKABLE QString getDocumentInfo(QString data);
5978 Q_INVOKABLE QVariant documentInfo(DocumentInfo info);
60 QObject *tocModel() const { return m_tocModel; }79
80 Q_INVOKABLE bool unlock(const QString &ownerPassword, const QString &userPassword);
81
82 QObject *tocModel() const;
83
84 QSize pageSize(int index) const;
85
86 PopplerError::Error error() const;
87
88 RenderHints renderHints() const;
89 void setRenderHints(const RenderHints hints);
6190
62Q_SIGNALS:91Q_SIGNALS:
63 void pathChanged();92 void pathChanged();
64 void error(const QString& errorMessage);93 void pageCountChanged();
65 void pagesLoaded();
66 void providersNumberChanged();
67 void tocModelChanged();94 void tocModelChanged();
6895 void errorChanged();
69private slots:96 void renderHintsChanged();
70 void _q_populate(PdfPagesList pagesList);97
98private Q_SLOTS:
99 void updateRenderHints();
100
101private:
102 bool loadDocument();
103 void setError(const PopplerError::Error &error);
104 void completeIntialization();
71105
72private:106private:
73 QString m_path;107 QString m_path;
74 int m_providersNumber;
75
76 bool loadDocument(QString &pathNAme);
77 void loadProvider();
78 bool loadPages();
79
80 Poppler::Document *m_document;
81 QList<PdfItem> m_pages;
82 PdfTocModel* m_tocModel;108 PdfTocModel* m_tocModel;
109 PopplerError::Error m_error;
110 RenderHints m_renderHints;
111
112 QHash<int, QList<Poppler::Link *>> m_links;
113
114 QSharedPointer<Poppler::Document> m_popDocument;
83};115};
84116
85#endif // PDFDOCUMENT_H117#endif // PDFDOCUMENT_H
86118
=== added file 'src/plugin/poppler-qml-plugin/pdferror.h'
--- src/plugin/poppler-qml-plugin/pdferror.h 1970-01-01 00:00:00 +0000
+++ src/plugin/poppler-qml-plugin/pdferror.h 2016-04-22 10:31:39 +0000
@@ -0,0 +1,19 @@
1#ifndef PDFERROR_H
2#define PDFERROR_H
3
4#include <QObject>
5
6class PopplerError : public QObject
7{
8 Q_OBJECT
9 Q_ENUMS(Error)
10
11public:
12 enum Error {
13 NoError = 0,
14 FileNotFound = 1,
15 DocumentLocked = 2
16 };
17};
18
19#endif // PDFERROR_H
020
=== added file 'src/plugin/poppler-qml-plugin/pdfimageprovider.cpp'
--- src/plugin/poppler-qml-plugin/pdfimageprovider.cpp 1970-01-01 00:00:00 +0000
+++ src/plugin/poppler-qml-plugin/pdfimageprovider.cpp 2016-04-22 10:31:39 +0000
@@ -0,0 +1,60 @@
1/*
2 * Copyright (C) 2015, 2016 Stefano Verzegnassi
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "pdfimageprovider.h"
18#include "pdfimageresponse.h"
19
20#include "pdfdocument.h"
21
22#include "../../app/renderengine.h"
23#include "pdfrendertask.h"
24
25#include <QDebug>
26
27PdfImageProvider::PdfImageProvider(const QSharedPointer<PdfDocument>& d)
28 : QQuickAsyncImageProvider()
29 , m_document(d)
30{ }
31
32QQuickImageResponse *PdfImageProvider::requestImageResponse(const QString & id, const QSize & requestedSize)
33{
34 QString type = id.section("/", 0, 0);
35 int part = id.section("/", 1, 1).toInt();
36 int rotation = id.section("/", 2, 2).toInt();
37 bool isValid = bool(!requestedSize.isNull() && type == "page");
38
39 auto response = new PdfImageResponse(isValid);
40
41 if (isValid) {
42 int taskId = RenderEngine::getNextId();
43 response->setTaskId(taskId);
44 RenderEngine::instance()->enqueueTask(createTask(part, rotation, requestedSize, taskId));
45 }
46
47 return response;
48}
49
50PdfThumbnailRenderTask* PdfImageProvider::createTask(int pageIndex, int rotation, const QSize &size, int id) const
51{
52 auto task = new PdfThumbnailRenderTask();
53 task->setId(id);
54 task->setPage(pageIndex);
55 task->setDocument(m_document);
56 task->setRotation(rotation);
57 task->setSize(size.isEmpty() ? QSize(256, 256) : size);
58
59 return task;
60}
061
=== removed file 'src/plugin/poppler-qml-plugin/pdfimageprovider.cpp'
--- src/plugin/poppler-qml-plugin/pdfimageprovider.cpp 2015-02-03 18:50:36 +0000
+++ src/plugin/poppler-qml-plugin/pdfimageprovider.cpp 1970-01-01 00:00:00 +0000
@@ -1,75 +0,0 @@
1/*
2 * Copyright (C) 2013-2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Author: Anthony Granger <grangeranthony@gmail.com>
17 * Stefano Verzegnassi <stefano92.100@gmail.com
18 */
19
20#include <poppler/qt5/poppler-qt5.h>
21#include <QQuickImageProvider>
22#include <QDebug>
23
24#include "pdfimageprovider.h"
25
26PdfImageProvider::PdfImageProvider(Poppler::Document *pdfDocument)
27 : QQuickImageProvider(QQuickImageProvider::Image, QQuickImageProvider::ForceAsynchronousImageLoading)
28{
29 this->document = pdfDocument;
30}
31
32QImage PdfImageProvider::requestImage(const QString & id, QSize * size, const QSize & requestedSize)
33{
34 Q_UNUSED(size)
35
36 // If the requestedSize.width is 0, avoid Poppler rendering
37 // FIXME: Actually it works correctly, but an error is anyway shown in the application output.
38 if (requestedSize.width() > 0) {
39 QString type = id.section("/", 0, 0);
40 QImage result;
41 QSizeF pageSize;
42 QSizeF pageSizePhys;
43 float res = 0;
44 Poppler::Page *page;
45
46 if (type == "page")
47 {
48 int numPage = id.section("/", 1, 1).toInt();
49
50 // Useful for debugging, keep commented unless you need it.
51 // qDebug() << "Page" << numPage + 1 << "requested";
52
53 page = document->page(numPage);
54
55 pageSize = page->pageSizeF();
56 pageSizePhys.setWidth(pageSize.width() / 72);
57 res = requestedSize.width() / pageSizePhys.width();
58
59 // Useful for debugging, keep commented unless you need it.
60 /*
61 qDebug() << "Requested size :" << requestedSize.width() << ";" << requestedSize.height();
62 qDebug() << "Size :" << pageSizePhys.width() << ";" << pageSizePhys.height();
63 qDebug() << "Resolution :" << res;
64 */
65
66 // Render the page to QImage
67 result = page->renderToImage(res, res);
68 }
69
70 return result;
71 }
72
73 // Requested size is 0, so return a null image.
74 return QImage();
75}
760
=== added file 'src/plugin/poppler-qml-plugin/pdfimageprovider.h'
--- src/plugin/poppler-qml-plugin/pdfimageprovider.h 1970-01-01 00:00:00 +0000
+++ src/plugin/poppler-qml-plugin/pdfimageprovider.h 2016-04-22 10:31:39 +0000
@@ -0,0 +1,41 @@
1/*
2 * Copyright (C) 2015, 2016 Stefano Verzegnassi
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18#ifndef PDFIMAGEPROVIDER_H
19#define PDFIMAGEPROVIDER_H
20
21// For QQuickAsyncImageProvider
22#include <qquickimageprovider.h>
23#include <QSharedPointer>
24
25class PdfDocument;
26class PdfThumbnailRenderTask;
27
28class PdfImageProvider : public QQuickAsyncImageProvider
29{
30public:
31 PdfImageProvider(const QSharedPointer<PdfDocument>& d);
32 QQuickImageResponse* requestImageResponse(const QString & id, const QSize & requestedSize);
33
34private:
35 PdfThumbnailRenderTask* createTask(int pageIndex, int rotation, const QSize &size, int id) const;
36
37private:
38 QSharedPointer<PdfDocument> m_document;
39};
40
41#endif // PDFIMAGEPROVIDER_H
042
=== removed file 'src/plugin/poppler-qml-plugin/pdfimageprovider.h'
--- src/plugin/poppler-qml-plugin/pdfimageprovider.h 2015-01-30 18:05:22 +0000
+++ src/plugin/poppler-qml-plugin/pdfimageprovider.h 1970-01-01 00:00:00 +0000
@@ -1,36 +0,0 @@
1/*
2 * Copyright (C) 2013-2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Author: Anthony Granger <grangeranthony@gmail.com>
17 * Stefano Verzegnassi <stefano92.100@gmail.com>
18 */
19
20#ifndef PDFIMAGEPROVIDER_H
21#define PDFIMAGEPROVIDER_H
22
23#include <QQuickImageProvider>
24#include <poppler/qt5/poppler-qt5.h>
25
26class PdfImageProvider : public QQuickImageProvider
27{
28public:
29 PdfImageProvider(Poppler::Document *pdfDocument);
30 QImage requestImage(const QString & id, QSize * size, const QSize & requestedSize);
31
32private:
33 Poppler::Document *document;
34};
35
36#endif // PDFIMAGEPROVIDER_H
370
=== added file 'src/plugin/poppler-qml-plugin/pdfimageresponse.cpp'
--- src/plugin/poppler-qml-plugin/pdfimageresponse.cpp 1970-01-01 00:00:00 +0000
+++ src/plugin/poppler-qml-plugin/pdfimageresponse.cpp 2016-04-22 10:31:39 +0000
@@ -0,0 +1,55 @@
1/*
2 * Copyright (C) 2015 Roman Shchekin
3 * Copyright (C) 2015, 2016 Stefano Verzegnassi
4 *
5 * This program is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 3, as published
7 * by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranties of
11 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
12 * PURPOSE. See the GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "pdfimageresponse.h"
19#include "pdfdocument.h"
20
21#include "../../app/renderengine.h"
22
23PdfImageResponse::PdfImageResponse(bool isRequestValid)
24 : m_taskId(0)
25{
26 if (!isRequestValid) {
27 m_errorString = "Requested size or id are not valid.";
28
29 QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection);
30 return;
31 }
32
33 connect(RenderEngine::instance(), &RenderEngine::taskRenderFinished,
34 this, [&](AbstractRenderTask *task, QImage img)
35 {
36 if (m_taskId == task->id() && task->type() == RttPdfThumbnail) {
37 m_image = img;
38 Q_EMIT finished();
39 }
40 }, Qt::BlockingQueuedConnection);
41}
42
43PdfImageResponse::~PdfImageResponse()
44{
45 disconnect(this);
46
47 QMetaObject::invokeMethod(RenderEngine::instance(), "dequeueTask",
48 Qt::QueuedConnection,
49 Q_ARG(int, m_taskId));
50}
51
52QQuickTextureFactory * PdfImageResponse::textureFactory() const
53{
54 return QQuickTextureFactory::textureFactoryForImage(m_image);
55}
056
=== added file 'src/plugin/poppler-qml-plugin/pdfimageresponse.h'
--- src/plugin/poppler-qml-plugin/pdfimageresponse.h 1970-01-01 00:00:00 +0000
+++ src/plugin/poppler-qml-plugin/pdfimageresponse.h 2016-04-22 10:31:39 +0000
@@ -0,0 +1,41 @@
1/*
2 * Copyright (C) 2015, 2016 Stefano Verzegnassi
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18#ifndef PDFIMAGERESPONSE_H
19#define PDFIMAGERESPONSE_H
20
21// For QQuickImageResponse
22#include <qquickimageprovider.h>
23
24class PdfImageResponse : public QQuickImageResponse
25{
26public:
27 PdfImageResponse(bool isRequestValid);
28 ~PdfImageResponse();
29
30 void setTaskId(const int id) { m_taskId = id; }
31 QString errorString() const override { return m_errorString; }
32 QQuickTextureFactory * textureFactory() const override;
33
34private:
35 QString m_errorString;
36 QImage m_image;
37 int m_taskId;
38};
39
40
41#endif // PDFIMAGERESPONSE_H
042
=== removed file 'src/plugin/poppler-qml-plugin/pdfitem.cpp'
--- src/plugin/poppler-qml-plugin/pdfitem.cpp 2015-01-30 18:10:21 +0000
+++ src/plugin/poppler-qml-plugin/pdfitem.cpp 1970-01-01 00:00:00 +0000
@@ -1,36 +0,0 @@
1/*
2 * Copyright (C) 2014-2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Author: Stefano Verzegnassi <stefano92.100@gmail.com>
17 */
18
19#include "pdfitem.h"
20#include <poppler/qt5/poppler-qt5.h>
21
22PdfItem::PdfItem(Poppler::Page *page)
23{
24 m_width = page->pageSize().width();
25 m_height = page->pageSize().height();
26}
27
28int PdfItem::width() const
29{
30 return m_width;
31}
32
33int PdfItem::height() const
34{
35 return m_height;
36}
370
=== removed file 'src/plugin/poppler-qml-plugin/pdfitem.h'
--- src/plugin/poppler-qml-plugin/pdfitem.h 2015-01-30 18:10:21 +0000
+++ src/plugin/poppler-qml-plugin/pdfitem.h 1970-01-01 00:00:00 +0000
@@ -1,36 +0,0 @@
1/*
2 * Copyright (C) 2014-2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Author: Stefano Verzegnassi <stefano92.100@gmail.com>
17 */
18
19#ifndef PDFITEM_H
20#define PDFITEM_H
21
22#include <poppler/qt5/poppler-qt5.h>
23
24class PdfItem
25{
26public:
27 PdfItem(Poppler::Page *page);
28 int width() const;
29 int height() const;
30
31private:
32 int m_width;
33 int m_height;
34};
35
36#endif // PDFITEM_H
370
=== added file 'src/plugin/poppler-qml-plugin/pdfrendertask.cpp'
--- src/plugin/poppler-qml-plugin/pdfrendertask.cpp 1970-01-01 00:00:00 +0000
+++ src/plugin/poppler-qml-plugin/pdfrendertask.cpp 2016-04-22 10:31:39 +0000
@@ -0,0 +1,18 @@
1#include "pdfrendertask.h"
2
3bool PdfRenderTask::canBeRunInParallel(AbstractRenderTask* prevTask)
4{
5 Q_ASSERT(prevTask != nullptr);
6 return true;
7}
8
9QImage PdfTileRenderTask::doWork()
10{
11 return m_document.data()->paintTile(m_page, m_zoom, m_area, PdfRotation::Rotation(m_rotation));
12}
13
14QImage PdfThumbnailRenderTask::doWork()
15{
16 return m_document.data()->paintThumbnail(m_page, m_size, PdfRotation::Rotation(m_rotation));
17}
18
019
=== added file 'src/plugin/poppler-qml-plugin/pdfrendertask.h'
--- src/plugin/poppler-qml-plugin/pdfrendertask.h 1970-01-01 00:00:00 +0000
+++ src/plugin/poppler-qml-plugin/pdfrendertask.h 2016-04-22 10:31:39 +0000
@@ -0,0 +1,66 @@
1#ifndef LORENDERTASK_H
2#define LORENDERTASK_H
3
4#include <QObject>
5#include <QDebug>
6#include <QImage>
7#include <QSharedPointer>
8#include <QHash>
9#include <QQueue>
10#include <QAtomicInt>
11
12#include "../../app/rendertask.h"
13#include <QSharedPointer>
14#include "pdfdocument.h"
15
16class PdfRenderTask : public AbstractRenderTask
17{
18public:
19 virtual bool canBeRunInParallel(AbstractRenderTask* prevTask);
20 virtual void prepare() { }
21
22 int rotation() { return m_rotation; }
23 void setRotation(int r) { m_rotation = r; }
24
25 int page() { return m_page; }
26 void setPage(int p) { m_page = p; }
27
28 QSharedPointer<PdfDocument> document() { return m_document; }
29 void setDocument(QSharedPointer<PdfDocument> d) { m_document = d; }
30
31protected:
32 int m_page;
33 int m_rotation;
34 QSharedPointer<PdfDocument> m_document;
35};
36
37
38class PdfTileRenderTask : public PdfRenderTask
39{
40public:
41 virtual RenderTaskType type() { return RttPdfTile; }
42 virtual QImage doWork();
43
44 QRect area() { return m_area; }
45 void setArea(const QRect& a) { m_area = a; }
46 qreal zoom() { return m_zoom; }
47 void setZoom(qreal z) { m_zoom = z; }
48protected:
49 QRect m_area;
50 qreal m_zoom;
51};
52
53class PdfThumbnailRenderTask : public PdfRenderTask
54{
55public:
56 virtual RenderTaskType type() { return RttPdfThumbnail; }
57 virtual QImage doWork();
58
59 QSize size() const { return m_size; }
60 void setSize(const QSize & s) { m_size = s; }
61protected:
62 QSize m_size;
63};
64
65
66#endif // LORENDERTASK_H
067
=== modified file 'src/plugin/poppler-qml-plugin/pdftocmodel.cpp'
--- src/plugin/poppler-qml-plugin/pdftocmodel.cpp 2015-04-16 12:58:29 +0000
+++ src/plugin/poppler-qml-plugin/pdftocmodel.cpp 2016-04-22 10:31:39 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright (C) 20152 * Copyright (C) 2015, 2016
3 * Stefano Verzegnassi <verzegnassi.stefano@gmail.com>3 * Stefano Verzegnassi <verzegnassi.stefano@gmail.com>
4 *4 *
5 * This program is free software: you can redistribute it and/or modify it5 * This program is free software: you can redistribute it and/or modify it
@@ -26,16 +26,12 @@
2626
27PdfTocModel::PdfTocModel(QAbstractListModel *parent):27PdfTocModel::PdfTocModel(QAbstractListModel *parent):
28 QAbstractListModel(parent)28 QAbstractListModel(parent)
29{29{ }
30 connect(this, SIGNAL(documentChanged()), this, SLOT(fillModel()));
31}
3230
33void PdfTocModel::setDocument(Poppler::Document *document)31void PdfTocModel::setDocument(const QSharedPointer<Poppler::Document>& document)
34{32{
35 if (document != m_document) {33 m_document = document;
36 m_document = document;34 fillModel();
37 Q_EMIT documentChanged();
38 }
39}35}
4036
41QHash<int, QByteArray> PdfTocModel::roleNames() const37QHash<int, QByteArray> PdfTocModel::roleNames() const
@@ -43,6 +39,9 @@
43 QHash<int, QByteArray> roles;39 QHash<int, QByteArray> roles;
44 roles[TitleRole] = "title";40 roles[TitleRole] = "title";
45 roles[PageIndexRole] = "pageIndex";41 roles[PageIndexRole] = "pageIndex";
42 roles[NodeIndexRole] = "nodeIndex";
43 roles[ParentNodeIndexRole] = "parentNodeIndex";
44 roles[HasChildNodesRole] = "hasChildNodes";
46 roles[LevelRole] = "level";45 roles[LevelRole] = "level";
47 return roles;46 return roles;
48}47}
@@ -65,6 +64,12 @@
65 return tocEntry.title;64 return tocEntry.title;
66 case PageIndexRole:65 case PageIndexRole:
67 return tocEntry.pageIndex;66 return tocEntry.pageIndex;
67 case NodeIndexRole:
68 return tocEntry.nodeIndex;
69 case ParentNodeIndexRole:
70 return tocEntry.parentNodeIndex;
71 case HasChildNodesRole:
72 return tocEntry.hasChildNodes;
68 case LevelRole:73 case LevelRole:
69 return tocEntry.level;74 return tocEntry.level;
70 default:75 default:
@@ -84,6 +89,8 @@
84 QVariantMap map;89 QVariantMap map;
85 map["title"] = item.title;90 map["title"] = item.title;
86 map["pageIndex"] = item.pageIndex;91 map["pageIndex"] = item.pageIndex;
92 map["nodeIndex"] = item.nodeIndex;
93 map["parentNodeIndex"] = item.parentNodeIndex;
87 map["level"] = item.level;94 map["level"] = item.level;
8895
89 return map;96 return map;
@@ -91,7 +98,10 @@
9198
92void PdfTocModel::fillModel() {99void PdfTocModel::fillModel() {
93 if (m_entries.count() != 0) {100 if (m_entries.count() != 0) {
101 beginResetModel();
94 m_entries.clear();102 m_entries.clear();
103 endResetModel();
104
95 Q_EMIT countChanged();105 Q_EMIT countChanged();
96 }106 }
97107
@@ -104,13 +114,16 @@
104 }114 }
105}115}
106116
107void PdfTocModel::recursiveGetEntries(QDomNode node, int nodeLevel)117void PdfTocModel::recursiveGetEntries(QDomNode node, int nodeLevel, int parentNodeIndex)
108{118{
109 while(!node.isNull()) {119 while(!node.isNull()) {
110 QDomNode child = node.firstChild();120 QDomNode child = node.firstChild();
111121
112 TocEntry entry;122 TocEntry entry;
113 entry.title = node.toElement().tagName();123 entry.title = node.toElement().tagName();
124 entry.nodeIndex = m_entries.count();
125 entry.parentNodeIndex = parentNodeIndex;
126 entry.hasChildNodes = node.hasChildNodes();
114 entry.level = nodeLevel;127 entry.level = nodeLevel;
115128
116 QString dest = node.toElement().attribute("Destination");129 QString dest = node.toElement().attribute("Destination");
@@ -125,11 +138,14 @@
125 }138 }
126 }139 }
127140
141 beginInsertRows(QModelIndex(), rowCount(), rowCount());
128 m_entries.append(entry);142 m_entries.append(entry);
143 endInsertRows();
144
129 Q_EMIT countChanged();145 Q_EMIT countChanged();
130146
131 // Look for children entries147 // Look for children entries
132 recursiveGetEntries(child, nodeLevel + 1);148 recursiveGetEntries(child, nodeLevel + 1, m_entries.count() - 1);
133149
134 // Go to the next entry at the same level.150 // Go to the next entry at the same level.
135 node = node.nextSibling();151 node = node.nextSibling();
@@ -137,5 +153,4 @@
137}153}
138154
139PdfTocModel::~PdfTocModel()155PdfTocModel::~PdfTocModel()
140{156{ }
141}
142157
=== modified file 'src/plugin/poppler-qml-plugin/pdftocmodel.h'
--- src/plugin/poppler-qml-plugin/pdftocmodel.h 2015-04-08 14:11:02 +0000
+++ src/plugin/poppler-qml-plugin/pdftocmodel.h 2016-04-22 10:31:39 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright (C) 20152 * Copyright (C) 2015, 2016
3 * Stefano Verzegnassi <verzegnassi.stefano@gmail.com>3 * Stefano Verzegnassi <verzegnassi.stefano@gmail.com>
4 *4 *
5 * This program is free software: you can redistribute it and/or modify it5 * This program is free software: you can redistribute it and/or modify it
@@ -20,6 +20,7 @@
20#define PDFTOCMODEL_H20#define PDFTOCMODEL_H
2121
22#include <QAbstractListModel>22#include <QAbstractListModel>
23#include <QSharedPointer>
23#include <poppler/qt5/poppler-qt5.h>24#include <poppler/qt5/poppler-qt5.h>
24#include <QDomNode>25#include <QDomNode>
2526
@@ -28,6 +29,9 @@
28public:29public:
29 QString title;30 QString title;
30 int pageIndex = 0;31 int pageIndex = 0;
32 int nodeIndex = 0;
33 int parentNodeIndex = 0;
34 bool hasChildNodes = false;
31 int level = 0;35 int level = 0;
32};36};
3337
@@ -41,13 +45,16 @@
41 enum Roles {45 enum Roles {
42 TitleRole = Qt::UserRole + 1,46 TitleRole = Qt::UserRole + 1,
43 PageIndexRole,47 PageIndexRole,
48 NodeIndexRole,
49 ParentNodeIndexRole,
50 HasChildNodesRole,
44 LevelRole51 LevelRole
45 };52 };
4653
47 explicit PdfTocModel(QAbstractListModel *parent = 0);54 explicit PdfTocModel(QAbstractListModel *parent = 0);
48 virtual ~PdfTocModel();55 virtual ~PdfTocModel();
4956
50 void setDocument(Poppler::Document* document);57 void setDocument(const QSharedPointer<Poppler::Document>& document);
5158
52 QHash<int, QByteArray> roleNames() const;59 QHash<int, QByteArray> roleNames() const;
5360
@@ -57,18 +64,16 @@
57 Q_INVOKABLE QVariantMap get(int index) const;64 Q_INVOKABLE QVariantMap get(int index) const;
5865
59Q_SIGNALS:66Q_SIGNALS:
60 void documentChanged();
61 void countChanged();67 void countChanged();
6268
63private slots:69private slots:
64 void fillModel();70 void fillModel();
6571
66private:72private:
67 Poppler::Document* m_document;73 QSharedPointer<Poppler::Document> m_document;
68 QList<TocEntry> m_entries;74 QList<TocEntry> m_entries;
6975
70 void recursiveGetEntries(QDomNode node, int nodeLevel);76 void recursiveGetEntries(QDomNode node, int nodeLevel, int parentNodeIndex = -1);
71
72};77};
7378
74#endif // PDFTOCMODEL_H79#endif // PDFTOCMODEL_H
7580
=== added file 'src/plugin/poppler-qml-plugin/pdfzoom.cpp'
--- src/plugin/poppler-qml-plugin/pdfzoom.cpp 1970-01-01 00:00:00 +0000
+++ src/plugin/poppler-qml-plugin/pdfzoom.cpp 2016-04-22 10:31:39 +0000
@@ -0,0 +1,232 @@
1/*
2 * Copyright (C) 2016 Stefano Verzegnassi
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "pdfzoom.h"
18#include "verticalview.h"
19#include "pdfdocument.h"
20#include "twips.h"
21
22static qreal getZoomToFitWidth(const qreal &width, int documentWidth)
23{
24 return qreal(width / Twips::convertPointsToPixels(documentWidth, 1.0));
25}
26
27static qreal getZoomToFitHeight(const qreal &height, int documentHeight)
28{
29 return qreal(height / Twips::convertPointsToPixels(documentHeight, 1.0));
30}
31
32PdfZoom::PdfZoom(VerticalView *view)
33 : QObject(view)
34 , m_view(view)
35 , m_zoomMode(ZoomMode::Manual)
36 , m_zoomFactor(1.0)
37 , m_minimumZoom(0.25)
38 , m_maximumZoom(4.0)
39{ }
40
41PdfZoom::~PdfZoom()
42{ }
43
44PdfZoom::ZoomMode PdfZoom::zoomMode() const
45{
46 return m_zoomMode;
47}
48
49void PdfZoom::setZoomMode(const PdfZoom::ZoomMode zoomMode)
50{
51 if (m_zoomMode == zoomMode)
52 return;
53
54 m_zoomMode = zoomMode;
55 Q_EMIT zoomModeChanged();
56}
57
58void PdfZoom::updateZoomValues()
59{
60 int maxWidth = 0;
61 int maxHeight = 0;
62 for (int i=0; i<m_view->document()->pageCount(); ++i) {
63 int w, h;
64 if (m_view->rotation() == PdfRotation::Rotate0 || m_view->rotation() == PdfRotation::Rotate180) {
65 h = m_view->document()->pageSize(i).height();
66 w = m_view->document()->pageSize(i).width();
67 } else {
68 w = m_view->document()->pageSize(i).height();
69 h = m_view->document()->pageSize(i).width();
70 }
71
72 if (h > maxHeight)
73 maxHeight = h;
74
75 if (w > maxWidth)
76 maxWidth = w;
77 }
78
79 // Maximum zoom value to fit the width of the flickable
80 m_valueFitWidthZoom = getZoomToFitWidth(m_view->parentFlickable()->width(), maxWidth);
81
82 // Maximum zoom value that ensures that each page is fully visible in the view (without any
83 // need for scrolling)
84 m_valueFitPageZoom = qMin(getZoomToFitHeight(m_view->parentFlickable()->height(), maxHeight),
85 m_valueFitWidthZoom);
86
87 // Like ZoomMode::FitWidth, but its maximum value is limited to a 1.0x factor
88 m_valueAutomaticZoom = qMin(1.0, m_valueFitWidthZoom);
89
90 Q_EMIT valueFitWidthZoomChanged();
91 Q_EMIT valueFitPageZoomChanged();
92 Q_EMIT valueAutomaticZoomChanged();
93}
94
95qreal PdfZoom::zoomFactor() const
96{
97 return m_zoomFactor;
98}
99
100void PdfZoom::setZoomFactor(const qreal zoom)
101{
102 if (m_zoomFactor == zoom || zoom < m_minimumZoom || zoom > m_maximumZoom)
103 return;
104
105 m_zoomFactor = zoom;
106
107 if (m_zoomFactor != m_valueFitWidthZoom
108 && m_zoomFactor != m_valueFitPageZoom
109 && m_zoomFactor != m_valueAutomaticZoom)
110 setZoomMode(PdfZoom::Manual);
111
112 Q_EMIT zoomFactorChanged();
113}
114
115qreal PdfZoom::minimumZoom() const
116{
117 return m_minimumZoom;
118}
119
120/*
121void PdfZoom::setMinimumZoom(const qreal newValue)
122{
123 if (m_minimumZoom == newValue)
124 return;
125
126 m_minimumZoom = newValue;
127 Q_EMIT minimumZoomChanged();
128}
129*/
130
131qreal PdfZoom::maximumZoom() const
132{
133 return m_maximumZoom;
134}
135
136/*
137void PdfZoom::setMaximumZoom(const qreal newValue)
138{
139 if (m_maximumZoom == newValue)
140 return;
141
142 m_maximumZoom = newValue;
143 Q_EMIT maximumZoomChanged();
144}
145*/
146
147qreal PdfZoom::valueFitWidthZoom() const
148{
149 return m_valueFitWidthZoom;
150}
151
152qreal PdfZoom::valueFitPageZoom() const
153{
154 return m_valueFitPageZoom;
155}
156
157qreal PdfZoom::valueAutomaticZoom() const
158{
159 return m_valueAutomaticZoom;
160}
161
162bool PdfZoom::adjustZoomToWidth(bool changeMode)
163{
164 if (!m_view->document())
165 return false;
166
167 if (changeMode)
168 setZoomMode(PdfZoom::FitWidth);
169
170 int maxWidth = 0;
171 for (int i=0; i<m_view->document()->pageCount(); ++i) {
172 int w = m_view->document()->pageSize(i).width();
173 if (w > maxWidth)
174 maxWidth = w;
175 }
176
177 updateZoomValues();
178
179 if (m_zoomFactor != m_valueFitWidthZoom) {
180 setZoomFactor(m_valueFitWidthZoom);
181
182 qDebug() << Q_FUNC_INFO << "- value:" << m_zoomFactor << "- changeMode:" << changeMode;
183 return true;
184 }
185
186 return false;
187}
188
189bool PdfZoom::adjustZoomToPage(bool changeMode)
190{
191 if (!m_view->document())
192 return false;
193
194 if (changeMode)
195 setZoomMode(PdfZoom::FitPage);
196
197 updateZoomValues();
198
199 if (m_zoomFactor != m_valueFitPageZoom) {
200 setZoomFactor(m_valueFitPageZoom);
201
202 qDebug() << Q_FUNC_INFO << "- value:" << m_zoomFactor << "- changeMode:" << changeMode;
203 return true;
204 }
205
206 return false;
207}
208
209bool PdfZoom::adjustAutomaticZoom(bool changeMode)
210{
211 if (!m_view->document())
212 return false;
213
214 if (changeMode)
215 setZoomMode(PdfZoom::Automatic);
216
217 updateZoomValues();
218
219 if (m_zoomFactor != m_valueAutomaticZoom) {
220 setZoomFactor(m_valueAutomaticZoom);
221
222 qDebug() << Q_FUNC_INFO << "- value:" << m_zoomFactor << "- changeMode:" << changeMode;
223 return true;
224 }
225
226 return false;
227}
228
229void PdfZoom::init()
230{
231 setZoomMode(ZoomMode::Automatic);
232}
0233
=== added file 'src/plugin/poppler-qml-plugin/pdfzoom.h'
--- src/plugin/poppler-qml-plugin/pdfzoom.h 1970-01-01 00:00:00 +0000
+++ src/plugin/poppler-qml-plugin/pdfzoom.h 2016-04-22 10:31:39 +0000
@@ -0,0 +1,97 @@
1/*
2 * Copyright (C) 2016 Stefano Verzegnassi
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef PDFZOOM_H
18#define PDFZOOM_H
19
20#include <QObject>
21#include <QSharedPointer>
22
23class VerticalView;
24
25class PdfZoom : public QObject
26{
27 Q_OBJECT
28 Q_ENUMS(ZoomMode)
29 Q_PROPERTY(ZoomMode zoomMode READ zoomMode NOTIFY zoomModeChanged)
30 Q_PROPERTY(qreal zoomFactor READ zoomFactor WRITE setZoomFactor NOTIFY zoomFactorChanged)
31 Q_PROPERTY(qreal minimumZoom READ minimumZoom CONSTANT) //WRITE setMinimumZoom NOTIFY minimumZoomChanged)
32 Q_PROPERTY(qreal maximumZoom READ maximumZoom CONSTANT) //WRITE setMaximumZoom NOTIFY maximumZoomChanged)
33 Q_PROPERTY(qreal valueFitWidthZoom READ valueFitWidthZoom NOTIFY valueFitWidthZoomChanged)
34 Q_PROPERTY(qreal valueFitPageZoom READ valueFitPageZoom NOTIFY valueFitPageZoomChanged)
35 Q_PROPERTY(qreal valueAutomaticZoom READ valueAutomaticZoom NOTIFY valueAutomaticZoomChanged)
36
37public:
38 PdfZoom(VerticalView *view);
39 ~PdfZoom();
40
41 enum ZoomMode {
42 Manual = 0x0,
43 FitWidth = 0x1,
44 FitPage = 0x2,
45 Automatic = 0x4
46 };
47
48 ZoomMode zoomMode() const;
49 qreal zoomFactor() const;
50 void setZoomFactor(const qreal zoom);
51
52 qreal minimumZoom() const;
53// void setMinimumZoom(const qreal newValue);
54
55 qreal maximumZoom() const;
56// void setMaximumZoom(const qreal newValue);
57
58 qreal valueFitWidthZoom() const;
59 qreal valueFitPageZoom() const;
60 qreal valueAutomaticZoom() const;
61
62 bool adjustZoomToWidth(bool changeMode = true);
63 bool adjustZoomToPage(bool changeMode = true);
64 bool adjustAutomaticZoom(bool changeMode = true);
65
66 void init();
67
68Q_SIGNALS:
69 void zoomModeChanged();
70 void zoomModesAvailableChanged();
71 void zoomFactorChanged();
72// void minimumZoomChanged();
73// void maximumZoomChanged();
74 void valueFitWidthZoomChanged();
75 void valueFitPageZoomChanged();
76 void valueAutomaticZoomChanged();
77
78private:
79 VerticalView* m_view;
80
81 ZoomMode m_zoomMode;
82
83 qreal m_zoomFactor;
84
85 qreal m_minimumZoom;
86 qreal m_maximumZoom;
87
88 qreal m_valueFitWidthZoom;
89 qreal m_valueFitPageZoom;
90 qreal m_valueAutomaticZoom;
91
92private:
93 void setZoomMode(const ZoomMode zoomMode);
94 void updateZoomValues();
95};
96
97#endif // PDFZOOM_H
098
=== modified file 'src/plugin/poppler-qml-plugin/plugin.cpp'
--- src/plugin/poppler-qml-plugin/plugin.cpp 2015-04-15 14:47:28 +0000
+++ src/plugin/poppler-qml-plugin/plugin.cpp 2016-04-22 10:31:39 +0000
@@ -20,15 +20,22 @@
2020
21#include "plugin.h"21#include "plugin.h"
22#include "pdfdocument.h"22#include "pdfdocument.h"
23#include "pdfzoom.h"
24#include "pdferror.h"
23#include "verticalview.h"25#include "verticalview.h"
26#include "touchdetectionarea.h"
2427
25void PopplerPlugin::registerTypes(const char *uri)28void PopplerPlugin::registerTypes(const char *uri)
26{29{
27 Q_ASSERT(uri == QLatin1String("DocumentViewer.PDF"));30 Q_ASSERT(uri == QLatin1String("DocumentViewer.PDF"));
28 31
29 //@uri DocumentViewer.PDF32 //@uri DocumentViewer.PDF
30 qmlRegisterType<PdfDocument>(uri, 1, 0, "Document");33 qmlRegisterType<PdfDocument>(uri, 2, 0, "Document");
31 qmlRegisterType<VerticalView>(uri, 1, 0, "VerticalView");34 qmlRegisterUncreatableType<PdfZoom>(uri, 2, 0, "Zoom", "Not creatable as an object, use only to retrieve error enums (e.g. PDF.Zoom.Manual)");
35 qmlRegisterType<VerticalView>(uri, 2, 0, "VerticalView");
36 qmlRegisterType<TouchDetectionArea>(uri, 2, 0, "TouchDetectionArea");
37 qmlRegisterUncreatableType<PopplerError>(uri, 2, 0, "Error", "Not creatable as an object, use only to retrieve error enums (e.g. PDF.Error.FileNotFound)");
38 qmlRegisterUncreatableType<PdfRotation>(uri, 2, 0, "Rotation", "Not creatable as an object, use only to set rotation (e.g. PDF.Rotation.Rotate180)");
32}39}
3340
34void PopplerPlugin::initializeEngine(QQmlEngine *engine, const char *uri)41void PopplerPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
3542
=== added directory 'src/plugin/poppler-qml-plugin/qml'
=== added file 'src/plugin/poppler-qml-plugin/qml/Viewer.qml'
--- src/plugin/poppler-qml-plugin/qml/Viewer.qml 1970-01-01 00:00:00 +0000
+++ src/plugin/poppler-qml-plugin/qml/Viewer.qml 2016-04-22 10:31:39 +0000
@@ -0,0 +1,186 @@
1import QtQuick 2.4
2import DocumentViewer.PDF 2.0 as PDF
3
4Flickable {
5 id: rootFlickable
6
7 property alias document: view.document
8 property alias zoomSettings: view.zoomSettings
9 property alias cacheBuffer: view.cacheBuffer
10 property alias error: view.error
11 property alias currentPageIndex: view.currentPageIndex
12 property alias pagesCount: view.pagesCount
13 property alias spacing: view.spacing
14 property alias renderHints: view.renderHints
15 property alias showLinkHighlight: view.showLinkHighlight
16 property alias linkHighlightColor: view.linkHighlightColor
17 property alias rotation: view.rotation
18
19 property string documentPath: ""
20
21 property bool isLinkHovered: false
22 signal linkHovered(var linkInfo, var mouseX, var mouseY) // mouseX and mouseY are relative to rootFlickable
23 signal linkClicked(var isTouch, var linkInfo)
24 signal linkDoubleClicked(var isTouch, var linkInfo)
25 signal linkPressAndHold(var isTouch, var linkInfo)
26
27 function adjustZoomToWidth()
28 {
29 var oldZoom = view.zoomSettings.zoomFactor
30 view.adjustZoomToWidth()
31
32 var zoomScale = view.zoomSettings.zoomFactor / oldZoom
33 rootFlickable.contentX *= zoomScale
34 rootFlickable.contentY *= zoomScale
35 }
36
37 function adjustZoomToPage()
38 {
39 var oldZoom = view.zoomSettings.zoomFactor
40 view.adjustZoomToPage()
41
42 var zoomScale = view.zoomSettings.zoomFactor / oldZoom
43 rootFlickable.contentX *= zoomScale
44 rootFlickable.contentY *= zoomScale
45 }
46
47 function adjustAutomaticZoom()
48 {
49 var oldZoom = view.zoomSettings.zoomFactor
50 view.adjustAutomaticZoom()
51
52 var zoomScale = view.zoomSettings.zoomFactor / oldZoom
53 rootFlickable.contentX *= zoomScale
54 rootFlickable.contentY *= zoomScale
55 }
56
57 function setZoom(newValue)
58 {
59 var zoomScale = newValue / view.zoomSettings.zoomFactor;
60 view.zoomSettings.zoomFactor = newValue;
61
62 rootFlickable.contentX *= zoomScale;
63 rootFlickable.contentY *= zoomScale;
64 }
65
66 function moveView(axis, diff)
67 {
68 if (axis == "vertical") {
69 var maxContentY = Math.max(0, rootFlickable.contentHeight - rootFlickable.height)
70 rootFlickable.contentY = Math.max(0, Math.min(rootFlickable.contentY + diff, maxContentY ))
71 } else {
72 var maxContentX = Math.max(0, rootFlickable.contentWidth - rootFlickable.width)
73 rootFlickable.contentX = Math.max(0, Math.min(rootFlickable.contentX + diff, maxContentX ))
74 }
75 }
76
77 function positionAtBeginning() {
78 view.positionAtBeginning()
79 }
80
81 function positionAtIndex(index, top, left) {
82 if (typeof(top) === "undefined") top = 0
83 if (typeof(left) === "undefined") left = 0
84
85 view.positionAtIndex(index, top, left)
86 }
87
88 function positionAtEnd() {
89 view.positionAtEnd()
90 }
91
92 function unlock(ownerPassword, userPassword) {
93 return view.unlock(ownerPassword, userPassword)
94 }
95
96 onDocumentPathChanged: {
97 if (documentPath)
98 view.initializeDocument(documentPath)
99 }
100
101 // zoomFactor is not used here to set contentSize, since it's all managed
102 // internally, in the LibreOffice.View component.
103 contentHeight: Math.max(rootFlickable.height, view.height)
104 contentWidth: Math.max(rootFlickable.width, view.width)
105
106 boundsBehavior: Flickable.StopAtBounds
107
108 PDF.VerticalView {
109 id: view
110
111 x: Math.max(0, (rootFlickable.width - view.width) * 0.5)
112 y: Math.max(0, (rootFlickable.height - view.height) * 0.5)
113
114 parentFlickable: rootFlickable
115 }
116
117 MouseArea {
118 anchors.fill: parent
119 // Explicitely set rootFlickable as parent, otherwise it's rootFlickable.contentItem
120 parent: rootFlickable
121 enabled: !rootFlickable.moving
122
123 acceptedButtons: Qt.LeftButton
124
125 hoverEnabled: true
126 onPositionChanged: {
127 var linkInfo = view.linkAtPosition(rootFlickable.contentX + mouse.x - view.x,
128 rootFlickable.contentY + mouse.y - view.y);
129
130 // Don't emit linkHovered() if it's a touch event.
131 // Hover boxes are a mouse-related thing.
132 if (touchArea.touchPressed)
133 return
134
135 if (linkInfo.pageIndex || linkInfo.url) {
136 cursorShape = Qt.PointingHandCursor
137 rootFlickable.linkHovered(linkInfo, mouse.x, mouse.y)
138 rootFlickable.isLinkHovered = true
139 } else {
140 cursorShape = Qt.ArrowCursor
141 rootFlickable.isLinkHovered = false
142 }
143 }
144
145 onClicked: {
146 var isTouch = touchArea.touchPressed
147 var linkInfo = view.linkAtPosition(rootFlickable.contentX + mouse.x - view.x,
148 rootFlickable.contentY + mouse.y - view.y);
149
150 if (linkInfo.pageIndex || linkInfo.url) {
151 rootFlickable.linkClicked(isTouch, linkInfo)
152 }
153 }
154
155 onDoubleClicked: {
156 var isTouch = touchArea.touchPressed
157 var linkInfo = view.linkAtPosition(rootFlickable.contentX + mouse.x - view.x,
158 rootFlickable.contentY + mouse.y - view.y);
159
160 if (linkInfo.pageIndex || linkInfo.url) {
161 rootFlickable.linkDoubleClicked(isTouch, linkInfo)
162 }
163 }
164
165 onPressAndHold: {
166 var isTouch = touchArea.touchPressed
167 var linkInfo = view.linkAtPosition(rootFlickable.contentX + mouse.x - view.x,
168 rootFlickable.contentY + mouse.y - view.y);
169
170 if (linkInfo.pageIndex || linkInfo.url) {
171 rootFlickable.linkPressAndHold(isTouch, linkInfo)
172 }
173 }
174
175 // QML MultiPointTouchArea does not propagate events to its parent items. That
176 // would have led to a more complex logic.
177 // However, events returned by QML MouseArea signals don't inherit QEvent, so
178 // we can not check for the type event.
179 // We need to create our own component then.
180 PDF.TouchDetectionArea {
181 id: touchArea
182 anchors.fill: parent
183 enabled: !rootFlickable.moving
184 }
185 }
186}
0187
=== modified file 'src/plugin/poppler-qml-plugin/qmldir'
--- src/plugin/poppler-qml-plugin/qmldir 2015-04-15 14:47:28 +0000
+++ src/plugin/poppler-qml-plugin/qmldir 2016-04-22 10:31:39 +0000
@@ -1,2 +1,4 @@
1module DocumentViewer.PDF1module DocumentViewer.PDF
2plugin popplerqmlplugin2plugin popplerqmlplugin
3
4Viewer 2.0 Viewer.qml
35
=== added file 'src/plugin/poppler-qml-plugin/sgtileitem.cpp'
--- src/plugin/poppler-qml-plugin/sgtileitem.cpp 1970-01-01 00:00:00 +0000
+++ src/plugin/poppler-qml-plugin/sgtileitem.cpp 2016-04-22 10:31:39 +0000
@@ -0,0 +1,89 @@
1#include "sgtileitem.h"
2#include "pdfdocument.h"
3
4#include <QQuickWindow>
5#include <QSGSimpleTextureNode>
6
7#ifdef DEBUG_SHOW_TILE_BORDER
8#include <QSGGeometryNode>
9#include <QSGFlatColorMaterial>
10#endif
11
12SGTileItem::SGTileItem(const QRect& area, qreal zoom, int id, QQuickItem *parent)
13 : QQuickItem(parent)
14 , m_area(area)
15 , m_zoomFactor(zoom)
16 , m_id (id)
17{
18 setFlag(ItemHasContents, true);
19
20 setX(m_area.x());
21 setY(m_area.y());
22 setWidth(m_area.width());
23 setHeight(m_area.height());
24}
25
26SGTileItem::~SGTileItem()
27{ }
28
29QSGNode *SGTileItem::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *)
30{
31 QSGSimpleTextureNode* node = static_cast<QSGSimpleTextureNode*>(oldNode);
32 QQuickWindow* wnd = window();
33
34 if (!node && wnd && !m_data.isNull()) {
35 auto texture = wnd->createTextureFromImage(m_data);
36 node = new QSGSimpleTextureNode();
37 node->setTexture(texture);
38 node->setOwnsTexture(true);
39
40 node->setRect(QRect(0, 0, width(), height()));
41
42#ifdef DEBUG_SHOW_TILE_BORDER
43 drawTileBorders(node);
44#endif
45 }
46
47 return node;
48}
49
50void SGTileItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
51{
52 QQuickItem::geometryChanged(newGeometry, oldGeometry);
53}
54
55#ifdef DEBUG_SHOW_TILE_BORDER
56void SGTileItem::drawTileBorders(QSGSimpleTextureNode* parentNode)
57{
58 auto node = parentNode;
59 auto tileBorderGeometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 8);
60 tileBorderGeometry->setDrawingMode(GL_LINES);
61 tileBorderGeometry->setLineWidth(4);
62
63 QSGGeometry::Point2D* vertex = tileBorderGeometry->vertexDataAsPoint2D();
64 vertex[0].set(node->rect().left(), node->rect().top());
65 vertex[1].set(node->rect().left(), node->rect().bottom());
66
67 vertex[2].set(node->rect().right(), node->rect().top());
68 vertex[3].set(node->rect().right(), node->rect().bottom());
69
70 vertex[4].set(vertex[0].x, vertex[0].y);
71 vertex[5].set(vertex[2].x, vertex[2].y);
72
73 vertex[6].set(vertex[1].x, vertex[1].y);
74 vertex[7].set(vertex[3].x, vertex[3].y);
75
76 auto tileBorderMaterial = new QSGFlatColorMaterial;
77 tileBorderMaterial->setColor(Qt::red);
78
79 auto tileBorderNode = new QSGGeometryNode;
80
81 tileBorderNode->setGeometry(tileBorderGeometry);
82 tileBorderNode->setFlag(QSGNode::OwnsGeometry);
83
84 tileBorderNode->setMaterial(tileBorderMaterial);
85 tileBorderNode->setFlag(QSGNode::OwnsMaterial);
86
87 node->appendChildNode(tileBorderNode);
88}
89#endif
090
=== added file 'src/plugin/poppler-qml-plugin/sgtileitem.h'
--- src/plugin/poppler-qml-plugin/sgtileitem.h 1970-01-01 00:00:00 +0000
+++ src/plugin/poppler-qml-plugin/sgtileitem.h 2016-04-22 10:31:39 +0000
@@ -0,0 +1,48 @@
1#ifndef SGTILEITEM_H
2#define SGTILEITEM_H
3
4#include <QQuickItem>
5#include <QImage>
6
7class PdfDocument;
8
9//#ifdef DEBUG_SHOW_TILE_BORDER
10class QSGSimpleTextureNode;
11//#endif
12
13class SGTileItem : public QQuickItem
14{
15 Q_OBJECT
16public:
17 SGTileItem(const QRect& area, qreal zoom, int id, QQuickItem *parent = 0);
18 ~SGTileItem();
19
20 inline const QRect& area() { return m_area; }
21 inline void setArea(const QRect& rect) { m_area = rect; }
22
23 inline const qreal& zoomFactor() const { return m_zoomFactor; }
24 inline void setZoomFactor(const qreal &zoom) { m_zoomFactor = zoom; }
25
26 inline int id() { return m_id; }
27 inline void setId(int id) { m_id = id; }
28
29 inline QImage data() { return m_data; }
30 inline void setData(QImage data) { m_data = data; update(); }
31
32protected:
33 virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
34 virtual void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry);
35
36private:
37#ifdef DEBUG_SHOW_TILE_BORDER
38 void drawTileBorders(QSGSimpleTextureNode *parentNode);
39#endif
40
41private:
42 QRect m_area;
43 qreal m_zoomFactor;
44 QImage m_data;
45 int m_id;
46};
47
48#endif // SGTILEITEM_H
049
=== added file 'src/plugin/poppler-qml-plugin/touchdetectionarea.cpp'
--- src/plugin/poppler-qml-plugin/touchdetectionarea.cpp 1970-01-01 00:00:00 +0000
+++ src/plugin/poppler-qml-plugin/touchdetectionarea.cpp 2016-04-22 10:31:39 +0000
@@ -0,0 +1,21 @@
1#include "touchdetectionarea.h"
2
3#include <QDebug>
4
5TouchDetectionArea::TouchDetectionArea(QQuickItem *parent)
6 : QQuickItem(parent)
7 , m_touchPressed(false)
8{ }
9
10void TouchDetectionArea::touchEvent(QTouchEvent *event)
11{
12 if (event->type() == QEvent::TouchBegin) {
13 m_touchPressed = true;
14 Q_EMIT touchPressedChanged();
15 } else if (event->type() == QEvent::TouchEnd) {
16 m_touchPressed = false;
17 Q_EMIT touchPressedChanged();
18 }
19
20 event->ignore();
21}
022
=== added file 'src/plugin/poppler-qml-plugin/touchdetectionarea.h'
--- src/plugin/poppler-qml-plugin/touchdetectionarea.h 1970-01-01 00:00:00 +0000
+++ src/plugin/poppler-qml-plugin/touchdetectionarea.h 2016-04-22 10:31:39 +0000
@@ -0,0 +1,24 @@
1#ifndef TOUCHDETECTIONAREA_H
2#define TOUCHDETECTIONAREA_H
3
4#include <QQuickItem>
5
6class TouchDetectionArea : public QQuickItem
7{
8 Q_OBJECT
9 Q_PROPERTY(bool touchPressed READ touchPressed NOTIFY touchPressedChanged)
10public:
11 TouchDetectionArea(QQuickItem *parent = 0);
12 bool touchPressed() const { return m_touchPressed; }
13
14Q_SIGNALS:
15 void touchPressedChanged();
16
17protected:
18 virtual void touchEvent(QTouchEvent *event);
19
20private:
21 bool m_touchPressed;
22};
23
24#endif // TOUCHDETECTIONAREA_H
025
=== added file 'src/plugin/poppler-qml-plugin/twips.h'
--- src/plugin/poppler-qml-plugin/twips.h 1970-01-01 00:00:00 +0000
+++ src/plugin/poppler-qml-plugin/twips.h 2016-04-22 10:31:39 +0000
@@ -0,0 +1,98 @@
1/*
2 * Copyright (C) 2015, 2016 Stefano Verzegnassi
3 * Copyright (C) 2015 Roman Shchekin
4 *
5 * This program is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 3, as published
7 * by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranties of
11 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
12 * PURPOSE. See the GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 */
18
19#ifndef TWIPS_H
20#define TWIPS_H
21
22#include <QtGlobal>
23#include <QtWidgets/QApplication>
24#include <QScreen>
25
26#include "ucunits.h"
27
28#define DEFAULT_DPI 96
29#define DEFAULT_GRID_UNIT_PX 8
30
31class Twips
32{
33public:
34 enum ConvertionMode {
35 UseDPI = 0,
36 UseUnits = 1
37 };
38
39 static inline int convertPointsToPixels(int points, qreal zoom = 1.0,
40 ConvertionMode mode = ConvertionMode::UseUnits)
41 {
42 return convertTwipsToPixels(points * 20, zoom, mode);
43 }
44
45 static inline int convertPixelsToPoints(int pixels, qreal zoom = 1.0,
46 ConvertionMode mode = ConvertionMode::UseUnits)
47 {
48 return convertPixelsToTwips(pixels / 20, zoom, mode);
49 }
50
51 static inline int convertTwipsToPixels(int twips, qreal zoom = 1.0,
52 ConvertionMode mode = ConvertionMode::UseUnits)
53 {
54 if (mode == ConvertionMode::UseUnits) {
55 qreal ratio = getUnitsRatio();
56 return int(twips / 1440.0 * (DEFAULT_DPI * ratio) * zoom);
57 } else {
58 qreal dpi = getLogicalDotsPerInch();
59 return int(twips / 1440.0 * (dpi ? dpi : DEFAULT_DPI) * zoom);
60 }
61 }
62
63 static inline int convertPixelsToTwips(int pixels, qreal zoom = 1.0,
64 ConvertionMode mode = ConvertionMode::UseUnits)
65 {
66 if (mode == ConvertionMode::UseUnits) {
67 qreal ratio = getUnitsRatio();
68 return int(pixels * 1440.0 / (DEFAULT_DPI * ratio) / zoom);
69 } else {
70 qreal dpi = getLogicalDotsPerInch();
71 return int(pixels * 1440.0 / (dpi ? dpi : DEFAULT_DPI) / zoom);
72 }
73 }
74
75 static inline qreal getLogicalDotsPerInch()
76 {
77 static qreal value = 0;
78 if (!value) {
79 QList<QScreen*> screens = QGuiApplication::screens();
80 if (screens.size()) {
81 QScreen *screen = screens.at(0);
82 // Subscribe for changing signal (just to make caching rock-solid).
83 QObject::connect(screen, &QScreen::logicalDotsPerInchChanged,
84 [] (const qreal newValue) { value = newValue; } );
85 value = screen->logicalDotsPerInch();
86 }
87 }
88
89 return value;
90 }
91
92 static inline qreal getUnitsRatio()
93 {
94 return UCUnits::instance().gridUnit() / DEFAULT_GRID_UNIT_PX;
95 }
96};
97
98#endif // TWIPS_H
099
=== added file 'src/plugin/poppler-qml-plugin/ucunits.cpp'
--- src/plugin/poppler-qml-plugin/ucunits.cpp 1970-01-01 00:00:00 +0000
+++ src/plugin/poppler-qml-plugin/ucunits.cpp 2016-04-22 10:31:39 +0000
@@ -0,0 +1,241 @@
1/*
2 * Copyright 2012 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Author: Florian Boucault <florian.boucault@canonical.com>
17 */
18
19#include "ucunits.h"
20
21#include <QtQml/QQmlContext>
22#include <QtQml/QQmlFile>
23#include <QtCore/QFileInfo>
24#include <QtCore/QDir>
25#include <QtCore/QRegularExpression>
26#include <QtCore/qmath.h>
27#include <QtGui/QGuiApplication>
28#include <QtGui/QScreen>
29
30#define ENV_GRID_UNIT_PX "GRID_UNIT_PX"
31#define DEFAULT_GRID_UNIT_PX 8
32
33static float getenvFloat(const char* name, float defaultValue)
34{
35 QByteArray stringValue = qgetenv(name);
36 bool ok;
37 float value = stringValue.toFloat(&ok);
38 return ok ? value : defaultValue;
39}
40
41
42/*!
43 \qmltype Units
44 \instantiates UCUnits
45 \inqmlmodule Ubuntu.Components 1.1
46 \ingroup resolution-independence
47 \brief Units of measurement for sizes, spacing, margin, etc.
48
49 Units provides facilities for measuring UI elements in a variety
50 of units other than just pixels.
51
52 A global instance of Units is exposed as the \b{units} context property.
53 Example usage:
54
55 \qml
56 import QtQuick 2.4
57 import Ubuntu.Components 1.2
58
59 Item {
60 width: units.gu(2)
61 height: units.gu(5)
62 }
63 \endqml
64
65 \sa {Resolution Independence}
66*/
67
68/*
69 * Note on the interaction between GRID_UNIT_PX and QT_DEVICE_PIXEL_RATIO
70 *
71 * In Qt5.4 there is a single means to scale the UI: the QT_DEVICE_PIXEL_RATIO environment
72 * variable. This accepts only integer values, thus allowing a x2 or x3 scaling of any
73 * Qt-based UI, that includes QWidget as well as any QML UI.
74 *
75 * Setting QT_DEVICE_PIXEL_RATIO=2 implies one density-independent pixel corresponds to 2
76 * physical pixels. Developers describe their UI in terms of density-independent pixels.
77 * Qt scales accordingly.
78 *
79 * The Ubuntu UI Toolkit has solved the scaling problem with the GRID_UNIT_PX variable.
80 * It offers more flexibility, but only scales QML applications written to use the UITK
81 * (since it uses this Units class) as it is built on top of QML.
82 *
83 * There are additional areas in Qt where QT_DEVICE_PIXEL_RATIO causes correct scaling which
84 * GRID_UNIT_PX cannot, for example:
85 * 1. cacheBuffer for ListView/GridViews - specified in density-independent pixels
86 * 2. gesture recognition matches what is on screen better, as it is density-independent
87 * pixel aware
88 *
89 * In order to get the best of both worlds, Ubuntu will set both GRID_UNIT_PX and
90 * QT_DEVICE_PIXEL_RATIO. Thus all Qt apps will scale reasonably well, with UITK-based apps
91 * scaling perfectly for any desired scale (i.e. non-integer scales).
92 *
93 * However UITK developers can just use this Units class as usual, and will be almost totally
94 * isolated from Qt's own scaling concept.
95 */
96
97UCUnits::UCUnits(QObject *parent) :
98 QObject(parent),
99 m_devicePixelRatio(qGuiApp->devicePixelRatio())
100{
101 // If GRID_UNIT_PX set, always use it. If not, 1GU := DEFAULT_GRID_UNIT_PX * m_devicePixelRatio
102 if (qEnvironmentVariableIsSet(ENV_GRID_UNIT_PX)) {
103 m_gridUnit = getenvFloat(ENV_GRID_UNIT_PX, DEFAULT_GRID_UNIT_PX);
104 } else {
105 m_gridUnit = DEFAULT_GRID_UNIT_PX * m_devicePixelRatio;
106 }
107}
108
109/*!
110 \qmlproperty real Units::gridUnit
111
112 The number of pixels 1 grid unit corresponds to.
113*/
114float UCUnits::gridUnit()
115{
116 return m_gridUnit;
117}
118
119void UCUnits::setGridUnit(float gridUnit)
120{
121 m_gridUnit = gridUnit;
122 Q_EMIT gridUnitChanged();
123}
124
125/*!
126 \qmlmethod real Units::dp(real value)
127
128 Returns the number of pixels \a value density independent pixels correspond to.
129*/
130// Density-independent pixels (and not physical pixels) because Qt sizes in terms of density-independent pixels.
131float UCUnits::dp(float value)
132{
133 const float ratio = m_gridUnit / DEFAULT_GRID_UNIT_PX;
134 if (value <= 2.0) {
135 // for values under 2dp, return only multiples of the value
136 return qRound(value * qFloor(ratio)) / m_devicePixelRatio;
137 } else {
138 return qRound(value * ratio) / m_devicePixelRatio;
139 }
140}
141
142/*!
143 \qmlmethod real Units::gu(real value)
144
145 Returns the number of pixels \a value grid units correspond to.
146*/
147// Density-independent pixels (and not physical pixels) because Qt sizes in terms of density-independent pixels.
148
149float UCUnits::gu(float value)
150{
151 return qRound(value * m_gridUnit) / m_devicePixelRatio;
152}
153
154QString UCUnits::resolveResource(const QUrl& url)
155{
156 if (url.isEmpty()) {
157 return QString();
158 }
159
160 QString path = QQmlFile::urlToLocalFileOrQrc(url);
161
162 if (path.isEmpty()) {
163 return QString();
164 }
165
166 QFileInfo fileInfo(path);
167 if (fileInfo.exists() && !fileInfo.isFile()) {
168 return QString();
169 }
170
171 QString prefix = fileInfo.dir().absolutePath() + QDir::separator() + fileInfo.baseName();
172 QString suffix = "." + fileInfo.completeSuffix();
173
174 /* Use file with expected grid unit suffix if it exists.
175 For example, if m_gridUnit = 10, look for resource@10.png.
176 */
177
178 path = prefix + suffixForGridUnit(m_gridUnit) + suffix;
179 if (QFile::exists(path)) {
180 return QString("1") + "/" + path;
181 }
182
183 /* No file with expected grid unit suffix exists.
184 List all the files of the form fileBaseName@[0-9]*.fileSuffix and select
185 the most appropriate one privileging downscaling high resolution assets
186 over upscaling low resolution assets.
187
188 The most appropriate file has a grid unit suffix greater than the target
189 grid unit (m_gridUnit) yet as small as possible.
190 If no file with a grid unit suffix greater than the target grid unit
191 exists, then select one with a grid unit suffix as close as possible to
192 the target grid unit.
193
194 For example, if m_gridUnit = 10 and the available files are
195 resource@9.png, resource@14.png and resource@18.png, the most appropriate
196 file would be resource@14.png since it is above 10 and smaller
197 than resource@18.png.
198 */
199 QStringList nameFilters;
200 nameFilters << fileInfo.baseName() + "@[0-9]*" + suffix;
201 QStringList files = fileInfo.dir().entryList(nameFilters, QDir::Files);
202
203 if (!files.empty()) {
204 float selectedGridUnitSuffix = gridUnitSuffixFromFileName(files.first());
205
206 Q_FOREACH (const QString& fileName, files) {
207 float gridUnitSuffix = gridUnitSuffixFromFileName(fileName);
208 if ((selectedGridUnitSuffix >= m_gridUnit && gridUnitSuffix >= m_gridUnit && gridUnitSuffix < selectedGridUnitSuffix)
209 || (selectedGridUnitSuffix < m_gridUnit && gridUnitSuffix > selectedGridUnitSuffix)) {
210 selectedGridUnitSuffix = gridUnitSuffix;
211 }
212 }
213
214 path = prefix + suffixForGridUnit(selectedGridUnitSuffix) + suffix;
215 float scaleFactor = m_gridUnit / selectedGridUnitSuffix;
216 return QString::number(scaleFactor) + "/" + path;
217 }
218
219 path = prefix + suffix;
220 if (QFile::exists(path)) {
221 return QString("1") + "/" + path;
222 }
223
224 return QString();
225}
226
227QString UCUnits::suffixForGridUnit(float gridUnit)
228{
229 return "@" + QString::number(gridUnit);
230}
231
232float UCUnits::gridUnitSuffixFromFileName(const QString& fileName)
233{
234 QRegularExpression re("^.*@([0-9]*).*$");
235 QRegularExpressionMatch match = re.match(fileName);
236 if (match.hasMatch()) {
237 return match.captured(1).toFloat();
238 } else {
239 return 0;
240 }
241}
0242
=== added file 'src/plugin/poppler-qml-plugin/ucunits.h'
--- src/plugin/poppler-qml-plugin/ucunits.h 1970-01-01 00:00:00 +0000
+++ src/plugin/poppler-qml-plugin/ucunits.h 2016-04-22 10:31:39 +0000
@@ -0,0 +1,60 @@
1/*
2 * Copyright 2012 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Author: Florian Boucault <florian.boucault@canonical.com>
17 */
18
19#ifndef UBUNTU_COMPONENTS_UNITS_H
20#define UBUNTU_COMPONENTS_UNITS_H
21
22#include <QObject>
23#include <QtCore/QHash>
24#include <QtCore/QUrl>
25
26class UCUnits : public QObject
27{
28 Q_OBJECT
29 Q_PROPERTY(float gridUnit READ gridUnit WRITE setGridUnit NOTIFY gridUnitChanged)
30
31public:
32 static UCUnits& instance() {
33 static UCUnits instance;
34 return instance;
35 }
36
37 explicit UCUnits(QObject *parent = 0);
38 Q_INVOKABLE float dp(float value);
39 Q_INVOKABLE float gu(float value);
40 QString resolveResource(const QUrl& url);
41
42 // getters
43 float gridUnit();
44
45 // setters
46 void setGridUnit(float gridUnit);
47
48Q_SIGNALS:
49 void gridUnitChanged();
50
51protected:
52 QString suffixForGridUnit(float gridUnit);
53 float gridUnitSuffixFromFileName(const QString &fileName);
54
55private:
56 float m_devicePixelRatio;
57 float m_gridUnit;
58};
59
60#endif // UBUNTU_COMPONENTS_UNITS_H
061
=== modified file 'src/plugin/poppler-qml-plugin/verticalview.cpp'
--- src/plugin/poppler-qml-plugin/verticalview.cpp 2015-04-26 14:39:20 +0000
+++ src/plugin/poppler-qml-plugin/verticalview.cpp 2016-04-22 10:31:39 +0000
@@ -1,187 +1,117 @@
1/*
2 * Copyright (C) 2013-2015 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17/*
18 * Some documentation on how this thing works:
19 *
20 * A flickable has two very important concepts that define the top and
21 * height of the flickable area.
22 * The top is returned in minYExtent()
23 * The height is set using setContentHeight()
24 * By changing those two values we can make the list grow up or down
25 * as needed. e.g. if we are in the middle of the list
26 * and something that is above the viewport grows, since we do not
27 * want to change the viewport because of that we just adjust the
28 * minYExtent so that the list grows up.
29 *
30 * The implementation on the list relies on the delegateModel doing
31 * most of the instantiation work. You call createItem() when you
32 * need to create an item asking for it async or not. If returns null
33 * it means the item will be created async and the model will call the
34 * itemCreated slot with the item.
35 *
36 * updatePolish is the central point of dispatch for the work of the
37 * class. It is called by the scene graph just before drawing the class.
38 * In it we:
39 * * Make sure all items are positioned correctly
40 * * Add/Remove items if needed
41 * * Update the content height if it was dirty
42 *
43 * m_visibleItems contains all the items we have created at the moment.
44 * Actually not all of them are visible since it includes the ones
45 * in the cache area we create asynchronously to help performance.
46 * The first item in m_visibleItems has the m_firstVisibleIndex in
47 * the model. If you actually want to know what is the first
48 * item in the viewport you have to find the first non culled element
49 * in m_visibleItems
50 *
51 * The first item of m_visibleItems is the one that defines the
52 * positions of all the rest of items (see updatePolish()) and
53 * this is why sometimes we move it even if it's not the item
54 * that has triggered the function (i.e. in itemGeometryChanged())
55 *
56 * m_visibleItems is a list of ListItem. Each ListItem
57 * will contain a item and potentially a sectionItem. The sectionItem
58 * is only there when the list is using sectionDelegate+sectionProperty
59 * and this is the first item of the section. Each ListItem is vertically
60 * layouted with the sectionItem first and then the item.
61 *
62 * Note that minYExtent and height are not always totally accurate, since
63 * we don't have the items created we can't guess their heights
64 * so we can only guarantee the values are correct when the first/last
65 * items of the list are visible, otherwise we just live with good enough
66 * values that make the list scrollable
67 *
68 * There are a few things that are not really implemented or tested properly
69 * which we don't use at the moment like changing the model, etc.
70 * The known missing features are marked with TODOs along the code.
71 */
72
73#include "verticalview.h"1#include "verticalview.h"
742//#include "pdfdocument.h"
75#include <QCoreApplication>3#include "pdfzoom.h"
76#include <QDebug>4#include "twips.h"
77#include <qqmlinfo.h>5#include "sgtileitem.h"
78#include <qqmlengine.h>6#include "pagedecoration.h"
79#pragma GCC diagnostic push7#include "pageoverlay.h"
80#pragma GCC diagnostic ignored "-pedantic"8
81#include <private/qqmldelegatemodel_p.h>9#include "config.h"
82#include <private/qqmlglobal_p.h>10
83#include <private/qquickitem_p.h>11#include <QImage>
84#include <private/qquickanimation_p.h>12#include <QtCore/qmath.h>
85#pragma GCC diagnostic pop13
8614// FIXME: Sometimes layout is not created when a document is opened
87qreal VerticalView::ListItem::height() const15// TODO: Check if everything works as expected when zooming
88{16
89 return m_item->height();17#define UPDATE_TIMER_MSECS 20
90}18
9119VerticalView::VerticalView(QQuickItem *parent)
92qreal VerticalView::ListItem::y() const20 : QQuickItem(parent)
93{21 , m_parentFlickable(nullptr)
94 return m_item->y();22 , m_document(nullptr)
95}23 , m_zoomSettings(new PdfZoom(this))
9624 , m_cacheBuffer(200)
97void VerticalView::ListItem::setY(qreal newY)25 , m_spacing(12)
98{26 , m_rotation(PdfRotation::Rotate0)
99 m_item->setY(newY);27 , m_currentPageIndex(-1)
100}28 , m_visibleArea(0, 0, 0, 0)
10129 , m_bufferArea(0, 0, 0, 0)
102bool VerticalView::ListItem::culled() const30 , m_renderHints(0)
103{31 , m_showLinkHighlight(true)
104 return QQuickItemPrivate::get(m_item)->culled;32 , m_linkHighlightColor(Qt::red)
105}33 , m_error(PopplerError::NoError)
10634 , m_hasZoomChanged(false)
107void VerticalView::ListItem::setCulled(bool culled)35 , m_hasRotationChanged(false)
108{36 , m_hasFlickableBeenScrolled(false)
109 QQuickItemPrivate::get(m_item)->setCulled(culled);37 , m_hasFlickableBeenResized(false)
110}38 , m_hasRenderHintsChanged(false)
11139{
112VerticalView::VerticalView()40 // Connect signals
113 : m_delegateModel(nullptr)41 connect(this, &VerticalView::documentChanged, this, &VerticalView::updateLayout);
114 , m_asyncRequestedIndex(-1)42 connect(this, &VerticalView::parentFlickableChanged, this, &VerticalView::updateLayout);
115 , m_delegateValidated(false)43 connect(this, &VerticalView::cacheBufferChanged, this, &VerticalView::updateLayout);
116 , m_firstVisibleIndex(-1)44 connect(this, &VerticalView::spacingChanged, this, &VerticalView::updateLayout);
117 , m_currentPageIndex(-1)45 connect(this, &VerticalView::renderHintsChanged, this, &VerticalView::onRenderHintsChanged);
118 , m_minYExtent(0)46
119 , m_contentHeightDirty(false)47 connect(RenderEngine::instance(), &RenderEngine::taskRenderFinished,
120 , m_previousContentY(0)48 this, &VerticalView::slotTaskRenderFinished);
121 , m_inLayout(false)49
122 , m_cacheBuffer(0)50 connect(&m_updateTimer, &QTimer::timeout, this, &VerticalView::updateLayout);
123 , m_spacing(0)51
124{52 connect(m_zoomSettings, &PdfZoom::zoomFactorChanged, [&]() {
125 connect(this, SIGNAL(heightChanged()), this, SLOT(_q_heightChanged()));53 m_hasZoomChanged = true;
126 connect(this, SIGNAL(contentYChanged()), this, SLOT(_q_updateCurrentPageIndex()));54 updateLayout();
12755 });
128 setFlickableDirection(QQuickFlickable::HorizontalAndVerticalFlick);56
57 connect(this, &VerticalView::rotationChanged, [&]() {
58 m_hasRotationChanged = true;
59 updateLayout();
60 });
129}61}
13062
131VerticalView::~VerticalView()63VerticalView::~VerticalView()
132{64{
133}65 disconnect(RenderEngine::instance(), &RenderEngine::taskRenderFinished,
13466 this, &VerticalView::slotTaskRenderFinished);
135QAbstractItemModel *VerticalView::model() const67
136{68 qDeleteAll(m_decorations);
137 return m_delegateModel ? m_delegateModel->model().value<QAbstractItemModel *>() : nullptr;69 qDeleteAll(m_overlays);
138}70 qDeleteAll(m_pages);
13971}
140void VerticalView::setModel(QAbstractItemModel *model)72
141{73// Returns the parent QML Flickable
142 if (model != this->model()) {74QQuickItem* VerticalView::parentFlickable() const
143 if (!m_delegateModel) {75{
144 createDelegateModel();76 return m_parentFlickable;
145 } else {77}
146 disconnect(m_delegateModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)), this, SLOT(_q_modelUpdated(QQmlChangeSet,bool)));78
147 }79// Set the parent QML Flickable
148 m_delegateModel->setModel(QVariant::fromValue<QAbstractItemModel *>(model));80void VerticalView::setParentFlickable(QQuickItem *flickable)
149 connect(m_delegateModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)), this, SLOT(_q_modelUpdated(QQmlChangeSet,bool)));81{
150 Q_EMIT modelChanged();82 if (m_parentFlickable == flickable)
151 polish();83 return;
152 // TODO?84
153// Q_EMIT contentHeightChanged();85 if (m_parentFlickable)
154// Q_EMIT contentYChanged();86 m_parentFlickable->disconnect(this);
155 }87
156}88 m_parentFlickable = flickable;
15789
158QQmlComponent *VerticalView::delegate() const90 connect(m_parentFlickable, &QQuickItem::widthChanged, this, &VerticalView::onFlickableSizeChanged);
159{91 connect(m_parentFlickable, &QQuickItem::heightChanged, this, &VerticalView::onFlickableSizeChanged);
160 return m_delegateModel ? m_delegateModel->delegate() : nullptr;92
161}93 connect(m_parentFlickable, SIGNAL(contentXChanged()), this, SLOT(onFlickableScrolled()));
16294 connect(m_parentFlickable, SIGNAL(contentYChanged()), this, SLOT(onFlickableScrolled()));
163void VerticalView::setDelegate(QQmlComponent *delegate)95
164{96 Q_EMIT parentFlickableChanged();
165 if (delegate != this->delegate()) {97}
166 if (!m_delegateModel) {98
167 createDelegateModel();99PdfDocument* VerticalView::document() const
168 }100{
169101 return m_document.data();
170 // Cleanup the existing items102}
171 Q_FOREACH(ListItem *item, m_visibleItems)103
172 releaseItem(item);104PdfZoom *VerticalView::zoomSettings() const
173 m_visibleItems.clear();105{
174 m_firstVisibleIndex = -1;106 return m_zoomSettings;
175 adjustMinYExtent();107}
176 setContentY(0);108void VerticalView::setCurrentPageIndex(int currentPageIndex)
177109{
178 m_delegateModel->setDelegate(delegate);110 if (m_currentPageIndex == currentPageIndex)
179111 return;
180 Q_EMIT delegateChanged();112
181 m_delegateValidated = false;113 m_currentPageIndex = currentPageIndex;
182 m_contentHeightDirty = true;114 Q_EMIT currentPageIndexChanged();
183 polish();
184 }
185}115}
186116
187int VerticalView::cacheBuffer() const117int VerticalView::cacheBuffer() const
@@ -191,43 +121,25 @@
191121
192void VerticalView::setCacheBuffer(int cacheBuffer)122void VerticalView::setCacheBuffer(int cacheBuffer)
193{123{
194 if (cacheBuffer < 0) {124 if (m_cacheBuffer == cacheBuffer)
195 qmlInfo(this) << "Cannot set a negative cache buffer";
196 return;125 return;
197 }
198126
199 if (cacheBuffer != m_cacheBuffer) {127 m_cacheBuffer = cacheBuffer;
200 m_cacheBuffer = cacheBuffer;128 Q_EMIT cacheBufferChanged();
201 Q_EMIT cacheBufferChanged();
202 polish();
203 }
204}129}
205130
206qreal VerticalView::spacing() const131int VerticalView::spacing() const
207{132{
208 return m_spacing;133 return m_spacing;
209}134}
210135
211void VerticalView::setSpacing(qreal spacing)136void VerticalView::setSpacing(int spacing)
212{137{
213 if (spacing < 0) {138 if (m_spacing == spacing)
214 qmlInfo(this) << "Cannot set a negative spacing";
215 return;139 return;
216 }140
217141 m_spacing = spacing;
218 if (spacing != m_spacing) {142 Q_EMIT spacingChanged();
219 m_spacing = spacing;
220 Q_EMIT spacingChanged();
221 polish();
222 }
223}
224
225int VerticalView::count() const
226{
227 if (m_delegateModel)
228 return m_delegateModel->count();
229 else
230 return 0;
231}143}
232144
233int VerticalView::currentPageIndex() const145int VerticalView::currentPageIndex() const
@@ -235,659 +147,583 @@
235 return m_currentPageIndex;147 return m_currentPageIndex;
236}148}
237149
238QQuickItem *VerticalView::currentPageItem() const150int VerticalView::pagesCount() const
239{151{
240 return itemAt(m_currentPageIndex);152 if (!m_document || m_document.data()->isLocked())
241}153 return 0;
242154
243void VerticalView::_q_updateCurrentPageIndex()155 return m_document.data()->pageCount();
244{156}
245 if (!m_visibleItems.isEmpty()) {157
246 qreal pos = this->contentY() + (this->height() * 0.5);158PdfRotation::Rotation VerticalView::rotation() const
247159{
248 int oldCurrentPageIndex = m_currentPageIndex;160 return m_rotation;
249 int i = 0;161}
250162
251 Q_FOREACH(ListItem * item, m_visibleItems) {163void VerticalView::setRotation(PdfRotation::Rotation rotation)
252 if (item->y() < pos && item->y() + item->height() > pos)164{
253 break;165 if (m_rotation == rotation)
254166 return;
255 i++;167
256 }168 m_rotation = rotation;
257169 Q_EMIT rotationChanged();
258 // If spacing is set, there may be no page on posY position,170}
259 // and the Q_FOREACH loop keep on running until the end.171
260 if (i != m_visibleItems.length())172PopplerError::Error VerticalView::error() const
261 m_currentPageIndex = m_firstVisibleIndex + i;173{
262174 return m_error;
263 if (m_currentPageIndex != oldCurrentPageIndex) {175}
264 Q_EMIT currentPageIndexChanged();176
265 Q_EMIT currentPageItemChanged();177PdfDocument::RenderHints VerticalView::renderHints() const
266 }178{
267179 return m_renderHints;
180}
181
182void VerticalView::setRenderHints(const PdfDocument::RenderHints hints)
183{
184 if (m_renderHints == hints)
185 return;
186
187 m_renderHints = hints;
188 Q_EMIT renderHintsChanged();
189}
190
191bool VerticalView::showLinkHighlight() const
192{
193 return m_showLinkHighlight;
194}
195
196void VerticalView::setShowLinkHighlight(bool show)
197{
198 if (m_showLinkHighlight == show)
199 return;
200
201 m_showLinkHighlight = show;
202 Q_EMIT showLinkHighlightChanged();
203}
204
205QColor VerticalView::linkHighlightColor() const
206{
207 return m_linkHighlightColor;
208}
209
210void VerticalView::setLinkHighlightColor(const QColor &color)
211{
212 if (m_linkHighlightColor == color)
213 return;
214
215 m_linkHighlightColor = color;
216 Q_EMIT linkHighlightColorChanged();
217}
218
219void VerticalView::setError(const PopplerError::Error &error)
220{
221 if (m_error == error)
222 return;
223
224 m_error = error;
225 Q_EMIT errorChanged();
226}
227
228void VerticalView::initializeDocument(const QString &path)
229{
230 if (m_document)
231 m_document->disconnect(this);
232
233 setError(PopplerError::NoError);
234
235 m_document = QSharedPointer<PdfDocument>(new PdfDocument());
236 m_document->setPath(path);
237
238 /* A lot of things happens when we set the path property in
239 * m_document. Need to check if an error has been emitted. */
240 setError(m_document->error());
241
242 if (m_error != PopplerError::NoError && m_error != PopplerError::DocumentLocked) {
243 m_document.clear();
244
245 // Stop doing anything below.
246 return;
268 }247 }
248
249 m_document.data()->setRenderHints(m_renderHints);
250
251 // --------------------------------------------------
252 QQmlEngine *engine = QQmlEngine::contextForObject(this)->engine();
253 if (engine->imageProvider("poppler"))
254 engine->removeImageProvider("poppler");
255
256 m_imageProvider = new PdfImageProvider(m_document);
257 engine->addImageProvider("poppler", m_imageProvider);
258 // --------------------------------------------------
259
260 Q_EMIT documentChanged();
261
262 // Init zoom settings
263 m_zoomSettings->init();
264}
265
266bool VerticalView::adjustZoomToWidth()
267{
268 if (!m_zoomSettings)
269 return false;
270
271 bool result;
272
273 result = m_zoomSettings->adjustZoomToWidth();
274 m_hasZoomChanged = result;
275
276 return result;
277}
278
279bool VerticalView::adjustZoomToPage()
280{
281 if (!m_zoomSettings)
282 return false;
283
284 bool result;
285
286 result = m_zoomSettings->adjustZoomToPage();
287 m_hasZoomChanged = result;
288
289 return result;
290}
291
292bool VerticalView::adjustAutomaticZoom()
293{
294 if (!m_zoomSettings)
295 return false;
296
297 bool result;
298
299 result = m_zoomSettings->adjustAutomaticZoom();
300 m_hasZoomChanged = result;
301
302 return result;
269}303}
270304
271void VerticalView::positionAtBeginning()305void VerticalView::positionAtBeginning()
272{306{
273 if (m_delegateModel->count() <= 0)307 m_parentFlickable->setProperty("contentY", 0);
274 return;308}
275309
276 if (m_firstVisibleIndex != 0) {310void VerticalView::positionAtIndex(int index, qreal top, qreal left)
277 // TODO This could be optimized by trying to reuse the interesection311{
278 // of items that may end up intersecting between the existing312 SGTileItem* page = m_pages.value(index);
279 // m_visibleItems and the items we are creating in the next loop313
280 Q_FOREACH(ListItem *item, m_visibleItems)314 if (!page) {
281 releaseItem(item);315 PdfDocument* doc = m_document.data();
282 m_visibleItems.clear();316
283 m_firstVisibleIndex = -1;317 const qreal &zoomFactor = m_zoomSettings->zoomFactor();
284318 qreal totalHeight = 0;
285 // Create the item 0, it will be already correctly positioned at createItem()319
286 ListItem *item = createItem(0, false);320 for (int j=0; j < doc->pageCount(); ++j) {
287 // Create the subsequent items321 const QSize &s = doc->pageSize(j);
288 int modelIndex = 1;322 QRect pageRect;
289 qreal pos = item->y() + item->height();323
290 const qreal bufferTo = height() + m_cacheBuffer;324 if (m_rotation == PdfRotation::Rotate0 || m_rotation == PdfRotation::Rotate180) {
291 while (modelIndex < m_delegateModel->count() && pos <= bufferTo) {325 pageRect = QRect(
292 if (!(item = createItem(modelIndex, false)))326 (this->width() - Twips::convertPointsToPixels(s.width(), zoomFactor)) * 0.5,
327 totalHeight,
328 Twips::convertPointsToPixels(s.width(), zoomFactor),
329 Twips::convertPointsToPixels(s.height(), zoomFactor)
330 );
331 } else {
332 pageRect = QRect(
333 (this->width() - Twips::convertPointsToPixels(s.height(), zoomFactor)) * 0.5,
334 totalHeight,
335 Twips::convertPointsToPixels(s.height(), zoomFactor),
336 Twips::convertPointsToPixels(s.width(), zoomFactor)
337 );
338 }
339
340 if (j == index) {
341 page = createPage(j, pageRect);
293 break;342 break;
294 pos += item->height();
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches