← Back to team overview

ubuntu-touch-coreapps-reviewers team mailing list archive

[Merge] lp:~verzegnassi-stefano/ubuntu-docviewer-app/lok-content-centered into lp:ubuntu-docviewer-app

 

Stefano Verzegnassi has proposed merging lp:~verzegnassi-stefano/ubuntu-docviewer-app/lok-content-centered into lp:ubuntu-docviewer-app.

Commit message:
LibreOffice viewer:
* Show the viewer content at the center of the canvas (excluded spreadsheets)
* Fixed some bug in ScalingPinchArea
* Added a ScalingMouseArea component, for handling the double-tap-to-zoom gesture
* Set the zoom behaviour according to the parameters returned by LOZoom class
* Changed background color for the viewer
* Fixed 'rebound' behaviour for the LOK Viewer
* Added missing signal emissions in LOZoom

Requested reviews:
  Ubuntu Document Viewer Developers (ubuntu-docviewer-dev)
Related bugs:
  Bug #1501424 in Ubuntu Document Viewer App: "Follow zoom maximum/minimum limit in view controls"
  https://bugs.launchpad.net/ubuntu-docviewer-app/+bug/1501424
  Bug #1515655 in Ubuntu Document Viewer App: "LO content should be centred to the window, if it's smaller than the window itself."
  https://bugs.launchpad.net/ubuntu-docviewer-app/+bug/1515655
  Bug #1541582 in Ubuntu Document Viewer App: "Add double-tap-to-zoom gesture in the LibreOffice viewer"
  https://bugs.launchpad.net/ubuntu-docviewer-app/+bug/1541582

For more details, see:
https://code.launchpad.net/~verzegnassi-stefano/ubuntu-docviewer-app/lok-content-centered/+merge/283196

