← Back to team overview

ubuntu-touch-coreapps-reviewers team mailing list archive

[Merge] lp:~verzegnassi-stefano/ubuntu-docviewer-app/reboot-merged-trunk-revno-181 into lp:ubuntu-docviewer-app/reboot

 

Stefano Verzegnassi has proposed merging lp:~verzegnassi-stefano/ubuntu-docviewer-app/reboot-merged-trunk-revno-181 into lp:ubuntu-docviewer-app/reboot.

Commit message:
Merged trunk (rev. 181) into "reboot" branch

Requested reviews:
  Ubuntu Document Viewer Developers (ubuntu-docviewer-dev)

For more details, see:
https://code.launchpad.net/~verzegnassi-stefano/ubuntu-docviewer-app/reboot-merged-trunk-revno-181/+merge/266904

Merged trunk (rev. 181) into "reboot" branch
-- 
Your team Ubuntu Document Viewer Developers is requested to review the proposed merge of lp:~verzegnassi-stefano/ubuntu-docviewer-app/reboot-merged-trunk-revno-181 into lp:ubuntu-docviewer-app/reboot.
=== added file 'AUTHORS'
--- AUTHORS	1970-01-01 00:00:00 +0000
+++ AUTHORS	2015-08-04 16:03:21 +0000
@@ -0,0 +1,26 @@
+DocViewer was started in 2013 and has received many contributions from the following people. 
+
+In addition, numerous translations, bug reports and other non-code contributions have been made which are equally valued.
+
+Adolfo Jayme Barrientos <fitojb@xxxxxxxxxx>
+Akiva Abraham <akiva@xxxxxxxxx>
+Alan Pope <alan.pope@xxxxxxxxxxxxx>
+Andrew Hayzen <ahayzen@xxxxxxxxx>
+Arto Jalkanen <ajalkane@xxxxxxxxx>
+Bartosz Kosiorek <gang65@xxxxxxxxxxxxxx>
+Carla Sella <carla.sella@xxxxxxxxx>
+Daniel Holbach <daniel.holbach@xxxxxxxxxxxxx>
+David Planella <david.planella@xxxxxxxxxx>
+Didier Roche <didrocks@xxxxxxxxxx>
+Fabio Colella <fcole90@xxxxxxxxx>
+Francis Ginther <francis.ginther@xxxxxxxxxxxxx>
+Granger Anthony <grangeranthony@xxxxxxxxx>
+Michael Hall <mhall119@xxxxxxxxxx>
+Nicholas Skaggs <nicholas.skaggs@xxxxxxxxxxxxx>
+Olivier Tilloy <olivier.tilloy@xxxxxxxxxxxxx>
+Omer Akram <om26er@xxxxxxxxxx>
+Richard Somlói <level@xxxxxxxxxxxxxxxx>
+Roman Shchekin <mrqtros@xxxxxxxxx>
+Sergio Schvezov <sergio.schvezov@xxxxxxxxxxxxx>
+Stefano Verzegnassi <stefano92.100@xxxxxxxxx>
+xeranas <anorkus@xxxxxxxxxxx>

