Commit be2e7220 authored by Thomas BOUTROUE's avatar Thomas BOUTROUE

Add FastObjectList model/view components for C++/QML

Fix issue with ***Container's going to 0x0 because relayout while hidden
parent 9c4ec790
Pipeline #978 passed with stage
in 13 seconds
#include "QtQmlTricks.h"
#include "QQmlContainerEnums.h"
#include "QQmlObjectListModel.h"
#include "QQuickColumnContainer.h"
#include "QQuickContainerAttachedObject.h"
#include "QQuickExtraAnchors.h"
#include "QQuickGridContainer.h"
#include "QQuickRowContainer.h"
#include "QQuickFastObjectListView.h"
#include "QQmlFastObjectListModel.h"
#include "QQmlContainerEnums.h"
#include "QQmlObjectListModel.h"
#include <qqml.h>
......@@ -15,10 +17,12 @@ void QtQmlTricks::registerComponents (void) {
qmlRegisterType<QQuickColumnContainer> ("QtQmlTricks", 3, 0, "ColumnContainer");
qmlRegisterType<QQuickGridContainer> ("QtQmlTricks", 3, 0, "GridContainer");
qmlRegisterType<QQuickRowContainer> ("QtQmlTricks", 3, 0, "RowContainer");
qmlRegisterType<QQuickFastObjectListView> ("QtQmlTricks", 3, 0, "FastObjectListView");
qmlRegisterUncreatableType<VerticalDirections> ("QtQmlTricks", 3, 0, "VerticalDirections", "Enum-class !");
qmlRegisterUncreatableType<HorizontalDirections> ("QtQmlTricks", 3, 0, "HorizontalDirections", "Enum-class !");
qmlRegisterUncreatableType<FlowDirections> ("QtQmlTricks", 3, 0, "FlowDirections", "Enum-class !");
qmlRegisterUncreatableType<QQuickExtraAnchors> ("QtQmlTricks", 3, 0, "ExtraAnchors", "Attached-object class !");
qmlRegisterUncreatableType<QQuickContainerAttachedObject> ("QtQmlTricks", 3, 0, "Container", "Attached-object class !");
qmlRegisterUncreatableType<QQmlObjectListModelBase> ("QtQmlTricks", 3, 0, "ObjectListModel", "Abstract base class !");
qmlRegisterUncreatableType<QQmlFastObjectListModelBase> ("QtQmlTricks", 3, 0, "FastObjectListModel", "Abstract base class !");
}
#ifndef QQMLFASTOBJECTLISTMODEL_H
#define QQMLFASTOBJECTLISTMODEL_H
#include <QObject>
#include <QList>
class QQmlFastObjectListModelBase : public QObject {
Q_OBJECT
Q_PROPERTY (int count READ getCount NOTIFY countChanged)
Q_PROPERTY (QObject * firstItem READ getFirstItem NOTIFY firstChanged)
Q_PROPERTY (QObject * lastItem READ getLastItem NOTIFY lastChanged)
public:
explicit QQmlFastObjectListModelBase (QObject * parent = Q_NULLPTR) : QObject { parent } { }
virtual ~QQmlFastObjectListModelBase (void) { }
virtual int getCount (void) const { return 0; }
virtual QObject * getFirstItem (void) const { return Q_NULLPTR; }
virtual QObject * getLastItem (void) const { return Q_NULLPTR; }
virtual QObject * getItem (const int) const { return Q_NULLPTR; }
signals:
void countChanged (void);
void firstChanged (void);
void lastChanged (void);
void itemsCleared (void);
void itemInserted (QObject * item, const int idx);
void itemRemoved (QObject * item, const int idx);
};
template<class T> class QQmlFastObjectListModel : public QQmlFastObjectListModelBase {
private:
QList<T *> m_itemsList { };
public:
explicit QQmlFastObjectListModel (QObject * parent = Q_NULLPTR) : QQmlFastObjectListModelBase { parent } { }
virtual ~QQmlFastObjectListModel (void) { }
using Iterator = typename QList<T *>::const_iterator;
Iterator begin (void) const {
return m_itemsList.constBegin ();
}
Iterator end (void) const {
return m_itemsList.constEnd ();
}
int count (void) const {
return m_itemsList.count ();
}
int indexOf (T * item) const {
return (item ? m_itemsList.indexOf (item) : -1);
}
bool isEmpty (void) const {
return m_itemsList.isEmpty ();
}
bool contains (T * item) const {
return (item != Q_NULLPTR && m_itemsList.contains (item));
}
T * getFirst (void) const {
return (!isEmpty () ? m_itemsList.first () : Q_NULLPTR);
}
T * getLast (void) const {
return (!isEmpty () ? m_itemsList.last () : Q_NULLPTR);
}
T * getAt (const int idx) const {
return (idx >= 0 && idx < count () ? m_itemsList.at (idx) : Q_NULLPTR);
}
void append (T * item) {
if (item != Q_NULLPTR && !contains (item)) {
const int idx { m_itemsList.count () };
m_itemsList.append (item);
emit itemInserted (item, idx);
emit lastChanged ();
if (count () == 1) {
emit firstChanged ();
}
emit countChanged ();
}
}
void appendList (const QList<T *> itemsList) {
if (!itemsList.isEmpty ()) {
for (T * item : itemsList) {
int idx { m_itemsList.count () };
if (item != Q_NULLPTR && !contains (item)) {
m_itemsList.append (item);
emit itemInserted (item, idx);
if (count () == 1) {
emit firstChanged ();
}
++idx;
}
}
emit lastChanged ();
emit countChanged ();
}
}
void prepend (T * item) {
if (item != Q_NULLPTR && !contains (item)) {
const int idx { 0 };
m_itemsList.prepend (item);
emit itemInserted (item, idx);
emit firstChanged ();
if (count () == 1) {
emit lastChanged ();
}
emit countChanged ();
}
}
void insert (T * item, const int idx) {
if (item != Q_NULLPTR && !contains (item)) {
m_itemsList.insert (idx, item);
emit itemInserted (item, idx);
if (idx == 0) {
emit firstChanged ();
}
if (idx == count ()) {
emit lastChanged ();
}
emit countChanged ();
}
}
void remove (T * item) {
if (item != Q_NULLPTR) {
const int idx { m_itemsList.indexOf (item) };
if (idx >= 0 && idx < count ()) {
m_itemsList.removeAt (idx);
emit itemRemoved (item, idx);
if (idx == 0) {
emit firstChanged ();
}
if (idx == count ()) {
emit lastChanged ();
}
emit countChanged ();
}
}
}
void clear (void) {
m_itemsList.clear ();
emit itemsCleared ();
emit firstChanged ();
emit lastChanged ();
emit countChanged ();
}
protected: // API for QQuickFastObjectListView only
int getCount (void) const Q_DECL_FINAL {
return count ();
}
QObject * getItem (const int idx) const Q_DECL_FINAL {
return getAt (idx);
}
QObject * getFirstItem (void) const Q_DECL_FINAL {
return getFirst ();
}
QObject * getLastItem (void) const Q_DECL_FINAL {
return getLast ();
}
};
#define QML_FASTOBJMODEL_PROPERTY(NAME,TYPE) \
private: Q_PROPERTY (QQmlFastObjectListModelBase * NAME READ get_##NAME CONSTANT) \
public: QQmlFastObjectListModel<TYPE> NAME { }; \
public: QQmlFastObjectListModelBase * get_##NAME (void) { return &NAME; } \
private:
#endif // QQMLFASTOBJECTLISTMODEL_H
......@@ -65,7 +65,9 @@ void QQuickAbstractContainerBase::itemChange (ItemChange change, const ItemChang
}
void QQuickAbstractContainerBase::updatePolish (void) {
QQuickItem::updatePolish ();
relayout ();
emit layoutDone ();
if (isVisible ()) {
QQuickItem::updatePolish ();
relayout ();
emit layoutDone ();
}
}
This diff is collapsed.
#ifndef QQUICKFASTOBJECTLISTVIEW_H
#define QQUICKFASTOBJECTLISTVIEW_H
#include <QQuickItem>
#include <QQmlComponent>
#include <QDateTime>
#include <QPropertyAnimation>
#include <QEasingCurve>
#include "QmlPropertyHelpers.h"
class QQmlFastObjectListModelBase;
class QQuickFastObjectListView : public QQuickItem {
Q_OBJECT
QML_WRITABLE_PTR_PROPERTY (current, QObject)
QML_WRITABLE_VAR_PROPERTY (behavior, int)
QML_WRITABLE_VAR_PROPERTY (spaceBefore, int)
QML_WRITABLE_VAR_PROPERTY (spaceAfter, int)
Q_PROPERTY (QQmlFastObjectListModelBase * model READ getModel WRITE setModel NOTIFY modelChanged)
Q_PROPERTY (QQmlComponent * delegate READ getDelegate WRITE setDelegate NOTIFY delegateChanged)
struct Holder {
QObject * modelItem { Q_NULLPTR };
QQuickItem * delegateInstance { Q_NULLPTR };
QQmlContext * context { Q_NULLPTR };
};
public:
explicit QQuickFastObjectListView (QQuickItem * parent = Q_NULLPTR);
virtual ~QQuickFastObjectListView (void);
enum Behavior {
FREE_MOVE = 0,
KEEP_AT_TOP,
KEEP_AT_BOTTOM,
KEEP_CENTERED,
};
Q_ENUM (Behavior)
QQmlFastObjectListModelBase * getModel (void) const;
QQmlComponent * getDelegate (void) const;
void setModel (QQmlFastObjectListModelBase * model);
void setDelegate (QQmlComponent * delegate);
signals:
void modelChanged (void);
void delegateChanged (void);
protected slots:
void doMarkDirty (void);
void doResetInstances (void);
void doPrepareInstances (void);
void doAttachToModel (void);
void doDetachFromModel (void);
void doChangePositionY (const int posY);
void doInstantiate (Holder * holder);
void doEliminate (Holder * holder);
void onItemInserted (QObject * item, const int idx);
void onItemRemoved (QObject * item, const int idx);
void onItemsCleared (void);
void onUserInteraction (void);
protected:
void classBegin (void) Q_DECL_FINAL;
void componentComplete (void) Q_DECL_FINAL;
void updatePolish (void) Q_DECL_FINAL;
private:
const QString MODEL_ITEM { "modelItem" };
const char * FLICKABLE { "QQuickFlickable" };
const char * FLICKING_V { "flickingVertically" };
const char * DRAGGING_V { "draggingVertically" };
const char * CONTENT_Y { "contentY" };
const char * CONTENT_W { "contentWidth" };
const char * CONTENT_H { "contentHeight" };
const char * ANCHORS { "anchors" };
const char * TOP { "top" };
const char * LEFT { "left" };
const char * RIGHT { "right" };
QQuickItem * m_flickable { Q_NULLPTR };
QQmlComponent * m_delegate { Q_NULLPTR };
QQmlFastObjectListModelBase * m_model { Q_NULLPTR };
QList<Holder *> m_holdersList { };
};
#endif // QQUICKFASTOBJECTLISTVIEW_H
Markdown is supported
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