Merge lp:~verzegnassi-stefano/ubuntu-docviewer-app/reboot-qsg-impress-support into lp:ubuntu-docviewer-app

Proposed by Stefano Verzegnassi
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
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/qml/loView/KeybHelper.js
* [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

To post a comment you must log in.
Revision history for this message
Alan Pope 🍺🐧🐱 🦄 (popey) wrote :

Seems the cmake isn't putting the following files into the build directory:-

com.ubuntu.docviewer.url-dispatcher
docviewer.apparmor
docviewer-content.json

I had to manually put them in the build to make a click.

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Roman Shchekin (mrqtros) wrote :

No automatic merge?

Revision history for this message
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.

Revision history for this message
Stefano Verzegnassi (verzegnassi-stefano) wrote :

Ok. False allarm, everything is okay.

Please approve this MP too: https://code.launchpad.net/~verzegnassi-stefano/ubuntu-docviewer-app/reboot-lok-qsg-zoom/+merge/271895

We've already reviewed its code when you started to rewrite the RenderEngine with thumbnails support.

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
182. By Stefano Verzegnassi

Updated translation template

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'po/com.ubuntu.docviewer.pot'
2--- po/com.ubuntu.docviewer.pot 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

Subscribers

People subscribed via source and target branches