← Back to team overview

ubuntu-touch-coreapps-reviewers team mailing list archive

[Merge] lp:~verzegnassi-stefano/ubuntu-docviewer-app/lok-new-zoom-modes+spreadsheet-zoom into lp:ubuntu-docviewer-app

 

Stefano Verzegnassi has proposed merging lp:~verzegnassi-stefano/ubuntu-docviewer-app/lok-new-zoom-modes+spreadsheet-zoom into lp:ubuntu-docviewer-app.

Commit message:
LibreOffice Viewer - LibreOfficeKit QML plugin:
- Open spreadsheet with manual zoom (1.0x factor)
- Added "Fit to height" and "Automatic" zoom behaviours
- Added a "zoomModesAvailable" which returns the zoom modes available for a given document.
- Minor changes

Requested reviews:
  Ubuntu Document Viewer Developers (ubuntu-docviewer-dev)
Related bugs:
  Bug #1513960 in Ubuntu Document Viewer App: "Don't use automatic zoom when opening a spreadsheet document"
  https://bugs.launchpad.net/ubuntu-docviewer-app/+bug/1513960
  Bug #1515649 in Ubuntu Document Viewer App: "Add more zoom settings for Presentation documents"
  https://bugs.launchpad.net/ubuntu-docviewer-app/+bug/1515649

For more details, see:
https://code.launchpad.net/~verzegnassi-stefano/ubuntu-docviewer-app/lok-new-zoom-modes+spreadsheet-zoom/+merge/281385

LibreOffice Viewer - LibreOfficeKit QML plugin:
- Open spreadsheet with manual zoom (1.0x factor)
- Added "Fit to height" and "Automatic" zoom behaviours
- Added a "zoomModesAvailable" which returns the zoom modes available for a given document.
- Minor changes

*** NOTE FOR REVIEWERS ***
Please let me know what do you think about the usage of manual zoom as default for spreadsheet documents.
It behaves properly on desktop, but on phones it looks overzoomed.
I believe it's anyway better than earlier, since the zoom value does not depend on the number of columns with content.
Ideally we want in future to set a different default zoom value when running on a mobile device (but it could be a bit complex to do)
-- 
Your team Ubuntu Document Viewer Developers is requested to review the proposed merge of lp:~verzegnassi-stefano/ubuntu-docviewer-app/lok-new-zoom-modes+spreadsheet-zoom into lp:ubuntu-docviewer-app.
=== modified file 'po/com.ubuntu.docviewer.pot'
--- po/com.ubuntu.docviewer.pot	2015-12-26 18:33:55 +0000
+++ po/com.ubuntu.docviewer.pot	2015-12-29 13:19:41 +0000
@@ -8,7 +8,7 @@
 msgstr ""
 "Project-Id-Version: \n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2015-12-26 19:31+0100\n"
+"POT-Creation-Date: 2015-12-27 15:50+0100\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@xxxxxx>\n"
@@ -47,23 +47,23 @@
 msgid "Details"
 msgstr ""
 
-#: ../src/app/qml/common/DetailsPage.qml:36
+#: ../src/app/qml/common/DetailsPage.qml:41
 msgid "Location"
 msgstr ""
 
-#: ../src/app/qml/common/DetailsPage.qml:41
+#: ../src/app/qml/common/DetailsPage.qml:46
 msgid "Size"
 msgstr ""
 
-#: ../src/app/qml/common/DetailsPage.qml:46
+#: ../src/app/qml/common/DetailsPage.qml:51
 msgid "Created"
 msgstr ""
 
-#: ../src/app/qml/common/DetailsPage.qml:51
+#: ../src/app/qml/common/DetailsPage.qml:56
 msgid "Last modified"
 msgstr ""
 
-#: ../src/app/qml/common/DetailsPage.qml:58
+#: ../src/app/qml/common/DetailsPage.qml:63
 msgid "MIME type"
 msgstr ""
 
@@ -72,18 +72,18 @@
 msgstr ""
 
 #: ../src/app/qml/common/ErrorDialog.qml:26
