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
=== modified file 'po/com.ubuntu.docviewer.pot'
--- po/com.ubuntu.docviewer.pot 2015-10-10 12:15:07 +0000
+++ po/com.ubuntu.docviewer.pot 2015-10-10 12:33:09 +0000
@@ -8,7 +8,7 @@
8msgstr ""8msgstr ""
9"Project-Id-Version: \n"9"Project-Id-Version: \n"
10"Report-Msgid-Bugs-To: \n"10"Report-Msgid-Bugs-To: \n"
11"POT-Creation-Date: 2015-10-10 14:14+0200\n"11"POT-Creation-Date: 2015-10-10 14:32+0200\n"
12"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"12"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"13"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14"Language-Team: LANGUAGE <LL@li.org>\n"14"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -19,7 +19,7 @@
19"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"19"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
2020
21#: ../src/app/docviewer-application.cpp:16221#: ../src/app/docviewer-application.cpp:162
22#: /tmp/build-reboot-lok-qsg-zoom-Desktop-Default/po/com.ubuntu.docviewer.desktop.in.in.h:122#: /tmp/build-reboot-qsg-impress-support-Desktop-Default/po/com.ubuntu.docviewer.desktop.in.in.h:1
23msgid "Document Viewer"23msgid "Document Viewer"
24msgstr ""24msgstr ""
2525
@@ -255,7 +255,7 @@
255255
256#: ../src/app/qml/documentPage/DocumentPageSearchHeader.qml:27256#: ../src/app/qml/documentPage/DocumentPageSearchHeader.qml:27
257#: ../src/app/qml/loView/LOViewDefaultHeader.qml:80257#: ../src/app/qml/loView/LOViewDefaultHeader.qml:80
258#: ../src/app/qml/loView/LOViewPage.qml:186258#: ../src/app/qml/loView/LOViewPage.qml:191
259#: ../src/app/qml/pdfView/PdfViewDefaultHeader.qml:61259#: ../src/app/qml/pdfView/PdfViewDefaultHeader.qml:61
260#: ../src/app/qml/textView/TextViewDefaultHeader.qml:61260#: ../src/app/qml/textView/TextViewDefaultHeader.qml:61
261msgid "Back"261msgid "Back"
@@ -368,8 +368,8 @@
368msgid "GO!"368msgid "GO!"
369msgstr ""369msgstr ""
370370
371#: ../src/app/qml/loView/LOViewPage.qml:41371#: ../src/app/qml/loView/LOViewPage.qml:34
372#: ../src/app/qml/loView/LOViewPage.qml:184372#: ../src/app/qml/loView/LOViewPage.qml:189
373msgid "Slides"373msgid "Slides"
374msgstr ""374msgstr ""
375375
@@ -385,6 +385,11 @@
385msgid "Zoom out"385msgid "Zoom out"
386msgstr ""386msgstr ""
387387
388#: ../src/app/qml/loView/SlideControllerPanel.qml:62
389#, qt-format
390msgid "Slide %1 of %2"
391msgstr ""
392
388#: ../src/app/qml/loView/ZoomSelector.qml:29393#: ../src/app/qml/loView/ZoomSelector.qml:29
389msgid "Automatic (Fit width)"394msgid "Automatic (Fit width)"
390msgstr ""395msgstr ""
@@ -443,6 +448,6 @@
443msgid "copy %1"448msgid "copy %1"
444msgstr ""449msgstr ""
445450
446#: /tmp/build-reboot-lok-qsg-zoom-Desktop-Default/po/com.ubuntu.docviewer.desktop.in.in.h:2451#: /tmp/build-reboot-qsg-impress-support-Desktop-Default/po/com.ubuntu.docviewer.desktop.in.in.h:2
447msgid "documents;viewer;pdf;reader;"452msgid "documents;viewer;pdf;reader;"
448msgstr ""453msgstr ""
449454
=== modified file 'src/app/qml/loView/KeybHelper.js'
--- src/app/qml/loView/KeybHelper.js 2015-09-15 18:20:00 +0000
+++ src/app/qml/loView/KeybHelper.js 2015-10-10 12:33:09 +0000
@@ -16,42 +16,129 @@
16 16
17function parseEvent(event) {17function parseEvent(event) {
18 var pixelDiff = 5;18 var pixelDiff = 5;
19 19
20 var view = loPageContentLoader.item.loView
21 var isPresentation = view.document.documentType === LO.Document.PresentationDocument
22
20 if (event.key == Qt.Key_PageUp) {23 if (event.key == Qt.Key_PageUp) {
21 if (loDocument.documentType == LO.Document.PresentationDocument)24 if (isPresentation)
22 loDocument.currentPart -= 125 view.document.currentPart -= 1
23 else26 else
24 loPage.moveView("vertical", -loView.height)27 view.moveView("vertical", -view.height)
25 28
26 return;29 return;
27 }30 }
28 31
29 if (event.key == Qt.Key_PageDown) {32 if (event.key == Qt.Key_PageDown) {
30 if (loDocument.documentType == LO.Document.PresentationDocument)33 if (isPresentation)
31 loDocument.currentPart += 134 view.document.currentPart += 1
32 else35 else
33 loPage.moveView("vertical", loView.height)36 view.moveView("vertical", view.height)
34 37
35 return;38 return;
36 }39 }
37 40
41 if (event.key == Qt.Key_Home) {
42 if (event.modifiers & Qt.ControlModifier) {
43 view.contentX = 0
44 view.contentY = 0
45 view.document.currentPart = 0
46 } else {
47 view.contentX = 0
48 view.contentY = 0
49 }
50 }
51
52 if (event.key == Qt.Key_End) {
53 if (event.modifiers & Qt.ControlModifier) {
54 view.contentX = view.contentWidth - view.width
55 view.contentY = view.contentHeight - view.height
56 console.log(view.document.currentPart, view.document.partsCount - 1)
57 view.document.currentPart = view.document.partsCount - 1
58 } else {
59 view.contentX = view.contentWidth - view.width
60 view.contentY = view.contentHeight - view.height
61 }
62 }
63
38 if (event.key == Qt.Key_Up) {64 if (event.key == Qt.Key_Up) {
39 loPage.moveView("vertical", -pixelDiff)65 view.moveView("vertical", -pixelDiff)
40 return;66 return;
41 }67 }
42 68
43 if (event.key == Qt.Key_Down) {69 if (event.key == Qt.Key_Down) {
44 loPage.moveView("vertical", pixelDiff)70 view.moveView("vertical", pixelDiff)
45 return;71 return;
46 }72 }
47 73
48 if (event.key == Qt.Key_Left) {74 if (event.key == Qt.Key_Left) {
49 loPage.moveView("horizontal", -pixelDiff)75 view.moveView("horizontal", -pixelDiff)
50 return;76 return;
51 }77 }
52 78
53 if (event.key == Qt.Key_Right) {79 if (event.key == Qt.Key_Right) {
54 loPage.moveView("horizontal", pixelDiff)80 view.moveView("horizontal", pixelDiff)
55 return;81 return;
56 }82 }
83
84 if (event.key == Qt.Key_Plus) {
85 if (event.modifiers & Qt.ControlModifier) {
86 view.zoomFactor = Math.max(4.0, view.zoomFactor + 0.25)
87 }
88 }
89
90 if (event.key == Qt.Key_Minus) {
91 if (event.modifiers & Qt.ControlModifier) {
92 view.zoomFactor = Math.min(0.5, view.zoomFactor - 0.25)
93 }
94 }
95
96
97 /*
98 if (event.key == Qt.Key_C) {
99 if (event.modifiers & Qt.ControlModifier) {
100
101 }
102 }
103 */
104
105 /*
106 if (event.key == Qt.Key_X) {
107 if (event.modifiers & Qt.ControlModifier) {
108
109 }
110 }
111 */
112
113 /*
114 if (event.key == Qt.Key_V) {
115 if (event.modifiers & Qt.ControlModifier) {
116
117 }
118 }
119 */
120
121 /*
122 if (event.key == Qt.Key_A) {
123 if (event.modifiers & Qt.ControlModifier) {
124
125 }
126 }
127 */
128
129 /*
130 if (event.key == Qt.Key_L) {
131 if (event.modifiers & Qt.ControlModifier) {
132 // TODO: Go to page dialog
133 }
134 }
135 */
136
137 /*
138 if (event.key == Qt.Key_Question) {
139 if (event.modifiers & (Qt.ControlModifier | Qt.ShiftModifier)) {
140 // TODO: Keyboard shortcuts
141 }
142 }
143 */
57}144}
58145
=== modified file 'src/app/qml/loView/LOViewPage.qml'
--- src/app/qml/loView/LOViewPage.qml 2015-09-22 19:02:46 +0000
+++ src/app/qml/loView/LOViewPage.qml 2015-10-10 12:33:09 +0000
@@ -31,6 +31,7 @@
3131
32 readonly property bool wideWindow: width > units.gu(120)32 readonly property bool wideWindow: width > units.gu(120)
3333
34 bottomEdgeTitle: i18n.tr("Slides")
34 bottomEdgeEnabled: {35 bottomEdgeEnabled: {
35 if (!loPageContentLoader.loaded)36 if (!loPageContentLoader.loaded)
36 return false37 return false
@@ -38,7 +39,6 @@
38 // else39 // else
39 return loPageContentLoader.item.loDocument.documentType == LO.Document.PresentationDocument && !wideWindow40 return loPageContentLoader.item.loDocument.documentType == LO.Document.PresentationDocument && !wideWindow
40 }41 }
41 bottomEdgeTitle: i18n.tr("Slides")
4242
43 Loader {43 Loader {
44 id: loPageContentLoader44 id: loPageContentLoader
@@ -70,23 +70,14 @@
70 Component {70 Component {
71 id: loPageContentComponent71 id: loPageContentComponent
7272
73 Item {73 FocusScope {
74 id: loPageContent74 id: loPageContent
75 anchors.fill: parent75 anchors.fill: parent
76
76 property alias loDocument: loView.document77 property alias loDocument: loView.document
77 property alias loView: loView78 property alias loView: loView
78 property alias bottomEdgePartsPage: bottomEdgePartsPage79 property alias bottomEdgePartsPage: bottomEdgePartsPage
7980
80 function moveView(axis, diff) {
81 if (axis == "vertical") {
82 var maxContentY = Math.max(0, loView.contentHeight - loView.height)
83 loView.contentY = Math.max(0, Math.min(loView.contentY + diff, maxContentY ))
84 } else {
85 var maxContentX = Math.max(0, loView.contentWidth - loView.width)
86 loView.contentX = Math.max(0, Math.min(loView.contentX + diff, maxContentX ))
87 }
88 }
89
90 Layouts {81 Layouts {
91 id: layouts82 id: layouts
92 anchors.fill: parent83 anchors.fill: parent
@@ -108,8 +99,8 @@
108 left: parent.left99 left: parent.left
109 }100 }
110101
111 model: partsModel102 model: LO.PartsModel { document: loPageContent.loDocument }
112 visible: model103 visible: model && loDocument.documentType == LO.Document.PresentationDocument
113 width: visible ? units.gu(40) : 0104 width: visible ? units.gu(40) : 0
114 }105 }
115106
@@ -120,7 +111,16 @@
120 top: parent.top111 top: parent.top
121 bottom: bottomBarLayoutItem.top112 bottom: bottomBarLayoutItem.top
122 }113 }
123 ItemLayout { item: "loView"; anchors.fill: parent }114
115 ItemLayout {
116 item: "loView"
117 anchors.fill: parent
118
119 // Keyboard events
120 focus: true
121 Keys.onPressed: KeybHelper.parseEvent(event)
122 Component.onCompleted: loPageContent.forceActiveFocus()
123 }
124 }124 }
125125
126 Item {126 Item {
@@ -153,10 +153,15 @@
153 clip: true153 clip: true
154 documentPath: file.path154 documentPath: file.path
155155
156 // Keyboard events
157 focus: true
158 Keys.onPressed: KeybHelper.parseEvent(event)
159
156 Component.onCompleted: {160 Component.onCompleted: {
157 // WORKAROUND: Fix for wrong grid unit size161 // WORKAROUND: Fix for wrong grid unit size
158 flickDeceleration = 1500 * units.gridUnit / 8162 flickDeceleration = 1500 * units.gridUnit / 8
159 maximumFlickVelocity = 2500 * units.gridUnit / 8163 maximumFlickVelocity = 2500 * units.gridUnit / 8
164 loPageContent.forceActiveFocus()
160 }165 }
161166
162 Scrollbar { flickableItem: loView; parent: loView.parent }167 Scrollbar { flickableItem: loView; parent: loView.parent }
@@ -191,6 +196,7 @@
191 flickable: null196 flickable: null
192197
193 PartsView {198 PartsView {
199 property bool belongsToNestedPage: true
194 anchors.fill: parent200 anchors.fill: parent
195 model: LO.PartsModel { document: loPageContent.loDocument }201 model: LO.PartsModel { document: loPageContent.loDocument }
196 }202 }
197203
=== modified file 'src/app/qml/loView/PartsView.qml'
--- src/app/qml/loView/PartsView.qml 2015-09-15 18:20:00 +0000
+++ src/app/qml/loView/PartsView.qml 2015-10-10 12:33:09 +0000
@@ -29,6 +29,7 @@
29 property bool expanded: true29 property bool expanded: true
3030
31 currentIndex: view.model ? view.model.document.currentPart : -131 currentIndex: view.model ? view.model.document.currentPart : -1
32 highlightMoveDuration: UbuntuAnimation.SnapDuration
3233
33 delegate: ListItemWithActions {34 delegate: ListItemWithActions {
34 id: delegate35 id: delegate
@@ -45,7 +46,12 @@
4546
46 onClicked: {47 onClicked: {
47 view.model.document.currentPart = model.index48 view.model.document.currentPart = model.index
48 pageStack.pop();49
50 // Check if the view has been included in a nested page (e.g.
51 // bottomEdge). If so, close that page and return to the
52 // main viewer.
53 if (view.hasOwnProperty("belongsToNestedPage"))
54 pageStack.pop();
49 }55 }
50 }56 }
5157
@@ -57,6 +63,9 @@
57 Layout.fillHeight: true63 Layout.fillHeight: true
58 Layout.preferredWidth: height64 Layout.preferredWidth: height
59 fillMode: Image.PreserveAspectFit65 fillMode: Image.PreserveAspectFit
66 // Do not store a cache of the thumbnail, so that we don't show
67 // thumbnails of a previously loaded document.
68 cache: false
6069
61 source: "image://lok/part/" + model.index70 source: "image://lok/part/" + model.index
62 }71 }
6372
=== modified file 'src/app/qml/loView/SlideControllerPanel.qml'
--- src/app/qml/loView/SlideControllerPanel.qml 2015-09-22 19:02:46 +0000
+++ src/app/qml/loView/SlideControllerPanel.qml 2015-10-10 12:33:09 +0000
@@ -34,14 +34,24 @@
3434
35 Row {35 Row {
36 anchors.centerIn: parent36 anchors.centerIn: parent
37 spacing: units.gu(2)37 //spacing: units.gu(2)
3838
39 AbstractButton {39 AbstractButton {
40 width: units.gu(4); height: parent.height40 width: units.gu(4); height: parent.height
41 onClicked: loPageContentLoader.item.loDocument.currentPart -= 141 onClicked: loPageContentLoader.item.loView.goFirstPart()
4242
43 Icon {43 Icon {
44 id: icon44 anchors.centerIn: parent
45 width: units.gu(2.5); height: width
46 name: "go-first"
47 }
48 }
49
50 AbstractButton {
51 width: units.gu(4); height: parent.height
52 onClicked: loPageContentLoader.item.loView.goPreviousPart()
53
54 Icon {
45 anchors.centerIn: parent55 anchors.centerIn: parent
46 width: units.gu(2.5); height: width56 width: units.gu(2.5); height: width
47 name: "go-previous"57 name: "go-previous"
@@ -49,13 +59,12 @@
49 }59 }
5060
51 Label {61 Label {
52 text: "%1 of %2".arg(loPageContentLoader.item.loDocument.currentPart + 1)62 text: i18n.tr("Slide %1 of %2").arg(loPageContentLoader.item.loDocument.currentPart + 1).arg(loPageContentLoader.item.loDocument.partsCount)
53 .arg(loPageContentLoader.item.loDocument.partsCount)
54 }63 }
5564
56 AbstractButton {65 AbstractButton {
57 width: units.gu(4); height: parent.height66 width: units.gu(4); height: parent.height
58 onClicked: loPageContentLoader.item.loDocument.currentPart += 167 onClicked: loPageContentLoader.item.loView.goNextPart()
5968
60 Icon {69 Icon {
61 anchors.centerIn: parent70 anchors.centerIn: parent
@@ -63,5 +72,16 @@
63 name: "go-next"72 name: "go-next"
64 }73 }
65 }74 }
75
76 AbstractButton {
77 width: units.gu(4); height: parent.height
78 onClicked: loPageContentLoader.item.loView.goLastPart()
79
80 Icon {
81 anchors.centerIn: parent
82 width: units.gu(2.5); height: width
83 name: "go-last"
84 }
85 }
66 }86 }
67}87}
6888
=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/lodocument.cpp'
--- src/plugin/libreofficetoolkit-qml-plugin/lodocument.cpp 2015-09-22 19:02:46 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/lodocument.cpp 2015-10-10 12:33:09 +0000
@@ -36,6 +36,7 @@
3636
37LODocument::LODocument()37LODocument::LODocument()
38 : m_path("")38 : m_path("")
39 , m_currentPart(-1)
39 , m_document(nullptr)40 , m_document(nullptr)
40{41{
41 // This space is intentionally empty.42 // This space is intentionally empty.
@@ -61,21 +62,18 @@
61}62}
6263
63int LODocument::currentPart() {64int LODocument::currentPart() {
64 if (!m_document)65 return m_currentPart;
65 return int(-1);
66
67 return m_document->getPart();
68}66}
69 67
70void LODocument::setCurrentPart(int index)68void LODocument::setCurrentPart(int index)
71{69{
72 if (!m_document)70 if (!m_document)
73 return;71 return;
74 72
75 if (this->currentPart() == index || index < 0 || index > partsCount() - 1)73 if (m_currentPart == index || index < 0 || index > partsCount() - 1)
76 return;74 return;
77 75
78 m_document->setPart(index);76 m_currentPart = index;
79 Q_EMIT currentPartChanged();77 Q_EMIT currentPartChanged();
80}78}
8179
@@ -97,6 +95,8 @@
97 m_docType = DocumentType(m_document->getDocumentType());95 m_docType = DocumentType(m_document->getDocumentType());
98 Q_EMIT documentTypeChanged();96 Q_EMIT documentTypeChanged();
9997
98 setCurrentPart(m_document->getPart());
99
100 m_document->initializeForRendering();100 m_document->initializeForRendering();
101 qDebug() << "Document loaded successfully !";101 qDebug() << "Document loaded successfully !";
102102
@@ -127,6 +127,12 @@
127// the rect tileSize.127// the rect tileSize.
128QImage LODocument::paintTile(const QSize& canvasSize, const QRect& tileSize, const qreal &zoom)128QImage LODocument::paintTile(const QSize& canvasSize, const QRect& tileSize, const qreal &zoom)
129{129{
130 if (!m_document)
131 return QImage();
132
133 if (m_currentPart != m_document->getPart())
134 m_document->setPart(m_currentPart);
135
130 QImage result = QImage(canvasSize.width(), canvasSize.height(), QImage::Format_RGB32);136 QImage result = QImage(canvasSize.width(), canvasSize.height(), QImage::Format_RGB32);
131137
132#ifdef DEBUG_TILE_BENCHMARK138#ifdef DEBUG_TILE_BENCHMARK
@@ -148,6 +154,52 @@
148 return result.rgbSwapped();154 return result.rgbSwapped();
149}155}
150156
157QImage LODocument::paintThumbnail(int part, qreal size)
158{
159 if (!m_document)
160 return QImage();
161
162#ifdef DEBUG_TILE_BENCHMARK
163 QElapsedTimer renderTimer;
164 renderTimer.start();
165#endif
166
167 // This is used by LOPartsImageProvider to temporarily change the current part,
168 // in order to generate thumbnails.
169
170 // FIXME: Sometimes docviewer crashes at m_document->getPart() when a
171 // document is being loaded.
172 if (m_document->getPart() != part)
173 m_document->setPart(part);
174
175 qreal tWidth = this->documentSize().width();
176 qreal tHeight = this->documentSize().height();
177
178 QSize resultSize;
179
180 if (tWidth > tHeight) {
181 resultSize.setWidth(size);
182 resultSize.setHeight(size * tHeight / tWidth);
183 } else {
184 resultSize.setHeight(size);
185 resultSize.setWidth(size * tWidth / tHeight);
186 }
187
188 QImage result = QImage(resultSize.width(), resultSize.height(), QImage::Format_RGB32);
189 m_document->paintTile(result.bits(), resultSize.width(), resultSize.height(),
190 0, 0, tWidth, tHeight);
191
192 // Restore the active part used for tile rendering.
193 if (m_currentPart != part)
194 m_document->setPart(m_currentPart);
195
196#ifdef DEBUG_TILE_BENCHMARK
197 qDebug() << "Time to render the thumbnail:" << renderTimer.elapsed() << "ms";
198#endif
199
200 return result.rgbSwapped();
201}
202
151int LODocument::partsCount()203int LODocument::partsCount()
152{204{
153 if (!m_document)205 if (!m_document)
@@ -161,20 +213,9 @@
161 if (!m_document)213 if (!m_document)
162 return QString();214 return QString();
163 215
164 return QString::fromLatin1(m_document->getPartName(index));216 return QString::fromUtf8(m_document->getPartName(index));
165}217}
166 218
167// This is used by LOPartsImageProvider to temporarily change the current part,
168// in order to generate thumbnails.
169// FIXME: We need to disable tiled rendering when we're generating the thumbnail.
170int LODocument::swapCurrentPart(int newPartIndex)
171{
172 int oldIndex = this->currentPart();
173
174 m_document->setPart(newPartIndex);
175 return oldIndex;
176}
177
178/* Export the file in a given format:219/* Export the file in a given format:
179 * - url is a mandatory argument.220 * - url is a mandatory argument.
180 * - format is optional. If not specified, lok will try to get it from the file221 * - format is optional. If not specified, lok will try to get it from the file
181222
=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/lodocument.h'
--- src/plugin/libreofficetoolkit-qml-plugin/lodocument.h 2015-09-22 19:02:46 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/lodocument.h 2015-10-10 12:33:09 +0000
@@ -60,12 +60,10 @@
60 QSize documentSize() const;60 QSize documentSize() const;
6161
62 QImage paintTile(const QSize& canvasSize, const QRect& tileSize, const qreal& zoom = 1.0);62 QImage paintTile(const QSize& canvasSize, const QRect& tileSize, const qreal& zoom = 1.0);
63 QImage paintThumbnail(int part, qreal size);
6364
64 int partsCount();65 int partsCount();
65
66 QString getPartName(int index) const;66 QString getPartName(int index) const;
67 int swapCurrentPart(int newPartIndex);
68
69 void setPart(int index);67 void setPart(int index);
7068
71 Q_INVOKABLE bool saveAs(QString url, QString format, QString filterOptions);69 Q_INVOKABLE bool saveAs(QString url, QString format, QString filterOptions);
@@ -77,6 +75,7 @@
7775
78private:76private:
79 QString m_path;77 QString m_path;
78 int m_currentPart;
80 DocumentType m_docType;79 DocumentType m_docType;
8180
82 bool loadDocument(const QString &pathNAme);81 bool loadDocument(const QString &pathNAme);
8382
=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/lopartsimageprovider.cpp'
--- src/plugin/libreofficetoolkit-qml-plugin/lopartsimageprovider.cpp 2015-09-22 19:02:46 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/lopartsimageprovider.cpp 2015-10-10 12:33:09 +0000
@@ -16,62 +16,35 @@
1616
17#include "lopartsimageprovider.h"17#include "lopartsimageprovider.h"
18#include "lodocument.h"18#include "lodocument.h"
19#include "config.h"19#include "renderengine.h"
20#include "twips.h"
21
22#include <QDebug>
2320
24LOPartsImageProvider::LOPartsImageProvider(LODocument *document)21LOPartsImageProvider::LOPartsImageProvider(LODocument *document)
25 : QQuickImageProvider(QQuickImageProvider::Image, QQuickImageProvider::ForceAsynchronousImageLoading)22 : QQuickImageProvider(QQuickImageProvider::Image, QQuickImageProvider::ForceAsynchronousImageLoading)
26{23 , m_document(document)
27 m_document = document;24{ }
28}
2925
30QImage LOPartsImageProvider::requestImage(const QString & id, QSize * size, const QSize & requestedSize)26QImage LOPartsImageProvider::requestImage(const QString & id, QSize * size, const QSize & requestedSize)
31{27{
32 Q_UNUSED(size)28 Q_UNUSED(size)
33 Q_UNUSED(requestedSize)29
34
35 if (m_document->documentType() != LODocument::PresentationDocument)
36 return QImage();
37
38 // Here's the tricky magic. For getting a thumbnail of a document part
39 // (e.g. a specific slide in a Impress document), we need to change the
40 // current active part in LODocument, render the thumbnail, then re-set
41 // the previous value through lok::Document::setPath(index).
42 QString type = id.section("/", 0, 0);30 QString type = id.section("/", 0, 0);
4331
44 if (type != "part")32 if (requestedSize.isNull() || type != "part" ||
33 m_document->documentType() != LODocument::PresentationDocument)
45 return QImage();34 return QImage();
4635
36 // Wait for any in-progress rendering to be completed
37 while (RenderEngine::instance()->activeTaskCount() != 0) { }
38
39 // Lock the render engine
40 RenderEngine::instance()->setEnabled(false);
41
42 // Render the part to QImage
47 int partNumber = id.section("/", 1, 1).toInt();43 int partNumber = id.section("/", 1, 1).toInt();
48 QImage result;44 QImage result = m_document->paintThumbnail(partNumber, 256.0);
49 QSize partSize;45
50 QSize resultSize;46 // Unlock the render engine
5147 RenderEngine::instance()->setEnabled(true);
52 // Get the current part index and set the index of the part to be rendered.
53 int currentPart = m_document->swapCurrentPart(partNumber);
54
55 // Get the size of the part
56 partSize = m_document->documentSize();
57 partSize.setHeight(Twips::convertTwipsToPixels(partSize.height()));
58 partSize.setWidth(Twips::convertTwipsToPixels(partSize.width()));
59
60 // Set the size of the rendered thumbnail
61 if (partSize.width() > partSize.height()) {
62 resultSize.setWidth(TILE_SIZE);
63 resultSize.setHeight(TILE_SIZE * partSize.height() / partSize.width());
64 } else {
65 resultSize.setHeight(TILE_SIZE);
66 resultSize.setWidth(TILE_SIZE * partSize.width() / partSize.height());
67 }
68
69 // Render the part to QImage
70 result = m_document->paintTile(resultSize, QRect(QPoint(0, 0), partSize));
71
72 // Re-set the earlier current part
73 m_document->swapCurrentPart(currentPart);
7448
75 return result;49 return result;
76
77}50}
7851
=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/lopartsmodel.cpp'
--- src/plugin/libreofficetoolkit-qml-plugin/lopartsmodel.cpp 2015-09-15 18:20:00 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/lopartsmodel.cpp 2015-10-10 12:33:09 +0000
@@ -111,9 +111,9 @@
111 part.index = i;111 part.index = i;
112 part.name = m_document->getPartName(i);112 part.name = m_document->getPartName(i);
113113
114 beginRemoveRows(QModelIndex(), rowCount(), rowCount());114 beginInsertRows(QModelIndex(), rowCount(), rowCount());
115 m_entries.append(part);115 m_entries.append(part);
116 endRemoveRows();116 endInsertRows();
117 }117 }
118118
119 Q_EMIT countChanged();119 Q_EMIT countChanged();
120120
=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/qml/Viewer.qml'
--- src/plugin/libreofficetoolkit-qml-plugin/qml/Viewer.qml 2015-09-22 00:01:22 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/qml/Viewer.qml 2015-10-10 12:33:09 +0000
@@ -32,6 +32,37 @@
32 view.adjustZoomToWidth();32 view.adjustZoomToWidth();
33 }33 }
3434
35 function moveView(axis, diff)
36 {
37 if (axis == "vertical") {
38 var maxContentY = Math.max(0, rootFlickable.contentHeight - rootFlickable.height)
39 rootFlickable.contentY = Math.max(0, Math.min(rootFlickable.contentY + diff, maxContentY ))
40 } else {
41 var maxContentX = Math.max(0, rootFlickable.contentWidth - rootFlickable.width)
42 rootFlickable.contentX = Math.max(0, Math.min(rootFlickable.contentX + diff, maxContentX ))
43 }
44 }
45
46 function goNextPart()
47 {
48 document.currentPart = Math.min(document.currentPart + 1, document.partsCount - 1)
49 }
50
51 function goPreviousPart()
52 {
53 document.currentPart = Math.max(0, document.currentPart - 1)
54 }
55
56 function goFirstPart()
57 {
58 document.currentPart = 0
59 }
60
61 function goLastPart()
62 {
63 document.currentPart = document.partsCount - 1
64 }
65
35 onDocumentPathChanged: {66 onDocumentPathChanged: {
36 if (documentPath)67 if (documentPath)
37 view.initializeDocument(documentPath)68 view.initializeDocument(documentPath)
@@ -51,4 +82,14 @@
5182
52 parentFlickable: rootFlickable83 parentFlickable: rootFlickable
53 }84 }
85
86 Connections {
87 target: view.document
88
89 onCurrentPartChanged: {
90 // Position view at top-left corner
91 rootFlickable.contentX = 0
92 rootFlickable.contentY = 0
93 }
94 }
54}95}
5596
=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/renderengine.cpp'
--- src/plugin/libreofficetoolkit-qml-plugin/renderengine.cpp 2015-09-22 00:01:22 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/renderengine.cpp 2015-10-10 12:33:09 +0000
@@ -6,10 +6,13 @@
66
7RenderEngine::RenderEngine():7RenderEngine::RenderEngine():
8 QObject(nullptr),8 QObject(nullptr),
9 m_activeTaskCount(0)9 m_activeTaskCount(0),
10 m_enabled(true)
10{11{
11 int itc = QThread::idealThreadCount();12 int itc = QThread::idealThreadCount();
12 m_idealThreadCount = itc == -1 ? DefaultIdealThreadCount : itc;13 m_idealThreadCount = itc == -1 ? DefaultIdealThreadCount : itc;
14
15 connect(this, SIGNAL(enabledChanged()), this, SLOT(doNextTask()));
13}16}
1417
15void RenderEngine::enqueueTask(const QSharedPointer<LODocument>& doc, const QRect& area, const qreal &zoom, int id)18void RenderEngine::enqueueTask(const QSharedPointer<LODocument>& doc, const QRect& area, const qreal &zoom, int id)
@@ -43,7 +46,7 @@
43 qDebug() << " ---- doNextTask" << m_activeTaskCount << m_queue.count();46 qDebug() << " ---- doNextTask" << m_activeTaskCount << m_queue.count();
44#endif47#endif
4548
46 if (m_activeTaskCount >= m_idealThreadCount || !m_queue.count())49 if (m_activeTaskCount >= m_idealThreadCount || !m_queue.count() || !m_enabled)
47 return;50 return;
4851
49 m_activeTaskCount++;52 m_activeTaskCount++;
5053
=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/renderengine.h'
--- src/plugin/libreofficetoolkit-qml-plugin/renderengine.h 2015-09-22 00:01:22 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/renderengine.h 2015-10-10 12:33:09 +0000
@@ -6,6 +6,7 @@
6#include <QSharedPointer>6#include <QSharedPointer>
7#include <QHash>7#include <QHash>
8#include <QQueue>8#include <QQueue>
9#include <QAtomicInt>
910
10#include "lodocument.h"11#include "lodocument.h"
1112
@@ -45,17 +46,33 @@
45 return s_instance;46 return s_instance;
46 }47 }
4748
49 int activeTaskCount() { return m_activeTaskCount; }
50
51 bool enabled() { return m_enabled.loadAcquire(); }
52 void setEnabled(bool enabled) {
53 if (m_enabled.loadAcquire() == enabled)
54 return;
55
56 m_enabled.storeRelease(enabled);
57 Q_EMIT enabledChanged();
58 }
59
48Q_SIGNALS:60Q_SIGNALS:
49 void renderFinished(int id, QImage img);61 void renderFinished(int id, QImage img);
62 void enabledChanged();
5063
51private:64private:
52 Q_INVOKABLE void internalRenderCallback(int id, QImage img);65 Q_INVOKABLE void internalRenderCallback(int id, QImage img);
66
67private slots:
53 void doNextTask();68 void doNextTask();
5469
55private:70private:
56 QQueue<EngineTask> m_queue;71 QQueue<EngineTask> m_queue;
57 int m_activeTaskCount;72 int m_activeTaskCount;
58 int m_idealThreadCount;73 int m_idealThreadCount;
74
75 QAtomicInt m_enabled;
59};76};
6077
61#endif // RENDERENGINE_H78#endif // RENDERENGINE_H

Subscribers

People subscribed via source and target branches