LibreOffice viewer:
* Show the viewer content at the center of the canvas (excluded spreadsheets)
* Fixed some bug in ScalingPinchArea
* Added a ScalingMouseArea component, for handling the double-tap-to-zoom gesture
* Set the zoom behaviour according to the parameters returned by LOZoom class
* Changed background color for the viewer
* Fixed 'rebound' behaviour for the LOK Viewer
* Added missing signal emissions in LOZoom
-- 
Your team Ubuntu Document Viewer Developers is requested to review the proposed merge of lp:~verzegnassi-stefano/ubuntu-docviewer-app/lok-content-centered into lp:ubuntu-docviewer-app.
=== added file 'src/app/qml/common/ScalingMouseArea.qml'
--- src/app/qml/common/ScalingMouseArea.qml	1970-01-01 00:00:00 +0000
+++ src/app/qml/common/ScalingMouseArea.qml	2016-02-03 21:36:44 +0000
@@ -0,0 +1,116 @@
+import QtQuick 2.4
+
+MouseArea {
+    id: mouseArea
+    property Flickable targetFlickable: null
+    property real totalScale: 1
+
+    property real minimumZoom: 0.5
+    property real thresholdZoom: 1.0
+    property real maximumZoom: 4.0
+    property int zoomDuration: 100
+
+    property real zoomValue: 1
+
+    onDoubleClicked: {
+        var flick = targetFlickable
+
+        var tpt = mouseArea.mapToItem(flick, mouse.x, mouse.y )
+        tpt.x -= flick.width * 0.5
+        tpt.y -= flick.height * 0.5
+
+        var pt = mouseArea.mapToItem(flick.contentItem, mouse.x, mouse.y)
+
+        scaleInfo.fromZoom = zoomValue
+
+        if (zoomValue <= thresholdZoom) {
+            scaleInfo.toZoom = maximumZoom
+        } else {
+            scaleInfo.toZoom = minimumZoom
+        }
+
+        scaleInfo.tempContentX = tpt.x * scaleInfo.effectiveZoom - (flick.width * 0.5)
+        scaleInfo.tempContentY = tpt.y * scaleInfo.effectiveZoom - (flick.height * 0.5)
+
+        scaleInfo.finalContentX = Math.max(0, Math.min(pt.x * scaleInfo.effectiveZoom - (flick.width * 0.5),
+                                                            (flick.contentWidth * scaleInfo.effectiveZoom) - flick.width))
+
+        scaleInfo.finalContentY = Math.max(0, Math.min(pt.y * scaleInfo.effectiveZoom - (flick.height * 0.5),
+                                                            (flick.contentHeight * scaleInfo.effectiveZoom) - flick.height))
+
+        if (zoomValue <= thresholdZoom) {
+            zoomInAnimation.start()
+        } else {
+            zoomOutAnimation.start()
+        }
+    }
+
+
+    QtObject {
+        id: scaleInfo
+
+        property real fromZoom: 1.0
+        property real toZoom: 1.0
+        property real effectiveZoom: toZoom / fromZoom
+
+        property int tempContentX: 0
+        property int tempContentY: 0
+
+        property int finalContentX: 0
+        property int finalContentY: 0
+    }
+
+    SequentialAnimation {
+        id: zoomInAnimation
+
+        ScriptAction { script: targetFlickable.interactive = false; }
+
+        // Fake zooming
+        ParallelAnimation {
+            NumberAnimation {
+                target: targetFlickable.contentItem
+                property: "scale"
+                duration: mouseArea.zoomDuration
+                to: scaleInfo.effectiveZoom
+            }
+
+            NumberAnimation {
+                target: targetFlickable
+                property: "contentX"
+                duration: mouseArea.zoomDuration
+                to: scaleInfo.tempContentX
+            }
+
+            NumberAnimation {
+                target: targetFlickable
+                property: "contentY"
+                duration: mouseArea.zoomDuration
+                to: scaleInfo.tempContentY
+            }
+        }
+
+        ScriptAction { script: targetFlickable.contentItem.scale = 1; }
+
+        ScriptAction { script: totalScale = scaleInfo.toZoom; }
+        ScriptAction { script: targetFlickable.contentX = scaleInfo.finalContentX; }
+        ScriptAction { script: targetFlickable.contentY = scaleInfo.finalContentY; }
+
+        ScriptAction { script: targetFlickable.returnToBounds(); }
+
+        ScriptAction { script: targetFlickable.interactive = true; }
+    }
+
+    SequentialAnimation {
+        id: zoomOutAnimation
+
+        ScriptAction { script: targetFlickable.interactive = false; }
+
+        ScriptAction { script: totalScale = scaleInfo.toZoom; }
+        ScriptAction { script: targetFlickable.contentX = scaleInfo.finalContentX; }
+        ScriptAction { script: targetFlickable.contentY = scaleInfo.finalContentY; }
+
+        ScriptAction { script: targetFlickable.returnToBounds(); }
+
+        ScriptAction { script: targetFlickable.interactive = true; }
+    }
+}

=== modified file 'src/app/qml/common/ScalingPinchArea.qml'
--- src/app/qml/common/ScalingPinchArea.qml	2015-11-21 18:47:25 +0000
+++ src/app/qml/common/ScalingPinchArea.qml	2016-02-03 21:36:44 +0000
@@ -3,53 +3,57 @@
 PinchArea {
     id: pinchArea
 
-    property var targetFlickable: null
+    property Flickable targetFlickable: null
     property real totalScale: 1
 
+    property real minimumZoom: 0.5
+    property real maximumZoom: 4.0
+    property alias zoomValue: zoomHelper.scale
+
+    pinch {
+        target: Item { id: zoomHelper }
+        minimumScale: pinchArea.minimumZoom
+        maximumScale: pinchArea.maximumZoom
+    }
+
+    onPinchStarted: {
+        targetFlickable.interactive = false
+    }
+
     onPinchUpdated: {
         pinchUpdatedHandler(pinch)
     }
+
     onPinchFinished: {
+        targetFlickable.interactive = true
         pinchFinishedHandler()
     }
 
-    // ------------------------ Desktop DEBUG
-
-//    MouseArea {
-//        id: testMa
-//        anchors.fill: parent
-//        visible: Qt.platform.os == "linux"
-//        z: 19
-//        acceptedButtons: Qt.RightButton
-
-//        property int touchPointY
-//        property int touchPointX
-//        onPressed: {
-//            touchPointY = mouse.y
-//            touchPointX = mouse.x
-//        }
-//        onPositionChanged: {
-//            var sc = (1 + (mouse.y - touchPointY) / 200)
-//            pinchUpdatedHandler({"center" : { "x" : mouse.x, "y" : mouse.y }, "scale" : sc })
-//        }
-//        onReleased: {
-//            pinchFinishedHandler()
-//        }
-//    }
-
-    // ------------------------ Desktop DEBUG end
-
     function pinchUpdatedHandler(pinch) {
-        targetFlickable.scale = pinch.scale
+        if (zoomHelper.scale < pinchArea.maximumZoom &&
+                zoomHelper.scale > pinchArea.minimumZoom) {
+            targetFlickable.scale = pinch.scale
+        }
     }
 
     function pinchFinishedHandler() {
         var pt = pinchArea.mapFromItem(targetFlickable, -targetFlickable.contentX , -targetFlickable.contentY )
         // console.log("pinchFinishedHandler", -myItem.contentX, -myItem.contentY, Math.round(pt.x), Math.round(pt.y))
-        targetFlickable.contentX = -pt.x
-        targetFlickable.contentY = -pt.y
 
-        totalScale = targetFlickable.scale * totalScale
+        totalScale = zoomHelper.scale
         targetFlickable.scale = 1
+
+        // Overwrite contentX and contentY values.
+        // This is required since a change in contentWidth or contentHeight causes
+        // the Flickable to reset the position of the its content.
+
+        if (targetFlickable.contentWidth > targetFlickable.width)
+            targetFlickable.contentX = -pt.x
+
+        if (targetFlickable.contentHeight > targetFlickable.height)
+            targetFlickable.contentY = -pt.y
+
+        // Return to the legal bounds
+        targetFlickable.returnToBounds()
     }
 }

=== modified file 'src/app/qml/loView/LOViewPage.qml'
--- src/app/qml/loView/LOViewPage.qml	2016-01-29 12:12:54 +0000
+++ src/app/qml/loView/LOViewPage.qml	2016-02-03 21:36:44 +0000
@@ -95,10 +95,26 @@
                 id: pinchArea
                 objectName: "pinchArea"
                 Layouts.item: "pinchArea"
+                clip: true
 
                 targetFlickable: loView
                 onTotalScaleChanged: targetFlickable.updateContentSize(totalScale)
 
+                maximumZoom: loView.zoomSettings.maximumZoom
+                minimumZoom: {
+                    if (DocumentViewer.desktopMode || mainView.wideWindow)
+                        return loView.zoomSettings.minimumZoom
+
+                    switch(loView.document.documentType) {
+                    case LibreOffice.Document.TextDocument:
+                        return loView.zoomSettings.valueFitToWidthZoom
+                    case LibreOffice.Document.PresentationDocument:
+                        return loView.zoomSettings.valueAutomaticZoom
+                    default:
+                        return loView.zoomSettings.minimumZoom
+                    }
+                }
+
                 anchors {
                     top: parent.top
                     left: parent.left
@@ -106,12 +122,26 @@
                     bottom: bottomBar.top
                 }
 
+                Binding {
+                    when: !pinchArea.pinch.active
+                    target: pinchArea
+                    property: "zoomValue"
+                    value: loView.zoomSettings.zoomFactor
+                }
+
+                Rectangle {
+                    // Since UITK 1.3, the MainView background is white.
+                    // We need to set a different color, otherwise pages
+                    // boundaries are not visible.
+                    anchors.fill: parent
+                    color: "#f5f5f5"
+                }
+
                 LibreOffice.Viewer {
                     id: loView
                     objectName: "loView"
                     anchors.fill: parent
 
-                    clip: true
                     documentPath: file.path
 
                     function updateContentSize(tgtScale) {
@@ -154,6 +184,40 @@
                         }
                     }
 
+                    ScalingMouseArea {
+                        id: mouseArea
+                        anchors.fill: parent
+                        targetFlickable: loView
+                        onTotalScaleChanged: targetFlickable.updateContentSize(totalScale)
+
+                        thresholdZoom: minimumZoom + (maximumZoom - minimumZoom) * 0.75
+                        maximumZoom: {
+                            if (DocumentViewer.desktopMode || mainView.wideWindow)
+                                return 3.0
+
+                            return minimumZoom * 3
+                        }
+                        minimumZoom: {
+                            if (DocumentViewer.desktopMode || mainView.wideWindow)
+                                return loView.zoomSettings.minimumZoom
+
+                            switch(loView.document.documentType) {
+                            case LibreOffice.Document.TextDocument:
+                                return loView.zoomSettings.valueFitToWidthZoom
+                            case LibreOffice.Document.PresentationDocument:
+                                return loView.zoomSettings.valueAutomaticZoom
+                            default:
+                                return loView.zoomSettings.minimumZoom
+                            }
+                        }
+
+                        Binding {
+                            target: mouseArea
+                            property: "zoomValue"
+                            value: loView.zoomSettings.zoomFactor
+                        }
+                    }
+
                     Scrollbar { flickableItem: loView; parent: loView.parent }
                     Scrollbar { flickableItem: loView; parent: loView.parent; align: Qt.AlignBottom }
 

=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/lozoom.cpp'
--- src/plugin/libreofficetoolkit-qml-plugin/lozoom.cpp	2016-01-29 12:12:54 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/lozoom.cpp	2016-02-03 21:36:44 +0000
@@ -166,6 +166,8 @@
     m_valueFitToWidthZoom = getZoomToFitWidth(m_view->parentFlickable()->width(),
                                               m_view->document()->documentSize(currentPart).width());
 
+    Q_EMIT valueFitToWidthZoomChanged();
+
     if (m_zoomFactor != m_valueFitToWidthZoom) {
         setZoomFactor(m_valueFitToWidthZoom);
 
@@ -189,6 +191,8 @@
     m_valueFitToHeightZoom = getZoomToFitHeight(m_view->parentFlickable()->height(),
                                                 m_view->document()->documentSize(currentPart).height());
 
+    Q_EMIT valueFitToHeightZoomChanged();
+
     if (m_zoomFactor != m_valueFitToHeightZoom) {
         setZoomFactor(m_valueFitToHeightZoom);
 
@@ -217,6 +221,10 @@
 
     m_valueAutomaticZoom = qMin(m_valueFitToWidthZoom, m_valueFitToHeightZoom);
 
+    Q_EMIT valueFitToWidthZoomChanged();
+    Q_EMIT valueFitToHeightZoomChanged();
+    Q_EMIT valueAutomaticZoomChanged();
+
     if (m_zoomFactor != m_valueAutomaticZoom) {
         setZoomFactor(m_valueAutomaticZoom);
 

=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/qml/Viewer.qml'
--- src/plugin/libreofficetoolkit-qml-plugin/qml/Viewer.qml	2016-01-20 21:48:21 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/qml/Viewer.qml	2016-02-03 21:36:44 +0000
@@ -109,17 +109,41 @@
     contentHeight: view.height
     contentWidth: view.width
 
+    topMargin: internal.isSpreadSheet ? 0 : Math.max((rootFlickable.height - view.height) * 0.5, 0)
+    leftMargin: internal.isSpreadSheet ? 0 : Math.max((rootFlickable.width - view.width) * 0.5, 0)
+
     boundsBehavior: Flickable.StopAtBounds
 
+    // WORKAROUND: By default, the rebound transition is active only
+    // when returnToBounds() is called (since 'boundsBehavior' is set to
+    // StopAtBounds - see above).
+    // The default transition is not so aesthetic when we call returnToBounds()
+    // (i.e. while switching current part, or after a zoom gesture), for that
+    // reason we completely disable the transition.
+    // FIXME: This is completely broken if a different transition is set by an Item
+    // that uses the Viewer. Should we perhaps store the default transition somewhere,
+    // apply the "fake" transition only when required, and then restore the default
+    // transition?
+    rebound: Transition {
+        NumberAnimation { properties: "x,y"; duration: 0 }
+    }
+
     LibreOffice.View {
         id: view
-
         parentFlickable: rootFlickable
 
         onCurrentPartChanged: {
             // Position view at top-left corner
             rootFlickable.contentX = 0
             rootFlickable.contentY = 0
+
+            rootFlickable.returnToBounds()
         }
     }
+
+    QtObject {
+        id: internal
+
+        property bool isSpreadSheet: document.documentType == LibreOffice.Document.SpreadsheetDocument
+    }
 }


Follow ups