Commit 8d4414b5 authored by Richard Moe Gustavsen's avatar Richard Moe Gustavsen Committed by The Qt Project
Browse files

PageStack: add recursion guard


We need to protect the page stack while it updates properties to
ensure that the update is atomic. Otherwise the user can e.g
push a new page upon receiving Page.onStatusChanged or
Page.onCompleted, which will recursively start a new transition
while we prepare for another. Calling push/pop while the transition
runs is fine.

Change-Id: Ib9453b1a61f8c8cee19f5e748bb75a1a30614119
Reviewed-by: default avatarRichard Moe Gustavsen <richard.gustavsen@digia.com>
parent 2570ef63
6.2 5.10 5.11 5.12 5.12.1 5.12.10 5.12.11 5.12.12 5.12.2 5.12.3 5.12.4 5.12.5 5.12.6 5.12.7 5.12.8 5.12.9 5.13 5.13.0 5.13.1 5.13.2 5.14 5.14.0 5.14.1 5.14.2 5.15 5.15.0 5.15.1 5.15.2 5.3 5.4 5.5 5.6 5.7 5.8 5.9 5.9.8 dev old/5.1 old/5.2 wip/calendar wip/tizen v5.15.0-alpha1 v5.14.1 v5.14.0 v5.14.0-rc2 v5.14.0-rc1 v5.14.0-beta3 v5.14.0-beta2 v5.14.0-beta1 v5.14.0-alpha1 v5.13.2 v5.13.1 v5.13.0 v5.13.0-rc3 v5.13.0-rc2 v5.13.0-rc1 v5.13.0-beta4 v5.13.0-beta3 v5.13.0-beta2 v5.13.0-beta1 v5.13.0-alpha1 v5.12.7 v5.12.6 v5.12.5 v5.12.4 v5.12.3 v5.12.2 v5.12.1 v5.12.0 v5.12.0-rc2 v5.12.0-rc1 v5.12.0-beta4 v5.12.0-beta3 v5.12.0-beta2 v5.12.0-beta1 v5.12.0-alpha1 v5.11.3 v5.11.2 v5.11.1 v5.11.0 v5.11.0-rc2 v5.11.0-rc1 v5.11.0-beta4 v5.11.0-beta3 v5.11.0-beta2 v5.11.0-beta1 v5.11.0-alpha1 v5.10.1 v5.10.0 v5.10.0-rc3 v5.10.0-rc2 v5.10.0-rc1 v5.10.0-beta4 v5.10.0-beta3 v5.10.0-beta2 v5.10.0-beta1 v5.10.0-alpha1 v5.9.9 v5.9.8 v5.9.7 v5.9.6 v5.9.5 v5.9.4 v5.9.3 v5.9.2 v5.9.1 v5.9.0 v5.9.0-rc2 v5.9.0-rc1 v5.9.0-beta4 v5.9.0-beta3 v5.9.0-beta2 v5.9.0-beta1 v5.9.0-alpha1 v5.8.0 v5.8.0-rc1 v5.8.0-beta1 v5.8.0-alpha1 v5.7.1 v5.7.0 v5.7.0-rc1 v5.7.0-beta1 v5.7.0-alpha1 v5.6.3 v5.6.2 v5.6.1 v5.6.1-1 v5.6.0 v5.6.0-rc1 v5.6.0-beta1 v5.6.0-alpha1 v5.5.1 v5.5.0 v5.5.0-rc1 v5.5.0-beta1 v5.5.0-alpha1 v5.4.2 v5.4.1 v5.4.0 v5.4.0-rc1 v5.4.0-beta1 v5.4.0-alpha1 v5.3.2 v5.3.1 v5.3.0 v5.3.0-rc1 v5.3.0-beta1 v5.3.0-alpha1 v5.2.1 v5.2.0 v5.2.0-rc1 v5.2.0-beta1 v5.2.0-alpha1 v5.1.1 v5.1.0 v5.1.0-rc2 v5.1.0-rc1 v5.1.0-beta1 v5.1.0-alpha1
No related merge requests found
Showing with 41 additions and 8 deletions
...@@ -547,6 +547,8 @@ Item { ...@@ -547,6 +547,8 @@ Item {
// Note: we support two different APIs in this function; The old meego API, and // Note: we support two different APIs in this function; The old meego API, and
// the new "property list" API. Hence the reason for hiding the fact that you // the new "property list" API. Hence the reason for hiding the fact that you
// can pass more arguments than shown in the signature: // can pass more arguments than shown in the signature:
if (__recursionGuard(true))
return
var properties = arguments[1] var properties = arguments[1]
var immediate = arguments[2] var immediate = arguments[2]
var replace = arguments[3] var replace = arguments[3]
...@@ -584,6 +586,7 @@ Item { ...@@ -584,6 +586,7 @@ Item {
push: true push: true
} }
__performPageTransition(transition) __performPageTransition(transition)
__recursionGuard(false)
return __currentPage return __currentPage
} }
...@@ -625,6 +628,9 @@ Item { ...@@ -625,6 +628,9 @@ Item {
if (page === __currentPage) if (page === __currentPage)
return return
if (__recursionGuard(true))
return
var outElement = JSArray.pop() var outElement = JSArray.pop()
var transitionElement = outElement var transitionElement = outElement
var inElement = JSArray.current() var inElement = JSArray.current()
...@@ -654,12 +660,16 @@ Item { ...@@ -654,12 +660,16 @@ Item {
push: false push: false
} }
__performPageTransition(transition) __performPageTransition(transition)
__recursionGuard(false)
return outElement.page; return outElement.page;
} }
/*! Remove all pages from the stack. No animations will be applied. */ /*! Remove all pages from the stack. No animations will be applied. */
function clear() { function clear() {
completeTransition() if (__recursionGuard(true))
return
if (__currentTransition)
__currentTransition.animation.complete()
__currentPage = null __currentPage = null
var count = __depth var count = __depth
for (var i=0; i<count; ++i) { for (var i=0; i<count; ++i) {
...@@ -667,6 +677,7 @@ Item { ...@@ -667,6 +677,7 @@ Item {
if (element.page) if (element.page)
__cleanup(element); __cleanup(element);
} }
__recursionGuard(false)
} }
/*! Search for a specific page inside the stack. \a func will /*! Search for a specific page inside the stack. \a func will
...@@ -712,8 +723,11 @@ Item { ...@@ -712,8 +723,11 @@ Item {
*/ */
function completeTransition() function completeTransition()
{ {
if (__recursionGuard(true))
return
if (__currentTransition) if (__currentTransition)
__currentTransition.animation.complete() __currentTransition.animation.complete()
__recursionGuard(false)
} }
/********* DEPRECATED API *********/ /********* DEPRECATED API *********/
...@@ -735,6 +749,8 @@ Item { ...@@ -735,6 +749,8 @@ Item {
property int __depth: 0 property int __depth: 0
/*! \internal Stores the transition info while a transition is ongoing */ /*! \internal Stores the transition info while a transition is ongoing */
property var __currentTransition: null property var __currentTransition: null
/*! \internal Stops the user from pushing pages while preparing a transition */
property bool __guard: false
/*! \internal */ /*! \internal */
Component.onCompleted: { Component.onCompleted: {
...@@ -744,10 +760,21 @@ Item { ...@@ -744,10 +760,21 @@ Item {
/*! \internal */ /*! \internal */
Component.onDestruction: { Component.onDestruction: {
completeTransition() if (__currentTransition)
__currentTransition.animation.complete()
__currentPage = null __currentPage = null
} }
function __recursionGuard(use)
{
if (use && __guard) {
console.warn("Warning: PageStack: You cannot push/pop recursively!")
console.trace()
return true
}
__guard = use
}
/*! \internal */ /*! \internal */
function __loadElement(element) function __loadElement(element)
{ {
...@@ -858,12 +885,13 @@ Item { ...@@ -858,12 +885,13 @@ Item {
/*! \internal */ /*! \internal */
function __performPageTransition(transition) function __performPageTransition(transition)
{ {
// Animate page in "outElement" out, and page in "inElement" in. Ensure entering page is // Animate page in "outElement" out, and page in "inElement" in. Set a guard to protect
// loaded. Loading a page can result in the loaded page recursively pushing or popping // the user from pushing new pages on signals that will fire while preparing for the transition
// other pages, so we need to check for this. // (e.g Page.onCompleted, Page.onStatusChanged, Page.onIndexChanged etc). Otherwise, we will enter
completeTransition() // this function several times, which causes the pages to be half-way updated.
if (__currentTransition)
__currentTransition.animation.complete()
__loadElement(transition.inElement) __loadElement(transition.inElement)
var currentElement = JSArray.current()
transition.name = transition.replace ? "replaceAnimation" : (transition.push ? "pushAnimation" : "popAnimation") transition.name = transition.replace ? "replaceAnimation" : (transition.push ? "pushAnimation" : "popAnimation")
var enterPage = transition.inElement.page var enterPage = transition.inElement.page
......
...@@ -135,7 +135,8 @@ Window { ...@@ -135,7 +135,8 @@ Window {
Page { Page {
id: page id: page
Component.onDestruction: console.log("destroyed component page: " + index) Component.onDestruction: console.log("destroyed component page: " + index)
property bool pushFromOnCompleted: false
Component.onCompleted: if (pushFromOnCompleted) pageStack.push(pageComponent)
//pageTransition: rotateTransition //pageTransition: rotateTransition
Rectangle { Rectangle {
...@@ -178,6 +179,10 @@ Window { ...@@ -178,6 +179,10 @@ Window {
text: "Push component page with destroyOnPop == false" text: "Push component page with destroyOnPop == false"
onClicked: pageStack.push({page:pageComponent, destroyOnPop:false}) onClicked: pageStack.push({page:pageComponent, destroyOnPop:false})
} }
Button {
text: "Push from Page.onCompleted"
onClicked: pageStack.push({page:pageComponent, properties:{pushFromOnCompleted:true}})
}
Button { Button {
text: "Pop" text: "Pop"
onClicked: pageStack.pop() onClicked: pageStack.pop()
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment