Merge lp:~verzegnassi-stefano/ubuntu-docviewer-app/reboot-qsg-impress-support into lp:ubuntu-docviewer-app
- reboot-qsg-impress-support
- Merge into lo-viewer
Status: | Merged |
---|---|
Approved by: | Stefano Verzegnassi |
Approved revision: | 182 |
Merged at revision: | 185 |
Proposed branch: | lp:~verzegnassi-stefano/ubuntu-docviewer-app/reboot-qsg-impress-support |
Merge into: | lp:ubuntu-docviewer-app |
Prerequisite: | lp:~verzegnassi-stefano/ubuntu-docviewer-app/reboot-lok-qsg-zoom |
Diff against target: |
807 lines (+319/-118) 12 files modified
po/com.ubuntu.docviewer.pot (+11/-6) src/app/qml/loView/KeybHelper.js (+98/-11) src/app/qml/loView/LOViewPage.qml (+21/-15) src/app/qml/loView/PartsView.qml (+10/-1) src/app/qml/loView/SlideControllerPanel.qml (+31/-11) src/plugin/libreofficetoolkit-qml-plugin/lodocument.cpp (+64/-23) src/plugin/libreofficetoolkit-qml-plugin/lodocument.h (+2/-3) src/plugin/libreofficetoolkit-qml-plugin/lopartsimageprovider.cpp (+17/-44) src/plugin/libreofficetoolkit-qml-plugin/lopartsmodel.cpp (+2/-2) src/plugin/libreofficetoolkit-qml-plugin/qml/Viewer.qml (+41/-0) src/plugin/libreofficetoolkit-qml-plugin/renderengine.cpp (+5/-2) src/plugin/libreofficetoolkit-qml-plugin/renderengine.h (+17/-0) |
To merge this branch: | bzr merge lp:~verzegnassi-stefano/ubuntu-docviewer-app/reboot-qsg-impress-support |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu Phone Apps Jenkins Bot | continuous-integration | Approve | |
Ubuntu Document Viewer Developers | Pending | ||
Review via email: mp+272146@code.launchpad.net |
Commit message
* [loviewer] Improved support for presentation document type
* [loviewer] Added keyboard shortcuts.
* [loviewer] Added an image provider for slides thumbnails, sync'd with RenderEngine
* [loviewer] Conditional layout for the presentation view: use a bottom edge or a sidebar to show the list of slides
* [loviewer] Moved zoom controls into a separate page head
* Updated translation template
Description of the change
* [loviewer] Improved support for presentation document type
* [loviewer] Added keyboard shortcuts.
(PgUp, PgDown, Ctrl+Home, Ctrl+End, Up, Down, Left, Right, Ctrl+Plus, Ctrl+Minus)
See src/app/
* [loviewer] Added an image provider for slides thumbnails, sync'd with RenderEngine
* [loviewer] Conditional layout for the presentation view: use a bottom edge or a sidebar to show the list of slides
* [loviewer] Moved zoom controls into a separate page head
* Updated translation template
Alan Pope 🍺🐧🐱 🦄 (popey) wrote : | # |
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:178
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild:
http://
Roman Shchekin (mrqtros) wrote : | # |
No automatic merge?
Stefano Verzegnassi (verzegnassi-stefano) wrote : | # |
I've done some mess with prerequisite branches, which is required to be already merged...
I honestly need a moment for checking if I have proposed this with the proper prerequisite. I'm sorry for this.
Stefano Verzegnassi (verzegnassi-stefano) wrote : | # |
Ok. False allarm, everything is okay.
Please approve this MP too: https:/
We've already reviewed its code when you started to rewrite the RenderEngine with thumbnails support.
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
FAILURE: http://
- 182. By Stefano Verzegnassi
-
Updated translation template
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) : | # |
Preview Diff
1 | === modified file 'po/com.ubuntu.docviewer.pot' |
2 | --- po/com.ubuntu.docviewer.pot 2015-10-10 12:15:07 +0000 |
3 | +++ po/com.ubuntu.docviewer.pot 2015-10-10 12:33:09 +0000 |
4 | @@ -8,7 +8,7 @@ |
5 | msgstr "" |
6 | "Project-Id-Version: \n" |
7 | "Report-Msgid-Bugs-To: \n" |
8 | -"POT-Creation-Date: 2015-10-10 14:14+0200\n" |
9 | +"POT-Creation-Date: 2015-10-10 14:32+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 | @@ -19,7 +19,7 @@ |
14 | "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" |
15 | |
16 | #: ../src/app/docviewer-application.cpp:162 |
17 | -#: /tmp/build-reboot-lok-qsg-zoom-Desktop-Default/po/com.ubuntu.docviewer.desktop.in.in.h:1 |
18 | +#: /tmp/build-reboot-qsg-impress-support-Desktop-Default/po/com.ubuntu.docviewer.desktop.in.in.h:1 |
19 | msgid "Document Viewer" |
20 | msgstr "" |
21 | |
22 | @@ -255,7 +255,7 @@ |
23 | |
24 | #: ../src/app/qml/documentPage/DocumentPageSearchHeader.qml:27 |
25 | #: ../src/app/qml/loView/LOViewDefaultHeader.qml:80 |
26 | -#: ../src/app/qml/loView/LOViewPage.qml:186 |
27 | +#: ../src/app/qml/loView/LOViewPage.qml:191 |
28 | #: ../src/app/qml/pdfView/PdfViewDefaultHeader.qml:61 |
29 | #: ../src/app/qml/textView/TextViewDefaultHeader.qml:61 |
30 | msgid "Back" |
31 | @@ -368,8 +368,8 @@ |
32 | msgid "GO!" |
33 | msgstr "" |
34 | |
35 | -#: ../src/app/qml/loView/LOViewPage.qml:41 |
36 | -#: ../src/app/qml/loView/LOViewPage.qml:184 |
37 | +#: ../src/app/qml/loView/LOViewPage.qml:34 |
38 | +#: ../src/app/qml/loView/LOViewPage.qml:189 |
39 | msgid "Slides" |
40 | msgstr "" |
41 | |
42 | @@ -385,6 +385,11 @@ |
43 | msgid "Zoom out" |
44 | msgstr "" |
45 | |
46 | +#: ../src/app/qml/loView/SlideControllerPanel.qml:62 |
47 | +#, qt-format |
48 | +msgid "Slide %1 of %2" |
49 | +msgstr "" |
50 | + |
51 | #: ../src/app/qml/loView/ZoomSelector.qml:29 |
52 | msgid "Automatic (Fit width)" |
53 | msgstr "" |
54 | @@ -443,6 +448,6 @@ |
55 | msgid "copy %1" |
56 | msgstr "" |
57 | |
58 | -#: /tmp/build-reboot-lok-qsg-zoom-Desktop-Default/po/com.ubuntu.docviewer.desktop.in.in.h:2 |
59 | +#: /tmp/build-reboot-qsg-impress-support-Desktop-Default/po/com.ubuntu.docviewer.desktop.in.in.h:2 |
60 | msgid "documents;viewer;pdf;reader;" |
61 | msgstr "" |
62 | |
63 | === modified file 'src/app/qml/loView/KeybHelper.js' |
64 | --- src/app/qml/loView/KeybHelper.js 2015-09-15 18:20:00 +0000 |
65 | +++ src/app/qml/loView/KeybHelper.js 2015-10-10 12:33:09 +0000 |
66 | @@ -16,42 +16,129 @@ |
67 | |
68 | function parseEvent(event) { |
69 | var pixelDiff = 5; |
70 | - |
71 | + |
72 | + var view = loPageContentLoader.item.loView |
73 | + var isPresentation = view.document.documentType === LO.Document.PresentationDocument |
74 | + |
75 | if (event.key == Qt.Key_PageUp) { |
76 | - if (loDocument.documentType == LO.Document.PresentationDocument) |
77 | - loDocument.currentPart -= 1 |
78 | + if (isPresentation) |
79 | + view.document.currentPart -= 1 |
80 | else |
81 | - loPage.moveView("vertical", -loView.height) |
82 | + view.moveView("vertical", -view.height) |
83 | |
84 | return; |
85 | } |
86 | |
87 | if (event.key == Qt.Key_PageDown) { |
88 | - if (loDocument.documentType == LO.Document.PresentationDocument) |
89 | - loDocument.currentPart += 1 |
90 | + if (isPresentation) |
91 | + view.document.currentPart += 1 |
92 | else |
93 | - loPage.moveView("vertical", loView.height) |
94 | + view.moveView("vertical", view.height) |
95 | |
96 | return; |
97 | } |
98 | |
99 | + if (event.key == Qt.Key_Home) { |
100 | + if (event.modifiers & Qt.ControlModifier) { |
101 | + view.contentX = 0 |
102 | + view.contentY = 0 |
103 | + view.document.currentPart = 0 |
104 | + } else { |
105 | + view.contentX = 0 |
106 | + view.contentY = 0 |
107 | + } |
108 | + } |
109 | + |
110 | + if (event.key == Qt.Key_End) { |
111 | + if (event.modifiers & Qt.ControlModifier) { |
112 | + view.contentX = view.contentWidth - view.width |
113 | + view.contentY = view.contentHeight - view.height |
114 | + console.log(view.document.currentPart, view.document.partsCount - 1) |
115 | + view.document.currentPart = view.document.partsCount - 1 |
116 | + } else { |
117 | + view.contentX = view.contentWidth - view.width |
118 | + view.contentY = view.contentHeight - view.height |
119 | + } |
120 | + } |
121 | + |
122 | if (event.key == Qt.Key_Up) { |
123 | - loPage.moveView("vertical", -pixelDiff) |
124 | + view.moveView("vertical", -pixelDiff) |
125 | return; |
126 | } |
127 | |
128 | if (event.key == Qt.Key_Down) { |
129 | - loPage.moveView("vertical", pixelDiff) |
130 | + view.moveView("vertical", pixelDiff) |
131 | return; |
132 | } |
133 | |
134 | if (event.key == Qt.Key_Left) { |
135 | - loPage.moveView("horizontal", -pixelDiff) |
136 | + view.moveView("horizontal", -pixelDiff) |
137 | return; |
138 | } |
139 | |
140 | if (event.key == Qt.Key_Right) { |
141 | - loPage.moveView("horizontal", pixelDiff) |
142 | + view.moveView("horizontal", pixelDiff) |
143 | return; |
144 | } |
145 | + |
146 | + if (event.key == Qt.Key_Plus) { |
147 | + if (event.modifiers & Qt.ControlModifier) { |
148 | + view.zoomFactor = Math.max(4.0, view.zoomFactor + 0.25) |
149 | + } |
150 | + } |
151 | + |
152 | + if (event.key == Qt.Key_Minus) { |
153 | + if (event.modifiers & Qt.ControlModifier) { |
154 | + view.zoomFactor = Math.min(0.5, view.zoomFactor - 0.25) |
155 | + } |
156 | + } |
157 | + |
158 | + |
159 | + /* |
160 | + if (event.key == Qt.Key_C) { |
161 | + if (event.modifiers & Qt.ControlModifier) { |
162 | + |
163 | + } |
164 | + } |
165 | + */ |
166 | + |
167 | + /* |
168 | + if (event.key == Qt.Key_X) { |
169 | + if (event.modifiers & Qt.ControlModifier) { |
170 | + |
171 | + } |
172 | + } |
173 | + */ |
174 | + |
175 | + /* |
176 | + if (event.key == Qt.Key_V) { |
177 | + if (event.modifiers & Qt.ControlModifier) { |
178 | + |
179 | + } |
180 | + } |
181 | + */ |
182 | + |
183 | + /* |
184 | + if (event.key == Qt.Key_A) { |
185 | + if (event.modifiers & Qt.ControlModifier) { |
186 | + |
187 | + } |
188 | + } |
189 | + */ |
190 | + |
191 | + /* |
192 | + if (event.key == Qt.Key_L) { |
193 | + if (event.modifiers & Qt.ControlModifier) { |
194 | + // TODO: Go to page dialog |
195 | + } |
196 | + } |
197 | + */ |
198 | + |
199 | + /* |
200 | + if (event.key == Qt.Key_Question) { |
201 | + if (event.modifiers & (Qt.ControlModifier | Qt.ShiftModifier)) { |
202 | + // TODO: Keyboard shortcuts |
203 | + } |
204 | + } |
205 | + */ |
206 | } |
207 | |
208 | === modified file 'src/app/qml/loView/LOViewPage.qml' |
209 | --- src/app/qml/loView/LOViewPage.qml 2015-09-22 19:02:46 +0000 |
210 | +++ src/app/qml/loView/LOViewPage.qml 2015-10-10 12:33:09 +0000 |
211 | @@ -31,6 +31,7 @@ |
212 | |
213 | readonly property bool wideWindow: width > units.gu(120) |
214 | |
215 | + bottomEdgeTitle: i18n.tr("Slides") |
216 | bottomEdgeEnabled: { |
217 | if (!loPageContentLoader.loaded) |
218 | return false |
219 | @@ -38,7 +39,6 @@ |
220 | // else |
221 | return loPageContentLoader.item.loDocument.documentType == LO.Document.PresentationDocument && !wideWindow |
222 | } |
223 | - bottomEdgeTitle: i18n.tr("Slides") |
224 | |
225 | Loader { |
226 | id: loPageContentLoader |
227 | @@ -70,23 +70,14 @@ |
228 | Component { |
229 | id: loPageContentComponent |
230 | |
231 | - Item { |
232 | + FocusScope { |
233 | id: loPageContent |
234 | anchors.fill: parent |
235 | + |
236 | property alias loDocument: loView.document |
237 | property alias loView: loView |
238 | property alias bottomEdgePartsPage: bottomEdgePartsPage |
239 | |
240 | - function moveView(axis, diff) { |
241 | - if (axis == "vertical") { |
242 | - var maxContentY = Math.max(0, loView.contentHeight - loView.height) |
243 | - loView.contentY = Math.max(0, Math.min(loView.contentY + diff, maxContentY )) |
244 | - } else { |
245 | - var maxContentX = Math.max(0, loView.contentWidth - loView.width) |
246 | - loView.contentX = Math.max(0, Math.min(loView.contentX + diff, maxContentX )) |
247 | - } |
248 | - } |
249 | - |
250 | Layouts { |
251 | id: layouts |
252 | anchors.fill: parent |
253 | @@ -108,8 +99,8 @@ |
254 | left: parent.left |
255 | } |
256 | |
257 | - model: partsModel |
258 | - visible: model |
259 | + model: LO.PartsModel { document: loPageContent.loDocument } |
260 | + visible: model && loDocument.documentType == LO.Document.PresentationDocument |
261 | width: visible ? units.gu(40) : 0 |
262 | } |
263 | |
264 | @@ -120,7 +111,16 @@ |
265 | top: parent.top |
266 | bottom: bottomBarLayoutItem.top |
267 | } |
268 | - ItemLayout { item: "loView"; anchors.fill: parent } |
269 | + |
270 | + ItemLayout { |
271 | + item: "loView" |
272 | + anchors.fill: parent |
273 | + |
274 | + // Keyboard events |
275 | + focus: true |
276 | + Keys.onPressed: KeybHelper.parseEvent(event) |
277 | + Component.onCompleted: loPageContent.forceActiveFocus() |
278 | + } |
279 | } |
280 | |
281 | Item { |
282 | @@ -153,10 +153,15 @@ |
283 | clip: true |
284 | documentPath: file.path |
285 | |
286 | + // Keyboard events |
287 | + focus: true |
288 | + Keys.onPressed: KeybHelper.parseEvent(event) |
289 | + |
290 | Component.onCompleted: { |
291 | // WORKAROUND: Fix for wrong grid unit size |
292 | flickDeceleration = 1500 * units.gridUnit / 8 |
293 | maximumFlickVelocity = 2500 * units.gridUnit / 8 |
294 | + loPageContent.forceActiveFocus() |
295 | } |
296 | |
297 | Scrollbar { flickableItem: loView; parent: loView.parent } |
298 | @@ -191,6 +196,7 @@ |
299 | flickable: null |
300 | |
301 | PartsView { |
302 | + property bool belongsToNestedPage: true |
303 | anchors.fill: parent |
304 | model: LO.PartsModel { document: loPageContent.loDocument } |
305 | } |
306 | |
307 | === modified file 'src/app/qml/loView/PartsView.qml' |
308 | --- src/app/qml/loView/PartsView.qml 2015-09-15 18:20:00 +0000 |
309 | +++ src/app/qml/loView/PartsView.qml 2015-10-10 12:33:09 +0000 |
310 | @@ -29,6 +29,7 @@ |
311 | property bool expanded: true |
312 | |
313 | currentIndex: view.model ? view.model.document.currentPart : -1 |
314 | + highlightMoveDuration: UbuntuAnimation.SnapDuration |
315 | |
316 | delegate: ListItemWithActions { |
317 | id: delegate |
318 | @@ -45,7 +46,12 @@ |
319 | |
320 | onClicked: { |
321 | view.model.document.currentPart = model.index |
322 | - pageStack.pop(); |
323 | + |
324 | + // Check if the view has been included in a nested page (e.g. |
325 | + // bottomEdge). If so, close that page and return to the |
326 | + // main viewer. |
327 | + if (view.hasOwnProperty("belongsToNestedPage")) |
328 | + pageStack.pop(); |
329 | } |
330 | } |
331 | |
332 | @@ -57,6 +63,9 @@ |
333 | Layout.fillHeight: true |
334 | Layout.preferredWidth: height |
335 | fillMode: Image.PreserveAspectFit |
336 | + // Do not store a cache of the thumbnail, so that we don't show |
337 | + // thumbnails of a previously loaded document. |
338 | + cache: false |
339 | |
340 | source: "image://lok/part/" + model.index |
341 | } |
342 | |
343 | === modified file 'src/app/qml/loView/SlideControllerPanel.qml' |
344 | --- src/app/qml/loView/SlideControllerPanel.qml 2015-09-22 19:02:46 +0000 |
345 | +++ src/app/qml/loView/SlideControllerPanel.qml 2015-10-10 12:33:09 +0000 |
346 | @@ -34,14 +34,24 @@ |
347 | |
348 | Row { |
349 | anchors.centerIn: parent |
350 | - spacing: units.gu(2) |
351 | - |
352 | - AbstractButton { |
353 | - width: units.gu(4); height: parent.height |
354 | - onClicked: loPageContentLoader.item.loDocument.currentPart -= 1 |
355 | - |
356 | - Icon { |
357 | - id: icon |
358 | + //spacing: units.gu(2) |
359 | + |
360 | + AbstractButton { |
361 | + width: units.gu(4); height: parent.height |
362 | + onClicked: loPageContentLoader.item.loView.goFirstPart() |
363 | + |
364 | + Icon { |
365 | + anchors.centerIn: parent |
366 | + width: units.gu(2.5); height: width |
367 | + name: "go-first" |
368 | + } |
369 | + } |
370 | + |
371 | + AbstractButton { |
372 | + width: units.gu(4); height: parent.height |
373 | + onClicked: loPageContentLoader.item.loView.goPreviousPart() |
374 | + |
375 | + Icon { |
376 | anchors.centerIn: parent |
377 | width: units.gu(2.5); height: width |
378 | name: "go-previous" |
379 | @@ -49,13 +59,12 @@ |
380 | } |
381 | |
382 | Label { |
383 | - text: "%1 of %2".arg(loPageContentLoader.item.loDocument.currentPart + 1) |
384 | - .arg(loPageContentLoader.item.loDocument.partsCount) |
385 | + text: i18n.tr("Slide %1 of %2").arg(loPageContentLoader.item.loDocument.currentPart + 1).arg(loPageContentLoader.item.loDocument.partsCount) |
386 | } |
387 | |
388 | AbstractButton { |
389 | width: units.gu(4); height: parent.height |
390 | - onClicked: loPageContentLoader.item.loDocument.currentPart += 1 |
391 | + onClicked: loPageContentLoader.item.loView.goNextPart() |
392 | |
393 | Icon { |
394 | anchors.centerIn: parent |
395 | @@ -63,5 +72,16 @@ |
396 | name: "go-next" |
397 | } |
398 | } |
399 | + |
400 | + AbstractButton { |
401 | + width: units.gu(4); height: parent.height |
402 | + onClicked: loPageContentLoader.item.loView.goLastPart() |
403 | + |
404 | + Icon { |
405 | + anchors.centerIn: parent |
406 | + width: units.gu(2.5); height: width |
407 | + name: "go-last" |
408 | + } |
409 | + } |
410 | } |
411 | } |
412 | |
413 | === modified file 'src/plugin/libreofficetoolkit-qml-plugin/lodocument.cpp' |
414 | --- src/plugin/libreofficetoolkit-qml-plugin/lodocument.cpp 2015-09-22 19:02:46 +0000 |
415 | +++ src/plugin/libreofficetoolkit-qml-plugin/lodocument.cpp 2015-10-10 12:33:09 +0000 |
416 | @@ -36,6 +36,7 @@ |
417 | |
418 | LODocument::LODocument() |
419 | : m_path("") |
420 | + , m_currentPart(-1) |
421 | , m_document(nullptr) |
422 | { |
423 | // This space is intentionally empty. |
424 | @@ -61,21 +62,18 @@ |
425 | } |
426 | |
427 | int LODocument::currentPart() { |
428 | - if (!m_document) |
429 | - return int(-1); |
430 | - |
431 | - return m_document->getPart(); |
432 | + return m_currentPart; |
433 | } |
434 | - |
435 | + |
436 | void LODocument::setCurrentPart(int index) |
437 | { |
438 | if (!m_document) |
439 | return; |
440 | - |
441 | - if (this->currentPart() == index || index < 0 || index > partsCount() - 1) |
442 | + |
443 | + if (m_currentPart == index || index < 0 || index > partsCount() - 1) |
444 | return; |
445 | - |
446 | - m_document->setPart(index); |
447 | + |
448 | + m_currentPart = index; |
449 | Q_EMIT currentPartChanged(); |
450 | } |
451 | |
452 | @@ -97,6 +95,8 @@ |
453 | m_docType = DocumentType(m_document->getDocumentType()); |
454 | Q_EMIT documentTypeChanged(); |
455 | |
456 | + setCurrentPart(m_document->getPart()); |
457 | + |
458 | m_document->initializeForRendering(); |
459 | qDebug() << "Document loaded successfully !"; |
460 | |
461 | @@ -127,6 +127,12 @@ |
462 | // the rect tileSize. |
463 | QImage LODocument::paintTile(const QSize& canvasSize, const QRect& tileSize, const qreal &zoom) |
464 | { |
465 | + if (!m_document) |
466 | + return QImage(); |
467 | + |
468 | + if (m_currentPart != m_document->getPart()) |
469 | + m_document->setPart(m_currentPart); |
470 | + |
471 | QImage result = QImage(canvasSize.width(), canvasSize.height(), QImage::Format_RGB32); |
472 | |
473 | #ifdef DEBUG_TILE_BENCHMARK |
474 | @@ -148,6 +154,52 @@ |
475 | return result.rgbSwapped(); |
476 | } |
477 | |
478 | +QImage LODocument::paintThumbnail(int part, qreal size) |
479 | +{ |
480 | + if (!m_document) |
481 | + return QImage(); |
482 | + |
483 | +#ifdef DEBUG_TILE_BENCHMARK |
484 | + QElapsedTimer renderTimer; |
485 | + renderTimer.start(); |
486 | +#endif |
487 | + |
488 | + // This is used by LOPartsImageProvider to temporarily change the current part, |
489 | + // in order to generate thumbnails. |
490 | + |
491 | + // FIXME: Sometimes docviewer crashes at m_document->getPart() when a |
492 | + // document is being loaded. |
493 | + if (m_document->getPart() != part) |
494 | + m_document->setPart(part); |
495 | + |
496 | + qreal tWidth = this->documentSize().width(); |
497 | + qreal tHeight = this->documentSize().height(); |
498 | + |
499 | + QSize resultSize; |
500 | + |
501 | + if (tWidth > tHeight) { |
502 | + resultSize.setWidth(size); |
503 | + resultSize.setHeight(size * tHeight / tWidth); |
504 | + } else { |
505 | + resultSize.setHeight(size); |
506 | + resultSize.setWidth(size * tWidth / tHeight); |
507 | + } |
508 | + |
509 | + QImage result = QImage(resultSize.width(), resultSize.height(), QImage::Format_RGB32); |
510 | + m_document->paintTile(result.bits(), resultSize.width(), resultSize.height(), |
511 | + 0, 0, tWidth, tHeight); |
512 | + |
513 | + // Restore the active part used for tile rendering. |
514 | + if (m_currentPart != part) |
515 | + m_document->setPart(m_currentPart); |
516 | + |
517 | +#ifdef DEBUG_TILE_BENCHMARK |
518 | + qDebug() << "Time to render the thumbnail:" << renderTimer.elapsed() << "ms"; |
519 | +#endif |
520 | + |
521 | + return result.rgbSwapped(); |
522 | +} |
523 | + |
524 | int LODocument::partsCount() |
525 | { |
526 | if (!m_document) |
527 | @@ -161,20 +213,9 @@ |
528 | if (!m_document) |
529 | return QString(); |
530 | |
531 | - return QString::fromLatin1(m_document->getPartName(index)); |
532 | -} |
533 | - |
534 | -// This is used by LOPartsImageProvider to temporarily change the current part, |
535 | -// in order to generate thumbnails. |
536 | -// FIXME: We need to disable tiled rendering when we're generating the thumbnail. |
537 | -int LODocument::swapCurrentPart(int newPartIndex) |
538 | -{ |
539 | - int oldIndex = this->currentPart(); |
540 | - |
541 | - m_document->setPart(newPartIndex); |
542 | - return oldIndex; |
543 | -} |
544 | - |
545 | + return QString::fromUtf8(m_document->getPartName(index)); |
546 | +} |
547 | + |
548 | /* Export the file in a given format: |
549 | * - url is a mandatory argument. |
550 | * - format is optional. If not specified, lok will try to get it from the file |
551 | |
552 | === modified file 'src/plugin/libreofficetoolkit-qml-plugin/lodocument.h' |
553 | --- src/plugin/libreofficetoolkit-qml-plugin/lodocument.h 2015-09-22 19:02:46 +0000 |
554 | +++ src/plugin/libreofficetoolkit-qml-plugin/lodocument.h 2015-10-10 12:33:09 +0000 |
555 | @@ -60,12 +60,10 @@ |
556 | QSize documentSize() const; |
557 | |
558 | QImage paintTile(const QSize& canvasSize, const QRect& tileSize, const qreal& zoom = 1.0); |
559 | + QImage paintThumbnail(int part, qreal size); |
560 | |
561 | int partsCount(); |
562 | - |
563 | QString getPartName(int index) const; |
564 | - int swapCurrentPart(int newPartIndex); |
565 | - |
566 | void setPart(int index); |
567 | |
568 | Q_INVOKABLE bool saveAs(QString url, QString format, QString filterOptions); |
569 | @@ -77,6 +75,7 @@ |
570 | |
571 | private: |
572 | QString m_path; |
573 | + int m_currentPart; |
574 | DocumentType m_docType; |
575 | |
576 | bool loadDocument(const QString &pathNAme); |
577 | |
578 | === modified file 'src/plugin/libreofficetoolkit-qml-plugin/lopartsimageprovider.cpp' |
579 | --- src/plugin/libreofficetoolkit-qml-plugin/lopartsimageprovider.cpp 2015-09-22 19:02:46 +0000 |
580 | +++ src/plugin/libreofficetoolkit-qml-plugin/lopartsimageprovider.cpp 2015-10-10 12:33:09 +0000 |
581 | @@ -16,62 +16,35 @@ |
582 | |
583 | #include "lopartsimageprovider.h" |
584 | #include "lodocument.h" |
585 | -#include "config.h" |
586 | -#include "twips.h" |
587 | - |
588 | -#include <QDebug> |
589 | +#include "renderengine.h" |
590 | |
591 | LOPartsImageProvider::LOPartsImageProvider(LODocument *document) |
592 | : QQuickImageProvider(QQuickImageProvider::Image, QQuickImageProvider::ForceAsynchronousImageLoading) |
593 | -{ |
594 | - m_document = document; |
595 | -} |
596 | + , m_document(document) |
597 | +{ } |
598 | |
599 | QImage LOPartsImageProvider::requestImage(const QString & id, QSize * size, const QSize & requestedSize) |
600 | { |
601 | Q_UNUSED(size) |
602 | - Q_UNUSED(requestedSize) |
603 | - |
604 | - if (m_document->documentType() != LODocument::PresentationDocument) |
605 | - return QImage(); |
606 | - |
607 | - // Here's the tricky magic. For getting a thumbnail of a document part |
608 | - // (e.g. a specific slide in a Impress document), we need to change the |
609 | - // current active part in LODocument, render the thumbnail, then re-set |
610 | - // the previous value through lok::Document::setPath(index). |
611 | + |
612 | QString type = id.section("/", 0, 0); |
613 | |
614 | - if (type != "part") |
615 | + if (requestedSize.isNull() || type != "part" || |
616 | + m_document->documentType() != LODocument::PresentationDocument) |
617 | return QImage(); |
618 | |
619 | + // Wait for any in-progress rendering to be completed |
620 | + while (RenderEngine::instance()->activeTaskCount() != 0) { } |
621 | + |
622 | + // Lock the render engine |
623 | + RenderEngine::instance()->setEnabled(false); |
624 | + |
625 | + // Render the part to QImage |
626 | int partNumber = id.section("/", 1, 1).toInt(); |
627 | - QImage result; |
628 | - QSize partSize; |
629 | - QSize resultSize; |
630 | - |
631 | - // Get the current part index and set the index of the part to be rendered. |
632 | - int currentPart = m_document->swapCurrentPart(partNumber); |
633 | - |
634 | - // Get the size of the part |
635 | - partSize = m_document->documentSize(); |
636 | - partSize.setHeight(Twips::convertTwipsToPixels(partSize.height())); |
637 | - partSize.setWidth(Twips::convertTwipsToPixels(partSize.width())); |
638 | - |
639 | - // Set the size of the rendered thumbnail |
640 | - if (partSize.width() > partSize.height()) { |
641 | - resultSize.setWidth(TILE_SIZE); |
642 | - resultSize.setHeight(TILE_SIZE * partSize.height() / partSize.width()); |
643 | - } else { |
644 | - resultSize.setHeight(TILE_SIZE); |
645 | - resultSize.setWidth(TILE_SIZE * partSize.width() / partSize.height()); |
646 | - } |
647 | - |
648 | - // Render the part to QImage |
649 | - result = m_document->paintTile(resultSize, QRect(QPoint(0, 0), partSize)); |
650 | - |
651 | - // Re-set the earlier current part |
652 | - m_document->swapCurrentPart(currentPart); |
653 | + QImage result = m_document->paintThumbnail(partNumber, 256.0); |
654 | + |
655 | + // Unlock the render engine |
656 | + RenderEngine::instance()->setEnabled(true); |
657 | |
658 | return result; |
659 | - |
660 | } |
661 | |
662 | === modified file 'src/plugin/libreofficetoolkit-qml-plugin/lopartsmodel.cpp' |
663 | --- src/plugin/libreofficetoolkit-qml-plugin/lopartsmodel.cpp 2015-09-15 18:20:00 +0000 |
664 | +++ src/plugin/libreofficetoolkit-qml-plugin/lopartsmodel.cpp 2015-10-10 12:33:09 +0000 |
665 | @@ -111,9 +111,9 @@ |
666 | part.index = i; |
667 | part.name = m_document->getPartName(i); |
668 | |
669 | - beginRemoveRows(QModelIndex(), rowCount(), rowCount()); |
670 | + beginInsertRows(QModelIndex(), rowCount(), rowCount()); |
671 | m_entries.append(part); |
672 | - endRemoveRows(); |
673 | + endInsertRows(); |
674 | } |
675 | |
676 | Q_EMIT countChanged(); |
677 | |
678 | === modified file 'src/plugin/libreofficetoolkit-qml-plugin/qml/Viewer.qml' |
679 | --- src/plugin/libreofficetoolkit-qml-plugin/qml/Viewer.qml 2015-09-22 00:01:22 +0000 |
680 | +++ src/plugin/libreofficetoolkit-qml-plugin/qml/Viewer.qml 2015-10-10 12:33:09 +0000 |
681 | @@ -32,6 +32,37 @@ |
682 | view.adjustZoomToWidth(); |
683 | } |
684 | |
685 | + function moveView(axis, diff) |
686 | + { |
687 | + if (axis == "vertical") { |
688 | + var maxContentY = Math.max(0, rootFlickable.contentHeight - rootFlickable.height) |
689 | + rootFlickable.contentY = Math.max(0, Math.min(rootFlickable.contentY + diff, maxContentY )) |
690 | + } else { |
691 | + var maxContentX = Math.max(0, rootFlickable.contentWidth - rootFlickable.width) |
692 | + rootFlickable.contentX = Math.max(0, Math.min(rootFlickable.contentX + diff, maxContentX )) |
693 | + } |
694 | + } |
695 | + |
696 | + function goNextPart() |
697 | + { |
698 | + document.currentPart = Math.min(document.currentPart + 1, document.partsCount - 1) |
699 | + } |
700 | + |
701 | + function goPreviousPart() |
702 | + { |
703 | + document.currentPart = Math.max(0, document.currentPart - 1) |
704 | + } |
705 | + |
706 | + function goFirstPart() |
707 | + { |
708 | + document.currentPart = 0 |
709 | + } |
710 | + |
711 | + function goLastPart() |
712 | + { |
713 | + document.currentPart = document.partsCount - 1 |
714 | + } |
715 | + |
716 | onDocumentPathChanged: { |
717 | if (documentPath) |
718 | view.initializeDocument(documentPath) |
719 | @@ -51,4 +82,14 @@ |
720 | |
721 | parentFlickable: rootFlickable |
722 | } |
723 | + |
724 | + Connections { |
725 | + target: view.document |
726 | + |
727 | + onCurrentPartChanged: { |
728 | + // Position view at top-left corner |
729 | + rootFlickable.contentX = 0 |
730 | + rootFlickable.contentY = 0 |
731 | + } |
732 | + } |
733 | } |
734 | |
735 | === modified file 'src/plugin/libreofficetoolkit-qml-plugin/renderengine.cpp' |
736 | --- src/plugin/libreofficetoolkit-qml-plugin/renderengine.cpp 2015-09-22 00:01:22 +0000 |
737 | +++ src/plugin/libreofficetoolkit-qml-plugin/renderengine.cpp 2015-10-10 12:33:09 +0000 |
738 | @@ -6,10 +6,13 @@ |
739 | |
740 | RenderEngine::RenderEngine(): |
741 | QObject(nullptr), |
742 | - m_activeTaskCount(0) |
743 | + m_activeTaskCount(0), |
744 | + m_enabled(true) |
745 | { |
746 | int itc = QThread::idealThreadCount(); |
747 | m_idealThreadCount = itc == -1 ? DefaultIdealThreadCount : itc; |
748 | + |
749 | + connect(this, SIGNAL(enabledChanged()), this, SLOT(doNextTask())); |
750 | } |
751 | |
752 | void RenderEngine::enqueueTask(const QSharedPointer<LODocument>& doc, const QRect& area, const qreal &zoom, int id) |
753 | @@ -43,7 +46,7 @@ |
754 | qDebug() << " ---- doNextTask" << m_activeTaskCount << m_queue.count(); |
755 | #endif |
756 | |
757 | - if (m_activeTaskCount >= m_idealThreadCount || !m_queue.count()) |
758 | + if (m_activeTaskCount >= m_idealThreadCount || !m_queue.count() || !m_enabled) |
759 | return; |
760 | |
761 | m_activeTaskCount++; |
762 | |
763 | === modified file 'src/plugin/libreofficetoolkit-qml-plugin/renderengine.h' |
764 | --- src/plugin/libreofficetoolkit-qml-plugin/renderengine.h 2015-09-22 00:01:22 +0000 |
765 | +++ src/plugin/libreofficetoolkit-qml-plugin/renderengine.h 2015-10-10 12:33:09 +0000 |
766 | @@ -6,6 +6,7 @@ |
767 | #include <QSharedPointer> |
768 | #include <QHash> |
769 | #include <QQueue> |
770 | +#include <QAtomicInt> |
771 | |
772 | #include "lodocument.h" |
773 | |
774 | @@ -45,17 +46,33 @@ |
775 | return s_instance; |
776 | } |
777 | |
778 | + int activeTaskCount() { return m_activeTaskCount; } |
779 | + |
780 | + bool enabled() { return m_enabled.loadAcquire(); } |
781 | + void setEnabled(bool enabled) { |
782 | + if (m_enabled.loadAcquire() == enabled) |
783 | + return; |
784 | + |
785 | + m_enabled.storeRelease(enabled); |
786 | + Q_EMIT enabledChanged(); |
787 | + } |
788 | + |
789 | Q_SIGNALS: |
790 | void renderFinished(int id, QImage img); |
791 | + void enabledChanged(); |
792 | |
793 | private: |
794 | Q_INVOKABLE void internalRenderCallback(int id, QImage img); |
795 | + |
796 | +private slots: |
797 | void doNextTask(); |
798 | |
799 | private: |
800 | QQueue<EngineTask> m_queue; |
801 | int m_activeTaskCount; |
802 | int m_idealThreadCount; |
803 | + |
804 | + QAtomicInt m_enabled; |
805 | }; |
806 | |
807 | #endif // RENDERENGINE_H |
Seems the cmake isn't putting the following files into the build directory:-
com.ubuntu. docviewer. url-dispatcher content. json
docviewer.apparmor
docviewer-
I had to manually put them in the build to make a click.