I have made the following changes intended for :
  CE:Apps:MTF / qmlgallery

Please review and accept or decline.
BOSS has already run some checks on this request.
See the "Messages from BOSS" section below.

https://build.pub.meego.com//request/show/5956

Thank You,
John Brooks

[This message was auto-generated]

---

Request # 5956:

Messages from BOSS:

State: review at 2012-08-21T04:48:04 by bossbot

Reviews:
       accepted by bossbot : Prechecks succeeded.
       new for CE-maintainers : Please replace this text with a review and 
approve/reject the review (not the SR). BOSS will take care of the rest

Changes:
  submit: home:special:branches:CE:Apps:MTF / qmlgallery -> CE:Apps:MTF / 
qmlgallery
  
changes files:
--------------
--- qmlgallery.changes
+++ qmlgallery.changes
@@ -0,0 +1,10 @@
+* Mon Aug 20 2012 John Brooks <[email protected]> - 0.0.8
+- Fixes NEMO#191: No way to refresh gallery
+- Fixes NEMO#238: Support formats other than JPEG
+- Fixes NEMO#186: If no images are available tell user about it
+- Fixes NEMO#231: Flipping orientation in full image view can change image
+- Display name of the menu entry changed from qmlgallery to Gallery
+- Fixes NEMO#192: Slideshow feature for gallery
+- Fixes NEMO#252: Not possible to determine position in the gallery when 
scrolling
+- Fixes NEMO#185 : Unable to show photos full screen
+

old:
----
  qmlgallery-0.0.7.tar.bz2

new:
----
  qmlgallery-0.0.8.tar.bz2

spec files:
-----------
--- qmlgallery.spec
+++ qmlgallery.spec
@@ -1,6 +1,6 @@
 # 
 # Do NOT Edit the Auto-generated Part!
-# Generated by: spectacle version 0.24.1
+# Generated by: spectacle version 0.25
 # 
 
 Name:       qmlgallery
@@ -9,7 +9,7 @@
 # << macros
 
 Summary:    Photo Gallery for Nemo
-Version:    0.0.7
+Version:    0.0.8
 Release:    1
 Group:      Applications/System
 License:    BSD

other changes:
--------------

++++++ qmlgallery-0.0.7.tar.bz2 -> qmlgallery-0.0.8.tar.bz2
--- qml/ImageContainer.qml
+++ qml/ImageContainer.qml
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2012 Andrea Bernabei <[email protected]>
+ *
+ * You may use this file under the terms of the BSD license as follows:
+ *
+ * "Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *   * Neither the name of Nemo Mobile nor the names of its contributors
+ *     may be used to endorse or promote products derived from this
+ *     software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+ */
+
+import QtQuick 1.1
+import com.nokia.meego 1.0
+
+Item {
+    id: imgContainer
+
+    property int index: -1
+    width: imgController.imgContainerWidth
+    height: imgController.imgContainerHeight
+
+    //This item has to be child of the controller
+    property variant imgController: parent
+
+    function resetZoom() {
+        //resetting all variables related to pinch-to-zoom
+        img.scale = 1
+        flickImg.contentX = flickImg.contentY = 0
+        pinchImg.lastContentX = pinchImg.lastContentY = pinchImg.deltaX = 
pinchImg.deltaY = 0
+        pinchImg.lastScaleX = pinchImg.lastScaleY = 1
+        pinchImg.isZoomingOut = false
+    }
+
+    PinchArea {
+        id: pinchImg
+        anchors.fill: imgContainer
+
+        //Disable the pincharea if the listview is scrolling, to avoid problems
+        enabled: !imgController.moving
+        pinch.target: img
+        pinch.maximumScale: 5
+        pinch.dragAxis: Pinch.NoDrag
+
+        property real lastContentX: 0
+        property real lastContentY: 0
+        property real lastScaleX: 1
+        property real lastScaleY: 1
+        property real deltaX: 0
+        property real deltaY: 0
+        property bool initializedX: false
+        property bool initializedY: false
+        property bool isZoomingOut: false
+
+
+        function updateContentX() {
+
+            //Only calculate the correct ContentX if the image is wider than 
the screen, otherwise keep it centered (contentX = 0 in the else branch)
+            if (rect.width == imgController.width) {
+
+                //Anchors the image to the left
+                if (flickImg.contentX < 0){
+                    deltaX = 0.0
+                    lastContentX = 0.0
+                    flickImg.contentX = 0.0
+                }
+                else {
+                    //if the right end of the image is inside the screen area, 
lock it to the right and zoom out using right edge as an anchor
+                    if ((flickImg.contentWidth - flickImg.contentX < 
parent.width) && isZoomingOut) {
+
+                        //align to the right
+                        flickImg.contentX -= parent.width - 
(flickImg.contentWidth - flickImg.contentX)
+
+                        //Algo: set variable as if a new pinch starting from 
right edge were triggered
+                        lastContentX = flickImg.contentX
+                        deltaX = flickImg.contentX + parent.width
+                        lastScaleX = img.scale
+                    }
+
+                    flickImg.contentX = (lastContentX + deltaX * ((img.scale / 
lastScaleX) - 1.0 ))
+                }
+            }
+            else {
+                flickImg.contentX = 0
+            }
+        }
+
+        function updateContentY() {
+
+            //Only calculate the correct ContentY if the image is taller than 
the screen, otherwise keep it centered (contentY = 0 in the else branch)
+            if (rect.height == imgController.height) {
+
+                //Anchors the image to the top when zooming out
+                if (flickImg.contentY < 0) {
+                    deltaY = 0.0
+                    lastContentY = 0.0
+                    flickImg.contentY = 0.0
+                }
+                else {
+                    //if the bottom end of the image is inside the screen 
area, lock it to the bottom and zoom out using bottom edge as an anchor
+                    if ((flickImg.contentHeight - flickImg.contentY < 
parent.height) && isZoomingOut) {
+                        //align to the bottom
+                        flickImg.contentY -= parent.height - 
(flickImg.contentHeight - flickImg.contentY)
+
+                        //Algo: set variable as if a new pinch starting from 
bottom edge were triggered
+                        lastContentY = flickImg.contentY
+                        deltaY = flickImg.contentY + parent.height
+                        lastScaleY = img.scale
+                    }
+                    flickImg.contentY = (lastContentY + deltaY * ((img.scale / 
lastScaleY) - 1.0 ))
+                }
+            }
+            else {
+                flickImg.contentY = 0
+            }
+        }
+
+
+        onPinchUpdated: {
+            //Am I zooming in or out?
+            if (pinch.scale > pinch.previousScale) isZoomingOut = false
+            else isZoomingOut = true
+
+            //Get updated "zoom center point" values when the image is 
completely zoomed out
+            if(img.scale == 1) {
+                //This is so that everytime you zoom out, the new zoom is 
started with updated values
+                initializedX = false
+                initializedY = false
+            }
+
+            //i.e. everytime the image is wider than the screen, it should 
actually be
+            // img.width == imgController.width, but this condition is rarely 
met because of numeric error
+            if (rect.width == imgController.width) {
+                if (!initializedX ) {
+                    //If it has not already been set by the "if (height == 
parent.imgController.height)" branch, set the scale here
+                    lastScaleX = img.scale
+
+                    lastContentX = flickImg.contentX
+                    deltaX = flickImg.contentX + pinch.center.x
+                    initializedX = true;
+                }
+
+            }
+
+            if (rect.height == imgController.height) {
+                if (!initializedY) {
+                    //If it has not already been set by the "if (width == 
imgController.width)", set the scale here
+                    lastScaleY = img.scale
+
+                    lastContentY = flickImg.contentY
+                    deltaY = flickImg.contentY + pinch.center.y
+                    initializedY = true;
+                }
+            }
+            // updateContentX and updateContentY are called after the scale on 
the target item updates bindings
+        }
+
+        onPinchFinished: {
+            lastContentX = flickImg.contentX
+            lastContentY = flickImg.contentY
+
+            initializedX = false
+            initializedY = false
+        }
+
+    }
+
+    Item {
+        id: rect
+        anchors.centerIn: parent
+
+        width: Math.min(img.width*img.scale, parent.width)
+        height: Math.min(img.height*img.scale, parent.height)
+
+        Flickable {
+            id: flickImg
+
+            anchors.fill: rect
+            transformOrigin: Item.TopLeft
+
+            contentWidth: img.width * img.scale
+            contentHeight: img.height * img.scale
+
+            onContentWidthChanged: {
+                pinchImg.updateContentX()
+                pinchImg.updateContentY()
+            }
+            onContentHeightChanged: {
+                pinchImg.updateContentX()
+                pinchImg.updateContentY()
+            }
+
+            Image {
+                id: img
+
+                //For Harmattan/Nemo ( THIS PART HAS TO BE FIXED , THE IMAGE 
IS NOT SCALED TO FILL THE SCREEN ATM)
+                property real imgRatio: galleryModel.get(index).width / 
galleryModel.get(index).height
+                property bool fitsVertically: imgRatio < (imgContainer.width / 
imgContainer.height)
+                width: (fitsVertically) ? (imgController.height * imgRatio) : 
imgController.width
+                height: (fitsVertically) ? (imgController.height) : 
(imgController.width / imgRatio)
+
+                //For Simulator:
+                //width: 480
+                //fillMode: Image.PreserveAspectFit
+
+                transformOrigin: Item.TopLeft
+                asynchronous: true
+                source: galleryModel.get(index).url
+                sourceSize.width: 2000
+                sourceSize.height: 2000
+
+                //Disable ListView scrolling if you're zooming
+                onScaleChanged: {
+                    if (scale != 1 && imgController.flickAreaEnabled == true) 
imgController.flickAreaEnabled = false
+                    else if (scale == 1 && imgController.flickAreaEnabled == 
false) imgController.flickAreaEnabled = true
+                }
+
+                MouseArea {
+                    anchors.fill: parent
+
+                    Timer {
+                        id: doubleClickTimer
+                        interval: 350
+                    }
+
+                    // onDoubleClicked seems broken on-device with all of the 
flickable/pincharea here
+                    onClicked: {
+                        if (doubleClickTimer.running) resetZoom()
+                        else doubleClickTimer.start()
+                    }
+                }
+            }
+
+        }
+
+    }
+
+
+}
--- qml/ImagePage.qml
+++ qml/ImagePage.qml
@@ -33,256 +33,209 @@
 import com.nokia.meego 1.0
 import QtMobility.gallery 1.1
 