=== modified file 'src/app/qml/common/ToastWithAction.qml'
--- src/app/qml/common/ToastWithAction.qml	2015-04-07 22:52:48 +0000
+++ src/app/qml/common/ToastWithAction.qml	2015-08-04 16:03:21 +0000
@@ -60,8 +60,8 @@
         }
 
         AbstractButton {
-            width: actionLabel.paintedWidth
-            height: parent.height
+            Layout.preferredWidth: actionLabel.paintedWidth
+            Layout.fillHeight: true
 
             onClicked: {
                 action.triggered("[Toast] Action %1 clicked!".arg(action.text))

=== modified file 'src/app/qml/documentPage/DeleteFileDialog.qml'
--- src/app/qml/documentPage/DeleteFileDialog.qml	2015-04-29 15:23:32 +0000
+++ src/app/qml/documentPage/DeleteFileDialog.qml	2015-08-04 16:03:21 +0000
@@ -25,6 +25,14 @@
     property string path
     property int __deleteCount: documentPage.view.item.selectedItems.count
 
+    // WORKAROUND: This property is used only when user wants to remove a single
+    // file from a delegate action, and the value of the property is read during
+    // the Component.onDestruction event.
+    // We do this because we need to avoid that the entry in the model is removed
+    // before this dialog is closed.
+    // See src/app/qml/documentPage/DocumentDelegateActions.qml
+    property bool confirmed: false
+
     title: path ? i18n.tr("Delete file") :
                   i18n.tr("Delete %1 file", "Delete %1 files", __deleteCount).arg(__deleteCount)
     text: path ? i18n.tr("Are you sure you want to permanently delete this file?") :
@@ -43,17 +51,19 @@
 
         onClicked: {
             if (deleteFileDialog.path) {
-                docModel.rm(path)
+               deleteFileDialog.confirmed = true;
             } else {
+                // This is called from selection mode
                 var items = documentPage.view.item.selectedItems;
 
                 for (var i=0; i < items.count; i++) {
                     console.log("Removing:", items.get(i).model.path);
                     docModel.rm(items.get(i).model.path);
                 }
+
+                viewLoader.item.endSelection();
             }
 
-            viewLoader.item.endSelection();
             PopupUtils.close(deleteFileDialog)
         }
     }

=== added file 'src/app/qml/documentPage/DocumentDelegateActions.qml'
--- src/app/qml/documentPage/DocumentDelegateActions.qml	1970-01-01 00:00:00 +0000
+++ src/app/qml/documentPage/DocumentDelegateActions.qml	2015-08-04 16:03:21 +0000
@@ -0,0 +1,41 @@
+/*
+  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 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 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.0
+import Ubuntu.Components 1.1
+import Ubuntu.Components.Popups 1.0
+
+QtObject {
+    property list<Action> leadingActions: [
+        Action {
+            iconName: "delete"
+            text: i18n.tr("Delete")
+            onTriggered: {
+                var dialog = PopupUtils.open(Qt.resolvedUrl("DeleteFileDialog.qml"),
+                                documentPage, { path: model.path })
+
+                dialog.Component.destruction.connect(function() {
+                    if (dialog.confirmed) {
+                        console.log("Removing:", model.path);
+                        docModel.rm(model.path);
+                    }
+                });
+            }
+        }
+    ]
+
+    property list<Action> trailingActions
+}

=== modified file 'src/app/qml/documentPage/DocumentGridDelegate.qml'
--- src/app/qml/documentPage/DocumentGridDelegate.qml	2015-07-14 01:35:59 +0000
+++ src/app/qml/documentPage/DocumentGridDelegate.qml	2015-08-04 16:03:21 +0000
@@ -16,14 +16,11 @@
 
 import QtQuick 2.0
 import Ubuntu.Components 1.1
-import QtQuick.Layouts 1.1
 
 import "../common/utils.js" as Utils
 
-AbstractButton {
+TileBase {
     id: root
-    property bool selected: false
-    property bool selectionMode: false
 
     function formattedDateTime() {
         var date = new Date(model.date)
@@ -49,169 +46,68 @@
         return Qt.formatDateTime(date, i18n.tr("dd-MM-yyyy hh:mm"))
     }
 
-    Rectangle {
-        anchors { fill: parent; margins: units.gu(0.5) }
-
-        color: Qt.lighter(UbuntuColors.lightGrey)
-        clip: true
-
-        Loader {
-            id: selectionIcon
-
-            anchors {
-                right: parent.right
-                top: parent.top
-            }
-
-            z: 10
-
-            width: (status === Loader.Ready) ? item.implicitWidth : 0
-            visible: (status === Loader.Ready) && (item.width === item.implicitWidth)
-            Behavior on opacity {
-                NumberAnimation {
-                    duration: UbuntuAnimation.SnapDuration
-                }
-            }
-        }
-
-        Icon {
-            id: extStorageIcon
-
-            width: units.gu(4)
-            height: units.gu(4)
-            anchors {
-                left: parent.left
-                top: parent.top
-                margins: units.gu(0.5)
-            }
-
-            visible: model.isFromExternalStorage
-            source: Qt.resolvedUrl("../../graphics/sd-card-symbolic.png")
-        }
-
-        // Document mimetype icon
-        Icon {
-            anchors.centerIn: parent
-            anchors.verticalCenterOffset: - infoColumn.height * 0.3
-
-            width: units.gu(8); height: width
-
-            // At the moment the suru icon theme doesn't have much icons.
-            // Just some note for the future:
-            // TODO: Add icons for Office/ODF documents
-            // TODO: Whenever there will be icons for source code files, add them.
-            name: {
-                if (model.mimetype.substring(0, 5) === "text/")
-                    return "text-x-generic-symbolic"
-
-                if (model.mimetype.substring(0, 5) === "image")
-                    return "image-x-generic-symbolic"
-
-                if (model.mimetype === "application/pdf")
-                    return "application-pdf-symbolic"
-
-                if (model.mimetype === "application/vnd.oasis.opendocument.text"
-                        || model.mimetype === "application/msword"
-                        || model.mimetype === "application/vnd.openxmlformats-officedocument.wordprocessingml.document")
-                    return "x-office-document-symbolic"
-
-                if (model.mimetype === "application/vnd.oasis.opendocument.spreadsheet"
-                        || model.mimetype === "application/vnd.ms-excel"
-                        || model.mimetype === "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
-                    return "x-office-spreadsheet-symbolic"
-
-                if (model.mimetype === "application/vnd.oasis.opendocument.presentation"
-                        || model.mimetype === "application/vnd.ms-powerpoint"
-                        || model.mimetype === "application/vnd.openxmlformats-officedocument.presentationml.presentation")
-                    return "x-office-presentation-symbolic"
-
-                return "package-x-generic-symbolic"
-            }
-        }
-
-        // Cover
-       /* Image {
-            anchors.fill: parent
-
-            source: {
-                if (model.cover !== "" && typeof model.cover !== "undefined")
-                    return model.cover
-
-                if (model.mimetype.toString().indexOf("image") !== -1)
-                    return model.path
-
-                return ""
-            }
-
-            sourceSize.width: width
-            fillMode: Image.PreserveAspectCrop
-        }*/
-
-        // Document info overlay
-        Rectangle {
-            id: overlay
-
-            anchors {
-                left: parent.left
-                right: parent.right
-                bottom: parent.bottom
-            }
-
-            height: infoColumn.height + units.gu(1)
-
-            color: UbuntuColors.darkGrey
-            opacity: 0.75
-            layer.enabled: true
-
-            // Document info
-            Column {
-                id: infoColumn
-                anchors {
-                    left: parent.left;
-                    right: parent.right
-                    verticalCenter: parent.verticalCenter
-                    margins: units.gu(0.5)
-                }
-
-                Label {
-                    text: model.name
-                    color: "white"
-
-                    elide: Text.ElideRight
-                    font.weight: Font.DemiBold
-                    fontSize: "small"
-
-                    anchors { left: parent.left; right: parent.right }
-                }
-
-                Label {
-                    text: formattedDateTime()
-                    color: "white"
-                    fontSize: "small"
-
-                    anchors { left: parent.left; right: parent.right }
-                }
-
-                Label {
-                    text: Utils.printSize(i18n, model.size)
-                    color: "white"
-                    fontSize: "small"
-
-                    anchors { left: parent.left; right: parent.right }
-                }
-            }   // Document info end
-        }
-
-        states: [
-            State {
-                name: "select"
-                when: selectionMode || selected
-                PropertyChanges {
-                    target: selectionIcon
-                    source: Qt.resolvedUrl("../upstreamComponents/ListItemWithActionsCheckBox.qml")
-                    anchors.margins: units.gu(1)
-                }
-            }
-        ]
-    }
+    title: model.name
+    text: formattedDateTime()
+    subText: Utils.printSize(i18n, model.size)
+
+    leadingActions: documentDelegateActions.leadingActions
+    trailingActions: documentDelegateActions.trailingActions
+
+    Icon {
+        id: extStorageIcon
+
+        width: units.gu(4)
+        height: units.gu(4)
+        anchors {
+            left: parent.left
+            top: parent.top
+            margins: units.gu(0.5)
+        }
+
+        visible: model.isFromExternalStorage
+        source: Qt.resolvedUrl("../../graphics/sd-card-symbolic.png")
+    }
+
+    // Document mimetype icon
+    Icon {
+        anchors.centerIn: parent
+        width: units.gu(8); height: width
+
+        // At the moment the suru icon theme doesn't have much icons.
+        // Just some note for the future:
+        // TODO: Add icons for Office/ODF documents
+        // TODO: Whenever there will be icons for source code files, add them.
+        name: {
+            if (model.mimetype.substring(0, 5) === "text/")
+                return "text-x-generic-symbolic"
+
+            if (model.mimetype.substring(0, 5) === "image")
+                return "image-x-generic-symbolic"
+
+            if (model.mimetype === "application/pdf")
+                return "application-pdf-symbolic"
+
+            return "package-x-generic-symbolic"
+        }
+    }
+
+    // Cover
+    /* Image {
+        anchors.fill: parent
+
+        source: {
+            if (model.cover !== "" && typeof model.cover !== "undefined")
+                return model.cover
+
+            if (model.mimetype.toString().indexOf("image") !== -1)
+                return model.path
+
+            return ""
+        }
+
+        sourceSize.width: width
+        fillMode: Image.PreserveAspectCrop
+    }*/
+
+    DocumentDelegateActions { id: documentDelegateActions }
 }

=== modified file 'src/app/qml/documentPage/DocumentListDelegate.qml'
--- src/app/qml/documentPage/DocumentListDelegate.qml	2015-07-14 01:35:59 +0000
+++ src/app/qml/documentPage/DocumentListDelegate.qml	2015-08-04 16:03:21 +0000
@@ -23,6 +23,8 @@
 import "../upstreamComponents"
 
 ListItemWithActions {
+    property QtObject documentDelegateActions: DocumentDelegateActions { }
+
     function formattedDateTime() {
         var date = new Date(model.date)
         var diff = model.dateDiff
@@ -30,16 +32,14 @@
         if (sortSettings.sortMode !== 0) {  // The sort rule is not "by date"
             switch(diff) {
             case 0:     // DocumentsModel.Today
-                // TRANSLATORS: this is a datetime formatting string, and the
-                // singlequote is an escape character.
-                // See http://qt-project.org/doc/qt-5/qml-qtqml-date.html#details for valid expressions.
-                return Qt.formatDateTime(date, i18n.tr("'Today', hh:mm"))
+                // TRANSLATORS: %1 refers to a time formatted as Locale.ShortFormat (e.g. hh:mm). It depends on system settings.
+                // http://qt-project.org/doc/qt-4.8/qlocale.html#FormatType-enum
+                return i18n.tr("Today, %1").arg(Qt.formatTime(date, Qt.locale().timeFormat(Locale.ShortFormat)))
 
             case 1:     // DocumentsModel.Yesterday
-                // TRANSLATORS: this is a datetime formatting string, and the
-                // singlequote is an escape character.
-                // See http://qt-project.org/doc/qt-5/qml-qtqml-date.html#details for valid expressions.
-                return Qt.formatDateTime(date, i18n.tr("'Yesterday', hh:mm"))
+                // TRANSLATORS: %1 refers to a time formatted as Locale.ShortFormat (e.g. hh:mm). It depends on system settings.
+                // http://qt-project.org/doc/qt-4.8/qlocale.html#FormatType-enum
+                return i18n.tr("Yesterday, %1").arg(Qt.formatTime(date, Qt.locale().timeFormat(Locale.ShortFormat)))
 
             default:    // DocumentsModel.LastWeek || DocumentsModel.LastMonth || DocumentsModel.Earlier
                 // TRANSLATORS: this is a datetime formatting string,
@@ -70,23 +70,16 @@
 
     locked: documentPage.state == "pickMode"
 
-    // TODO: NEEDS-DESIGN: Enable left action. Still need to find an equivalent for GridDelegate.
-   /* leftSideAction: Action {
-        iconName: "delete"
-        text: i18n.tr("Delete")
-        onTriggered: {
-            PopupUtils.open(Qt.resolvedUrl("DeleteFileDialog.qml"),
-                            documentPage, { path: model.filePath })
-        }
-    }*/
+    leftSideAction: documentDelegateActions.leadingActions[0]
+    rightSideActions: documentDelegateActions.trailingActions
 
     contents: RowLayout {
         anchors.fill: parent
         spacing: units.gu(2)
 
         Icon {
-            width: height
-            height: units.gu(5)
+            Layout.preferredWidth: height
+            Layout.preferredHeight: units.gu(5)
 
             // At the moment the suru icon theme doesn't have much icons.
             name: {

=== modified file 'src/app/qml/documentPage/SortSettingsDialog.qml'
--- src/app/qml/documentPage/SortSettingsDialog.qml	2015-06-10 17:17:47 +0000
+++ src/app/qml/documentPage/SortSettingsDialog.qml	2015-08-04 16:03:21 +0000
@@ -18,7 +18,7 @@
 import QtQuick 2.0
 import Ubuntu.Components 1.1
 import Ubuntu.Components.Popups 1.0
-import QtQuick.Layouts 1.0
+import QtQuick.Layouts 1.1
 
 Dialog {
     id: sortSettingsDialog

=== added file 'src/app/qml/documentPage/TileBase.qml'
--- src/app/qml/documentPage/TileBase.qml	1970-01-01 00:00:00 +0000
+++ src/app/qml/documentPage/TileBase.qml	2015-08-04 16:03:21 +0000
@@ -0,0 +1,369 @@
+/*
+  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 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 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.0
+import Ubuntu.Components 1.1
+import Ubuntu.Components.Popups 1.0
+import Ubuntu.Components.ListItems 1.0 as ListItem
+
+AbstractButton {
+    id: root
+
+    property bool selected: false
+    property bool selectionMode: false
+
+    default property alias content: tileContent.data
+
+    property alias title: titleLabel.text
+    property alias text: textLabel.text
+    property alias subText: subTextLabel.text
+
+    // We don't really have swipe gesture here, but we anyway use the same
+    // properties' name used for UITK1.2 ListItem just for consistency.
+    property list<Action> trailingActions   // Right to Left gesture in ListItem
+    property list<Action> leadingActions    // Left to Right gesture in ListItem
+
+    Rectangle {
+        id: rect
+
+        anchors { fill: parent; margins: units.gu(0.5) }
+
+        color: Qt.lighter(UbuntuColors.lightGrey)
+        clip: true
+
+        Item {
+            id: tileContent
+
+            height: parent.height - captionsLayout.height * 0.3 - units.gu(2)
+            anchors {
+                left: parent.left
+                right: parent.right
+                verticalCenter: parent.verticalCenter
+                verticalCenterOffset: - captionsLayout.height * 0.3
+            }
+        }
+
+        Loader {
+            id: overflowButton
+
+            anchors {
+                right: parent.right
+                top: parent.top
+            }
+
+            z: 10
+
+            sourceComponent: actionsOverflowButton
+
+            onStatusChanged: {
+                if (status === Loader.Ready) {
+                    item.iconName = "contextual-menu"
+                    item.color = UbuntuColors.darkGrey
+                    item.width = overflowButton.width
+                    item.height = overflowButton.height
+
+                    item.triggered.connect(function() {
+                        var overflowPanel = PopupUtils.open(actionsOverflowPopoverComponent, item)
+                        item.overflowPanelVisible = overflowPanel.visible;
+
+                        overflowPanel.visibleChanged.connect(function() {
+                            item.overflowPanelVisible = overflowPanel.visible
+                        });
+                    });
+                }
+            }
+
+            width: units.gu(5)
+            height: units.gu(5)
+            visible: rect.state !== "select" && (trailingActions.length > 0 || leadingActions.length > 0)
+
+            Behavior on opacity {
+                NumberAnimation {
+                    duration: UbuntuAnimation.SnapDuration
+                }
+            }
+        }
+
+        Loader {
+            id: selectionIcon
+
+            anchors {
+                right: parent.right
+                top: parent.top
+            }
+
+            z: 10
+
+            width: (status === Loader.Ready) ? item.implicitWidth : 0
+            visible: (status === Loader.Ready) && (item.width === item.implicitWidth)
+            Behavior on opacity {
+                NumberAnimation {
+                    duration: UbuntuAnimation.SnapDuration
+                }
+            }
+        }
+
+        // Tile captions
+        Rectangle {
+            id: captionsRect
+
+            anchors {
+                left: parent.left
+                right: parent.right
+                bottom: parent.bottom
+            }
+
+            height: captionsLayout.height + units.gu(1)
+
+            color: UbuntuColors.darkGrey
+            opacity: 0.75
+            layer.enabled: true
+
+            Column {
+                id: captionsLayout
+                anchors {
+                    left: parent.left;
+                    right: parent.right
+                    verticalCenter: parent.verticalCenter
+                    margins: units.gu(0.5)
+                }
+
+                Label {
+                    id: titleLabel
+                    color: "white"
+
+                    elide: Text.ElideRight
+                    font.weight: Font.DemiBold
+                    fontSize: "small"
+
+                    anchors { left: parent.left; right: parent.right }
+                }
+
+                Label {
+                    id: textLabel
+                    color: "white"
+                    fontSize: "small"
+
+                    anchors { left: parent.left; right: parent.right }
+                }
+
+                Label {
+                    id: subTextLabel
+                    color: "white"
+                    fontSize: "small"
+
+                    anchors { left: parent.left; right: parent.right }
+                }
+            }
+        }
+
+        states: [
+            State {
+                name: "select"
+                when: selectionMode || selected
+                PropertyChanges {
+                    target: selectionIcon
+                    sourceComponent: selectionCheckBox
+                    anchors.margins: units.gu(1)
+                }
+            }
+        ]
+    }
+
+    // *** COMPONENTS
+    Component {
+        id: selectionCheckBox
+
+        CheckBox {
+            checked: root.selected
+            width: implicitWidth
+            // disable item mouse area to avoid conflicts with parent mouse area
+            __mouseArea.enabled: false
+        }
+    }
+
+    Component {
+        id: actionsOverflowButton
+
+        AbstractButton {
+            id: button
+
+            property alias color: icon.color
+            property bool overflowPanelVisible: false
+
+            width: visible ? units.gu(5) : 0
+            height: parent ? parent.height : undefined
+            Rectangle {
+                visible: button.pressed || button.overflowPanelVisible
+                anchors.fill: parent
+                color: Theme.palette.selected.background
+            }
+
+            Icon {
+                id: icon
+                anchors.centerIn: parent
+
+                // prevent trying to render the icon with an invalid source
+                // when the button is invisible by setting width and height to 0
+                width: visible ? units.gu(2.5) : 0
+                height: visible ? units.gu(2.5) : 0
+                source: button.iconSource
+                color: Qt.rgba(0, 0, 0, 0)
+                opacity: button.enabled ? 1.0 : 0.3
+            }
+
+            Component {
+                id: labelComponent
+                Label {
+                    id: label
+                    objectName: button.objectName + "_label"
+                    color: button.color
+                    opacity: button.enabled ? 1.0 : 0.3
+                    text: button.text
+                    fontSize: "xx-small"
+                }
+            }
+            Loader {
+                anchors {
+                    top: icon.bottom
+                    topMargin: units.gu(0.5)
+                    horizontalCenter: parent.horizontalCenter
+                }
+                sourceComponent: button.state === "IconAndLabel" ? labelComponent : null
+            }
+        }
+    }
+
+    Component {
+        id: actionsOverflowPopoverComponent
+
+        Popover {
+            id: actionsOverflowPopover
+            property bool square: true
+            callerMargin: -units.gu(1) + units.dp(4)
+            contentWidth: units.gu(20)
+            contentHeight: popoverActionsLayout.height
+
+            Connections {
+                target: root
+                onLeadingActionsChanged: {
+                    actionsOverflowPopover.hide();
+                }
+                onTrailingActionsChanged: {
+                    actionsOverflowPopover.hide();
+                }
+            }
+
+            Column {
+                id: popoverActionsLayout
+                anchors {
+                    left: parent.left
+                    top: parent.top
+                    right: parent.right
+                }
+                Repeater {
+                    id: overflowTrailingRepeater
+                    model: root.trailingActions
+
+                    delegate: overflowPanelDelegate
+                    onItemAdded: {
+                        item.action = model[index]
+                        item.clicked.connect(function() {
+                            actionsOverflowPopover.hide()
+                        })
+
+                        item.showDivider = (overflowLeadingRepeater.count === 0) ? (index !== overflowTrailingRepeater.count - 1) : true
+                    }
+                }
+
+                Repeater {
+                    id: overflowLeadingRepeater
+                    model: root.leadingActions
+
+                    delegate: overflowPanelDelegate
+                    onItemAdded: {
+                        item.action = model[index]
+                        item.clicked.connect(function() {
+                            actionsOverflowPopover.hide()
+                        })
+
+                        item.showDivider = (index !== overflowLeadingRepeater.count - 1)
+                    }
+                }
+            }
+        }
+    }
+
+    Component {
+        id: overflowPanelDelegate
+
+        AbstractButton {
+            id: rootItem
+            implicitHeight: units.gu(6) + bottomDividerLine.height
+            width: parent ? parent.width : units.gu(31)
+
+            property bool showDivider: true
+            property color foregroundColor: Theme.palette.selected.backgroundText
+
+            Rectangle {
+                visible: parent.pressed
+                anchors {
+                    left: parent.left
+                    right: parent.right
+                    top: parent.top
+                }
+                height: parent.height - bottomDividerLine.height
+                color: Theme.palette.selected.background
+            }
+
+            Icon {
+                id: actionIcon
+                source: action.iconSource
+                color: rootItem.foregroundColor
+                anchors {
+                    verticalCenter: parent.verticalCenter
+                    verticalCenterOffset: units.dp(-1)
+                    left: parent.left
+                    leftMargin: units.gu(2)
+                }
+                width: units.gu(2)
+                height: units.gu(2)
+                opacity: action.enabled ? 1.0 : 0.5
+            }
+
+            Label {
+                anchors {
+                    verticalCenter: parent.verticalCenter
+                    verticalCenterOffset: units.dp(-1)
+                    left: actionIcon.right
+                    leftMargin: units.gu(2)
+                    right: parent.right
+                }
+                fontSize: "small"
+                elide: Text.ElideRight
+                text: action.text
+                color: rootItem.foregroundColor
+                opacity: action.enabled ? 1.0 : 0.5
+            }
+
+            ListItem.ThinDivider {
+                id: bottomDividerLine
+                anchors.bottom: parent.bottom
+                visible: rootItem.showDivider
+            }
+        }
+    }
+}

=== modified file 'src/plugin/file-qml-plugin/documentmodel.cpp'
--- src/plugin/file-qml-plugin/documentmodel.cpp	2015-07-14 01:35:59 +0000
+++ src/plugin/file-qml-plugin/documentmodel.cpp	2015-08-04 16:03:21 +0000
@@ -240,15 +240,9 @@
             QString rootPath = volume.rootPath();
 
             if (rootPath.startsWith("/media/")) {
-                // In a Unix filesystem, names are case sentitive.
-                // For that reason we need to check twice.
                 QDir dir;
-
                 dir.setPath(rootPath + "/Documents");
-                if (dir.exists())
-                    m_docsMonitor->addDirectory(dir.canonicalPath());
 
-                dir.setPath(rootPath + "/documents");
                 if (dir.exists())
                     m_docsMonitor->addDirectory(dir.canonicalPath());
             }

=== modified file 'src/plugin/poppler-qml-plugin/CMakeLists.txt'
--- src/plugin/poppler-qml-plugin/CMakeLists.txt	2015-04-15 14:47:28 +0000
+++ src/plugin/poppler-qml-plugin/CMakeLists.txt	2015-08-04 16:03:21 +0000
@@ -11,7 +11,6 @@
     plugin.cpp
     pdfdocument.cpp
     pdfimageprovider.cpp
-    pdfthread.cpp
     pdfitem.cpp
     verticalview.cpp
     pdftocmodel.cpp
@@ -23,7 +22,7 @@
 
 target_link_libraries(popplerqmlplugin poppler-qt5)
 
-qt5_use_modules(popplerqmlplugin Gui Qml Quick Xml)
+qt5_use_modules(popplerqmlplugin Gui Qml Quick Xml Concurrent)
 
 # Copy the plugin, the qmldir file and other assets to the build dir for running in QtCreator
 if(NOT "${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}")

=== modified file 'src/plugin/poppler-qml-plugin/pdfdocument.cpp'
--- src/plugin/poppler-qml-plugin/pdfdocument.cpp	2015-03-25 16:51:53 +0000
+++ src/plugin/poppler-qml-plugin/pdfdocument.cpp	2015-08-04 16:03:21 +0000
@@ -19,13 +19,13 @@
 
 #include "pdfdocument.h"
 #include "pdfimageprovider.h"
-#include "pdfthread.h"
 
 #include <poppler/qt5/poppler-qt5.h>
 #include <QDebug>
 #include <QQmlEngine>
 #include <QQmlContext>
-#include <QThread>
+
+#include <QtConcurrent/QtConcurrent>
 
 PdfDocument::PdfDocument(QAbstractListModel *parent):
     QAbstractListModel(parent)
@@ -145,12 +145,15 @@
     if (!m_document)
         return false;
 
-    PdfThread *pdfThread = new PdfThread();
-    pdfThread->setDocument(m_document);
-
-    connect(pdfThread, SIGNAL(resultReady(PdfPagesList)), this, SLOT(_q_populate(PdfPagesList)));
-    connect(pdfThread, SIGNAL(finished()), pdfThread, SLOT(deleteLater()));
-    pdfThread->start();
+    Poppler::Document* document = m_document;
+    QtConcurrent::run( [=] {
+        PdfPagesList pages;
+
+        for( int i = 0; i < document->numPages(); ++i )
+            pages.append(document->page(i));
+
+        QMetaObject::invokeMethod(this, "_q_populate", Qt::QueuedConnection, Q_ARG(PdfPagesList, pages));
+    });
 
     return true;
 }

=== removed file 'src/plugin/poppler-qml-plugin/pdfthread.cpp'
--- src/plugin/poppler-qml-plugin/pdfthread.cpp	2015-01-30 18:42:00 +0000
+++ src/plugin/poppler-qml-plugin/pdfthread.cpp	1970-01-01 00:00:00 +0000
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2014 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/>.
- *
- * Author: Stefano Verzegnassi <stefano92.100@xxxxxxxxx>
- */
-
-#include "pdfthread.h"
-#include <QDebug>
-
-void PdfThread::run()
-{
-    PdfPagesList pages;
-
-    for( int i=0; i<m_document->numPages(); i++ )
-        pages.append(m_document->page(i));
-
-    Q_EMIT resultReady(pages);
-}
-
-void PdfThread::setDocument(Poppler::Document *document)
-{
-    m_document = document;
-}

=== removed file 'src/plugin/poppler-qml-plugin/pdfthread.h'
--- src/plugin/poppler-qml-plugin/pdfthread.h	2015-01-30 18:42:00 +0000
+++ src/plugin/poppler-qml-plugin/pdfthread.h	1970-01-01 00:00:00 +0000
@@ -1,42 +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 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/>.
- *
- * Author: Stefano Verzegnassi <stefano92.100@xxxxxxxxx>
- */
-
-#ifndef PDFTHREAD_H
-#define PDFTHREAD_H
-
-#include <QThread>
-#include <poppler/qt5/poppler-qt5.h>
-
-typedef QList<Poppler::Page*> PdfPagesList;
-
-class PdfThread : public QThread
-{
-    Q_OBJECT
-
-public:
-    void run();
-    void setDocument(Poppler::Document *document);
-
-Q_SIGNALS:
-    void resultReady(PdfPagesList pages);
-
-private:
-    Poppler::Document *m_document;
-};
-
-#endif // PDFTHREAD_H


Follow ups