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