Merge lp:~zsombi/ubuntu-ui-toolkit/33-listitem-attached into lp:~zsombi/ubuntu-ui-toolkit/listitem-master

Proposed by Zsombor Egri
Status: Merged
Approved by: Zsombor Egri
Approved revision: 1329
Merged at revision: 1270
Proposed branch: lp:~zsombi/ubuntu-ui-toolkit/33-listitem-attached
Merge into: lp:~zsombi/ubuntu-ui-toolkit/listitem-master
Prerequisite: lp:~zsombi/ubuntu-ui-toolkit/32-listitemactions-attached
Diff against target: 582 lines (+406/-20)
8 files modified
components.api (+1/-0)
modules/Ubuntu/Components/plugin/plugin.pro (+5/-2)
modules/Ubuntu/Components/plugin/propertychange_p.cpp (+76/-0)
modules/Ubuntu/Components/plugin/propertychange_p.h (+39/-0)
modules/Ubuntu/Components/plugin/uclistitem.cpp (+30/-18)
modules/Ubuntu/Components/plugin/uclistitem.h (+25/-0)
modules/Ubuntu/Components/plugin/uclistitem_p.h (+23/-0)
modules/Ubuntu/Components/plugin/uclistitemattached.cpp (+207/-0)
To merge this branch: bzr merge lp:~zsombi/ubuntu-ui-toolkit/33-listitem-attached
Reviewer Review Type Date Requested Status
Tim Peeters Approve
Zsombor Egri Pending
Review via email: mp+240836@code.launchpad.net

Description of the change

Introducing ListItem attached to ListItem's parent item, or to ListView. Yet handles ascending Flickables, further functionality will be introduced in later MRs.

To post a comment you must log in.
1319. By Zsombor Egri

small fixes

1320. By Zsombor Egri

prereq sync

1321. By Zsombor Egri

minor adjustments on global flickable interactive handling

1322. By Zsombor Egri

fix orphan disconnect warnings

1323. By Zsombor Egri

prereq sync

1324. By Zsombor Egri

prereq sync

1325. By Zsombor Egri

prereq sync

1326. By Zsombor Egri

prereq sync

1327. By Zsombor Egri

redo binding and property change as flickables may be added to the parent change while initialiozation completes

1328. By Zsombor Egri

typo fixed

Revision history for this message
Tim Peeters (tpeeters) wrote :

229 + // about to be deleted or reparrented, disable attached

*reparented

Revision history for this message
Tim Peeters (tpeeters) wrote :

537 +void UCListItemAttached::disableInteractive(UCListItem *item, bool disable)

maybe it is a matter of taste, but here you have to set the bool to TRUE in order to DISABLE interactive. Wouldn't be the other way around (enableInteractive(item, bool enable)) be more logical?

Revision history for this message
Tim Peeters (tpeeters) wrote :

