Fix StackView::busy and child event filtering

1) renamed busy() to isBusy() to follow the Qt convention :)
2) fixed spurious busyChanged() emissions (it was always emitted on
   push/replace/pop even when the state didn't change (null transitions)
3) with null transitions, the child event filter was never turned off
   and therefore StackView "froze" after the first push/replace/pop

Change-Id: I07fffa73db5a182865c7b2779641e1f95ed8b30b
Reviewed-by: Mitch Curtis <mitch.curtis@theqtcompany.com>
This commit is contained in:
J-P Nurmi 2015-10-29 15:50:39 +01:00
parent 2ee0e8770b
commit 497ac61380
5 changed files with 175 additions and 20 deletions

View File

@ -292,10 +292,10 @@ QQuickStackAttached *QQuickStackView::qmlAttachedProperties(QObject *object)
\readonly
This property holds whether a transition is running.
*/
bool QQuickStackView::busy() const
bool QQuickStackView::isBusy() const
{
Q_D(const QQuickStackView);
return d->transitioner && !d->transitioner->runningJobs.isEmpty();
return d->busy;
}
/*!

View File

@ -241,7 +241,7 @@ void QQuickStackElement::itemDestroyed(QQuickItem *)
item = Q_NULLPTR;
}
QQuickStackViewPrivate::QQuickStackViewPrivate() : currentItem(Q_NULLPTR), transitioner(Q_NULLPTR)
QQuickStackViewPrivate::QQuickStackViewPrivate() : busy(false), currentItem(Q_NULLPTR), transitioner(Q_NULLPTR)
{
}
@ -417,11 +417,10 @@ void QQuickStackViewPrivate::popTransition(QQuickStackElement *enter, QQuickStac
enter->startTransition(transitioner);
}
if (!immediate)
setBusy(true);
if (transitioner)
if (transitioner) {
setBusy(!transitioner->runningJobs.isEmpty());
transitioner->resetTargetLists();
}
}
void QQuickStackViewPrivate::pushTransition(QQuickStackElement *enter, QQuickStackElement *exit, const QRectF &viewBounds, bool immediate)
@ -450,11 +449,10 @@ void QQuickStackViewPrivate::pushTransition(QQuickStackElement *enter, QQuickSta
exit->startTransition(transitioner);
}
if (!immediate)
setBusy(true);
if (transitioner)
if (transitioner) {
setBusy(!transitioner->runningJobs.isEmpty());
transitioner->resetTargetLists();
}
}
void QQuickStackViewPrivate::replaceTransition(QQuickStackElement *enter, QQuickStackElement *exit, const QRectF &viewBounds, bool immediate)
@ -484,11 +482,10 @@ void QQuickStackViewPrivate::replaceTransition(QQuickStackElement *enter, QQuick
enter->startTransition(transitioner);
}
if (!immediate)
setBusy(true);
if (transitioner)
if (transitioner) {
setBusy(!transitioner->runningJobs.isEmpty());
transitioner->resetTargetLists();
}
}
void QQuickStackViewPrivate::completeTransition(QQuickStackElement *element, QQuickTransition *transition)
@ -525,11 +522,14 @@ void QQuickStackViewPrivate::viewItemTransitionFinished(QQuickItemViewTransition
}
}
void QQuickStackViewPrivate::setBusy(bool busy)
void QQuickStackViewPrivate::setBusy(bool b)
{
Q_Q(QQuickStackView);
q->setFiltersChildMouseEvents(busy);
emit q->busyChanged();
if (busy != b) {
busy = b;
q->setFiltersChildMouseEvents(busy);
emit q->busyChanged();
}
}
QT_END_NAMESPACE

View File

@ -61,7 +61,7 @@ class QQuickStackViewPrivate;
class Q_LABSTEMPLATES_EXPORT QQuickStackView : public QQuickControl
{
Q_OBJECT
Q_PROPERTY(bool busy READ busy NOTIFY busyChanged FINAL)
Q_PROPERTY(bool busy READ isBusy NOTIFY busyChanged FINAL)
Q_PROPERTY(int depth READ depth NOTIFY depthChanged FINAL)
Q_PROPERTY(QQuickItem *currentItem READ currentItem NOTIFY currentItemChanged FINAL)
Q_PROPERTY(QVariant initialItem READ initialItem WRITE setInitialItem FINAL)
@ -78,7 +78,7 @@ public:
static QQuickStackAttached *qmlAttachedProperties(QObject *object);
bool busy() const;
bool isBusy() const;
int depth() const;
QQuickItem *currentItem() const;

View File

@ -132,6 +132,7 @@ public:
void viewItemTransitionFinished(QQuickItemViewTransitionableItem *item) Q_DECL_OVERRIDE;
void setBusy(bool busy);
bool busy;
QVariant initialItem;
QQuickItem *currentItem;
QList<QQuickStackElement*> removals;

View File

@ -87,18 +87,63 @@ TestCase {
control.destroy()
}
SignalSpy {
id: busySpy
signalName: "busyChanged"
}
function test_busy() {
var control = stackView.createObject(testCase)
verify(control)
compare(control.busy, false)
var busyCount = 0
busySpy.target = control
verify(busySpy.valid)
control.push(component)
compare(control.busy, false)
compare(busySpy.count, busyCount)
control.push(component)
compare(control.busy, true)
compare(busySpy.count, ++busyCount)
tryCompare(control, "busy", false)
compare(busySpy.count, ++busyCount)
control.replace(component)
compare(control.busy, true)
compare(busySpy.count, ++busyCount)
tryCompare(control, "busy", false)
compare(busySpy.count, ++busyCount)
control.pop()
compare(control.busy, true)
compare(busySpy.count, ++busyCount)
tryCompare(control, "busy", false)
compare(busySpy.count, ++busyCount)
control.pushEnter = null
control.pushExit = null
control.push(component)
compare(control.busy, false)
compare(busySpy.count, busyCount)
control.replaceEnter = null
control.replaceExit = null
control.replace(component)
compare(control.busy, false)
compare(busySpy.count, busyCount)
control.popEnter = null
control.popExit = null
control.pop()
compare(control.busy, false)
compare(busySpy.count, busyCount)
control.destroy()
}
@ -590,4 +635,113 @@ TestCase {
control.destroy()
}
Component {
id: testButton
Button {
property int clicks: 0
onClicked: ++clicks
}
}
function test_interaction() {
var control = stackView.createObject(testCase, {initialItem: testButton, width: testCase.width, height: testCase.height})
verify(control)
var firstButton = control.currentItem
verify(firstButton)
var firstClicks = 0
var secondClicks = 0
var thirdClicks = 0
// push - default transition
var secondButton = control.push(testButton)
compare(control.busy, true)
mouseClick(firstButton) // filtered while busy
mouseClick(secondButton) // filtered while busy
compare(firstButton.clicks, firstClicks)
compare(secondButton.clicks, secondClicks)
tryCompare(control, "busy", false)
mouseClick(secondButton)
compare(secondButton.clicks, ++secondClicks)
// replace - default transition
var thirdButton = control.replace(testButton)
compare(control.busy, true)
mouseClick(secondButton) // filtered while busy
mouseClick(thirdButton) // filtered while busy
compare(secondButton.clicks, secondClicks)
compare(thirdButton.clicks, thirdClicks)
tryCompare(control, "busy", false)
secondButton = null
secondClicks = 0
mouseClick(thirdButton)
compare(thirdButton.clicks, ++thirdClicks)
// pop - default transition
control.pop()
compare(control.busy, true)
mouseClick(firstButton) // filtered while busy
mouseClick(thirdButton) // filtered while busy
compare(firstButton.clicks, firstClicks)
compare(thirdButton.clicks, thirdClicks)
tryCompare(control, "busy", false)
thirdButton = null
thirdClicks = 0
mouseClick(firstButton)
compare(firstButton.clicks, ++firstClicks)
// push - immediate operation
secondButton = control.push(testButton, StackView.Immediate)
compare(control.busy, false)
mouseClick(secondButton)
compare(secondButton.clicks, ++secondClicks)
// replace - immediate operation
thirdButton = control.replace(testButton, StackView.Immediate)
compare(control.busy, false)
secondButton = null
secondClicks = 0
mouseClick(thirdButton)
compare(thirdButton.clicks, ++thirdClicks)
// pop - immediate operation
control.pop(StackView.Immediate)
compare(control.busy, false)
thirdButton = null
thirdClicks = 0
mouseClick(firstButton)
compare(firstButton.clicks, ++firstClicks)
// push - null transition
control.pushEnter = null
control.pushExit = null
secondButton = control.push(testButton)
compare(control.busy, false)
mouseClick(secondButton)
compare(secondButton.clicks, ++secondClicks)
// replace - null transition
control.replaceEnter = null
control.replaceExit = null
thirdButton = control.replace(testButton)
compare(control.busy, false)
secondButton = null
secondClicks = 0
mouseClick(thirdButton)
compare(thirdButton.clicks, ++thirdClicks)
// pop - null transition
control.popEnter = null
control.popExit = null
control.pop()
compare(control.busy, false)
thirdButton = null
thirdClicks = 0
mouseClick(firstButton)
compare(firstButton.clicks, ++firstClicks)
control.destroy()
}
}