-Page{
-    id: imagepage
-    anchors.fill:parent
+Page {
+    id: imageController
+    anchors.fill: parent
 
+    clip: true
     tools: imgTools
 
-    property alias imageId: imageview.currentIndex
-    property alias galleryModel: imageview.model
+    property int imgContainerWidth: width
+    property int imgContainerHeight: height
+    property variant galleryModel
+    // XXX: This is not actually the visible index; it's the index shown when
+    // loading the page. Use middle.index instead. Should be refactored.
+    property int visibleIndex: 0
+    property real firstPressX
+    property real pressX
+    property int flickToX: 0
+    property int flickFromX: 0
+    property bool moving: false
+    property variant leftMost: one
+    property variant leftMiddle: two
+    property variant middle: three
+    property variant rightMiddle: four
+    property variant rightMost: five
+    property real swipeThreshold: 40
+    property real leftMostOptimalX: -width*2
+    //number of pixel you have to move before the Pinch Area is disabled
+    property real pinchThreshold: 3
+    property alias flickAreaEnabled: imgFlickable.enabled
+
+    onWidthChanged: {
+        middle.resetZoom()
+        alignToCenter()
+    }
+
+    function modulus(a, b) {
+        if (a < 0) return (a+b) % b
+        else return a % b
+    }
+
+    function alignToCenter() {
+        leftMost.x = leftMostOptimalX
+    }
+
+    function swapLeftMost() {
+        leftMiddle.anchors.left = undefined
+        leftMost.anchors.left = rightMost.right
+
+        //TODO: we could use a generic function instead of fixed assignments 
when shifting the positiong of the containers
+        //shift all elements left by one position, and make leftMost become 
rightMost
+        var oldLeftMost = leftMost
+        leftMost = leftMiddle
+        leftMiddle = middle
+        middle = rightMiddle
+        rightMiddle = rightMost
+        rightMost = oldLeftMost
+        //set the index (relative to galleryModel) of the image which has to 
be loaded by the shifted image container
+        rightMost.index = modulus(middle.index + 2, 
imageController.galleryModel.count);
+    }
 
-    ListView{
-        id: imageview
-        anchors.fill:parent
-        clip: true
-
-        orientation: ListView.Horizontal
-        highlightRangeMode: ListView.StrictlyEnforceRange
-
-        //Set duration to 0 to skip listview animation when passing from grid 
to listview
-        highlightMoveDuration: 1
-        highlightResizeDuration: 1
-
-        cacheBuffer:2*width
-
-        snapMode: ListView.SnapOneItem
-
-        delegate: Item{
-            id: imgContainer
-
-            width: imageview.width
-            height: imageview.height
-
-            PinchArea{
-                id: pinchImg
-                anchors.fill: imgContainer
-
-                //Disable the pincharea if the listview is scrolling, to avoid 
problems
-                enabled: !imageview.moving
-                pinch.target: img
-                pinch.maximumScale: 5
-                pinch.dragAxis: Pinch.NoDrag
-
-                property real lastContentX: 0
-                property real lastContentY: 0
-                property real lastScaleX: 1
-                property real lastScaleY: 1
-                property real deltaX: 0
-                property real deltaY: 0
-                property bool initializedX: false
-                property bool initializedY: false
-                property bool isZoomingOut: false
-
-
-                function updateContentX(){
-
-                    //Only calculate the correct ContentX if the image is 
wider than the screen, otherwise keep it centered (contentX = 0 in the else 
branch)
-                    if (rect.width == imageview.width){
-
-                        //Anchors the image to the left
-                        if (flickImg.contentX < 0){
-                            deltaX = 0.0
-                            lastContentX = 0.0
-                            flickImg.contentX = 0.0
-                        }
-                        else {
-                            //if the right end of the image is inside the 
screen area, lock it to the right and zoom out using right edge as an anchor
-                            if ((flickImg.contentWidth - flickImg.contentX < 
parent.width) && isZoomingOut){
-
-                                //align to the right
-                                flickImg.contentX -= parent.width - 
(flickImg.contentWidth - flickImg.contentX)
-
-                                //Algo: set variable as if a new pinch 
starting from right edge were triggered
-                                lastContentX = flickImg.contentX
-                                deltaX = flickImg.contentX + parent.width
-                                lastScaleX = img.scale
-                            }
-
-                            flickImg.contentX = (lastContentX + deltaX * 
((img.scale / lastScaleX) - 1.0 ))
-                        }
-                    }
-                    else{
-                        flickImg.contentX = 0
-                    }
-                }
-
-                function updateContentY(){
-
-                    //Only calculate the correct ContentY if the image is 
taller than the screen, otherwise keep it centered (contentY = 0 in the else 
branch)
-                    if (rect.height == imageview.height){
-
-                        //Anchors the image to the top when zooming out
-                        if (flickImg.contentY < 0){
-                            deltaY = 0.0
-                            lastContentY = 0.0
-                            flickImg.contentY = 0.0
-                        }
-                        else {
-                            //if the bottom end of the image is inside the 
screen area, lock it to the bottom and zoom out using bottom edge as an anchor
-                            if ((flickImg.contentHeight - flickImg.contentY < 
parent.height) && isZoomingOut){
-
-                                //align to the bottom
-                                flickImg.contentY -= parent.height - 
(flickImg.contentHeight - flickImg.contentY)
-
-                                //Algo: set variable as if a new pinch 
starting from bottom edge were triggered
-                                lastContentY = flickImg.contentY
-                                deltaY = flickImg.contentY + parent.height
-                                lastScaleY = img.scale
-                            }
-                            flickImg.contentY = (lastContentY + deltaY * 
((img.scale / lastScaleY) - 1.0 ))
-                        }
-                    }
-                    else{
-                        flickImg.contentY = 0
-                    }
-                }
-
-
-                onPinchUpdated:{
-                    //Am I zooming in or out?
-                    if (pinch.scale > pinch.previousScale) isZoomingOut = false
-                    else isZoomingOut = true
-
-                    //Get updated "zoom center point" values when the image is 
completely zoomed out
-                    if(img.scale == 1){
-                        //This is so that everytime you zoom out, the new zoom 
is started with updated values
-                        initializedX = false
-                        initializedY = false
-                    }
-
-                    //i.e. everytime the image is wider than the screen, it 
should actually be
-                    // img.width == imageview.width, but this condition is 
rarely met because of numeric error
-                    if (rect.width == imageview.width)
-                    {
-                        if (!initializedX )
-                        {
-                            //If it has not already been set by the "if 
(height == imageview.height)" branch, set the scale here
-                            lastScaleX = img.scale
-
-                            lastContentX = flickImg.contentX
-                            deltaX = flickImg.contentX + pinch.center.x
-                            initializedX = true;
-                        }
-
-                    }
-
-                    if (rect.height == imageview.height)
-                    {
-                        if (!initializedY)
-                        {
-                            //If it has not already been set by the "if (width 
== imageview.width)", set the scale here
-                            lastScaleY = img.scale
-
-                            lastContentY = flickImg.contentY
-                            deltaY = flickImg.contentY + pinch.center.y
-                            initializedY = true;
-                        }
-
-                    }
-
-                    // updateContentX and updateContentY are called after the 
scale on the target item updates bindings
-                }
-
-                onPinchFinished: {
-                    lastContentX = flickImg.contentX
-                    lastContentY = flickImg.contentY
-
-                    initializedX = false
-                    initializedY = false
-                }
+    function swapRightMost() {
+        rightMost.anchors.left = undefined
+        leftMost.anchors.left = rightMost.right
+
+        //shift all elements right by one position, and make rightMost become 
leftMost
+        var oldRightMost = rightMost
+        rightMost = rightMiddle
+        rightMiddle = middle
+        middle = leftMiddle
+        leftMiddle = leftMost
+        leftMost = oldRightMost
+        leftMost.index = modulus(middle.index - 2, 
imageController.galleryModel.count);
+    }
 
+    NumberAnimation {
+        id: flickTo;
+        target: leftMost;
+        property: "x";
+        from: flickFromX;
+        to: flickToX;
+        duration: 300;
+        easing.type: Easing.OutQuad
+        onCompleted: {
+            if (Math.abs(to - from) > swipeThreshold) {
+                if (from > to )
+                    swapLeftMost()
+                else
+                    swapRightMost()
+                //center flickable view, this allows endless scrolling
+                alignToCenter()
             }
 
-            Item{
-                id: rect
-                anchors.centerIn:parent
-
-                width:  Math.min(img.width*img.scale, parent.width)
-                height: Math.min(img.height*img.scale, parent.height)
-
-                Flickable{
-                    id: flickImg
-
-                    anchors.fill:rect
-                    transformOrigin: Item.TopLeft
-
-                    contentWidth: img.width * img.scale
-                    contentHeight: img.height * img.scale
-
-                    onContentWidthChanged: { pinchImg.updateContentX(); 
pinchImg.updateContentY(); }
-                    onContentHeightChanged: { pinchImg.updateContentX(); 
pinchImg.updateContentY(); }
-
-                    Image{
-                        id: img
-
-                        //For Harmattan/Nemo ( THIS PART HAS TO BE FIXED , THE 
IMAGE IS NOT SCALED TO FILL THE SCREEN ATM)
-                        property real imgRatio: galleryModel.get(index).width 
/ galleryModel.get(index).height
-                        property bool fitsVertically: imgRatio < 
(imgContainer.width / imgContainer.height)
-                        width: (fitsVertically) ? (imageview.height * 
imgRatio) : imageview.width
-                        height: (fitsVertically) ? (imageview.height) : 
(imageview.width / imgRatio)
-
-                        //For Simulator:
-                        //width: 480
-                        //fillMode: Image.PreserveAspectFit
-
-                        transformOrigin: Item.TopLeft
-                        asynchronous: true
-                        source: url
-                        sourceSize.width: 2000
-                        sourceSize.height: 2000
-
-                        //Disable ListView scrolling if you're zooming
-                        onScaleChanged: {
-                            if (scale != 1 && imageview.interactive == true) 
imageview.interactive = false
-                            else if (scale == 1 && imageview.interactive == 
false) imageview.interactive = true
-                        }
-
-                        MouseArea {
-                            anchors.fill: parent
-
-                            Timer {
-                                id: doubleClickTimer
-                                interval: 350
-                            }
-
-                            // onDoubleClicked seems broken on-device with all 
of the flickable/pincharea here
-                            onClicked: {
-                                if (doubleClickTimer.running) {
-                                    img.scale = 1
-                                    flickImg.contentX = flickImg.contentY = 0
-                                }
-                                else
-                                    doubleClickTimer.start()
-                            }
-                        }
-                    }
+            //This should be the only way the view can stop moving, so we set 
moving to false
+            moving = false
+        }
+    }
+
+    //create items and position them in a row,
+    // ------ImageContainer must be child of the images controller -----
+    ImageContainer {
+        id: one;
+        x: leftMostOptimalX;
+        index: modulus(visibleIndex - 2, galleryModel.count)
+    }
+    ImageContainer {
+        id: two
+        anchors.left: one.right
+        index: modulus(visibleIndex - 1, galleryModel.count)
+    }
+    ImageContainer {
+        id: three
+        anchors.left: two.right
+        index: visibleIndex
+    }
+    ImageContainer {
+        id: four
+        anchors.left: three.right
+        index: modulus (visibleIndex + 1, galleryModel.count)
+    }
+    ImageContainer {
+        id: five
+        anchors.left: four.right
+        index: modulus (visibleIndex + 2, galleryModel.count)
+    }
 
-                }
 
+    MouseArea {
+        id: imgFlickable
+        anchors.fill: parent
+
+        property bool pressedForClick: false
+
+        onPressed: {
+            firstPressX = mouseX
+            pressX = mouseX
+            pressedForClick = true
+
+            //if the animation is running, make it stop and immediately slide 
to the image that you were going to
+            //this allows very fast scrolling
+            if (flickTo.running) flickTo.stop()
+        }
+
+        onPositionChanged: {
+            if (Math.abs(firstPressX - mouseX) > pinchThreshold && moving == 
false) {
+                moving = true
+                pressedForClick = false
             }
 
+            //Only move the image if we're sure the user isn't trying to pinch
+            if (moving) {
+                leftMost.x = leftMost.x - (pressX - mouseX)
+                pressX = mouseX
+            }
         }
 
+        onReleased: {
+            if (middle.x >= swipeThreshold) {
+                //move it left
+                flickToX = leftMostOptimalX + imgContainerWidth
+            }
+            else if (middle.x <= -swipeThreshold) {
+                //move it right
+                flickToX = leftMostOptimalX -imgContainerWidth
+            }
+            else {
+                //bring it back
+                flickToX = leftMostOptimalX
+            }
 
-    }
+            if (pressedForClick) {
+                appWindow.fullscreen = !appWindow.fullscreen
+                pressedForClick = false
+            }
 
+            flickFromX = leftMost.x
+            flickTo.start()
+        }
+    }
+    Menu {
+        id: pageMenu
+        MenuLayout {
+            MenuItem {
+                text: "Slideshow"
+                onClicked: 
appWindow.pageStack.push(Qt.resolvedUrl("ImageSlideshowPage.qml"),
+                                                    {visibleIndex: 
imageController.middle.index,
+                                                    galleryModel: 
imageController.galleryModel},
+                                                    true)
+            }
+        }
+    }
     ToolBarLayout {
-            id: imgTools
-            ToolIcon {
-                platformIconId: "toolbar-back"
-                anchors.left: (parent === undefined) ? undefined : parent.left
-                onClicked: appWindow.pageStack.pop()
+        id: imgTools
+        ToolIcon {
+            platformIconId: "toolbar-back"
+            anchors.left: (parent === undefined) ? undefined : parent.left
+            onClicked: {
+                appWindow.fullscreen = false
+                appWindow.pageStack.pop()
             }
+        }
+        ToolIcon {
+            platformIconId: "toolbar-view-menu"
+            anchors.right: (parent === undefined) ? undefined : parent.right
+            onClicked: (pageMenu.status === DialogStatus.Closed) ? 
pageMenu.open() : pageMenu.close()
+        }
     }
 }
--- qml/ImageSlideshowPage.qml
+++ qml/ImageSlideshowPage.qml
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2012 Antti Seppälä <[email protected]>
+ *
+ * You may use this file under the terms of the BSD license as follows:
+ *
+ * "Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *   * Neither the name of Nemo Mobile nor the names of its contributors
+ *     may be used to endorse or promote products derived from this
+ *     software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+ */
+
+import QtQuick 1.1
+import com.nokia.meego 1.0
+import QtMobility.gallery 1.1
+
+Page {
+    id: imageSlideshow
+    anchors.fill: parent
+
+    property int slideVisibleTime: 4000
+    property int visibleIndex
+    property int phase
+    property variant galleryModel
+
+    Image {
+        id: image1
+        asynchronous: true
+        width: Math.min(sourceSize.width, parent.width)
+        height: Math.min(sourceSize.height, parent.height)
+        anchors.centerIn: parent
+        opacity: 1
+        fillMode: Image.PreserveAspectFit
+        Behavior on opacity { NumberAnimation { duration: 1000 } }
+    }
+    Image {
+        id: image2
+        asynchronous: true
+        width: Math.min(sourceSize.width, parent.width)
+        height: Math.min(sourceSize.height, parent.height)
+        anchors.centerIn: parent
+        opacity: 0
+        fillMode: Image.PreserveAspectFit
+        Behavior on opacity { NumberAnimation { duration: 1000 } }
+    }
+    SequentialAnimation {
+        id: mainLoop
+        loops: Animation.Infinite
+        PauseAnimation { duration: imageSlideshow.slideVisibleTime }
+        ScriptAction {
+            script: {
+                image1.opacity = image2.opacity
+                image2.opacity = 1-image2.opacity
+            }
+        }
+        PauseAnimation { duration: 1001 }
+        ScriptAction { script: loadNextImage() }
+    }
+    MouseArea {
+        anchors.fill: parent
+        onPressed: {
+            mainLoop.stop()
+            image1.source = ""
+            image2.source = ""
+            appWindow.fullscreen = false
+            appWindow.pageStack.pop()
+        }
+    }
+    Component.onCompleted: {
+        appWindow.fullscreen = true
+        if (visibleIndex < galleryModel.count) {
+            phase = 0
+            image1.source = galleryModel.get(visibleIndex).url
+            loadNextImage()
+            mainLoop.start()
+        }
+    }
+    function loadNextImage() {
+        visibleIndex++
+        if (visibleIndex >= galleryModel.count)
+            visibleIndex = 0
+
+        if (phase === 0)
+            image2.source = galleryModel.get(visibleIndex).url
+        else
+            image1.source = galleryModel.get(visibleIndex).url
+        phase = 1-phase
+    }
+}
--- qml/MainPage.qml
+++ qml/MainPage.qml
@@ -45,7 +45,7 @@
         delegate: GalleryDelegate {
             MouseArea {
                 anchors.fill: parent
-                onClicked: 
appWindow.pageStack.push(Qt.resolvedUrl("ImagePage.qml"), {imageId: index, 
galleryModel: gallery } )
+                onClicked: 
appWindow.pageStack.push(Qt.resolvedUrl("ImagePage.qml"), {visibleIndex: index, 
galleryModel: gallery} )
             }
         }
     }
@@ -55,13 +55,23 @@
         ToolIcon {
             platformIconId: "toolbar-view-menu"
             anchors.right: (parent === undefined) ? undefined : parent.right
-            //onClicked: (myMenu.status == DialogStatus.Closed) ? 
myMenu.open() : myMenu.close()
+            onClicked: (pageMenu.status === DialogStatus.Closed) ? 
pageMenu.open() : pageMenu.close()
+        }
+    }
+
+    Menu {
+        id: pageMenu
+        MenuLayout {
+            MenuItem {
+                text: "Slideshow"
+                onClicked: 
appWindow.pageStack.push(Qt.resolvedUrl("ImageSlideshowPage.qml"), 
{visibleIndex: 0, galleryModel: gallery})
+            }
         }
     }
 
     states: State {
         name: "active"
-        when: status == PageStatus.Active || status == PageStatus.Activating
+        when: status === PageStatus.Active || status === PageStatus.Activating
 
         PropertyChanges {
             target: appWindow.pageStack.toolBar
--- qml/api/GalleryModel.qml
+++ qml/api/GalleryModel.qml
@@ -34,10 +34,7 @@
 DocumentGalleryModel {
     id: gallery
 
-    rootType : DocumentGallery.Image
-    properties : [ "url", "width", "height" ]
-    filter : GalleryWildcardFilter {
-        property : "fileName";
-        value : "*.jpg";
-    }
+    autoUpdate: true
+    rootType: DocumentGallery.Image
+    properties: [ "url", "width", "height" ]
 }
--- qml/api/GalleryView.qml
+++ qml/api/GalleryView.qml
@@ -30,18 +30,18 @@
  */
 
 import QtQuick 1.1
+import com.nokia.meego 1.0
 import org.nemomobile.thumbnailer 1.0
 
 GridView {
+    id: grid
+    anchors.fill: parent
+
     // baseThumbnailSize is used to request images, and display size will be <=
     property int baseThumbnailSize: 160
     property int thumbnailSize: 0
     property int padding: 2
 
-    Component.onCompleted: updateThumbnailSize()
-    onPaddingChanged: updateThumbnailSize()
-    onBaseThumbnailSizeChanged: updateThumbnailSize()
- 
     // Calculate the thumbnail size to fit items of approximately 160px
     // onto each row with a minimal amount of extra space. The goal is
     // to avoid having a large unused area on the right edge.
@@ -53,17 +53,40 @@
         console.log("XXX: Thumb size is " + thumbnailSize)
     }
 
-    Connections {
-        target: screen
-        onCurrentOrientationChanged: updateThumbnailSize()
-    }
-
-    id: grid
-    anchors.fill: parent
+    Component.onCompleted: updateThumbnailSize()
+    onPaddingChanged: updateThumbnailSize()
+    onBaseThumbnailSizeChanged: updateThumbnailSize()
 
     flow: GridView.LeftToRight
     maximumFlickVelocity: 3000
     cellHeight: thumbnailSize + padding
     cellWidth: thumbnailSize + padding
     cacheBuffer: cellHeight * 3
+
+    ScrollDecorator {
+        flickableItem: grid
+        anchors.right: grid.right; anchors.bottom: grid.bottom
+    }
+
+    Connections {
+        target: screen
+        onCurrentOrientationChanged: updateThumbnailSize()
+    }
+
+    Text {
+        id: noElementsFoundText
+        anchors.verticalCenter: parent.verticalCenter
+        anchors.left: parent.left
+        anchors.right: parent.right
+        anchors.leftMargin: 20
+        anchors.rightMargin: 20
+
+        visible: parent.model.count == 0 && parent.model.progress == 1.0
+
+        text: parent.model.filter == null ?  "No images yet..." : "No matching 
images found..."
+        color: "lightgrey"
+        font.pointSize: 26
+        horizontalAlignment: Text.AlignHCenter
+        wrapMode: Text.WordWrap
+    }
 }
--- qml/main.qml
+++ qml/main.qml
@@ -36,6 +36,9 @@
     id: appWindow
 
     initialPage: mainPage
+    property bool fullscreen: false
+    showStatusBar: !fullscreen
+    showToolBar: !fullscreen
 
     MainPage {
         id: mainPage
--- qmlgallery.desktop
+++ qmlgallery.desktop
@@ -3,7 +3,7 @@
 Version=1.0
 Type=Application
 Terminal=false
-Name=qmlgallery
+Name=Gallery
 Exec=/opt/qmlgallery/bin/qmlgallery
 Icon=icons-Applications-photos
 X-Window-Icon=
--- res.qrc
+++ res.qrc
@@ -1,7 +1,9 @@
 <RCC>
     <qresource>
+        <file>qml/ImageContainer.qml</file>
         <file>qml/ImagePage.qml</file>
         <file>qml/MainPage.qml</file>
         <file>qml/main.qml</file>
+        <file>qml/ImageSlideshowPage.qml</file>
     </qresource>
 </RCC>

++++++ qmlgallery.yaml
--- qmlgallery.yaml
+++ qmlgallery.yaml
@@ -1,6 +1,6 @@
 Name:  qmlgallery
 Summary: Photo Gallery for Nemo
-Version: 0.0.7
+Version: 0.0.8
 Release: 1
 Group: Applications/System
 License: BSD



Reply via email to