-#: ../src/app/qml/common/PickImportedDialog.qml:53
+#: ../src/app/qml/common/PickImportedDialog.qml:54
 #: ../src/app/qml/common/RejectedImportDialog.qml:38
 #: ../src/app/qml/documentPage/DocumentPageSelectionModeHeader.qml:31
 #: ../src/app/qml/documentPage/SortSettingsDialog.qml:53
 msgid "Close"
 msgstr ""
 
-#: ../src/app/qml/common/PickImportedDialog.qml:28
+#: ../src/app/qml/common/PickImportedDialog.qml:29
 msgid "Multiple documents imported"
 msgstr ""
 
-#: ../src/app/qml/common/PickImportedDialog.qml:29
+#: ../src/app/qml/common/PickImportedDialog.qml:30
 msgid "Choose which one to open:"
 msgstr ""
 
@@ -305,7 +305,7 @@
 msgstr ""
 
 #: ../src/app/qml/loView/LOViewDefaultHeader.qml:51
-#: ../src/app/qml/textView/TextView.qml:42
+#: ../src/app/qml/textView/TextView.qml:43
 msgid "Loading..."
 msgstr ""
 
@@ -362,15 +362,15 @@
 msgid "GO!"
 msgstr ""
 
-#: ../src/app/qml/loView/LOViewPage.qml:128
+#: ../src/app/qml/loView/LOViewPage.qml:129
 msgid "LibreOffice binaries not found."
 msgstr ""
 
-#: ../src/app/qml/loView/LOViewPage.qml:131
+#: ../src/app/qml/loView/LOViewPage.qml:132
 msgid "Error while loading LibreOffice."
 msgstr ""
 
-#: ../src/app/qml/loView/LOViewPage.qml:134
+#: ../src/app/qml/loView/LOViewPage.qml:135
 msgid ""
 "Document not loaded.\n"
 "The requested document may be corrupt or protected by a password."
@@ -383,13 +383,21 @@
 msgid "Powered by LibreOfficeKit"
 msgstr ""
 
-#: ../src/app/qml/loView/ZoomSelector.qml:110
+#: ../src/app/qml/loView/ZoomSelector.qml:123
 msgid "Fit width"
 msgstr ""
 
+#: ../src/app/qml/loView/ZoomSelector.qml:130
+msgid "Fit height"
+msgstr ""
+
+#: ../src/app/qml/loView/ZoomSelector.qml:137
+msgid "Automatic"
+msgstr ""
+
 #. TRANSLATORS: "Contents" refers to the "Table of Contents" of a PDF document.
 #: ../src/app/qml/pdfView/PdfContentsPage.qml:30
-#: ../src/app/qml/pdfView/PdfView.qml:37
+#: ../src/app/qml/pdfView/PdfView.qml:38
 msgid "Contents"
 msgstr ""
 
@@ -399,7 +407,7 @@
 
 #. TRANSLATORS: the first argument (%1) refers to the page currently shown on the screen,
 #. while the second one (%2) refers to the total pages count.
-#: ../src/app/qml/pdfView/PdfView.qml:34
+#: ../src/app/qml/pdfView/PdfView.qml:35
 #, qt-format
 msgid "Page %1 of %2"
 msgstr ""

=== modified file 'src/app/qml/loView/ZoomSelector.qml'
--- src/app/qml/loView/ZoomSelector.qml	2015-11-30 12:12:10 +0000
+++ src/app/qml/loView/ZoomSelector.qml	2015-12-29 13:19:41 +0000
@@ -52,6 +52,10 @@
     popover: TextFieldButtonPopover {
         id: zoomSelectorDialogue
 
+        /************************************
+        *    Zoom in - Zoom out controls    *
+        ************************************/
+
         RowLayout {
             anchors { left: parent.left; right: parent.right }
             height: units.gu(4)
@@ -93,34 +97,68 @@
 
         HorizontalDivider { anchors { left: parent.left; right: parent.right } }
 
-        ListItem {
-            height: units.gu(4)
-            divider.visible: false
-
-            onClicked: {
-                textField.view.adjustZoomToWidth()
-                zoomSelectorDialogue.close()
-            }
-
-            /* UITK 1.3 specs: Two slot layout (A-B) */
-            ListItemLayout {
-                anchors.centerIn: parent
-
-                /* UITK 1.3 specs: Slot A */
-                title.text: i18n.tr("Fit width")
-
-                /* UITK 1.3 specs: Slot B */
-                Icon {
-                    SlotsLayout.position: SlotsLayout.Last
-                    width: units.gu(2); height: width
-                    name: "tick"
-                    color: UbuntuColors.green
-                    visible: textField.view.zoomMode == LibreOffice.View.FitToWidth
-                }
-            }
-        }   // ListItem
-
-        HorizontalDivider { anchors { left: parent.left; right: parent.right } }
+        /************************************
+        *       Zoom modes controls         *
+        ************************************/
+
+        Repeater {
+            id: zoomModesRepeater
+
+            function delegate_onClicked(mode) {
+                if (mode === LibreOffice.View.FitToWidth)
+                    textField.view.adjustZoomToWidth()
+
+                if (mode === LibreOffice.View.FitToHeight)
+                    textField.view.adjustZoomToHeight()
+
+                if (mode === LibreOffice.View.Automatic)
+                    textField.view.adjustAutomaticZoom()
+            }
+
+            // Used for hiding the HorizontalDivider below.
+            visible: view.zoomModesAvailable > LibreOffice.View.Manual
+
+            model: [
+                { text: i18n.tr("Fit width"),  mode: LibreOffice.View.FitToWidth  },
+                { text: i18n.tr("Fit height"), mode: LibreOffice.View.FitToHeight },
+                { text: i18n.tr("Automatic"),  mode: LibreOffice.View.Automatic   }
+            ]
+
+            ListItem {
+                height: units.gu(4)
+                divider.visible: false
+
+                visible: view.zoomModesAvailable & modelData.mode
+
+                onClicked: {
+                    zoomSelectorDialogue.close()
+                    zoomModesRepeater.delegate_onClicked(modelData.mode)
+                }
+
+                /* UITK 1.3 specs: Two slot layout (A-B) */
+                ListItemLayout {
+                    anchors.centerIn: parent
+
+                    /* UITK 1.3 specs: Slot A */
+                    title.text: modelData.text
+
+                    /* UITK 1.3 specs: Slot B */
+                    Icon {
+                        SlotsLayout.position: SlotsLayout.Last
+                        width: units.gu(2); height: width
+                        name: "tick"
+                        color: UbuntuColors.green
+                        visible: textField.view.zoomMode == modelData.mode
+                    }
+                }
+            }   // ListItem
+        }
+
+        HorizontalDivider { visible: zoomModesRepeater.visible; anchors { left: parent.left; right: parent.right } }
+
+        /************************************
+        *   Default zoom values controls    *
+        ************************************/
 
         Repeater {
             model: [

=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/loview.cpp'
--- src/plugin/libreofficetoolkit-qml-plugin/loview.cpp	2015-11-28 22:11:54 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/loview.cpp	2015-12-29 13:19:41 +0000
@@ -25,18 +25,25 @@
 #include <QtCore/qmath.h>
 
 static qreal zoomValueToFitWidth;
+static qreal zoomValueToFitHeight;
 
 static qreal getZoomToFitWidth(const qreal &width, int documentWidth)
 {
     return qreal(width / Twips::convertTwipsToPixels(documentWidth, 1.0));
 }
 
+static qreal getZoomToFitHeight(const qreal &height, int documentHeight)
+{
+    return qreal(height / Twips::convertTwipsToPixels(documentHeight, 1.0));
+}
+
 LOView::LOView(QQuickItem *parent)
     : QQuickItem(parent)
     , m_parentFlickable(nullptr)
     , m_document(nullptr)
     , m_partsModel(nullptr)
     , m_zoomFactor(1.0)
+    , m_zoomModesAvailable(ZoomMode::Manual)
     , m_cacheBuffer(TILE_SIZE * 3)
     , m_visibleArea(0, 0, 0, 0)
     , m_bufferArea(0, 0, 0, 0)
@@ -117,6 +124,22 @@
     connect(m_document.data(), SIGNAL(currentPartChanged()), this, SLOT(invalidateAllTiles()));
 
     Q_EMIT documentChanged();
+
+    // Set the proper zoom mode, according to the type of the loaded document.
+    setZoomModesAvailability();
+
+    switch (m_document.data()->documentType()) {
+    case LODocument::DocumentType::SpreadsheetDocument:
+        setZoomMode(ZoomMode::Manual);
+        setZoomFactor(1.0);
+        break;
+    case LODocument::DocumentType::PresentationDocument:
+        setZoomMode(ZoomMode::Automatic);
+        break;
+    default:
+        setZoomMode(ZoomMode::FitToWidth);
+        break;
+    }
 }
 
 // Return the LODocument rendered by this class
@@ -142,7 +165,7 @@
 
     m_zoomFactor = zoom;
 
-   if (m_zoomFactor != zoomValueToFitWidth)
+   if (m_zoomFactor != zoomValueToFitWidth && m_zoomFactor != zoomValueToFitHeight)
         setZoomMode(LOView::Manual);
 
     Q_EMIT zoomFactorChanged();
@@ -153,6 +176,11 @@
     return m_zoomMode;
 }
 
+LOView::ZoomModes LOView::zoomModesAvailable() const
+{
+    return m_zoomModesAvailable;
+}
+
 void LOView::setZoomMode(const ZoomMode zoomMode)
 {
     if (m_zoomMode == zoomMode)
@@ -181,18 +209,70 @@
     return m_error;
 }
 
-void LOView::adjustZoomToWidth()
-{
-    if (!m_document)
-        return;
-
-    setZoomMode(LOView::FitToWidth);
-
-    zoomValueToFitWidth = getZoomToFitWidth(m_parentFlickable->width(),
-                                            m_document->documentSize().width());
-
-    setZoomFactor(zoomValueToFitWidth);
-    qDebug() << "Adjust zoom to width - value:" << zoomValueToFitWidth;
+bool LOView::adjustZoomToWidth(bool changeMode)
+{
+    if (!m_document)
+        return false;
+
+    if (changeMode)
+        setZoomMode(LOView::FitToWidth);
+
+    zoomValueToFitWidth = getZoomToFitWidth(m_parentFlickable->width(),
+                                            m_document->documentSize().width());
+
+    if (m_zoomFactor != zoomValueToFitWidth) {
+        setZoomFactor(zoomValueToFitWidth);
+
+        qDebug() << Q_FUNC_INFO << "- value:" << m_zoomFactor << "- changeMode:" << changeMode;
+        return true;
+    }
+
+    return false;
+}
+
+bool LOView::adjustZoomToHeight(bool changeMode)
+{
+    if (!m_document)
+        return false;
+
+    if (changeMode)
+        setZoomMode(LOView::FitToHeight);
+
+    zoomValueToFitHeight = getZoomToFitHeight(m_parentFlickable->height(),
+                                              m_document->documentSize().height());
+
+    if (m_zoomFactor != zoomValueToFitHeight) {
+        setZoomFactor(zoomValueToFitHeight);
+
+        qDebug() << Q_FUNC_INFO << "- value:" << m_zoomFactor << "- changeMode:" << changeMode;
+        return true;
+    }
+
+    return false;
+}
+
+bool LOView::adjustAutomaticZoom(bool changeMode)
+{
+    if (!m_document)
+        return false;
+
+    if (changeMode)
+        setZoomMode(LOView::Automatic);
+
+    zoomValueToFitWidth = getZoomToFitWidth(m_parentFlickable->width(),
+                                            m_document->documentSize().width());
+
+    zoomValueToFitHeight = getZoomToFitHeight(m_parentFlickable->height(),
+                                              m_document->documentSize().height());
+
+    if (m_zoomFactor != qMin(zoomValueToFitHeight, zoomValueToFitWidth)) {
+        setZoomFactor(qMin(zoomValueToFitHeight, zoomValueToFitWidth));
+
+        qDebug() << Q_FUNC_INFO << "- value:" << m_zoomFactor << "- changeMode:" << changeMode;
+        return true;
+    }
+
+    return false;
 }
 
 void LOView::updateViewSize()
@@ -213,25 +293,69 @@
     if (!m_parentFlickable || !m_document)
         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.
+    /*
+     * Following code requires a bit of explanation:
+     *
+     * updateVisibleRect() is called when several events occures:
+     *   - cacheBuffer value changes;
+     *   - parentFlickable changes;
+     *   - parentFlickable size changes;
+     *   - parentFlickable is scrolled;
+     *   - A new document is loaded (through LOView::updateViewSize())
+     *   - The zoom value changes (through LOView::updateViewSize())
+     *
+     * We are interested to the last case.
+     * We have two different zoom behaviour: manual or automatic.
+     *
+     * When manual zoom is active, and a new zoom value is set, there is no
+     * other change/signal emission involved.
+     * The schema is:
+     *   zoomFactorChanged -> updateViewSize() -> updateVisibleRect()
+     *
+     * When automatic zoom is active, things are a bit different.
+     * updateVisibleRect() could be triggered for two reasons:
+     *   - User explicitely set the new zoom behaviour (e.g. through
+     *     LOView::adjustZoomToWidth())
+     *   - The parent flickable has been resized.
+     *
+     * For the former case, the schema is:
+     *   adjustZoomToWidth() -> zoomFactorChanged -> updateViewSize() ->
+     *     -> updateVisibleRect()
+     *
+     * For the latter, the code below is involved.
+     * At first we have:
+     *   parentFlickableSizeChanged -> updateVisibleRect()
+     *
+     * When this function is called, we need to check if the zoom value is still
+     * valid. If not, we need to adjust the zoom (e.g. calling
+     * LOView::adjustZoomToWidth(false)).
+     *
+     * If the zoom value changes (i.e. required an adjustment), we have a
+     * zoomFactorChanged signal emission, which would call this function twice
+     * (see manual zoom, explained above).
+     * We want to avoid updateVisibleRect() to be called for nothing, so we stop
+     * the first execution of the function when this happens, and wait for the
+     * second one (via updateViewSize()).
+     *
+     * A full schema is:
+     *   parentFlickableSizeChanged -> updateVisibleRect() ->
+     *     -> adjustZoomToWidth(false) -> STOP THIS EXECUTION, returns
+     *                                 L-> zoomFactorChanged() -> updateViewSize() -> updateVisibleRect()
+     */
+
     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;
-        }
+        if (adjustZoomToWidth(false))
+            return;
+    }
+
+    else if (m_zoomMode == LOView::FitToHeight) {
+        if (adjustZoomToHeight(false))
+            return;
+    }
+
+    else if (m_zoomMode == LOView::Automatic) {
+        if (adjustAutomaticZoom(false))
+            return;
     }
 
     // Check if current tiles have a different zoom value
@@ -291,7 +415,7 @@
 
     // Number of tiles per row
     int tilesPerWidth           = qCeil(this->width() / TILE_SIZE);
-    int tilesPerHeight           = qCeil(this->height() / TILE_SIZE);
+    int tilesPerHeight          = qCeil(this->height() / TILE_SIZE);
 
     // Get indexes for visible tiles
     int visiblesFromWidth       = int(m_visibleArea.left() / TILE_SIZE);
@@ -435,6 +559,33 @@
     Q_EMIT errorChanged();
 }
 