540 + if ((d->globalDisabled && disable) || (!d->globalDisabled && disable)) {

this is the same as: if (disable) {

Revision history for this message
Tim Peeters (tpeeters) wrote :

540 + if ((d->globalDisabled && disable) || (!d->globalDisabled && disable)) {
541 + // disabling or re-disabling
542 + d->disablerItem = item;
543 + if (d->globalDisabled == disable) {
544 + // was already disabled, leave
545 + return;
546 + }
547 + d->globalDisabled = disable;
548 + } else if (d->globalDisabled && !disable && d->disablerItem == item) {
549 + // the one disabled it will enable
550 + d->globalDisabled = disable;
551 + d->disablerItem.clear();
552 + } else {
553 + // none of the above, leave
554 + return;
555 + }

same as code below, which is simpler:

if (disable) {
  d->disablerItem = item; // what is this for?
  if (d->globalDisabled) {
    return;
  }
} else if (d->globalDisabled && item == d->disablerItem) {
  d->globalDisabled = false;
  d->disablerItem.clear();
} else {
  // !disabled && (!globalDisabled || item != d->disablerItem)
  return;
}

Revision history for this message
Tim Peeters (tpeeters) wrote :

178 +void UCListItemPrivate::promptRebound()

Maybe immediateRebound() is more clear?
Or add a "// rebound without animation"

Revision history for this message
Tim Peeters (tpeeters) wrote :

427 +}
428 +// connect all flickables

add empty line inbetween these two

Revision history for this message
Tim Peeters (tpeeters) wrote :

354 + void clearFlickableList();
355 + void buildFlickablesList();

rename the first function to clearFlickablesList()

Revision history for this message
Zsombor Egri (zsombi) wrote :

> 537 +void UCListItemAttached::disableInteractive(UCListItem *item, bool
> disable)
>
> maybe it is a matter of taste, but here you have to set the bool to TRUE in
> order to DISABLE interactive. Wouldn't be the other way around
> (enableInteractive(item, bool enable)) be more logical?

Well, as you said, it's a matter of taste :) The main purpose of the whole logic is to disable, not to enable. But it all depends on what naming convention do we keep in mind: positive naming, or negative naming. And in that sense you are right, a positive approach would fit better.

Revision history for this message
Tim Peeters (tpeeters) wrote :

490 +// register item to be rebount

rebounD, I think..

Revision history for this message
Tim Peeters (tpeeters) wrote :

493 + // we cannot bind the item until we have an other one bount

everywhere (also variable names): bount --> bound

Revision history for this message
Zsombor Egri (zsombi) wrote :

> > 537 +void UCListItemAttached::disableInteractive(UCListItem *item, bool
> > disable)
> >
> > maybe it is a matter of taste, but here you have to set the bool to TRUE in
> > order to DISABLE interactive. Wouldn't be the other way around
> > (enableInteractive(item, bool enable)) be more logical?
>
> Well, as you said, it's a matter of taste :) The main purpose of the whole
> logic is to disable, not to enable. But it all depends on what naming
> convention do we keep in mind: positive naming, or negative naming. And in
> that sense you are right, a positive approach would fit better.

Ah, the comment already went out. I was to say that I won't change it here :)

Revision history for this message
Zsombor Egri (zsombi) wrote :

> 540 + if ((d->globalDisabled && disable) || (!d->globalDisabled &&
> disable)) {
> 541 + // disabling or re-disabling
> 542 + d->disablerItem = item;
> 543 + if (d->globalDisabled == disable) {
> 544 + // was already disabled, leave
> 545 + return;
> 546 + }
> 547 + d->globalDisabled = disable;
> 548 + } else if (d->globalDisabled && !disable && d->disablerItem ==
> item) {
> 549 + // the one disabled it will enable
> 550 + d->globalDisabled = disable;
> 551 + d->disablerItem.clear();
> 552 + } else {
> 553 + // none of the above, leave
> 554 + return;
> 555 + }
>
> same as code below, which is simpler:
>
> if (disable) {
> d->disablerItem = item; // what is this for?
> if (d->globalDisabled) {
> return;
> }
> } else if (d->globalDisabled && item == d->disablerItem) {
> d->globalDisabled = false;
> d->disablerItem.clear();
> } else {
> // !disabled && (!globalDisabled || item != d->disablerItem)
> return;
> }

Right, changed it.
The disablerItem is there to know that we should re-enable the interactive flag only if the same item which disabled requests it. Example, you have a Flickable with ListItems, all having their own ListItemAction declared (not a shared one!!), one ListItem swiped in. You start to swipe an other one, in that moment the previous one will initiate rebounding, and the one you swiped will lock the Flickable and start swiping. At this point this will be the one who requested the lock. The other one finishes the rebound animation, and as part of the animation end, the lock is released. But that should not happen as you may still be dragging the other ListItem, right? So the member makes sure that we only unlock the Flickable when the one locking it requests it.

Revision history for this message
Zsombor Egri (zsombi) wrote :

> 178 +void UCListItemPrivate::promptRebound()
>
> Maybe immediateRebound() is more clear?
> Or add a "// rebound without animation"

comment added

1329. By Zsombor Egri

review comments applied

Revision history for this message
Zsombor Egri (zsombi) wrote :

All comments addressed

Revision history for this message
Tim Peeters (tpeeters) wrote :

thanks

review: Approve
1330. By Zsombor Egri

prereq sync

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'components.api'
2--- components.api 2014-11-19 15:10:32 +0000
3+++ components.api 2014-11-19 15:10:34 +0000
4@@ -902,6 +902,7 @@
5 Method {
6 name: "snapToPosition"
7 Parameter { name: "position"; type: "double" }
8+ Component { name: "UCListItemAttached"; prototype: "QObject" }
9 name: "UCListItemDivider"
10 prototype: "QObject"
11 Property { name: "visible"; type: "bool" }
12
13=== modified file 'modules/Ubuntu/Components/plugin/plugin.pro'
14--- modules/Ubuntu/Components/plugin/plugin.pro 2014-11-19 15:10:32 +0000
15+++ modules/Ubuntu/Components/plugin/plugin.pro 2014-11-19 15:10:34 +0000
16@@ -72,7 +72,8 @@
17 uclistitem.h \
18 uclistitem_p.h \
19 uclistitemactions.h \
20- uclistitemactions_p.h
21+ uclistitemactions_p.h \
22+ propertychange_p.h
23
24 SOURCES += plugin.cpp \
25 uctheme.cpp \
26@@ -112,7 +113,9 @@
27 adapters/actionsproxy_p.cpp \
28 uclistitem.cpp \
29 uclistitemactions.cpp \
30- uclistitemactionsattached.cpp
31+ uclistitemactionsattached.cpp \
32+ uclistitemattached.cpp \
33+ propertychange_p.cpp
34
35 # adapters
36 SOURCES += adapters/alarmsadapter_organizer.cpp
37
38=== added file 'modules/Ubuntu/Components/plugin/propertychange_p.cpp'
39--- modules/Ubuntu/Components/plugin/propertychange_p.cpp 1970-01-01 00:00:00 +0000
40+++ modules/Ubuntu/Components/plugin/propertychange_p.cpp 2014-11-19 15:10:34 +0000
41@@ -0,0 +1,76 @@
42+/*
43+ * Copyright 2014 Canonical Ltd.
44+ *
45+ * This program is free software; you can redistribute it and/or modify
46+ * it under the terms of the GNU Lesser General Public License as published by
47+ * the Free Software Foundation; version 3.
48+ *
49+ * This program is distributed in the hope that it will be useful,
50+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
51+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
52+ * GNU Lesser General Public License for more details.
53+ *
54+ * You should have received a copy of the GNU Lesser General Public License
55+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
56+ */
57+
58+#include "propertychange_p.h"
59+
60+#include <QtQml/private/qqmlabstractbinding_p.h>
61+#define foreach Q_FOREACH //workaround to fix private includes
62+#include <QtQml/private/qqmlbinding_p.h> // for QmlBinding
63+#undef foreach
64+
65+/*
66+ * The class is used to save properties and their bindings while the property is
67+ * altered temporarily.
68+ */
69+PropertyChange::PropertyChange(QObject *item, const char *property)
70+ : m_backedUp(false)
71+ , qmlProperty(item, property, qmlContext(item))
72+{
73+}
74+PropertyChange::~PropertyChange()
75+{
76+ restore(this);
77+}
78+
79+/*
80+ * Sets a value to the property. Will back up the original values if it wasn't yet.
81+ * This function can be called many times, it will not destroy the backed up value/binding.
82+ */
83+void PropertyChange::setValue(PropertyChange *change, const QVariant &value)
84+{
85+ if (!change) {
86+ return;
87+ }
88+ if (!change->m_backedUp) {
89+ change->backup.first = QQmlPropertyPrivate::setBinding(change->qmlProperty, 0);
90+ change->backup.second = change->qmlProperty.read();
91+ change->m_backedUp = true;
92+ }
93+ change->qmlProperty.write(value);
94+}
95+
96+/*
97+ * Restore backed up value or binding.
98+ */
99+void PropertyChange::restore(PropertyChange *change)
100+{
101+ if (!change) {
102+ return;
103+ }
104+ if (change->m_backedUp) {
105+ // if there was a binding, restore it
106+ if (change->backup.first) {
107+ QQmlAbstractBinding *prevBinding = QQmlPropertyPrivate::setBinding(change->qmlProperty, change->backup.first);
108+ if (prevBinding && prevBinding != change->backup.first) {
109+ prevBinding->destroy();
110+ }
111+ } else {
112+ // there was no binding, restore previous value
113+ change->qmlProperty.write(change->backup.second);
114+ }
115+ change->m_backedUp = false;
116+ }
117+}
118
119=== added file 'modules/Ubuntu/Components/plugin/propertychange_p.h'
120--- modules/Ubuntu/Components/plugin/propertychange_p.h 1970-01-01 00:00:00 +0000
121+++ modules/Ubuntu/Components/plugin/propertychange_p.h 2014-11-19 15:10:34 +0000
122@@ -0,0 +1,39 @@
123+/*
124+ * Copyright 2014 Canonical Ltd.
125+ *
126+ * This program is free software; you can redistribute it and/or modify
127+ * it under the terms of the GNU Lesser General Public License as published by
128+ * the Free Software Foundation; version 3.
129+ *
130+ * This program is distributed in the hope that it will be useful,
131+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
132+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
133+ * GNU Lesser General Public License for more details.
134+ *
135+ * You should have received a copy of the GNU Lesser General Public License
136+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
137+ */
138+
139+#ifndef PROPERTYCHANGE_P_H
140+#define PROPERTYCHANGE_P_H
141+
142+#include <QtCore/QVariant>
143+#include <QtCore/QObject>
144+#include <QtQml/QQmlProperty>
145+
146+class QQmlAbstractBinding;
147+class PropertyChange
148+{
149+public:
150+ PropertyChange(QObject *item, const char *property);
151+ ~PropertyChange();
152+
153+ static void setValue(PropertyChange* change, const QVariant &value);
154+ static void restore(PropertyChange* change);
155+private:
156+ bool m_backedUp;
157+ QQmlProperty qmlProperty;
158+ QPair<QQmlAbstractBinding*, QVariant> backup;
159+};
160+
161+#endif // PROPERTYCHANGE_P_H
162
163=== modified file 'modules/Ubuntu/Components/plugin/uclistitem.cpp'
164--- modules/Ubuntu/Components/plugin/uclistitem.cpp 2014-11-19 15:10:32 +0000
165+++ modules/Ubuntu/Components/plugin/uclistitem.cpp 2014-11-19 15:10:34 +0000
166@@ -197,6 +197,7 @@
167 , overshoot(UCUnits::instance().gu(2))
168 , color(Qt::transparent)
169 , highlightColor(Qt::transparent)
170+ , attachedProperties(0)
171 , contentItem(new QQuickItem)
172 , divider(new UCListItemDivider)
173 , leadingActions(0)
174@@ -245,6 +246,12 @@
175 listenToRebind(false);
176 }
177
178+// rebound without animation
179+void UCListItemPrivate::promptRebound()
180+{
181+ setPressed(false);
182+}
183+
184 // called when units size changes
185 void UCListItemPrivate::_q_updateSize()
186 {
187@@ -283,14 +290,9 @@
188 // connects/disconnects from the Flickable anchestor to get notified when to do rebound
189 void UCListItemPrivate::listenToRebind(bool listen)
190 {
191- if (flickable.isNull()) {
192- return;
193- }
194- Q_Q(UCListItem);
195- if (listen) {
196- QObject::connect(flickable.data(), SIGNAL(movementStarted()), q, SLOT(_q_rebound()));
197- } else {
198- QObject::disconnect(flickable.data(), SIGNAL(movementStarted()), q, SLOT(_q_rebound()));
199+ if (attachedProperties) {
200+ Q_Q(UCListItem);
201+ attachedProperties->listenToRebind(q, listen);
202 }
203 }
204
205@@ -359,6 +361,11 @@
206 {
207 }
208
209+UCListItemAttached *UCListItem::qmlAttachedProperties(QObject *owner)
210+{
211+ return new UCListItemAttached(owner);
212+}
213+
214 void UCListItem::componentComplete()
215 {
216 UCStyledItemBase::componentComplete();
217@@ -381,11 +388,18 @@
218 d->flickable = qobject_cast<QQuickFlickable*>(data.item->parentItem());
219 }
220
221+ // attach ListItem properties to the flickable or to the parent item
222 if (d->flickable) {
223- // connect to flickable to get width changes
224- QObject::connect(d->flickable, SIGNAL(widthChanged()), this, SLOT(_q_updateSize()));
225+ d->attachedProperties = static_cast<UCListItemAttached*>(qmlAttachedPropertiesObject<UCListItem>(d->flickable));
226 } else if (data.item) {
227- QObject::connect(data.item, SIGNAL(widthChanged()), this, SLOT(_q_updateSize()));
228+ d->attachedProperties = static_cast<UCListItemAttached*>(qmlAttachedPropertiesObject<UCListItem>(data.item));
229+ } else {
230+ // about to be deleted or reparented, disable attached
231+ d->attachedProperties = 0;
232+ }
233+
234+ if (data.item) {
235+ QObject::connect(d->flickable ? d->flickable : data.item, SIGNAL(widthChanged()), this, SLOT(_q_updateSize()));
236 }
237
238 // update size
239@@ -437,7 +451,7 @@
240 {
241 UCStyledItemBase::mousePressEvent(event);
242 Q_D(UCListItem);
243- if (!d->flickable.isNull() && d->flickable->isMoving()) {
244+ if (d->attachedProperties && d->attachedProperties->isMoving()) {
245 // while moving, we cannot select any items
246 return;
247 }
248@@ -445,22 +459,20 @@
249 d->setPressed(true);
250 // connect the Flickable to know when to rebound
251 d->listenToRebind(true);
252- // accept the event so we get the rest of the events as well
253- event->setAccepted(true);
254 }
255+ // accept the event so we get the rest of the events as well
256+ event->setAccepted(true);
257 }
258
259 void UCListItem::mouseReleaseEvent(QMouseEvent *event)
260 {
261+ UCStyledItemBase::mouseReleaseEvent(event);
262 Q_D(UCListItem);
263 // set released
264 if (d->pressed) {
265+ d->listenToRebind(false);
266 Q_EMIT clicked();
267 }
268- // save pressed state as UCFocusScope resets it seemlessly
269- bool wasPressed = d->pressed;
270- UCStyledItemBase::mouseReleaseEvent(event);
271- d->pressed = wasPressed;
272 d->setPressed(false);
273 }
274
275
276=== modified file 'modules/Ubuntu/Components/plugin/uclistitem.h'
277--- modules/Ubuntu/Components/plugin/uclistitem.h 2014-11-19 15:10:32 +0000
278+++ modules/Ubuntu/Components/plugin/uclistitem.h 2014-11-19 15:10:34 +0000
279@@ -23,6 +23,7 @@
280 class UCListItemContent;
281 class UCListItemDivider;
282 class UCListItemActions;
283+class UCListItemAttached;
284 class UCListItemPrivate;
285 class UCListItem : public UCStyledItemBase
286 {
287@@ -42,6 +43,8 @@
288 explicit UCListItem(QQuickItem *parent = 0);
289 ~UCListItem();
290
291+ static UCListItemAttached *qmlAttachedProperties(QObject *owner);
292+
293 QQuickItem *contentItem() const;
294 UCListItemDivider *divider() const;
295 UCListItemActions *leadingActions() const;
296@@ -87,4 +90,26 @@
297 Q_PRIVATE_SLOT(d_func(), void _q_updateSize())
298 };
299
300+QML_DECLARE_TYPEINFO(UCListItem, QML_HAS_ATTACHED_PROPERTIES)
301+
302+class UCListItemAttachedPrivate;
303+class UCListItemAttached : public QObject
304+{
305+ Q_OBJECT
306+public:
307+ explicit UCListItemAttached(QObject *owner);
308+ ~UCListItemAttached();
309+
310+ bool listenToRebind(UCListItem *item, bool listen);
311+ void disableInteractive(UCListItem *item, bool disable);
312+ bool isMoving();
313+ bool isBoundTo(UCListItem *item);
314+
315+private Q_SLOTS:
316+ void unbindItem();
317+private:
318+ Q_DECLARE_PRIVATE(UCListItemAttached)
319+ QScopedPointer<UCListItemAttachedPrivate> d_ptr;
320+};
321+
322 #endif // UCLISTITEM_H
323
324=== modified file 'modules/Ubuntu/Components/plugin/uclistitem_p.h'
325--- modules/Ubuntu/Components/plugin/uclistitem_p.h 2014-11-19 15:10:32 +0000
326+++ modules/Ubuntu/Components/plugin/uclistitem_p.h 2014-11-19 15:10:34 +0000
327@@ -42,6 +42,7 @@
328
329 void _q_updateColors();
330 void _q_rebound();
331+ void promptRebound();
332 void _q_updateSize();
333 int index();
334 void setPressed(bool pressed);
335@@ -57,6 +58,7 @@
336 QColor color;
337 QColor highlightColor;
338 QPointer<QQuickFlickable> flickable;
339+ UCListItemAttached *attachedProperties;
340 QQuickItem *contentItem;
341 UCListItemDivider *divider;
342 UCListItemActions *leadingActions;
343@@ -67,6 +69,27 @@
344 void setContentMoving(bool moved);
345 };
346
347+class PropertyChange;
348+class UCListItemAttachedPrivate
349+{
350+ Q_DECLARE_PUBLIC(UCListItemAttached)
351+public:
352+ UCListItemAttachedPrivate(UCListItemAttached *qq);
353+ ~UCListItemAttachedPrivate();
354+
355+ void clearFlickablesList();
356+ void buildFlickablesList();
357+ void clearChangesList();
358+ void buildChangesList(const QVariant &newValue);
359+
360+ UCListItemAttached *q_ptr;
361+ bool globalDisabled;
362+ QList< QPointer<QQuickFlickable> > flickables;
363+ QList< PropertyChange* > changes;
364+ QPointer<UCListItem> boundItem;
365+ QPointer<UCListItem> disablerItem;
366+};
367+
368 class UCListItemDivider : public QObject
369 {
370 Q_OBJECT
371
372=== added file 'modules/Ubuntu/Components/plugin/uclistitemattached.cpp'
373--- modules/Ubuntu/Components/plugin/uclistitemattached.cpp 1970-01-01 00:00:00 +0000
374+++ modules/Ubuntu/Components/plugin/uclistitemattached.cpp 2014-11-19 15:10:34 +0000
375@@ -0,0 +1,207 @@
376+/*
377+ * Copyright 2014 Canonical Ltd.
378+ *
379+ * This program is free software; you can redistribute it and/or modify
380+ * it under the terms of the GNU Lesser General Public License as published by
381+ * the Free Software Foundation; version 3.
382+ *
383+ * This program is distributed in the hope that it will be useful,
384+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
385+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
386+ * GNU Lesser General Public License for more details.
387+ *
388+ * You should have received a copy of the GNU Lesser General Public License
389+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
390+ */
391+
392+#include "ucunits.h"
393+#include "uctheme.h"
394+#include "uclistitem.h"
395+#include "uclistitem_p.h"
396+#include "propertychange_p.h"
397+#include <QtQuick/private/qquickflickable_p.h>
398+
399+/*
400+ * The properties are attached to the ListItem's parent item or to its closest
401+ * Flickable parent, when embedded in ListView or Flickable. There will be only
402+ * one attached property per Flickable for all embedded child ListItems, enabling
403+ * in this way the controlling of the interactive flag of the Flickable and all
404+ * its ascendant Flickables.
405+ */
406+UCListItemAttachedPrivate::UCListItemAttachedPrivate(UCListItemAttached *qq)
407+ : q_ptr(qq)
408+ , globalDisabled(false)
409+{
410+}
411+
412+UCListItemAttachedPrivate::~UCListItemAttachedPrivate()
413+{
414+ clearChangesList();
415+ clearFlickablesList();
416+}
417+
418+// disconnect all flickables
419+void UCListItemAttachedPrivate::clearFlickablesList()
420+{
421+ Q_Q(UCListItemAttached);
422+ Q_FOREACH(const QPointer<QQuickFlickable> &flickable, flickables) {
423+ if (flickable.data())
424+ QObject::disconnect(flickable.data(), &QQuickFlickable::movementStarted,
425+ q, &UCListItemAttached::unbindItem);
426+ }
427+ flickables.clear();
428+}
429+
430+// connect all flickables
431+void UCListItemAttachedPrivate::buildFlickablesList()
432+{
433+ Q_Q(UCListItemAttached);
434+ QQuickItem *item = qobject_cast<QQuickItem*>(q->parent());
435+ if (!item) {
436+ return;
437+ }
438+ clearFlickablesList();
439+ while (item) {
440+ QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(item);
441+ if (flickable) {
442+ QObject::connect(flickable, &QQuickFlickable::movementStarted,
443+ q, &UCListItemAttached::unbindItem);
444+ flickables << flickable;
445+ }
446+ item = item->parentItem();
447+ }
448+}
449+
450+void UCListItemAttachedPrivate::clearChangesList()
451+{
452+ // clear property change objects
453+ Q_Q(UCListItemAttached);
454+ Q_FOREACH(PropertyChange *change, changes) {
455+ // deleting PropertyChange will restore the saved property
456+ // to its original binding/value
457+ delete change;
458+ }
459+ changes.clear();
460+}
461+
462+void UCListItemAttachedPrivate::buildChangesList(const QVariant &newValue)
463+{
464+ // collect all ascendant flickables
465+ Q_Q(UCListItemAttached);
466+ QQuickItem *item = qobject_cast<QQuickItem*>(q->parent());
467+ if (!item) {
468+ return;
469+ }
470+ clearChangesList();
471+ while (item) {
472+ QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(item);
473+ if (flickable) {
474+ PropertyChange *change = new PropertyChange(item, "interactive");
475+ PropertyChange::setValue(change, newValue);
476+ changes << change;
477+ }
478+ item = item->parentItem();
479+ }
480+}
481+
482+UCListItemAttached::UCListItemAttached(QObject *owner)
483+ : QObject(owner)
484+ , d_ptr(new UCListItemAttachedPrivate(this))
485+{
486+}
487+
488+UCListItemAttached::~UCListItemAttached()
489+{
490+}
491+
492+// register item to be rebound
493+bool UCListItemAttached::listenToRebind(UCListItem *item, bool listen)
494+{
495+ // we cannot bind the item until we have an other one bound
496+ bool result = false;
497+ Q_D(UCListItemAttached);
498+ if (listen) {
499+ if (d->boundItem.isNull() || (d->boundItem == item)) {
500+ d->boundItem = item;
501+ // rebuild flickable list
502+ d->buildFlickablesList();
503+ result = true;
504+ }
505+ } else if (d->boundItem == item) {
506+ d->boundItem.clear();
507+ result = true;
508+ }
509+ return result;
510+}
511+
512+// reports true if any of the ascendant flickables is moving
513+bool UCListItemAttached::isMoving()
514+{
515+ Q_D(UCListItemAttached);
516+ Q_FOREACH(const QPointer<QQuickFlickable> &flickable, d->flickables) {
517+ if (flickable && flickable->isMoving()) {
518+ return true;
519+ }
520+ }
521+ return false;
522+}
523+
524+// returns true if the given ListItem is bound to listen on moving changes
525+bool UCListItemAttached::isBoundTo(UCListItem *item)
526+{
527+ Q_D(UCListItemAttached);
528+ return d->boundItem == item;
529+}
530+
531+/*
532+ * Disable/enable interactive flag for the ascendant flickables. The item is used
533+ * to detect whether the same item is trying to enable the flickables which disabled
534+ * it before. The enabled/disabled states are not equivalent to the enabled/disabled
535+ * state of the interactive flag.
536+ * When disabled, always the last item disabling will be kept as active disabler,
537+ * and only the active disabler can enable (restore) the interactive flag state.
538+ */
539+void UCListItemAttached::disableInteractive(UCListItem *item, bool disable)
540+{
541+ Q_D(UCListItemAttached);
542+ if (disable) {
543+ // disabling or re-disabling
544+ d->disablerItem = item;
545+ if (d->globalDisabled == disable) {
546+ // was already disabled, leave
547+ return;
548+ }
549+ d->globalDisabled = true;
550+ } else if (d->globalDisabled && d->disablerItem == item) {
551+ // the one disabled it will enable
552+ d->globalDisabled = false;
553+ d->disablerItem.clear();
554+ } else {
555+ // !disabled && (!globalDisabled || item != d->disablerItem)
556+ return;
557+ }
558+ if (disable) {
559+ // (re)build changes list with disabling the interactive value
560+ d->buildChangesList(false);
561+ } else {
562+ d->clearChangesList();
563+ }
564+}
565+
566+void UCListItemAttached::unbindItem()
567+{
568+ Q_D(UCListItemAttached);
569+ if (d->boundItem) {
570+ // depending on content item's X coordinate, we either do animated or prompt rebind
571+ if (d->boundItem->contentItem()->x() != 0.0) {
572+ // content is not in origin, rebind
573+ UCListItemPrivate::get(d->boundItem.data())->_q_rebound();
574+ } else {
575+ // do some cleanup
576+ UCListItemPrivate::get(d->boundItem.data())->promptRebound();
577+ }
578+ d->boundItem.clear();
579+ }
580+ // clear binding list
581+ d->clearFlickablesList();
582+}

Subscribers

People subscribed via source and target branches

to all changes: