ubuntu-touch-coreapps-reviewers team mailing list archive
-
ubuntu-touch-coreapps-reviewers team
-
Mailing list archive
-
Message #05208
[Merge] lp:~verzegnassi-stefano/ubuntu-docviewer-app/reboot-lok-qsg-zoom into lp:ubuntu-docviewer-app/reboot
Stefano Verzegnassi has proposed merging lp:~verzegnassi-stefano/ubuntu-docviewer-app/reboot-lok-qsg-zoom into lp:ubuntu-docviewer-app/reboot.
Commit message:
[loviewer] Implemented zoom:
* Added a manual zoom mode
* Added an automatic zoom mode (fit zoom to flickable width)
* Added a bottom panel with a zoom selector (which includes a TextField and an OptionSelector)
Requested reviews:
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot): continuous-integration
Ubuntu Document Viewer Developers (ubuntu-docviewer-dev)
For more details, see:
https://code.launchpad.net/~verzegnassi-stefano/ubuntu-docviewer-app/reboot-lok-qsg-zoom/+merge/271895
[loviewer] Implemented zoom:
* Added a manual zoom mode
* Added an automatic zoom mode (fit zoom to flickable width)
* Added a bottom panel with a zoom selector (which includes a TextField and an OptionSelector)
--
Your team Ubuntu Document Viewer Developers is requested to review the proposed merge of lp:~verzegnassi-stefano/ubuntu-docviewer-app/reboot-lok-qsg-zoom into lp:ubuntu-docviewer-app/reboot.
=== modified file 'po/com.ubuntu.docviewer.pot'
--- po/com.ubuntu.docviewer.pot 2015-09-21 10:39:04 +0000
+++ po/com.ubuntu.docviewer.pot 2015-09-22 19:03:33 +0000
@@ -8,7 +8,7 @@
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2015-09-21 12:38+0200\n"
+"POT-Creation-Date: 2015-09-22 21:00+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@xxxxxx>\n"
@@ -19,12 +19,12 @@
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
#: ../src/app/docviewer-application.cpp:162
-#: /tmp/build-20-reboot-contenthub-update-translations-Desktop-Default/po/com.ubuntu.docviewer.desktop.in.in.h:1
+#: /home/stefano/build-reboot-qsg-impress-support-Desktop-Default/po/com.ubuntu.docviewer.desktop.in.in.h:1
msgid "Document Viewer"
msgstr ""
#: ../src/app/qml/common/DetailsPage.qml:27
-#: ../src/app/qml/loView/LOViewDefaultHeader.qml:112
+#: ../src/app/qml/loView/LOViewDefaultHeader.qml:114
#: ../src/app/qml/pdfView/PdfViewDefaultHeader.qml:97
#: ../src/app/qml/textView/TextViewDefaultHeader.qml:83
msgid "Details"
@@ -63,7 +63,7 @@
#: ../src/app/qml/common/RejectedImportDialog.qml:38
#: ../src/app/qml/documentPage/DocumentPageSelectionModeHeader.qml:32
#: ../src/app/qml/documentPage/SortSettingsDialog.qml:53
-#: ../src/app/qml/loView/LOViewDefaultHeader.qml:76
+#: ../src/app/qml/loView/LOViewDefaultHeader.qml:79
#: ../src/app/qml/pdfView/PdfViewDefaultHeader.qml:61
#: ../src/app/qml/textView/TextViewDefaultHeader.qml:61
msgid "Close"
@@ -151,7 +151,6 @@
#: ../src/app/qml/documentPage/DeleteFileDialog.qml:44
#: ../src/app/qml/documentPage/DocumentPagePickModeHeader.qml:28
-#: ../src/app/qml/loView/LOViewGotoDialog.qml:52
#: ../src/app/qml/pdfView/PdfViewGotoDialog.qml:52
msgid "Cancel"
msgstr ""
@@ -254,7 +253,8 @@
msgstr ""
#: ../src/app/qml/documentPage/DocumentPageSearchHeader.qml:27
-#: ../src/app/qml/loView/LOViewDefaultHeader.qml:76
+#: ../src/app/qml/loView/LOViewDefaultHeader.qml:79
+#: ../src/app/qml/loView/LOViewPage.qml:186
#: ../src/app/qml/pdfView/PdfViewDefaultHeader.qml:61
#: ../src/app/qml/textView/TextViewDefaultHeader.qml:61
msgid "Back"
@@ -305,61 +305,85 @@
msgid "Reverse order"
msgstr ""
-#: ../src/app/qml/loView/LOViewDefaultHeader.qml:57
+#: ../src/app/qml/loView/LOViewDefaultHeader.qml:56
+#: ../src/app/qml/textView/TextView.qml:42
+msgid "Loading..."
+msgstr ""
+
+#: ../src/app/qml/loView/LOViewDefaultHeader.qml:60
msgid "LibreOffice text document"
msgstr ""
-#: ../src/app/qml/loView/LOViewDefaultHeader.qml:59
+#: ../src/app/qml/loView/LOViewDefaultHeader.qml:62
msgid "LibreOffice spread sheet"
msgstr ""
-#: ../src/app/qml/loView/LOViewDefaultHeader.qml:61
+#: ../src/app/qml/loView/LOViewDefaultHeader.qml:64
msgid "LibreOffice presentation"
msgstr ""
-#: ../src/app/qml/loView/LOViewDefaultHeader.qml:63
+#: ../src/app/qml/loView/LOViewDefaultHeader.qml:66
msgid "LibreOffice Draw document"
msgstr ""
-#: ../src/app/qml/loView/LOViewDefaultHeader.qml:65
+#: ../src/app/qml/loView/LOViewDefaultHeader.qml:68
msgid "Unknown LibreOffice document"
msgstr ""
-#: ../src/app/qml/loView/LOViewDefaultHeader.qml:67
+#: ../src/app/qml/loView/LOViewDefaultHeader.qml:70
msgid "Unknown type document"
msgstr ""
-#: ../src/app/qml/loView/LOViewDefaultHeader.qml:100
+#: ../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..."
msgstr ""
-#: ../src/app/qml/loView/LOViewDefaultHeader.qml:106
+#: ../src/app/qml/loView/LOViewDefaultHeader.qml:108
#: ../src/app/qml/pdfView/PdfViewDefaultHeader.qml:91
#: ../src/app/qml/textView/TextViewDefaultHeader.qml:77
msgid "Disable night mode"
msgstr ""
-#: ../src/app/qml/loView/LOViewDefaultHeader.qml:106
+#: ../src/app/qml/loView/LOViewDefaultHeader.qml:108
#: ../src/app/qml/pdfView/PdfViewDefaultHeader.qml:91
#: ../src/app/qml/textView/TextViewDefaultHeader.qml:77
msgid "Enable night mode"
msgstr ""
-#: ../src/app/qml/loView/LOViewGotoDialog.qml:25
-#: ../src/app/qml/pdfView/PdfViewGotoDialog.qml:25
-msgid "Go to page"
-msgstr ""
-
-#: ../src/app/qml/loView/LOViewGotoDialog.qml:26
-#: ../src/app/qml/pdfView/PdfViewGotoDialog.qml:26
-#, qt-format
-msgid "Choose a page between 1 and %1"
-msgstr ""
-
-#: ../src/app/qml/loView/LOViewGotoDialog.qml:44
-#: ../src/app/qml/pdfView/PdfViewGotoDialog.qml:44
-msgid "GO!"
+#: ../src/app/qml/loView/LOViewPage.qml:41
+#: ../src/app/qml/loView/LOViewPage.qml:184
+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/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%"
msgstr ""
#. TRANSLATORS: "Contents" refers to the "Table of Contents" of a PDF document.
@@ -379,8 +403,17 @@
msgid "Page %1 of %2"
msgstr ""
-#: ../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!"
msgstr ""
#. TRANSLATORS: This string is used for renaming a copied file,
@@ -392,11 +425,11 @@
#.
#. where "2" is given by the argument "%1"
#.
-#: ../src/plugin/file-qml-plugin/docviewerutils.cpp:99
+#: ../src/plugin/file-qml-plugin/docviewerutils.cpp:101
#, qt-format
msgid "copy %1"
msgstr ""
-#: /tmp/build-20-reboot-contenthub-update-translations-Desktop-Default/po/com.ubuntu.docviewer.desktop.in.in.h:2
+#: /home/stefano/build-reboot-qsg-impress-support-Desktop-Default/po/com.ubuntu.docviewer.desktop.in.in.h:2
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-09-22 19:03:33 +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-09-22 19:03:33 +0000
@@ -0,0 +1,57 @@
+/*
+ * 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;
+
+ if (event.key == Qt.Key_PageUp) {
+ if (loDocument.documentType == LO.Document.PresentationDocument)
+ loDocument.currentPart -= 1
+ else
+ loPage.moveView("vertical", -loView.height)
+
+ return;
+ }
+
+ if (event.key == Qt.Key_PageDown) {
+ if (loDocument.documentType == LO.Document.PresentationDocument)
+ loDocument.currentPart += 1
+ else
+ loPage.moveView("vertical", loView.height)
+
+ return;
+ }
+
+ if (event.key == Qt.Key_Up) {
+ loPage.moveView("vertical", -pixelDiff)
+ return;
+ }
+
+ if (event.key == Qt.Key_Down) {
+ loPage.moveView("vertical", pixelDiff)
+ return;
+ }
+
+ if (event.key == Qt.Key_Left) {
+ loPage.moveView("horizontal", -pixelDiff)
+ return;
+ }
+
+ if (event.key == Qt.Key_Right) {
+ loPage.moveView("horizontal", pixelDiff)
+ return;
+ }
+}
=== modified file 'src/app/qml/loView/LOViewDefaultHeader.qml'
--- src/app/qml/loView/LOViewDefaultHeader.qml 2015-06-26 14:56:23 +0000
+++ src/app/qml/loView/LOViewDefaultHeader.qml 2015-09-22 19:03:33 +0000
@@ -52,7 +52,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:
@@ -88,17 +91,16 @@
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"
text: i18n.tr("Go to page...")
- onTriggered: PopupUtils.open(Qt.resolvedUrl("LOViewGotoDialog.qml"), targetPage)
+ enabled: false
},
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();
- }
-}
=== removed file 'src/app/qml/loView/LOViewGotoDialog.qml'
--- src/app/qml/loView/LOViewGotoDialog.qml 2015-06-24 12:04:16 +0000
+++ src/app/qml/loView/LOViewGotoDialog.qml 1970-01-01 00:00:00 +0000
@@ -1,60 +0,0 @@
-/*
- * 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 Ubuntu.Components.Popups 1.0
-
-Dialog {
- id: goToPageDialog
- objectName:"LOViewGotoDialog"
-
- title: i18n.tr("Go to page")
- text: i18n.tr("Choose a page between 1 and %1").arg(loView.count)
-
- TextField {
- id: goToPageTextField
- objectName:"goToPageTextField"
-
- width: parent.width
-
- hasClearButton: true
- inputMethodHints: Qt.ImhFormattedNumbersOnly
- validator: IntValidator{ bottom: 1; top: loView.count }
-
- Keys.onReturnPressed: goToPage()
- Component.onCompleted: forceActiveFocus()
- }
-
- Button {
- objectName:"GOButton"
- text: i18n.tr("GO!")
- color: UbuntuColors.green
-
- enabled: goToPageTextField.acceptableInput
- onClicked: goToPage()
- }
-
- Button {
- text: i18n.tr("Cancel")
- onClicked: PopupUtils.close(goToPageDialog)
- }
-
- function goToPage() {
- loView.positionAtIndex((goToPageTextField.text - 1))
- PopupUtils.close(goToPageDialog)
- }
-}
=== 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-09-22 19:03:33 +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)
+
+ bottomEdgeEnabled: {
+ if (!loPageContentLoader.loaded)
+ return false
+
+ // else
+ return loPageContentLoader.item.loDocument.documentType == LO.Document.PresentationDocument && !wideWindow
+ }
+ bottomEdgeTitle: i18n.tr("Slides")
+
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
}
@@ -46,32 +71,145 @@
id: loPageContentComponent
Item {
+ id: loPageContent
+ anchors.fill: parent
property alias loDocument: loView.document
-
- LO.Viewer {
- id: loView
- objectName: "loView"
+ property alias loView: loView
+ property alias bottomEdgePartsPage: bottomEdgePartsPage
+
+ function moveView(axis, diff) {
+ if (axis == "vertical") {
+ var maxContentY = Math.max(0, loView.contentHeight - loView.height)
+ loView.contentY = Math.max(0, Math.min(loView.contentY + diff, maxContentY ))
+ } else {
+ var maxContentX = Math.max(0, loView.contentWidth - loView.width)
+ loView.contentX = Math.max(0, Math.min(loView.contentX + diff, maxContentX ))
+ }
+ }
+
+ 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: partsModel
+ visible: model
+ 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 }
+ }
+
+ 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
+
+ Component.onCompleted: {
+ // WORKAROUND: Fix for wrong grid unit size
+ flickDeceleration = 1500 * units.gridUnit / 8
+ maximumFlickVelocity = 2500 * units.gridUnit / 8
+ }
+
+ 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 {
+ anchors.fill: parent
+ model: 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-09-22 19:03:33 +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-09-22 19:03:33 +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-09-22 19:03:33 +0000
@@ -0,0 +1,81 @@
+/*
+ * 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 ? view.model.document.currentPart : -1
+
+ delegate: ListItemWithActions {
+ id: delegate
+
+ width: parent.width
+ height: units.gu(16)
+
+ color: (view.model.document.currentPart === model.index) ? Theme.palette.selected.background
+ : "transparent"
+
+ AbstractButton {
+ objectName: "abstractbutton"
+ anchors.fill: parent
+
+ onClicked: {
+ view.model.document.currentPart = model.index
+ pageStack.pop();
+ }
+ }
+
+ RowLayout {
+ anchors.fill: parent
+ spacing: units.gu(1)
+
+ Image {
+ Layout.fillHeight: true
+ Layout.preferredWidth: height
+ fillMode: Image.PreserveAspectFit
+
+ source: "image://lok/part/" + model.index
+ }
+
+ Label {
+ Layout.fillWidth: true
+ wrapMode: Text.WordWrap
+ text: model.name
+ color: (view.model.document.currentPart === model.index) ? UbuntuColors.orange
+ : Theme.palette.selected.backgroundText
+ }
+
+ Label {
+ text: model.index + 1
+ color: (view.model.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-09-22 19:03:33 +0000
@@ -0,0 +1,67 @@
+/*
+ * 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.loDocument.currentPart -= 1
+
+ Icon {
+ id: icon
+ anchors.centerIn: parent
+ width: units.gu(2.5); height: width
+ name: "go-previous"
+ }
+ }
+
+ Label {
+ text: "%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.loDocument.currentPart += 1
+
+ Icon {
+ anchors.centerIn: parent
+ width: units.gu(2.5); height: width
+ name: "go-next"
+ }
+ }
+ }
+}
=== 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-09-22 19:03:33 +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/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-09-22 19:03:33 +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-09-22 19:03:33 +0000
@@ -60,6 +60,25 @@
this->loadDocument(m_path);
}
+int LODocument::currentPart() {
+ if (!m_document)
+ return int(-1);
+
+ return m_document->getPart();
+}
+
+void LODocument::setCurrentPart(int index)
+{
+ if (!m_document)
+ return;
+
+ if (this->currentPart() == index || index < 0 || index > partsCount() - 1)
+ return;
+
+ m_document->setPart(index);
+ Q_EMIT currentPartChanged();
+}
+
// Load the document
bool LODocument::loadDocument(const QString &pathName)
{
@@ -106,7 +125,7 @@
// 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)
{
QImage result = QImage(canvasSize.width(), canvasSize.height(), QImage::Format_RGB32);
@@ -117,10 +136,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 +148,33 @@
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::fromLatin1(m_document->getPartName(index));
+}
+
+// This is used by LOPartsImageProvider to temporarily change the current part,
+// in order to generate thumbnails.
+// FIXME: We need to disable tiled rendering when we're generating the thumbnail.
+int LODocument::swapCurrentPart(int newPartIndex)
+{
+ int oldIndex = this->currentPart();
+
+ m_document->setPart(newPartIndex);
+ return oldIndex;
+}
+
/* 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-09-22 19:03:33 +0000
@@ -31,6 +31,9 @@
Q_DISABLE_COPY(LODocument)
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(DocumentType documentType READ documentType NOTIFY documentTypeChanged)
Q_ENUMS(DocumentType)
@@ -49,15 +52,27 @@
QString path() const;
void setPath(const QString& pathName);
+ int currentPart();
+ void setCurrentPart(int index);
+
DocumentType documentType() const;
QSize documentSize() const;
- QImage paintTile(const QSize& canvasSize, const QRect& tileSize);
+
+ QImage paintTile(const QSize& canvasSize, const QRect& tileSize, const qreal& zoom = 1.0);
+
+ int partsCount();
+
+ QString getPartName(int index) const;
+ int swapCurrentPart(int newPartIndex);
+
+ void setPart(int index);
Q_INVOKABLE bool saveAs(QString url, QString format, QString filterOptions);
Q_SIGNALS:
void pathChanged();
+ void currentPartChanged();
void documentTypeChanged();
private:
=== 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-09-22 19:03:33 +0000
@@ -0,0 +1,77 @@
+/*
+ * 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 "config.h"
+#include "twips.h"
+
+#include <QDebug>
+
+LOPartsImageProvider::LOPartsImageProvider(LODocument *document)
+ : QQuickImageProvider(QQuickImageProvider::Image, QQuickImageProvider::ForceAsynchronousImageLoading)
+{
+ m_document = document;
+}
+
+QImage LOPartsImageProvider::requestImage(const QString & id, QSize * size, const QSize & requestedSize)
+{
+ Q_UNUSED(size)
+ Q_UNUSED(requestedSize)
+
+ if (m_document->documentType() != LODocument::PresentationDocument)
+ return QImage();
+
+ // Here's the tricky magic. For getting a thumbnail of a document part
+ // (e.g. a specific slide in a Impress document), we need to change the
+ // current active part in LODocument, render the thumbnail, then re-set
+ // the previous value through lok::Document::setPath(index).
+ QString type = id.section("/", 0, 0);
+
+ if (type != "part")
+ return QImage();
+
+ int partNumber = id.section("/", 1, 1).toInt();
+ QImage result;
+ QSize partSize;
+ QSize resultSize;
+
+ // Get the current part index and set the index of the part to be rendered.
+ int currentPart = m_document->swapCurrentPart(partNumber);
+
+ // Get the size of the part
+ partSize = m_document->documentSize();
+ partSize.setHeight(Twips::convertTwipsToPixels(partSize.height()));
+ partSize.setWidth(Twips::convertTwipsToPixels(partSize.width()));
+
+ // Set the size of the rendered thumbnail
+ if (partSize.width() > partSize.height()) {
+ resultSize.setWidth(TILE_SIZE);
+ resultSize.setHeight(TILE_SIZE * partSize.height() / partSize.width());
+ } else {
+ resultSize.setHeight(TILE_SIZE);
+ resultSize.setWidth(TILE_SIZE * partSize.width() / partSize.height());
+ }
+
+ // Render the part to QImage
+ result = m_document->paintTile(resultSize, QRect(QPoint(0, 0), partSize));
+
+ // Re-set the earlier current part
+ m_document->swapCurrentPart(currentPart);
+
+ return result;
+
+}
=== 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-09-22 19:03:33 +0000
@@ -0,0 +1,35 @@
+/*
+ * 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>
+
+class LODocument;
+
+class LOPartsImageProvider : public QQuickImageProvider
+{
+public:
+ LOPartsImageProvider(LODocument *document);
+ QImage requestImage(const QString & id, QSize * size, const QSize & requestedSize);
+
+private:
+ 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-09-22 19:03:33 +0000
@@ -0,0 +1,125 @@
+/*
+ * 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(QAbstractListModel *parent):
+ QAbstractListModel(parent)
+{
+ connect(this, SIGNAL(documentChanged()), this, SLOT(fillModel()));
+}
+
+void LOPartsModel::setDocument(LODocument *document)
+{
+ if (m_document == document)
+ return;
+
+ m_document = document;
+ Q_EMIT documentChanged();
+
+ QQmlEngine *engine = QQmlEngine::contextForObject(this)->engine();
+ QString imageProviderName = "lok";
+
+ if (engine->imageProvider(imageProviderName))
+ engine->removeImageProvider(imageProviderName);
+
+ engine->addImageProvider(imageProviderName, new LOPartsImageProvider(m_document));
+
+}
+
+QHash<int, QByteArray> LOPartsModel::roleNames() const
+{
+ QHash<int, QByteArray> roles;
+ roles[IndexRole] = "index";
+ roles[NameRole] = "name";
+
+ 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;
+
+ 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;
+
+ return map;
+}
+
+void LOPartsModel::fillModel() {
+ if (m_document) {
+ if (!m_entries.isEmpty()) {
+ beginRemoveRows(QModelIndex(), 0, rowCount());
+ m_entries.clear();
+ endRemoveRows();
+ }
+
+ int partsCount = m_document->partsCount();
+
+ for (int i = 0; i < partsCount; i++) {
+ LOPartEntry part;
+ part.index = i;
+ part.name = m_document->getPartName(i);
+
+ beginRemoveRows(QModelIndex(), rowCount(), rowCount());
+ m_entries.append(part);
+ endRemoveRows();
+ }
+
+ 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-09-22 19:03:33 +0000
@@ -0,0 +1,70 @@
+/*
+ * 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>
+
+class LODocument;
+
+class LOPartEntry
+{
+public:
+ QString name;
+ int index = 0;
+};
+
+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,
+ IndexRole
+ };
+
+ explicit LOPartsModel(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;
+
+Q_SIGNALS:
+ void documentChanged();
+ void countChanged();
+
+private slots:
+ void fillModel();
+
+private:
+ 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-09-22 19:03:33 +0000
@@ -25,6 +25,13 @@
#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)
@@ -72,8 +79,14 @@
void LOView::initializeDocument(const QString &path)
{
+ if (m_document.data())
+ m_document.data()->disconnect(this);
+
m_document = QSharedPointer<LODocument>(new LODocument());
m_document->setPath(path);
+
+ connect(m_document.data(), SIGNAL(currentPartChanged()), this, SLOT(invalidateAllTiles()));
+
Q_EMIT documentChanged();
}
@@ -83,22 +96,38 @@
return m_document.data();
}
-// Not used yet.
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 +142,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 +181,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 +196,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 +300,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 +314,13 @@
qDebug() << "Creating tile indexed as" << index;
#endif
- auto tile = new SGTileItem(rect, this);
+ auto tile = new SGTileItem(rect, m_zoomFactor, this);
m_tiles.insert(index, tile);
- RenderEngine::instance()->enqueueTask(m_document, rect, tile->id());
+ RenderEngine::instance()->enqueueTask(m_document, rect, m_zoomFactor, tile->id());
}
#ifdef DEBUG_VERBOSE
else {
- qDebug() << "tile" << x << "x" << y << "already exists";
+ qDebug() << "tile" << index << "already exists";
}
#endif
}
@@ -251,6 +342,14 @@
}
}
+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)));
=== 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-09-22 19:03:33 +0000
@@ -30,17 +30,22 @@
class LOView : public QQuickItem
{
Q_OBJECT
+ Q_ENUMS(ZoomMode)
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(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);
@@ -49,28 +54,36 @@
LODocument* document() 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 zoomFactorChanged();
+ void zoomModeChanged();
void cacheBufferChanged();
private Q_SLOTS:
void updateViewSize();
void updateVisibleRect();
void scheduleVisibleRectUpdate();
+ void invalidateAllTiles();
void renderResultReceived(int id, QImage img);
private:
+
QQuickItem* m_parentFlickable;
QSharedPointer<LODocument> m_document;
qreal m_zoomFactor;
+ ZoomMode m_zoomMode;
int m_cacheBuffer;
QRect m_visibleArea;
@@ -82,6 +95,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-09-22 19:03:33 +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");
+ qmlRegisterType<LOPartsModel>(uri, 1, 0, "PartsModel");
}
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-09-22 19:03:33 +0000
@@ -24,18 +24,28 @@
property alias zoomFactor: view.zoomFactor
property alias cacheBuffer: view.cacheBuffer
+ property alias zoomMode: view.zoomMode
property string documentPath: ""
+ function adjustZoomToWidth()
+ {
+ view.adjustZoomToWidth();
+ }
+
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
=== 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-09-22 19:03:33 +0000
@@ -12,11 +12,11 @@
m_idealThreadCount = itc == -1 ? DefaultIdealThreadCount : itc;
}
-void RenderEngine::enqueueTask(const QSharedPointer<LODocument>& doc, const QRect& area, int id)
+void RenderEngine::enqueueTask(const QSharedPointer<LODocument>& doc, const QRect& area, const qreal &zoom, int id)
{
Q_ASSERT(doc != nullptr);
- m_queue.enqueue(EngineTask(doc, area, id));
+ m_queue.enqueue(EngineTask(doc, area, zoom, id));
doNextTask();
}
@@ -50,7 +50,7 @@
auto task = m_queue.dequeue();
QtConcurrent::run( [=] {
- QImage img = task.document->paintTile(task.area.size(), task.area);
+ 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));
});
}
=== 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-09-22 19:03:33 +0000
@@ -13,12 +13,14 @@
{
int id;
QRect area;
+ qreal zoom;
QSharedPointer<LODocument> document;
public:
- EngineTask(const QSharedPointer<LODocument>& d, const QRect& a, int i):
+ EngineTask(const QSharedPointer<LODocument>& d, const QRect& a, const qreal& z, int i):
id(i),
area(a),
+ zoom(z),
document(d)
{ }
};
@@ -34,7 +36,7 @@
const int DefaultIdealThreadCount = 2;
public:
- void enqueueTask(const QSharedPointer<LODocument>& doc, const QRect& area, int id);
+ void enqueueTask(const QSharedPointer<LODocument>& doc, const QRect& area, const qreal& zoom, int id);
void dequeueTask(int id);
static RenderEngine* instance() {
=== 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-09-22 19:03:33 +0000
@@ -10,9 +10,10 @@
int SGTileItem::s_idCounter = 0xDEAD0000;
-SGTileItem::SGTileItem(const QRect& area, QQuickItem *parent)
+SGTileItem::SGTileItem(const QRect& area, const qreal &zoom, QQuickItem *parent)
: QQuickItem(parent)
, m_area(area)
+ , m_zoomFactor(zoom)
, m_id (s_idCounter++)
{
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-09-22 19:03:33 +0000
@@ -14,12 +14,15 @@
{
Q_OBJECT
public:
- SGTileItem(const QRect& area, QQuickItem *parent = 0);
+ SGTileItem(const QRect& area, const qreal &zoom = 1.0, 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,6 +40,7 @@
private:
QRect m_area;
+ qreal m_zoomFactor;
QImage m_data;
int m_id;
Follow ups