ubuntu-touch-coreapps-reviewers team mailing list archive
-
ubuntu-touch-coreapps-reviewers team
-
Mailing list archive
-
Message #05195
[Merge] lp:~mrqtros/ubuntu-docviewer-app/reboot-qsg-impress-support into lp:ubuntu-docviewer-app/reboot
Roman Shchekin has proposed merging lp:~mrqtros/ubuntu-docviewer-app/reboot-qsg-impress-support into lp:ubuntu-docviewer-app/reboot.
Commit message:
RenderEngine - impress support.
Requested reviews:
Ubuntu Document Viewer Developers (ubuntu-docviewer-dev)
For more details, see:
https://code.launchpad.net/~mrqtros/ubuntu-docviewer-app/reboot-qsg-impress-support/+merge/273922
RenderEngine - impress support.
--
Your team Ubuntu Document Viewer Developers is requested to review the proposed merge of lp:~mrqtros/ubuntu-docviewer-app/reboot-qsg-impress-support into lp:ubuntu-docviewer-app/reboot.
=== modified file 'po/com.ubuntu.docviewer.pot'
--- po/com.ubuntu.docviewer.pot 2015-09-30 23:56:04 +0000
+++ po/com.ubuntu.docviewer.pot 2015-10-08 21:01:04 +0000
@@ -8,7 +8,11 @@
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
+<<<<<<< TREE
"POT-Creation-Date: 2015-10-01 01:55+0200\n"
+=======
+"POT-Creation-Date: 2015-10-08 23:48+0300\n"
+>>>>>>> MERGE-SOURCE
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@xxxxxx>\n"
@@ -19,7 +23,11 @@
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
#: ../src/app/docviewer-application.cpp:162
+<<<<<<< TREE
#: /tmp/build-reboot-lok-goto-dialog-Desktop-Default/po/com.ubuntu.docviewer.desktop.in.in.h:1
+=======
+#: /home/qtros/dev/build-reboot-qsg-impress-support-Desktop-Default/po/com.ubuntu.docviewer.desktop.in.in.h:1
+>>>>>>> MERGE-SOURCE
msgid "Document Viewer"
msgstr ""
@@ -63,7 +71,11 @@
#: ../src/app/qml/common/RejectedImportDialog.qml:38
#: ../src/app/qml/documentPage/DocumentPageSelectionModeHeader.qml:32
#: ../src/app/qml/documentPage/SortSettingsDialog.qml:53
+<<<<<<< TREE
#: ../src/app/qml/loView/LOViewDefaultHeader.qml:77
+=======
+#: ../src/app/qml/loView/LOViewDefaultHeader.qml:79
+>>>>>>> MERGE-SOURCE
#: ../src/app/qml/pdfView/PdfViewDefaultHeader.qml:61
#: ../src/app/qml/textView/TextViewDefaultHeader.qml:61
msgid "Close"
@@ -151,7 +163,10 @@
#: ../src/app/qml/documentPage/DeleteFileDialog.qml:44
#: ../src/app/qml/documentPage/DocumentPagePickModeHeader.qml:28
+<<<<<<< TREE
#: ../src/app/qml/loView/LOViewGotoDialog.qml:54
+=======
+>>>>>>> MERGE-SOURCE
#: ../src/app/qml/pdfView/PdfViewGotoDialog.qml:52
msgid "Cancel"
msgstr ""
@@ -254,7 +269,12 @@
msgstr ""
#: ../src/app/qml/documentPage/DocumentPageSearchHeader.qml:27
+<<<<<<< TREE
#: ../src/app/qml/loView/LOViewDefaultHeader.qml:77
+=======
+#: ../src/app/qml/loView/LOViewDefaultHeader.qml:79
+#: ../src/app/qml/loView/LOViewPage.qml:191
+>>>>>>> MERGE-SOURCE
#: ../src/app/qml/pdfView/PdfViewDefaultHeader.qml:61
#: ../src/app/qml/textView/TextViewDefaultHeader.qml:61
msgid "Back"
@@ -305,32 +325,71 @@
msgid "Reverse order"
msgstr ""
+<<<<<<< TREE
#: ../src/app/qml/loView/LOViewDefaultHeader.qml:58
+=======
+#: ../src/app/qml/loView/LOViewDefaultHeader.qml:56
+#: ../src/app/qml/textView/TextView.qml:42
+msgid "Loading..."
+msgstr ""
+
+#: ../src/app/qml/loView/LOViewDefaultHeader.qml:60
+>>>>>>> MERGE-SOURCE
msgid "LibreOffice text document"
msgstr ""
+<<<<<<< TREE
#: ../src/app/qml/loView/LOViewDefaultHeader.qml:60
+=======
+#: ../src/app/qml/loView/LOViewDefaultHeader.qml:62
+>>>>>>> MERGE-SOURCE
msgid "LibreOffice spread sheet"
msgstr ""
+<<<<<<< TREE
#: ../src/app/qml/loView/LOViewDefaultHeader.qml:62
+=======
+#: ../src/app/qml/loView/LOViewDefaultHeader.qml:64
+>>>>>>> MERGE-SOURCE
msgid "LibreOffice presentation"
msgstr ""
+<<<<<<< TREE
#: ../src/app/qml/loView/LOViewDefaultHeader.qml:64
+=======
+#: ../src/app/qml/loView/LOViewDefaultHeader.qml:66
+>>>>>>> MERGE-SOURCE
msgid "LibreOffice Draw document"
msgstr ""
+<<<<<<< TREE
#: ../src/app/qml/loView/LOViewDefaultHeader.qml:66
+=======
+#: ../src/app/qml/loView/LOViewDefaultHeader.qml:68
+>>>>>>> MERGE-SOURCE
msgid "Unknown LibreOffice document"
msgstr ""
+<<<<<<< TREE
#: ../src/app/qml/loView/LOViewDefaultHeader.qml:68
+=======
+#: ../src/app/qml/loView/LOViewDefaultHeader.qml:70
+>>>>>>> MERGE-SOURCE
msgid "Unknown type document"
msgstr ""
+<<<<<<< TREE
#: ../src/app/qml/loView/LOViewDefaultHeader.qml:101
msgid "Go to position..."
+=======
+#: ../src/app/qml/loView/LOViewDefaultHeader.qml:95
+msgid "Show zoom controls"
+msgstr ""
+
+#: ../src/app/qml/loView/LOViewDefaultHeader.qml:102
+#: ../src/app/qml/pdfView/PdfViewDefaultHeader.qml:85
+msgid "Go to page..."
+>>>>>>> MERGE-SOURCE
msgstr ""
#: ../src/app/qml/loView/LOViewDefaultHeader.qml:108
@@ -345,6 +404,7 @@
msgid "Enable night mode"
msgstr ""
+<<<<<<< TREE
#: ../src/app/qml/loView/LOViewGotoDialog.qml:27
msgid "Go to position"
msgstr ""
@@ -356,6 +416,42 @@
#: ../src/app/qml/loView/LOViewGotoDialog.qml:46
#: ../src/app/qml/pdfView/PdfViewGotoDialog.qml:44
msgid "GO!"
+=======
+#: ../src/app/qml/loView/LOViewPage.qml:34
+#: ../src/app/qml/loView/LOViewPage.qml:189
+msgid "Slides"
+msgstr ""
+
+#: ../src/app/qml/loView/LOViewZoomHeader.qml:42
+msgid "Hide zoom controls"
+msgstr ""
+
+#: ../src/app/qml/loView/LOViewZoomHeader.qml:49
+msgid "Zoom in"
+msgstr ""
+
+#: ../src/app/qml/loView/LOViewZoomHeader.qml:55
+msgid "Zoom out"
+msgstr ""
+
+#: ../src/app/qml/loView/SlideControllerPanel.qml:62
+#, qt-format
+msgid "Slide %1 of %2"
+msgstr ""
+
+#: ../src/app/qml/loView/ZoomSelector.qml:29
+msgid "Automatic (Fit width)"
+msgstr ""
+
+#: ../src/app/qml/loView/ZoomSelector.qml:94
+#, qt-format
+msgid "Automatic (%1%)"
+msgstr ""
+
+#: ../src/app/qml/loView/ZoomSelector.qml:95
+#, qt-format
+msgid "Zoom: %1%"
+>>>>>>> MERGE-SOURCE
msgstr ""
#. TRANSLATORS: "Contents" refers to the "Table of Contents" of a PDF document.
@@ -375,6 +471,7 @@
msgid "Page %1 of %2"
msgstr ""
+<<<<<<< TREE
#: ../src/app/qml/pdfView/PdfViewDefaultHeader.qml:85
msgid "Go to page..."
msgstr ""
@@ -390,6 +487,19 @@
#: ../src/app/qml/textView/TextView.qml:42
msgid "Loading..."
+=======
+#: ../src/app/qml/pdfView/PdfViewGotoDialog.qml:25
+msgid "Go to page"
+msgstr ""
+
+#: ../src/app/qml/pdfView/PdfViewGotoDialog.qml:26
+#, qt-format
+msgid "Choose a page between 1 and %1"
+msgstr ""
+
+#: ../src/app/qml/pdfView/PdfViewGotoDialog.qml:44
+msgid "GO!"
+>>>>>>> MERGE-SOURCE
msgstr ""
#. TRANSLATORS: This string is used for renaming a copied file,
@@ -406,6 +516,10 @@
msgid "copy %1"
msgstr ""
+<<<<<<< TREE
#: /tmp/build-reboot-lok-goto-dialog-Desktop-Default/po/com.ubuntu.docviewer.desktop.in.in.h:2
+=======
+#: /home/qtros/dev/build-reboot-qsg-impress-support-Desktop-Default/po/com.ubuntu.docviewer.desktop.in.in.h:2
+>>>>>>> MERGE-SOURCE
msgid "documents;viewer;pdf;reader;"
msgstr ""
=== modified file 'src/app/main.cpp'
--- src/app/main.cpp 2015-03-03 16:49:48 +0000
+++ src/app/main.cpp 2015-10-08 21:01:04 +0000
@@ -19,6 +19,7 @@
// Uncomment if you need to use QML analyzer
// #define QT_QML_DEBUG
+// #include <QtQuick>
#include "docviewer-application.h"
#include <QDebug>
=== added file 'src/app/qml/loView/KeybHelper.js'
--- src/app/qml/loView/KeybHelper.js 1970-01-01 00:00:00 +0000
+++ src/app/qml/loView/KeybHelper.js 2015-10-08 21:01:04 +0000
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2015 Stefano Verzegnassi
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+function parseEvent(event) {
+ var pixelDiff = 5;
+
+ var view = loPageContentLoader.item.loView
+ var isPresentation = view.document.documentType === LO.Document.PresentationDocument
+
+ if (event.key == Qt.Key_PageUp) {
+ if (isPresentation)
+ view.document.currentPart -= 1
+ else
+ view.moveView("vertical", -view.height)
+
+ return;
+ }
+
+ if (event.key == Qt.Key_PageDown) {
+ if (isPresentation)
+ view.document.currentPart += 1
+ else
+ view.moveView("vertical", view.height)
+
+ return;
+ }
+
+ if (event.key == Qt.Key_Home) {
+ if (event.modifiers & Qt.ControlModifier) {
+ view.contentX = 0
+ view.contentY = 0
+ view.document.currentPart = 0
+ } else {
+ view.contentX = 0
+ view.contentY = 0
+ }
+ }
+
+ if (event.key == Qt.Key_End) {
+ if (event.modifiers & Qt.ControlModifier) {
+ view.contentX = view.contentWidth - view.width
+ view.contentY = view.contentHeight - view.height
+ console.log(view.document.currentPart, view.document.partsCount - 1)
+ view.document.currentPart = view.document.partsCount - 1
+ } else {
+ view.contentX = view.contentWidth - view.width
+ view.contentY = view.contentHeight - view.height
+ }
+ }
+
+ if (event.key == Qt.Key_Up) {
+ view.moveView("vertical", -pixelDiff)
+ return;
+ }
+
+ if (event.key == Qt.Key_Down) {
+ view.moveView("vertical", pixelDiff)
+ return;
+ }
+
+ if (event.key == Qt.Key_Left) {
+ view.moveView("horizontal", -pixelDiff)
+ return;
+ }
+
+ if (event.key == Qt.Key_Right) {
+ view.moveView("horizontal", pixelDiff)
+ return;
+ }
+
+ if (event.key == Qt.Key_Plus) {
+ if (event.modifiers & Qt.ControlModifier) {
+ view.zoomFactor = Math.max(4.0, view.zoomFactor + 0.25)
+ }
+ }
+
+ if (event.key == Qt.Key_Minus) {
+ if (event.modifiers & Qt.ControlModifier) {
+ view.zoomFactor = Math.min(0.5, view.zoomFactor - 0.25)
+ }
+ }
+
+
+ /*
+ if (event.key == Qt.Key_C) {
+ if (event.modifiers & Qt.ControlModifier) {
+
+ }
+ }
+ */
+
+ /*
+ if (event.key == Qt.Key_X) {
+ if (event.modifiers & Qt.ControlModifier) {
+
+ }
+ }
+ */
+
+ /*
+ if (event.key == Qt.Key_V) {
+ if (event.modifiers & Qt.ControlModifier) {
+
+ }
+ }
+ */
+
+ /*
+ if (event.key == Qt.Key_A) {
+ if (event.modifiers & Qt.ControlModifier) {
+
+ }
+ }
+ */
+
+ /*
+ if (event.key == Qt.Key_L) {
+ if (event.modifiers & Qt.ControlModifier) {
+ // TODO: Go to page dialog
+ }
+ }
+ */
+
+ /*
+ if (event.key == Qt.Key_Question) {
+ if (event.modifiers & (Qt.ControlModifier | Qt.ShiftModifier)) {
+ // TODO: Keyboard shortcuts
+ }
+ }
+ */
+}
=== modified file 'src/app/qml/loView/LOViewDefaultHeader.qml'
--- src/app/qml/loView/LOViewDefaultHeader.qml 2015-09-18 18:30:05 +0000
+++ src/app/qml/loView/LOViewDefaultHeader.qml 2015-10-08 21:01:04 +0000
@@ -53,7 +53,10 @@
fontSize: "small"
text: {
- switch(loDocument.documentType) {
+ if (!loPageContentLoader.item)
+ return i18n.tr("Loading...")
+
+ switch(loPageContentLoader.item.loDocument.documentType) {
case 0:
return i18n.tr("LibreOffice text document")
case 1:
@@ -89,18 +92,22 @@
actions: [
Action {
- iconName: "search"
- // onTriggered: pageMain.state = "search"
- //Disable it until we provide search in Poppler plugin.
- enabled: false
+ iconName: "zoom-in"
+ text: i18n.tr("Show zoom controls")
+ onTriggered: targetPage.state = "zoom"
},
Action {
objectName: "gotopage"
iconName: "browser-tabs"
+<<<<<<< TREE
text: i18n.tr("Go to position...")
onTriggered: PopupUtils.open(Qt.resolvedUrl("LOViewGotoDialog.qml"), targetPage)
visible: loDocument.documentType == LibreOffice.Document.TextDocument
+=======
+ text: i18n.tr("Go to page...")
+ enabled: false
+>>>>>>> MERGE-SOURCE
},
Action {
=== removed file 'src/app/qml/loView/LOViewDelegate.qml'
--- src/app/qml/loView/LOViewDelegate.qml 2015-06-24 12:04:16 +0000
+++ src/app/qml/loView/LOViewDelegate.qml 1970-01-01 00:00:00 +0000
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2013-2015 Canonical, Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 3.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-import QtQuick 2.3
-import Ubuntu.Components 1.1
-
-Rectangle {
- id: loPage
-
- property int index: model.index
- property bool _previewFetched: false
-
- property alias status: pageImg.status
-
- width: parent.width
- height: width * (model.height / model.width)
- color: "#E6E6E6"
-
- // Preview page rendering. Used as placeholder while zooming the page.
- // We generate the low resolution preview from the texture of the PDF page,
- // so that we can keep page rendering as fast as possible.
- ShaderEffectSource {
- id: previewImg
- anchors.fill: parent
-
- // We cannot change its opacity or visibility, otherwise the texture will be refreshed,
- // even if live is false.
- live: false
- textureSize: Qt.size(256, 256 * (model.height / model.width))
- }
-
- Image {
- id: pageImg
- anchors.fill: parent
-
- source: "image://libreoffice/page/" + index;
- sourceSize.width: loPage.width
-
- onStatusChanged: {
- // This is supposed to run the first time PdfViewDelegate gets the page rendering.
- if (!_previewFetched) {
- if (status == Image.Ready) {
- previewImg.sourceItem = pageImg
- // Re-assign sourceItem property, so the texture is not updated when Image status changes.
- previewImg.sourceItem = loPage
- }
- }
- }
-
- // Request a new page rendering. The order, which pages are requested with, depends on the distance from the currentPage
- Timer {
- id: _zoomTimer
- interval: {
- var diff = Math.abs(loView.currentPageIndex - model.index)
- var prov = loDocument.providersNumber * 0.5
-
- if (diff < prov)
- return 0
- else
- return (diff - prov) * 10
- }
-
- onTriggered: {
- pageImg.sourceSize.width = loPage.width;
- }
- }
- }
-
- // Page rendering depends on the width of PdfViewDelegate.
- // Because of this, we have multiple callings to ImageProvider while zooming.
- // Just avoid it.
- Connections {
- target: pinchy
-
- onPinchStarted: _zoomTimer.stop();
- onPinchUpdated: {
- // This ensures that page image is not reloaded when the maximumScale or minimumScale has already been reached.
- if ( !(_zoomHelper.scale >= 2.5 && pinch.scale > 1.0) && !(_zoomHelper.scale <= 1.0 && pinch.scale < 1.0) )
- pageImg.sourceSize.width = 0;
- }
- onPinchFinished: _zoomTimer.restart();
- }
-}
=== renamed file 'src/app/qml/loView/LOViewGotoDialog.qml' => 'src/app/qml/loView/LOViewGotoDialog.qml.THIS'
=== modified file 'src/app/qml/loView/LOViewPage.qml'
--- src/app/qml/loView/LOViewPage.qml 2015-09-19 15:16:51 +0000
+++ src/app/qml/loView/LOViewPage.qml 2015-10-08 21:01:04 +0000
@@ -16,28 +16,53 @@
import QtQuick 2.3
import Ubuntu.Components 1.1
+import Ubuntu.Layouts 1.0
import DocumentViewer.LibreOffice 1.0 as LO
+import "../upstreamComponents"
+
import "../common/utils.js" as Utils
-import "../upstreamComponents"
+import "KeybHelper.js" as KeybHelper
-Page {
+PageWithBottomEdge {
id: loPage
title: Utils.getNameOfFile(file.path);
-
- // Disable header auto-hide.
flickable: null
+ readonly property bool wideWindow: width > units.gu(120)
+
+ bottomEdgeTitle: i18n.tr("Slides")
+ bottomEdgeEnabled: {
+ if (!loPageContentLoader.loaded)
+ return false
+
+ // else
+ return loPageContentLoader.item.loDocument.documentType == LO.Document.PresentationDocument && !wideWindow
+ }
+
Loader {
- id: contentLoader
+ id: loPageContentLoader
asynchronous: true
anchors.fill: parent
sourceComponent: loPageContentComponent
+
+ onLoaded: {
+ if (loaded) {
+ // FIXME: At the moment don't hide header if the document is a presentation
+ var isPresentation = (item.loDocument.documentType === LO.Document.PresentationDocument)
+ loPage.flickable = isPresentation ? null : item.loView
+
+ loPage.bottomEdgePageComponent = item.bottomEdgePartsPage
+
+ } else {
+ loPage.flickable = null
+ }
+ }
}
ActivityIndicator {
- running: contentLoader.status != Loader.Ready
+ running: loPageContentLoader.status != Loader.Ready
visible: running
anchors.centerIn: parent
}
@@ -45,33 +70,152 @@
Component {
id: loPageContentComponent
- Item {
+ FocusScope {
+ id: loPageContent
+ anchors.fill: parent
+
property alias loDocument: loView.document
+ property alias loView: loView
+ property alias bottomEdgePartsPage: bottomEdgePartsPage
- LO.Viewer {
- id: loView
- objectName: "loView"
+ Layouts {
+ id: layouts
anchors.fill: parent
- clip: true
- documentPath: file.path
-
- Component.onCompleted: {
- // WORKAROUND: Fix for wrong grid unit size
- flickDeceleration = 1500 * units.gridUnit / 8
- maximumFlickVelocity = 2500 * units.gridUnit / 8
- }
- }
-
- Scrollbar { flickableItem: loView }
- Scrollbar { flickableItem: loView; align: Qt.AlignBottom }
+ layouts: [
+ ConditionalLayout {
+ when: wideWindow
+ name: "wideWindowLayout"
+
+ Item {
+ anchors.fill: parent
+
+ // TODO: Add a setting to show/hide sidebar when width > units.gu(80)
+ PartsView {
+ id: partsView
+ anchors {
+ top: parent.top
+ bottom: bottomBarLayoutItem.top
+ left: parent.left
+ }
+
+ model: loView.partsModel //LO.PartsModel { document: loPageContent.loDocument }
+ visible: /*loView.partsModel &&*/ loDocument.documentType == LO.Document.PresentationDocument
+ width: visible ? units.gu(40) : 0
+ }
+
+ Item {
+ anchors {
+ left: partsView.right
+ right: parent.right
+ top: parent.top
+ bottom: bottomBarLayoutItem.top
+ }
+
+ ItemLayout {
+ item: "loView"
+ anchors.fill: parent
+
+ // Keyboard events
+ focus: true
+ Keys.onPressed: KeybHelper.parseEvent(event)
+ Component.onCompleted: loPageContent.forceActiveFocus()
+ }
+ }
+
+ Item {
+ id: bottomBarLayoutItem
+ visible: loDocument.documentType == LO.Document.PresentationDocument
+ height: visible ? units.gu(5) : 0
+ anchors {
+ left: parent.left
+ right: parent.right
+ bottom: parent.bottom
+ }
+
+ ItemLayout { item: "bottomBar"; anchors.fill: parent }
+ }
+ }
+ }
+ ]
+
+ LO.Viewer {
+ id: loView
+ objectName: "loView"
+ Layouts.item: "loView"
+ anchors {
+ left: parent.left
+ right: parent.right
+ top: parent.top
+ bottom: bottomBar.top
+ }
+
+ clip: true
+ documentPath: file.path
+
+ // Keyboard events
+ focus: true
+ Keys.onPressed: KeybHelper.parseEvent(event)
+
+ Component.onCompleted: {
+ // WORKAROUND: Fix for wrong grid unit size
+ flickDeceleration = 1500 * units.gridUnit / 8
+ maximumFlickVelocity = 2500 * units.gridUnit / 8
+ loPageContent.forceActiveFocus()
+ }
+
+ Scrollbar { flickableItem: loView; parent: loView.parent }
+ Scrollbar { flickableItem: loView; parent: loView.parent; align: Qt.AlignBottom }
+ }
+
+ // TODO: When we'll have to merge this with the zooming branch, replace this
+ // and use a single bottom panel
+ SlideControllerPanel {
+ id: bottomBar
+ Layouts.item: "bottomBar"
+ visible: loDocument.documentType == LO.Document.PresentationDocument
+ height: visible ? units.gu(5) : 0
+ anchors {
+ left: parent.left
+ right: parent.right
+ bottom: parent.bottom
+ }
+ }
+ }
+
+ Component {
+ id: bottomEdgePartsPage
+ Page {
+ title: i18n.tr("Slides")
+ head.backAction: Action {
+ text: i18n.tr("Back")
+ iconName: "down"
+ onTriggered: pageStack.pop()
+ }
+
+ flickable: null
+
+ PartsView {
+ property bool belongsToNestedPage: true
+ anchors.fill: parent
+ model: loView.partsModel //LO.PartsModel { document: loPageContent.loDocument }
+ }
+ }
+ }
}
}
// *** HEADER ***
state: "default"
- states: LOViewDefaultHeader {
- name: "default"
- targetPage: loPage
- }
+ states: [
+ LOViewDefaultHeader {
+ name: "default"
+ targetPage: loPage
+ },
+
+ LOViewZoomHeader {
+ name: "zoom"
+ targetPage: loPage
+ }
+ ]
}
=== added file 'src/app/qml/loView/LOViewZoomHeader.qml'
--- src/app/qml/loView/LOViewZoomHeader.qml 1970-01-01 00:00:00 +0000
+++ src/app/qml/loView/LOViewZoomHeader.qml 2015-10-08 21:01:04 +0000
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2014-2015 Canonical, Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import QtQuick 2.3
+import Ubuntu.Components 1.1
+import QtQuick.Layouts 1.1
+import Ubuntu.Components.Popups 1.0
+
+PageHeadState {
+ id: rootItem
+
+ property Page targetPage
+ head: targetPage.head
+
+ contents: Item {
+ anchors.fill: parent
+
+ ZoomSelector {
+ width: units.gu(24)
+ anchors {
+ right: parent.right
+ verticalCenter: parent.verticalCenter
+ }
+ }
+ }
+
+ backAction: Action {
+ iconName: "close"
+ text: i18n.tr("Hide zoom controls")
+ onTriggered: targetPage.state = "default"
+ }
+
+ actions: [
+ Action {
+ iconName: "zoom-in"
+ text: i18n.tr("Zoom in")
+ onTriggered: loPageContentLoader.item.loView.zoomFactor += 0.1
+ },
+
+ Action {
+ iconName: "zoom-out"
+ text: i18n.tr("Zoom out")
+ onTriggered: loPageContentLoader.item.loView.zoomFactor -= 0.1
+ }
+ ]
+}
=== added file 'src/app/qml/loView/PanelButton.qml'
--- src/app/qml/loView/PanelButton.qml 1970-01-01 00:00:00 +0000
+++ src/app/qml/loView/PanelButton.qml 2015-10-08 21:01:04 +0000
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 Canonical, Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import QtQuick 2.3
+import Ubuntu.Components 1.1
+
+AbstractButton {
+ width: units.gu(4); height: parent.height
+
+ property alias iconName: icon.name
+ property alias iconSource: icon.source
+
+ Icon {
+ id: icon
+ anchors.centerIn: parent
+ width: units.gu(2.5); height: width
+ }
+}
=== added file 'src/app/qml/loView/PartsView.qml'
--- src/app/qml/loView/PartsView.qml 1970-01-01 00:00:00 +0000
+++ src/app/qml/loView/PartsView.qml 2015-10-08 21:01:04 +0000
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2015 Stefano Verzegnassi
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import QtQuick 2.3
+import Ubuntu.Components 1.1
+import QtQuick.Layouts 1.1
+import DocumentViewer.LibreOffice 1.0 as LibreOffice
+
+import "../upstreamComponents"
+
+ListView {
+ id: view
+ objectName: "view"
+ clip: true
+
+ property bool expanded: true
+
+ currentIndex: view.model ? loView.document.currentPart : -1
+ highlightMoveDuration: UbuntuAnimation.SnapDuration
+
+ delegate: ListItemWithActions {
+ id: delegate
+
+ width: parent.width
+ height: units.gu(16)
+
+ color: (loView.document.currentPart === model.index) ? Theme.palette.selected.background
+ : "transparent"
+
+ AbstractButton {
+ objectName: "abstractbutton"
+ anchors.fill: parent
+
+ onClicked: {
+ loView.document.currentPart = model.index
+
+ // Check if the view has been included in a nested page (e.g.
+ // bottomEdge). If so, close that page and return to the
+ // main viewer.
+ if (view.hasOwnProperty("belongsToNestedPage"))
+ pageStack.pop();
+ }
+ }
+
+ RowLayout {
+ anchors.fill: parent
+ spacing: units.gu(1)
+
+ Image {
+ Layout.fillHeight: true
+ Layout.preferredWidth: height
+ fillMode: Image.PreserveAspectFit
+ // Do not store a cache of the thumbnail, so that we don't show
+ // thumbnails of a previously loaded document.
+ cache: true // TODO PLAY WITH IT
+ source: model.thumbnail
+ }
+
+ Label {
+ Layout.fillWidth: true
+ wrapMode: Text.WordWrap
+ text: model.name
+ color: (loView.document.currentPart === model.index) ? UbuntuColors.orange
+ : Theme.palette.selected.backgroundText
+ }
+
+ Label {
+ text: model.index + 1
+ color: (loView.document.currentPart === model.index) ? UbuntuColors.orange
+ : Theme.palette.selected.backgroundText
+ }
+ }
+ }
+
+ Scrollbar { flickableItem: view; parent: view.parent }
+}
=== added file 'src/app/qml/loView/SlideControllerPanel.qml'
--- src/app/qml/loView/SlideControllerPanel.qml 1970-01-01 00:00:00 +0000
+++ src/app/qml/loView/SlideControllerPanel.qml 2015-10-08 21:01:04 +0000
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2015 Stefano Verzegnassi
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import QtQuick 2.3
+import Ubuntu.Components 1.1
+import QtQuick.Layouts 1.1
+import Ubuntu.Components.ListItems 1.0 as ListItems
+
+Rectangle {
+ id: bottomBar
+ color: "transparent"
+ height: units.gu(5)
+
+ ListItems.ThinDivider {
+ anchors {
+ top: parent.top
+ left: parent.left
+ right: parent.right
+ }
+ }
+
+ Row {
+ anchors.centerIn: parent
+ //spacing: units.gu(2)
+
+ AbstractButton {
+ width: units.gu(4); height: parent.height
+ onClicked: loPageContentLoader.item.loView.goFirstPart()
+
+ Icon {
+ anchors.centerIn: parent
+ width: units.gu(2.5); height: width
+ name: "go-first"
+ }
+ }
+
+ AbstractButton {
+ width: units.gu(4); height: parent.height
+ onClicked: loPageContentLoader.item.loView.goPreviousPart()
+
+ Icon {
+ anchors.centerIn: parent
+ width: units.gu(2.5); height: width
+ name: "go-previous"
+ }
+ }
+
+ Label {
+ text: i18n.tr("Slide %1 of %2").arg(loPageContentLoader.item.loDocument.currentPart + 1).arg(loPageContentLoader.item.loDocument.partsCount)
+ }
+
+ AbstractButton {
+ width: units.gu(4); height: parent.height
+ onClicked: loPageContentLoader.item.loView.goNextPart()
+
+ Icon {
+ anchors.centerIn: parent
+ width: units.gu(2.5); height: width
+ name: "go-next"
+ }
+ }
+
+ AbstractButton {
+ width: units.gu(4); height: parent.height
+ onClicked: loPageContentLoader.item.loView.goLastPart()
+
+ Icon {
+ anchors.centerIn: parent
+ width: units.gu(2.5); height: width
+ name: "go-last"
+ }
+ }
+ }
+}
=== added file 'src/app/qml/loView/ZoomSelector.qml'
--- src/app/qml/loView/ZoomSelector.qml 1970-01-01 00:00:00 +0000
+++ src/app/qml/loView/ZoomSelector.qml 2015-10-08 21:01:04 +0000
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2015 Canonical, Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import QtQuick 2.3
+import Ubuntu.Components 1.1
+import Ubuntu.Components.Popups 1.0
+import DocumentViewer.LibreOffice 1.0 as LibreOffice
+
+TextField {
+ id: textField
+ anchors.verticalCenter: parent.verticalCenter
+ width: units.gu(24)
+
+ property var values: ["auto", 0.5, 0.7, 0.85, 1.0, 1.25, 1.5, 1.75, 2.0, 3.0, 4.0]
+ property var labels: [
+ i18n.tr("Automatic (Fit width)"),
+ "50%", "70%", "85%", "100%", "125%",
+ "150%", "175%","200%", "300%", "400%"
+ ]
+
+ property bool expanded: false
+
+ hasClearButton: true
+ inputMethodHints: Qt.ImhFormattedNumbersOnly
+ validator: IntValidator{ bottom: 50; top: 400 }
+
+ onAccepted: {
+ loPageContentLoader.item.loView.zoomFactor = parseInt(text) / 100
+ focus = false
+ }
+
+ secondaryItem: AbstractButton {
+ visible: !textField.highlighted
+ id: listButton
+ height: parent.height
+ width: visible ? height : 0
+
+ Rectangle {
+ anchors.left: parent.left
+ anchors.verticalCenter: parent.verticalCenter
+ height: parent.height - units.gu(1)
+
+ width: units.dp(1)
+ color: "Grey"
+ opacity: 0.5
+ }
+
+ Icon {
+ id: _upArrow
+
+ width: units.gu(2)
+ height: width
+ anchors.centerIn: parent
+
+ name: "go-down"
+ color: "Grey"
+ rotation: textField.expanded ? 180 : 0
+
+ Behavior on rotation {
+ UbuntuNumberAnimation {}
+ }
+ }
+
+ onClicked: {
+ textField.expanded = true
+ PopupUtils.open(zoomSelectorDialog, listButton)
+ }
+ }
+
+ onHighlightedChanged: {
+ if (highlighted) {
+ text = parseInt(loPageContentLoader.item.loView.zoomFactor * 100)
+ } else text = ""
+ }
+
+ Label {
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.left: parent.left
+ anchors.leftMargin: units.gu(2)
+ visible: !textField.highlighted
+ text: loPageContentLoader.item.loView.zoomMode == LibreOffice.View.FitToWidth ? i18n.tr("Automatic (%1%)").arg(parseInt(loPageContentLoader.item.loView.zoomFactor*100))
+ : i18n.tr("Zoom: %1%").arg(parseInt(loPageContentLoader.item.loView.zoomFactor*100))
+ }
+
+ Component {
+ id: zoomSelectorDialog
+ Popover {
+ id: zoomSelectorDialogue
+ autoClose: false
+ contentHeight: units.gu(24)
+ contentWidth: units.gu(24)
+ Component.onDestruction: textField.expanded = false
+
+ // We don't use 'autoClose' property, since we want to propagate
+ // mouse/touch events to other items (e.g. when zoomSelectorDialogue
+ // is visible, and user taps the zoom+ button on its right, we want
+ // the zoom button to receive the event).
+ InverseMouseArea {
+ anchors.fill: parent
+ propagateComposedEvents: true
+
+ onPressed: {
+ mouse.accepted = false
+ PopupUtils.close(zoomSelectorDialogue)
+ }
+ }
+
+ OptionSelector {
+ expanded: true
+ width: parent.width
+ containerHeight: units.gu(24)
+ model: textField.labels
+ selectedIndex: {
+ if (loPageContentLoader.item.loView.zoomMode == LibreOffice.View.FitToWidth)
+ return 0
+
+ for (var i=0; i<textField.values.length; i++) {
+ if (values[i] == loView.zoomFactor)
+ return i
+ }
+ return -1
+ }
+
+ onSelectedIndexChanged: {
+ if (selectedIndex == 0) {
+ loView.adjustZoomToWidth();
+ return;
+ }
+
+ loPageContentLoader.item.loView.zoomFactor = textField.values[selectedIndex]
+ PopupUtils.close(zoomSelectorDialogue)
+ }
+ }
+ }
+ }
+}
=== modified file 'src/app/qml/ubuntu-docviewer-app.qml'
--- src/app/qml/ubuntu-docviewer-app.qml 2015-09-11 14:48:57 +0000
+++ src/app/qml/ubuntu-docviewer-app.qml 2015-10-08 21:01:04 +0000
@@ -37,7 +37,7 @@
useDeprecatedToolbar: false
automaticOrientation: true
- width: units.gu(50)
+ width: units.gu(150)
height: units.gu(75)
function openDocument(path) {
=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/CMakeLists.txt'
--- src/plugin/libreofficetoolkit-qml-plugin/CMakeLists.txt 2015-09-18 09:35:04 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/CMakeLists.txt 2015-10-08 21:01:04 +0000
@@ -17,6 +17,8 @@
lodocument.cpp
loview.cpp
sgtileitem.cpp
+ lopartsimageprovider.cpp
+ lopartsmodel.cpp
renderengine.cpp
${QML_SRCS}
)
=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/lodocument.cpp'
--- src/plugin/libreofficetoolkit-qml-plugin/lodocument.cpp 2015-09-18 11:18:17 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/lodocument.cpp 2015-10-08 21:01:04 +0000
@@ -36,6 +36,7 @@
LODocument::LODocument()
: m_path("")
+ , m_currentPart(-1)
, m_document(nullptr)
{
// This space is intentionally empty.
@@ -60,6 +61,22 @@
this->loadDocument(m_path);
}
+int LODocument::currentPart() {
+ return m_currentPart;
+}
+
+void LODocument::setCurrentPart(int index)
+{
+ if (!m_document)
+ return;
+
+ if (m_currentPart == index || index < 0 || index > partsCount() - 1)
+ return;
+
+ m_currentPart = index;
+ Q_EMIT currentPartChanged();
+}
+
// Load the document
bool LODocument::loadDocument(const QString &pathName)
{
@@ -78,6 +95,8 @@
m_docType = DocumentType(m_document->getDocumentType());
Q_EMIT documentTypeChanged();
+ setCurrentPart(m_document->getPart());
+
m_document->initializeForRendering();
qDebug() << "Document loaded successfully !";
@@ -91,6 +110,17 @@
return m_docType;
}
+int LODocument::documentPart() const
+{
+ return m_document->getPart();
+}
+
+void LODocument::setDocumentPart(int p)
+{
+ if (documentPart() != p)
+ m_document->setPart(p);
+}
+
// Return the size of the document, in TWIPs
QSize LODocument::documentSize() const
{
@@ -106,8 +136,14 @@
// Paint a tile, with size=canvasSize, of the part of the document defined by
// the rect tileSize.
-QImage LODocument::paintTile(const QSize& canvasSize, const QRect& tileSize)
+QImage LODocument::paintTile(const QSize& canvasSize, const QRect& tileSize, const qreal &zoom)
{
+ if (!m_document)
+ return QImage();
+
+// if (m_currentPart != m_document->getPart())
+// m_document->setPart(m_currentPart);
+
QImage result = QImage(canvasSize.width(), canvasSize.height(), QImage::Format_RGB32);
#ifdef DEBUG_TILE_BENCHMARK
@@ -117,10 +153,10 @@
m_document->paintTile(result.bits(),
canvasSize.width(), canvasSize.height(),
- Twips::convertPixelsToTwips(tileSize.x()),
- Twips::convertPixelsToTwips(tileSize.y()),
- Twips::convertPixelsToTwips(tileSize.width()),
- Twips::convertPixelsToTwips(tileSize.height()));
+ Twips::convertPixelsToTwips(tileSize.x(), zoom),
+ Twips::convertPixelsToTwips(tileSize.y(), zoom),
+ Twips::convertPixelsToTwips(tileSize.width(), zoom),
+ Twips::convertPixelsToTwips(tileSize.height(), zoom));
#ifdef DEBUG_TILE_BENCHMARK
qDebug() << "Time to render the tile:" << renderTimer.elapsed() << "ms";
@@ -129,6 +165,56 @@
return result.rgbSwapped();
}
+QImage LODocument::paintThumbnail(qreal size)
+{
+ if (!m_document)
+ return QImage();
+
+#ifdef DEBUG_TILE_BENCHMARK
+ QElapsedTimer renderTimer;
+ renderTimer.start();
+#endif
+
+ qreal tWidth = this->documentSize().width();
+ qreal tHeight = this->documentSize().height();
+
+ QSize resultSize;
+
+ if (tWidth > tHeight) {
+ resultSize.setWidth(size);
+ resultSize.setHeight(size * tHeight / tWidth);
+ } else {
+ resultSize.setHeight(size);
+ resultSize.setWidth(size * tWidth / tHeight);
+ }
+
+ QImage result = QImage(resultSize.width(), resultSize.height(), QImage::Format_RGB32);
+ m_document->paintTile(result.bits(), resultSize.width(), resultSize.height(),
+ 0, 0, tWidth, tHeight);
+
+#ifdef DEBUG_TILE_BENCHMARK
+ qDebug() << "Time to render the thumbnail:" << renderTimer.elapsed() << "ms";
+#endif
+
+ return result.rgbSwapped();
+}
+
+int LODocument::partsCount()
+{
+ if (!m_document)
+ return int(0);
+
+ return m_document->getParts();
+}
+
+QString LODocument::getPartName(int index) const
+{
+ if (!m_document)
+ return QString();
+
+ return QString::fromUtf8(m_document->getPartName(index));
+}
+
/* Export the file in a given format:
* - url is a mandatory argument.
* - format is optional. If not specified, lok will try to get it from the file
=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/lodocument.h'
--- src/plugin/libreofficetoolkit-qml-plugin/lodocument.h 2015-09-18 11:18:17 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/lodocument.h 2015-10-08 21:01:04 +0000
@@ -30,8 +30,12 @@
Q_OBJECT
Q_DISABLE_COPY(LODocument)
- Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged)
- Q_PROPERTY(DocumentType documentType READ documentType NOTIFY documentTypeChanged)
+ Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged)
+ Q_PROPERTY(int currentPart READ currentPart WRITE setCurrentPart NOTIFY currentPartChanged)
+ // Declare partsCount as constant at the moment, since LOK-plugin is just a viewer for now.
+ Q_PROPERTY(int partsCount READ partsCount CONSTANT)
+ Q_PROPERTY(int documentPart READ documentPart WRITE setDocumentPart NOTIFY documentPartChanged)
+ Q_PROPERTY(DocumentType documentType READ documentType NOTIFY documentTypeChanged)
Q_ENUMS(DocumentType)
public:
@@ -49,19 +53,34 @@
QString path() const;
void setPath(const QString& pathName);
+ int currentPart();
+ void setCurrentPart(int index);
+
DocumentType documentType() const;
+ int documentPart() const;
+ void setDocumentPart(int p);
+
QSize documentSize() const;
- QImage paintTile(const QSize& canvasSize, const QRect& tileSize);
+
+ QImage paintTile(const QSize& canvasSize, const QRect& tileSize, const qreal& zoom = 1.0);
+ QImage paintThumbnail(qreal size);
+
+ int partsCount();
+ QString getPartName(int index) const;
+ void setPart(int index);
Q_INVOKABLE bool saveAs(QString url, QString format, QString filterOptions);
Q_SIGNALS:
void pathChanged();
+ void currentPartChanged();
void documentTypeChanged();
+ void documentPartChanged();
private:
QString m_path;
+ int m_currentPart;
DocumentType m_docType;
bool loadDocument(const QString &pathNAme);
=== added file 'src/plugin/libreofficetoolkit-qml-plugin/lopartsimageprovider.cpp'
--- src/plugin/libreofficetoolkit-qml-plugin/lopartsimageprovider.cpp 1970-01-01 00:00:00 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/lopartsimageprovider.cpp 2015-10-08 21:01:04 +0000
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2015 Canonical, Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "lopartsimageprovider.h"
+#include "lodocument.h"
+#include "renderengine.h"
+
+LOPartsImageProvider::LOPartsImageProvider(const QSharedPointer<LODocument>& d)
+ : QQuickImageProvider(QQuickImageProvider::Image),
+ m_document(d)
+{ }
+
+QImage LOPartsImageProvider::requestImage(const QString & id, QSize * size, const QSize & requestedSize)
+{
+ Q_UNUSED(size)
+
+ QString type = id.section("/", 0, 0);
+
+ if (requestedSize.isNull() || type != "part" ||
+ m_document->documentType() != LODocument::PresentationDocument)
+ return QImage();
+
+ // Get info from "id".
+ int partNumber = id.section("/", 1, 1).toInt();
+ int itemId = id.section("/", 2, 2).toInt();
+
+ // Once rendered images can be found in hash.
+ if (m_images.contains(itemId))
+ return m_images[itemId];
+
+ const int defaultSize = 256;
+
+ RenderEngine::instance()->enqueueTask(m_document, partNumber, defaultSize, itemId);
+
+ // Return default image (empty).
+ static QImage defaultImage;
+ if (defaultImage.isNull())
+ defaultImage = QImage(defaultSize, defaultSize, QImage::Format_ARGB32);
+
+ return defaultImage;
+}
=== added file 'src/plugin/libreofficetoolkit-qml-plugin/lopartsimageprovider.h'
--- src/plugin/libreofficetoolkit-qml-plugin/lopartsimageprovider.h 1970-01-01 00:00:00 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/lopartsimageprovider.h 2015-10-08 21:01:04 +0000
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2015 Canonical, Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef LOPARTSIMAGEPROVIDER_H
+#define LOPARTSIMAGEPROVIDER_H
+
+#include <QQuickImageProvider>
+#include <QSharedPointer>
+#include <QHash>
+#include <QDebug>
+
+class LODocument;
+
+class LOPartsImageProvider : public QQuickImageProvider
+{
+public:
+ LOPartsImageProvider(const QSharedPointer<LODocument>& d);
+ QImage requestImage(const QString & id, QSize * size, const QSize & requestedSize);
+
+ QHash<int, QImage> m_images;
+
+private:
+ QSharedPointer<LODocument> m_document;
+};
+
+#endif // LOPARTSIMAGEPROVIDER_H
=== added file 'src/plugin/libreofficetoolkit-qml-plugin/lopartsmodel.cpp'
--- src/plugin/libreofficetoolkit-qml-plugin/lopartsmodel.cpp 1970-01-01 00:00:00 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/lopartsmodel.cpp 2015-10-08 21:01:04 +0000
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2015 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "lopartsmodel.h"
+#include "lodocument.h"
+#include "lopartsimageprovider.h"
+
+#include <QQmlContext>
+#include <QQmlEngine>
+#include <QDebug>
+
+
+
+LOPartsModel::LOPartsModel(const QSharedPointer<LODocument>& document, QAbstractListModel *parent):
+ QAbstractListModel(parent)
+{
+ m_document = document;
+ fillModel();
+}
+
+QHash<int, QByteArray> LOPartsModel::roleNames() const
+{
+ QHash<int, QByteArray> roles;
+ roles[IndexRole] = "index";
+ roles[NameRole] = "name";
+ roles[IdRole] = "id";
+ roles[ThumbnailRole] = "thumbnail";
+
+ return roles;
+}
+
+int LOPartsModel::rowCount(const QModelIndex & parent) const
+{
+ Q_UNUSED(parent)
+ return m_entries.count();
+}
+
+QVariant LOPartsModel::data(const QModelIndex & index, int role) const
+{
+ if (index.row() < 0 || index.row() > m_entries.count())
+ return QVariant();
+
+ const LOPartEntry &part = m_entries.at(index.row());
+
+ switch (role) {
+ case IndexRole:
+ return part.index;
+ case NameRole:
+ return part.name;
+ case IdRole:
+ return part.id;
+ case ThumbnailRole:
+ return part.thumbnail;
+
+ default:
+ return 0;
+ }
+}
+
+QVariantMap LOPartsModel::get(int index) const
+{
+ if (index < 0 || index > m_entries.count() - 1) {
+ qWarning() << Q_FUNC_INFO << "Index not valid, return undefined";
+ return QVariantMap();
+ }
+
+ const LOPartEntry &part = m_entries.at(index);
+
+ QVariantMap map;
+ map["name"] = part.name;
+ map["index"] = part.index;
+ map["id"] = part.id;
+ map["thumbnail"] = part.thumbnail;
+
+ return map;
+}
+
+void LOPartsModel::notifyAboutChanges(int id)
+{
+ for (int i = 0; i < m_entries.size(); i++)
+ if (m_entries[i].id == id) {
+ m_entries[i].thumbnail += "/cached";
+ Q_EMIT dataChanged(createIndex(i, 0), createIndex(i + 1, 0));
+ break;
+ }
+}
+
+void LOPartsModel::fillModel() {
+ if (!m_document)
+ return;
+
+ if (!m_entries.isEmpty()) {
+ beginRemoveRows(QModelIndex(), 0, rowCount());
+ m_entries.clear();
+ endRemoveRows();
+ }
+
+ int partsCount = m_document->partsCount();
+ beginInsertColumns(QModelIndex(), 0, qMax(partsCount - 1, 0));
+ for (int i = 0; i < partsCount; i++) {
+ LOPartEntry part;
+
+ part.index = i;
+ part.name = m_document->getPartName(i);
+ part.id = RenderEngine::getNextId();
+ part.thumbnail = QString("image://lok/part/%1/%2").arg(QString::number(part.index)).arg(QString::number(part.id));
+
+ m_entries.append(part);
+ }
+ endInsertColumns();
+
+ Q_EMIT countChanged();
+}
+
+LOPartsModel::~LOPartsModel()
+{ }
=== added file 'src/plugin/libreofficetoolkit-qml-plugin/lopartsmodel.h'
--- src/plugin/libreofficetoolkit-qml-plugin/lopartsmodel.h 1970-01-01 00:00:00 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/lopartsmodel.h 2015-10-08 21:01:04 +0000
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2015 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef LOPARTSMODEL_H
+#define LOPARTSMODEL_H
+
+#include <QAbstractListModel>
+#include <QImage>
+#include <QHash>
+#include <QSharedPointer>
+
+#include "renderengine.h"
+
+class LODocument;
+
+class LOPartEntry
+{
+public:
+ LOPartEntry():
+ index(0)
+ {
+ id = RenderEngine::getNextId();
+ }
+
+ int id;
+ QString name;
+ int index;
+ QString thumbnail;
+};
+
+class LOPartsModel : public QAbstractListModel
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(LOPartsModel)
+ // Q_PROPERTY(LODocument* document READ document WRITE setDocument NOTIFY documentChanged)
+ Q_PROPERTY(int count READ rowCount NOTIFY countChanged)
+
+public:
+ enum Roles {
+ NameRole = Qt::UserRole + 1,
+ IndexRole,
+ IdRole,
+ ThumbnailRole
+ };
+
+ explicit LOPartsModel(const QSharedPointer<LODocument>& document, QAbstractListModel *parent = 0);
+ ~LOPartsModel();
+
+ // LODocument* document() { return m_document; }
+ //void setDocument(LODocument* document);
+
+ QHash<int, QByteArray> roleNames() const;
+
+ int rowCount(const QModelIndex & parent = QModelIndex()) const;
+ QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
+
+ Q_INVOKABLE QVariantMap get(int index) const;
+
+ void notifyAboutChanges(int id);
+
+Q_SIGNALS:
+ // void documentChanged();
+ void countChanged();
+
+private slots:
+ void fillModel();
+
+private:
+ QSharedPointer<LODocument> m_document;
+ QList<LOPartEntry> m_entries;
+};
+
+#endif // LOPARTSMODEL_H
=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/loview.cpp'
--- src/plugin/libreofficetoolkit-qml-plugin/loview.cpp 2015-09-19 13:31:19 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/loview.cpp 2015-10-08 21:01:04 +0000
@@ -25,10 +25,18 @@
#include <QTimer>
#include <QtCore/qmath.h>
+static qreal zoomValueToFitWidth;
+
+static qreal getZoomToFitWidth(const qreal &width, int documentWidth)
+{
+ return qreal(width / Twips::convertTwipsToPixels(documentWidth, 1.0));
+}
+
LOView::LOView(QQuickItem *parent)
: QQuickItem(parent)
, m_parentFlickable(nullptr)
, m_document(nullptr)
+ , m_partsModel(nullptr)
, m_zoomFactor(1.0)
, m_cacheBuffer(TILE_SIZE * 3)
, m_visibleArea(0, 0, 0, 0)
@@ -41,7 +49,11 @@
connect(this, SIGNAL(parentFlickableChanged()), this, SLOT(updateVisibleRect()));
connect(this, SIGNAL(cacheBufferChanged()), this, SLOT(updateVisibleRect()));
connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateVisibleRect()));
- connect(RenderEngine::instance(), SIGNAL(renderFinished(int,QImage)), this, SLOT(renderResultReceived(int,QImage)));
+
+ connect(RenderEngine::instance(), SIGNAL(renderFinished(int,QImage)),
+ this, SLOT(slotTileRenderFinished(int,QImage)));
+ connect(RenderEngine::instance(), SIGNAL(thumbnailRenderFinished(int,QImage)),
+ this, SLOT(slotThumbnailRenderFinished(int,QImage)));
}
// Returns the parent QML Flickable
@@ -72,8 +84,27 @@
void LOView::initializeDocument(const QString &path)
{
+ if (m_document)
+ m_document->disconnect(this);
+
m_document = QSharedPointer<LODocument>(new LODocument());
m_document->setPath(path);
+
+ // TODO MOVE
+ m_partsModel = new LOPartsModel(m_document);
+ Q_EMIT partsModelChanged();
+
+ // --------------------------------------------------
+ QQmlEngine *engine = QQmlEngine::contextForObject(this)->engine();
+ if (engine->imageProvider("lok"))
+ engine->removeImageProvider("lok");
+
+ m_imageProvider = new LOPartsImageProvider(m_document);
+ engine->addImageProvider("lok", m_imageProvider);
+ // --------------------------------------------------
+
+ connect(m_document.data(), SIGNAL(currentPartChanged()), this, SLOT(invalidateAllTiles()));
+
Q_EMIT documentChanged();
}
@@ -83,22 +114,43 @@
return m_document.data();
}
-// Not used yet.
+LOPartsModel *LOView::partsModel() const
+{
+ return m_partsModel;
+}
+
qreal LOView::zoomFactor() const
{
return m_zoomFactor;
}
-// Not used yet.
-void LOView::setZoomFactor(qreal zoom)
+void LOView::setZoomFactor(const qreal zoom)
{
if (m_zoomFactor == zoom)
return;
m_zoomFactor = zoom;
+
+ if (m_zoomFactor != zoomValueToFitWidth)
+ setZoomMode(LOView::Manual);
+
Q_EMIT zoomFactorChanged();
}
+LOView::ZoomMode LOView::zoomMode() const
+{
+ return m_zoomMode;
+}
+
+void LOView::setZoomMode(const ZoomMode zoomMode)
+{
+ if (m_zoomMode == zoomMode)
+ return;
+
+ m_zoomMode = zoomMode;
+ Q_EMIT zoomModeChanged();
+}
+
int LOView::cacheBuffer() const
{
return m_cacheBuffer;
@@ -113,6 +165,37 @@
Q_EMIT cacheBufferChanged();
}
+void LOView::adjustZoomToWidth()
+ {
+ setZoomMode(LOView::FitToWidth);
+
+ zoomValueToFitWidth = getZoomToFitWidth(m_parentFlickable->width(),
+ m_document->documentSize().width());
+
+ setZoomFactor(zoomValueToFitWidth);
+ qDebug() << "Adjust zoom to width - value:" << zoomValueToFitWidth;
+ }
+
+bool LOView::updateZoomIfAutomatic()
+{
+ // This function is only used in LOView::updateVisibleRect()
+ // It returns a bool, so that we can stop the execution of that function,
+ // which will be triggered again when we'll automatically update the zoom value.
+ if (m_zoomMode == LOView::FitToWidth) {
+ zoomValueToFitWidth = getZoomToFitWidth(m_parentFlickable->width(),
+ m_document->documentSize().width());
+
+ if (m_zoomFactor != zoomValueToFitWidth) {
+ setZoomFactor(zoomValueToFitWidth);
+
+ qDebug() << "Adjust automatic zoom to width - value:" << zoomValueToFitWidth;
+ return true;
+ }
+ }
+
+ return false;
+}
+
// Update the size of LOView, according to the size of the loaded document.
void LOView::updateViewSize()
{
@@ -121,9 +204,8 @@
QSize docSize = m_document->documentSize();
- // FIXME: Area may become too large, resulting in a black texture.
- this->setWidth(Twips::convertTwipsToPixels(docSize.width()) * m_zoomFactor);
- this->setHeight(Twips::convertTwipsToPixels(docSize.height()) * m_zoomFactor);
+ this->setWidth(Twips::convertTwipsToPixels(docSize.width(), m_zoomFactor));
+ this->setHeight(Twips::convertTwipsToPixels(docSize.height(), m_zoomFactor));
// TODO: Consider to use connections to widthChanged and heightChanged
this->updateVisibleRect();
@@ -137,6 +219,31 @@
if (!m_parentFlickable)
return;
+ // Changes in parentFlickable width/height trigger directly LOView::updateVisibleRect(),
+ // since they don't imply a change in the zoom factor - i.e. LOView::updateViewSize().
+ // Anyway, this class also handle an automatic zoom when the parentFlickable has been
+ // resized, so we need to take care of it.
+ // updateZoomIfAutomatic() returns a bool, which is true when the zoomFactor is
+ // set to a new value.
+ // If that happens, stop the execution of this function, since the change of
+ // zoomFactor will trigger the updateViewSize() function, which triggers this
+ // function again.
+ if (this->updateZoomIfAutomatic())
+ return;
+
+ // Check if current tiles have a different zoom value
+ if (!m_tiles.isEmpty()) {
+ SGTileItem* tile = m_tiles.first();
+
+ if (tile->zoomFactor() != m_zoomFactor) {
+ clearView();
+
+#ifdef DEBUG_VERBOSE
+ qDebug() << "Zoom value of tiles is different than the current zoom value. Erasing cache...";
+#endif
+ }
+ }
+
// Update information about the visible area
m_visibleArea.setRect(m_parentFlickable->property("contentX").toInt(),
m_parentFlickable->property("contentY").toInt(),
@@ -216,6 +323,13 @@
}
}
+// FIXME: Just for the moment. In zoom branch we have all we need :)
+void LOView::invalidateAllTiles()
+{
+ clearView();
+ updateViewSize();
+}
+
void LOView::createTile(int index, QRect rect)
{
if (!m_tiles.contains(index)) {
@@ -223,13 +337,13 @@
qDebug() << "Creating tile indexed as" << index;
#endif
- auto tile = new SGTileItem(rect, this);
+ auto tile = new SGTileItem(rect, m_zoomFactor, RenderEngine::getNextId(), this);
m_tiles.insert(index, tile);
- RenderEngine::instance()->enqueueTask(m_document, rect, tile->id());
+ RenderEngine::instance()->enqueueTask(m_document, m_document->currentPart(), rect, m_zoomFactor, tile->id());
}
#ifdef DEBUG_VERBOSE
else {
- qDebug() << "tile" << x << "x" << y << "already exists";
+ qDebug() << "tile" << index << "already exists";
}
#endif
}
@@ -240,7 +354,7 @@
m_updateTimer.start(20);
}
-void LOView::renderResultReceived(int id, QImage img)
+void LOView::slotTileRenderFinished(int id, QImage img)
{
for (auto i = m_tiles.begin(); i != m_tiles.end(); ++i) {
SGTileItem* sgtile = i.value();
@@ -251,9 +365,29 @@
}
}
+void LOView::slotThumbnailRenderFinished(int id, QImage img)
+{
+ if (!m_imageProvider->m_images.contains(id))
+ m_imageProvider->m_images.insert(id, img);
+ m_partsModel->notifyAboutChanges(id);
+}
+
+void LOView::clearView()
+{
+ for (auto i = m_tiles.begin(); i != m_tiles.end(); ++i)
+ RenderEngine::instance()->dequeueTask(i.value()->id());
+
+ m_tiles.clear();
+}
+
LOView::~LOView()
{
- disconnect(RenderEngine::instance(), SIGNAL(renderFinished(int,QImage)), this, SLOT(renderResultReceived(int,QImage)));
+ delete m_partsModel;
+
+ disconnect(RenderEngine::instance(), SIGNAL(renderFinished(int,QImage)),
+ this, SLOT(slotTileRenderFinished(int,QImage)));
+ disconnect(RenderEngine::instance(), SIGNAL(thumbnailRenderFinished(int,QImage)),
+ this, SLOT(slotThumbnailRenderFinished(int,QImage)));
// Remove all tasks from rendering queue.
for (auto i = m_tiles.begin(); i != m_tiles.end(); ++i)
=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/loview.h'
--- src/plugin/libreofficetoolkit-qml-plugin/loview.h 2015-09-19 14:00:41 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/loview.h 2015-10-08 21:01:04 +0000
@@ -21,8 +21,12 @@
#include <QQuickItem>
#include <QTimer>
#include <QSharedPointer>
+#include <QQmlContext>
+#include <QQmlEngine>
#include "renderengine.h"
+#include "lopartsmodel.h"
+#include "lopartsimageprovider.h"
class LODocument;
class SGTileItem;
@@ -30,47 +34,67 @@
class LOView : public QQuickItem
{
Q_OBJECT
- Q_PROPERTY(QQuickItem* parentFlickable READ parentFlickable WRITE setParentFlickable NOTIFY parentFlickableChanged)
- Q_PROPERTY(LODocument* document READ document /*WRITE setDocument*/ NOTIFY documentChanged)
-
- // TODO: Implement zoom!
- Q_PROPERTY(qreal zoomFactor READ zoomFactor WRITE setZoomFactor NOTIFY zoomFactorChanged)
- Q_PROPERTY(int cacheBuffer READ cacheBuffer WRITE setCacheBuffer NOTIFY cacheBufferChanged)
+ Q_ENUMS(ZoomMode)
+ Q_PROPERTY(QQuickItem* parentFlickable READ parentFlickable WRITE setParentFlickable NOTIFY parentFlickableChanged)
+ Q_PROPERTY(LODocument* document READ document /*WRITE setDocument*/ NOTIFY documentChanged)
+ Q_PROPERTY(LOPartsModel* partsModel READ partsModel NOTIFY partsModelChanged)
+ Q_PROPERTY(qreal zoomFactor READ zoomFactor WRITE setZoomFactor NOTIFY zoomFactorChanged)
+ Q_PROPERTY(ZoomMode zoomMode READ zoomMode NOTIFY zoomModeChanged)
+ Q_PROPERTY(int cacheBuffer READ cacheBuffer WRITE setCacheBuffer NOTIFY cacheBufferChanged)
public:
LOView(QQuickItem *parent = 0);
~LOView();
+ enum ZoomMode {
+ FitToWidth,
+ Manual
+ };
+
QQuickItem* parentFlickable() const;
void setParentFlickable(QQuickItem* flickable);
Q_INVOKABLE void initializeDocument(const QString& path);
LODocument* document() const;
+ LOPartsModel* partsModel() const;
qreal zoomFactor() const;
- void setZoomFactor(qreal zoom);
+ void setZoomFactor(const qreal zoom);
+
+ ZoomMode zoomMode() const;
int cacheBuffer() const;
void setCacheBuffer(int cacheBuffer);
+ Q_INVOKABLE void adjustZoomToWidth();
+
Q_SIGNALS:
void parentFlickableChanged();
void documentChanged();
+ void partsModelChanged();
void zoomFactorChanged();
+ void zoomModeChanged();
void cacheBufferChanged();
private Q_SLOTS:
void updateViewSize();
void updateVisibleRect();
void scheduleVisibleRectUpdate();
- void renderResultReceived(int id, QImage img);
+ void invalidateAllTiles();
+
+ void slotTileRenderFinished(int id, QImage img);
+ void slotThumbnailRenderFinished(int id, QImage img);
private:
+
QQuickItem* m_parentFlickable;
QSharedPointer<LODocument> m_document;
+ LOPartsModel* m_partsModel; // TODO MB move to document.
+ LOPartsImageProvider* m_imageProvider; // The QQmlEngine takes ownership of provider.
qreal m_zoomFactor;
+ ZoomMode m_zoomMode;
int m_cacheBuffer;
QRect m_visibleArea;
@@ -82,6 +106,9 @@
void generateTiles(int x1, int y1, int x2, int y2, int tilesPerWidth);
void createTile(int index, QRect rect);
+ void setZoomMode(const ZoomMode zoomMode);
+ bool updateZoomIfAutomatic();
+ void clearView();
};
#endif // LOVIEW_H
=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/plugin.cpp'
--- src/plugin/libreofficetoolkit-qml-plugin/plugin.cpp 2015-07-04 16:00:33 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/plugin.cpp 2015-10-08 21:01:04 +0000
@@ -21,6 +21,7 @@
#include "plugin.h"
#include "lodocument.h"
#include "loview.h"
+#include "lopartsmodel.h"
void LOPlugin::registerTypes(const char *uri)
{
@@ -29,6 +30,7 @@
//@uri DocumentViewer.LibreOffice
qmlRegisterType<LODocument>(uri, 1, 0, "Document");
qmlRegisterType<LOView>(uri, 1, 0, "View");
+ qmlRegisterUncreatableType<LOPartsModel>(uri, 1, 0, "PartsModel", "You shouldn't create LOPartsModel in QML");
}
void LOPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/qml/Viewer.qml'
--- src/plugin/libreofficetoolkit-qml-plugin/qml/Viewer.qml 2015-09-18 11:18:17 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/qml/Viewer.qml 2015-10-08 21:01:04 +0000
@@ -23,22 +23,74 @@
property alias document: view.document
property alias zoomFactor: view.zoomFactor
property alias cacheBuffer: view.cacheBuffer
+ property alias partsModel: view.partsModel
+ property alias zoomMode: view.zoomMode
property string documentPath: ""
+ function adjustZoomToWidth()
+ {
+ view.adjustZoomToWidth();
+ }
+
+ function moveView(axis, diff)
+ {
+ if (axis == "vertical") {
+ var maxContentY = Math.max(0, rootFlickable.contentHeight - rootFlickable.height)
+ rootFlickable.contentY = Math.max(0, Math.min(rootFlickable.contentY + diff, maxContentY ))
+ } else {
+ var maxContentX = Math.max(0, rootFlickable.contentWidth - rootFlickable.width)
+ rootFlickable.contentX = Math.max(0, Math.min(rootFlickable.contentX + diff, maxContentX ))
+ }
+ }
+
+ function goNextPart()
+ {
+ document.currentPart = Math.min(document.currentPart + 1, document.partsCount - 1)
+ }
+
+ function goPreviousPart()
+ {
+ document.currentPart = Math.max(0, document.currentPart - 1)
+ }
+
+ function goFirstPart()
+ {
+ document.currentPart = 0
+ }
+
+ function goLastPart()
+ {
+ document.currentPart = document.partsCount - 1
+ }
+
onDocumentPathChanged: {
if (documentPath)
view.initializeDocument(documentPath)
}
- contentHeight: view.height * view.zoomFactor
- contentWidth: view.width * view.zoomFactor
+ // zoomFactor is not used here to set contentSize, since it's all managed
+ // internally, in the LibreOffice.View component.
+ contentHeight: view.height
+ contentWidth: view.width
boundsBehavior: Flickable.StopAtBounds
+ Component.onCompleted: adjustZoomToWidth()
+
LibreOffice.View {
id: view
parentFlickable: rootFlickable
}
+
+ Connections {
+ target: view.document
+
+ onCurrentPartChanged: {
+ // Position view at top-left corner
+ rootFlickable.contentX = 0
+ rootFlickable.contentY = 0
+ }
+ }
}
=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/renderengine.cpp'
--- src/plugin/libreofficetoolkit-qml-plugin/renderengine.cpp 2015-09-18 13:00:43 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/renderengine.cpp 2015-10-08 21:01:04 +0000
@@ -6,17 +6,30 @@
RenderEngine::RenderEngine():
QObject(nullptr),
- m_activeTaskCount(0)
+ m_activeTaskCount(0),
+ m_enabled(true),
+ m_lastPart(-1)
{
int itc = QThread::idealThreadCount();
m_idealThreadCount = itc == -1 ? DefaultIdealThreadCount : itc;
-}
-
-void RenderEngine::enqueueTask(const QSharedPointer<LODocument>& doc, const QRect& area, int id)
-{
- Q_ASSERT(doc != nullptr);
-
- m_queue.enqueue(EngineTask(doc, area, id));
+
+ connect(this, SIGNAL(enabledChanged()), this, SLOT(doNextTask()));
+}
+
+void RenderEngine::enqueueTask(const QSharedPointer<LODocument>& doc, int part, const QRect& area, const qreal &zoom, int id)
+{
+ Q_ASSERT(doc != nullptr);
+
+ m_queue.enqueue(EngineTask(doc, part, area, zoom, id));
+
+ doNextTask();
+}
+
+void RenderEngine::enqueueTask(const QSharedPointer<LODocument> &doc, int part, qreal size, int id)
+{
+ Q_ASSERT(doc != nullptr);
+
+ m_queue.enqueue(EngineTask(doc, part, size, id));
doNextTask();
}
@@ -30,10 +43,12 @@
}
}
-void RenderEngine::internalRenderCallback(int id, QImage img)
+void RenderEngine::internalRenderCallback(int id, QImage img, bool isThumbnail)
{
m_activeTaskCount--;
- Q_EMIT renderFinished(id, img);
+ if (isThumbnail)
+ Q_EMIT thumbnailRenderFinished(id, img);
+ else Q_EMIT renderFinished(id, img);
doNextTask();
}
@@ -43,14 +58,36 @@
qDebug() << " ---- doNextTask" << m_activeTaskCount << m_queue.count();
#endif
- if (m_activeTaskCount >= m_idealThreadCount || !m_queue.count())
+ // Check for too much threads or empty queue.
+ if (m_activeTaskCount >= m_idealThreadCount || !m_queue.count() || !m_enabled)
+ return;
+
+ // We should avoid different part rendering in the same time.
+ if (m_activeTaskCount && m_queue.head().part != m_lastPart)
return;
m_activeTaskCount++;
- auto task = m_queue.dequeue();
+ EngineTask task = m_queue.dequeue();
+
+ // Set correct part.
+ m_lastPart = task.part;
+ task.document->setDocumentPart(m_lastPart);
QtConcurrent::run( [=] {
- QImage img = task.document->paintTile(task.area.size(), task.area);
- QMetaObject::invokeMethod(this, "internalRenderCallback", Q_ARG(int, task.id), Q_ARG(QImage, img));
+ if (task.isThumbnail) {
+ QImage img = task.document->paintThumbnail(task.size);
+ QMetaObject::invokeMethod(this, "internalRenderCallback",
+ Q_ARG(int, task.id), Q_ARG(QImage, img), Q_ARG(bool, task.isThumbnail));
+ } else {
+ QImage img = task.document->paintTile(task.area.size(), task.area, task.zoom);
+ QMetaObject::invokeMethod(this, "internalRenderCallback",
+ Q_ARG(int, task.id), Q_ARG(QImage, img), Q_ARG(bool, task.isThumbnail));
+ }
+// QImage img = task.isThumbnail ?
+// //task.document->paintThumbnail(task.size) :
+// task.document->paintTile(task.area.size(), task.area, task.zoom) :
+// task.document->paintTile(task.area.size(), task.area, task.zoom);
+// QMetaObject::invokeMethod(this, "internalRenderCallback",
+// Q_ARG(int, task.id), Q_ARG(QImage, img), Q_ARG(bool, task.isThumbnail));
});
}
=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/renderengine.h'
--- src/plugin/libreofficetoolkit-qml-plugin/renderengine.h 2015-09-18 13:00:43 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/renderengine.h 2015-10-08 21:01:04 +0000
@@ -6,20 +6,46 @@
#include <QSharedPointer>
#include <QHash>
#include <QQueue>
+#include <QAtomicInt>
#include "lodocument.h"
+// TODO replace with class.
+
+
+// TODO Need more OOP here.
struct EngineTask
{
int id;
+ int part;
+ QSharedPointer<LODocument> document;
+ // Used in thumbnail rendering.
+ qreal size;
+ // Used in tile rendering.
QRect area;
- QSharedPointer<LODocument> document;
-
+ qreal zoom;
+ // Internal.
+ bool isThumbnail;
public:
- EngineTask(const QSharedPointer<LODocument>& d, const QRect& a, int i):
- id(i),
- area(a),
- document(d)
+
+ EngineTask(const QSharedPointer<LODocument>& d, int p, const QRect& a, const qreal& z, int i):
+ id(i),
+ part(p),
+ document(d),
+ size(0),
+ area(a),
+ zoom(z),
+ isThumbnail(false)
+ { }
+
+ EngineTask(const QSharedPointer<LODocument>& d, int p, qreal s, int i):
+ id(i),
+ part(p),
+ document(d),
+ size(s),
+ area(),
+ zoom(0),
+ isThumbnail(true)
{ }
};
@@ -34,7 +60,8 @@
const int DefaultIdealThreadCount = 2;
public:
- void enqueueTask(const QSharedPointer<LODocument>& doc, const QRect& area, int id);
+ void enqueueTask(const QSharedPointer<LODocument>& doc, int part, const QRect& area, const qreal& zoom, int id);
+ void enqueueTask(const QSharedPointer<LODocument>& doc, int part, qreal size, int id);
void dequeueTask(int id);
static RenderEngine* instance() {
@@ -43,17 +70,29 @@
return s_instance;
}
+ static int getNextId() {
+ static int idCounter = 0xDEAD0000;
+ return idCounter++;
+ }
+
Q_SIGNALS:
void renderFinished(int id, QImage img);
+ void thumbnailRenderFinished(int id, QImage img);
+ void enabledChanged();
private:
- Q_INVOKABLE void internalRenderCallback(int id, QImage img);
+ Q_INVOKABLE void internalRenderCallback(int id, QImage img, bool isThumbnail);
+
+private slots:
void doNextTask();
private:
QQueue<EngineTask> m_queue;
int m_activeTaskCount;
int m_idealThreadCount;
+ int m_lastPart;
+
+ QAtomicInt m_enabled;
};
#endif // RENDERENGINE_H
=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/sgtileitem.cpp'
--- src/plugin/libreofficetoolkit-qml-plugin/sgtileitem.cpp 2015-09-19 13:31:19 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/sgtileitem.cpp 2015-10-08 21:01:04 +0000
@@ -8,12 +8,13 @@
#include <QSGFlatColorMaterial>
#endif
-int SGTileItem::s_idCounter = 0xDEAD0000;
+//int SGTileItem::s_idCounter = 0xDEAD0000;
-SGTileItem::SGTileItem(const QRect& area, QQuickItem *parent)
+SGTileItem::SGTileItem(const QRect& area, qreal zoom, int id, QQuickItem *parent)
: QQuickItem(parent)
, m_area(area)
- , m_id (s_idCounter++)
+ , m_zoomFactor(zoom)
+ , m_id (id)
{
setFlag(ItemHasContents, true);
}
=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/sgtileitem.h'
--- src/plugin/libreofficetoolkit-qml-plugin/sgtileitem.h 2015-09-18 12:02:42 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/sgtileitem.h 2015-10-08 21:01:04 +0000
@@ -14,12 +14,15 @@
{
Q_OBJECT
public:
- SGTileItem(const QRect& area, QQuickItem *parent = 0);
+ SGTileItem(const QRect& area, qreal zoom, int id, QQuickItem *parent = 0);
~SGTileItem();
inline const QRect& area() { return m_area; }
inline void setArea(const QRect& rect) { m_area = rect; }
+ inline const qreal& zoomFactor() const { return m_zoomFactor; }
+ inline void setZoomFactor(const qreal &zoom) { m_zoomFactor = zoom; }
+
inline int id() { return m_id; }
inline void setId(int id) { m_id = id; }
@@ -37,10 +40,11 @@
private:
QRect m_area;
+ qreal m_zoomFactor;
QImage m_data;
int m_id;
- static int s_idCounter;
+ // static int s_idCounter;
};
#endif // SGTILEITEM_H
Follow ups