+void LOView::setZoomModesAvailability()
+{
+    if (!m_document)
+        return;
+
+    ZoomModes newZoomModesAvailable;
+    newZoomModesAvailable |= ZoomMode::Manual;
+
+    switch (m_document.data()->documentType()) {
+    case LODocument::DocumentType::TextDocument:
+        newZoomModesAvailable |= ZoomMode::FitToWidth;
+        break;
+    case LODocument::DocumentType::SpreadsheetDocument:
+        break;
+    default:
+        newZoomModesAvailable |= ZoomMode::FitToWidth;
+        newZoomModesAvailable |= ZoomMode::FitToHeight;
+        newZoomModesAvailable |= ZoomMode::Automatic;
+        break;
+    }
+
+    if (m_zoomModesAvailable != newZoomModesAvailable) {
+        m_zoomModesAvailable = newZoomModesAvailable;
+        Q_EMIT zoomModesAvailableChanged();
+    }
+}
+
 LOView::~LOView()
 {
     delete m_partsModel;

=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/loview.h'
--- src/plugin/libreofficetoolkit-qml-plugin/loview.h	2015-12-12 10:06:55 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/loview.h	2015-12-29 13:19:41 +0000
@@ -36,22 +36,27 @@
 {
     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)
-    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)
-    Q_PROPERTY(LibreOfficeError::Error  error           READ error                                    NOTIFY errorChanged)
+    Q_FLAGS(ZoomModes)
+    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)
+    Q_PROPERTY(LibreOfficeError::Error  error              READ error                                    NOTIFY errorChanged)
+    Q_PROPERTY(ZoomModes                zoomModesAvailable READ zoomModesAvailable                       NOTIFY zoomModesAvailableChanged)
 
 public:
     LOView(QQuickItem *parent = 0);
     ~LOView();
 
     enum ZoomMode {
-        FitToWidth,
-        Manual
+        Manual = 0x0,
+        FitToWidth = 0x1,
+        FitToHeight = 0x2,
+        Automatic = 0x4
     };
+    Q_DECLARE_FLAGS(ZoomModes, ZoomMode)
 
     QQuickItem* parentFlickable() const;
     void        setParentFlickable(QQuickItem* flickable);
@@ -66,12 +71,16 @@
 
     ZoomMode    zoomMode() const;
 
+    ZoomModes   zoomModesAvailable() const;
+
     int         cacheBuffer() const;
     void        setCacheBuffer(int cacheBuffer);
 
     LibreOfficeError::Error error() const;
 
-    Q_INVOKABLE void adjustZoomToWidth();
+    Q_INVOKABLE bool adjustZoomToWidth(bool changeMode = true);
+    Q_INVOKABLE bool adjustZoomToHeight(bool changeMode = true);
+    Q_INVOKABLE bool adjustAutomaticZoom(bool changeMode = true);
 
 Q_SIGNALS:
     void parentFlickableChanged();
@@ -81,6 +90,7 @@
     void zoomModeChanged();
     void cacheBufferChanged();
     void errorChanged();
+    void zoomModesAvailableChanged();
 
 private Q_SLOTS:
     void updateViewSize();
@@ -98,6 +108,7 @@
 
     qreal                       m_zoomFactor;
     ZoomMode                    m_zoomMode;
+    ZoomModes                   m_zoomModesAvailable;
     int                         m_cacheBuffer;
 
     QRect                       m_visibleArea;
@@ -109,6 +120,7 @@
 
     QMap<int, SGTileItem*>      m_tiles;
 
+private:
     void generateTiles(int x1, int y1, int x2, int y2, int tilesPerWidth, int tilesPerHeight);
     void createTile(int index, const QRect& rect);
     void setZoomMode(const ZoomMode zoomMode);
@@ -118,6 +130,7 @@
     void updateThumbnailModel(AbstractRenderTask* task, QImage img);
 
     void setError(const LibreOfficeError::Error &error);
+    void setZoomModesAvailability();
 };
 
 #endif // LOVIEW_H

=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/qml/Viewer.qml'
--- src/plugin/libreofficetoolkit-qml-plugin/qml/Viewer.qml	2015-11-27 16:39:21 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/qml/Viewer.qml	2015-12-29 13:19:41 +0000
@@ -27,6 +27,8 @@
     property alias zoomMode:    view.zoomMode
     property alias error:       view.error
 
+    property alias zoomModesAvailable: view.zoomModesAvailable
+
     property string documentPath: ""
 
     function adjustZoomToWidth()
@@ -39,6 +41,26 @@
         rootFlickable.contentY *= zoomScale
     }
 
+    function adjustZoomToHeight()
+    {
+        var oldZoom = view.zoomFactor
+        view.adjustZoomToHeight()
+
+        var zoomScale = view.zoomFactor / oldZoom
+        rootFlickable.contentX *= zoomScale
+        rootFlickable.contentY *= zoomScale
+    }
+
+    function adjustAutomaticZoom()
+    {
+        var oldZoom = view.zoomFactor
+        view.adjustAutomaticZoom()
+
+        var zoomScale = view.zoomFactor / oldZoom
+        rootFlickable.contentX *= zoomScale
+        rootFlickable.contentY *= zoomScale
+    }
+
     function setZoom(newValue)
     {
         var zoomScale = newValue / view.zoomFactor;
@@ -91,7 +113,7 @@
 
     boundsBehavior: Flickable.StopAtBounds
 
-    Component.onCompleted: adjustZoomToWidth()
+    //Component.onCompleted: adjustZoomToWidth()
 
     LibreOffice.View {
         id: view


Follow ups