statemachine: Use new QQmlListProperty capabilities

Change-Id: Ic471ba4f82bdf1ac63953927d0a83f514d0e49d0
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
This commit is contained in:
Ulf Hermann 2020-01-15 14:31:35 +01:00
parent 96d2c71c88
commit 053547fba7
7 changed files with 128 additions and 34 deletions

View File

@ -46,54 +46,142 @@
#include <QQmlInfo>
#include <QQmlListProperty>
template <class T>
enum class ChildrenMode {
None = 0x0,
State = 0x1,
Transition = 0x2,
StateOrTransition = State | Transition
};
template<typename T>
static T *parentObject(QQmlListProperty<QObject> *prop) { return static_cast<T *>(prop->object); }
template<class T, ChildrenMode Mode>
struct ParentHandler
{
static bool unparentItem(QQmlListProperty<QObject> *prop, QObject *oldItem);
static bool parentItem(QQmlListProperty<QObject> *prop, QObject *item);
};
template<class T>
struct ParentHandler<T, ChildrenMode::None>
{
static bool unparentItem(QQmlListProperty<QObject> *, QObject *) { return true; }
static bool parentItem(QQmlListProperty<QObject> *, QObject *) { return true; }
};
template<class T>
struct ParentHandler<T, ChildrenMode::State>
{
static bool parentItem(QQmlListProperty<QObject> *prop, QObject *item)
{
if (QAbstractState *state = qobject_cast<QAbstractState *>(item)) {
state->setParent(parentObject<T>(prop));
return true;
}
return false;
}
static bool unparentItem(QQmlListProperty<QObject> *, QObject *oldItem)
{
if (QAbstractState *state = qobject_cast<QAbstractState *>(oldItem)) {
state->setParent(nullptr);
return true;
}
return false;
}
};
template<class T>
struct ParentHandler<T, ChildrenMode::Transition>
{
static bool parentItem(QQmlListProperty<QObject> *prop, QObject *item)
{
if (QAbstractTransition *trans = qobject_cast<QAbstractTransition *>(item)) {
parentObject<T>(prop)->addTransition(trans);
return true;
}
return false;
}
static bool unparentItem(QQmlListProperty<QObject> *prop, QObject *oldItem)
{
if (QAbstractTransition *trans = qobject_cast<QAbstractTransition *>(oldItem)) {
parentObject<T>(prop)->removeTransition(trans);
return true;
}
return false;
}
};
template<class T>
struct ParentHandler<T, ChildrenMode::StateOrTransition>
{
static bool parentItem(QQmlListProperty<QObject> *prop, QObject *oldItem)
{
return ParentHandler<T, ChildrenMode::State>::parentItem(prop, oldItem)
|| ParentHandler<T, ChildrenMode::Transition>::parentItem(prop, oldItem);
}
static bool unparentItem(QQmlListProperty<QObject> *prop, QObject *oldItem)
{
return ParentHandler<T, ChildrenMode::State>::unparentItem(prop, oldItem)
|| ParentHandler<T, ChildrenMode::Transition>::unparentItem(prop, oldItem);
}
};
template <class T, ChildrenMode Mode>
class ChildrenPrivate
{
public:
ChildrenPrivate()
{}
static void append(QQmlListProperty<QObject> *prop, QObject *item)
{
QAbstractState *state = qobject_cast<QAbstractState*>(item);
if (state) {
item->setParent(prop->object);
} else {
QAbstractTransition *trans = qobject_cast<QAbstractTransition*>(item);
if (trans)
static_cast<T *>(prop->object)->addTransition(trans);
}
static_cast<ChildrenPrivate<T>*>(prop->data)->children.append(item);
emit static_cast<T *>(prop->object)->childrenChanged();
}
static void appendNoTransition(QQmlListProperty<QObject> *prop, QObject *item)
{
QAbstractState *state = qobject_cast<QAbstractState*>(item);
if (state) {
item->setParent(prop->object);
}
static_cast<ChildrenPrivate<T>*>(prop->data)->children.append(item);
emit static_cast<T *>(prop->object)->childrenChanged();
Handler::parentItem(prop, item);
static_cast<Self *>(prop->data)->children.append(item);
emit parentObject<T>(prop)->childrenChanged();
}
static int count(QQmlListProperty<QObject> *prop)
{
return static_cast<ChildrenPrivate<T>*>(prop->data)->children.count();
return static_cast<Self *>(prop->data)->children.count();
}
static QObject *at(QQmlListProperty<QObject> *prop, int index)
{
return static_cast<ChildrenPrivate<T>*>(prop->data)->children.at(index);
return static_cast<Self *>(prop->data)->children.at(index);
}
static void clear(QQmlListProperty<QObject> *prop)
{
static_cast<ChildrenPrivate<T>*>(prop->data)->children.clear();
emit static_cast<T *>(prop->object)->childrenChanged();
auto &children = static_cast<Self *>(prop->data)->children;
for (QObject *oldItem : qAsConst(children))
Handler::unparentItem(prop, oldItem);
children.clear();
emit parentObject<T>(prop)->childrenChanged();
}
static void replace(QQmlListProperty<QObject> *prop, int index, QObject *item)
{
auto &children = static_cast<Self *>(prop->data)->children;
Handler::unparentItem(prop, children.at(index));
Handler::parentItem(prop, item);
children.replace(index, item);
emit parentObject<T>(prop)->childrenChanged();
}
static void removeLast(QQmlListProperty<QObject> *prop)
{
Handler::unparentItem(prop, static_cast<Self *>(prop->data)->children.takeLast());
emit parentObject<T>(prop)->childrenChanged();
}
private:
using Self = ChildrenPrivate<T, Mode>;
using Handler = ParentHandler<T, Mode>;
QList<QObject *> children;
};

View File

@ -50,7 +50,9 @@ FinalState::FinalState(QState *parent)
QQmlListProperty<QObject> FinalState::children()
{
return QQmlListProperty<QObject>(this, &m_children, m_children.appendNoTransition, m_children.count, m_children.at, m_children.clear);
return QQmlListProperty<QObject>(this, &m_children,
m_children.append, m_children.count, m_children.at,
m_children.clear, m_children.replace, m_children.removeLast);
}
/*!

View File

@ -66,7 +66,7 @@ Q_SIGNALS:
void childrenChanged();
private:
ChildrenPrivate<FinalState> m_children;
ChildrenPrivate<FinalState, ChildrenMode::State> m_children;
};
QT_END_NAMESPACE

View File

@ -61,7 +61,9 @@ void State::componentComplete()
QQmlListProperty<QObject> State::children()
{
return QQmlListProperty<QObject>(this, &m_children, m_children.append, m_children.count, m_children.at, m_children.clear);
return QQmlListProperty<QObject>(this, &m_children,
m_children.append, m_children.count, m_children.at,
m_children.clear, m_children.replace, m_children.removeLast);
}
/*!

View File

@ -69,7 +69,7 @@ Q_SIGNALS:
void childrenChanged();
private:
ChildrenPrivate<State> m_children;
ChildrenPrivate<State, ChildrenMode::StateOrTransition> m_children;
};
QT_END_NAMESPACE

View File

@ -90,7 +90,9 @@ void StateMachine::componentComplete()
QQmlListProperty<QObject> StateMachine::children()
{
return QQmlListProperty<QObject>(this, &m_children, m_children.append, m_children.count, m_children.at, m_children.clear);
return QQmlListProperty<QObject>(this, &m_children,
m_children.append, m_children.count, m_children.at,
m_children.clear, m_children.replace, m_children.removeLast);
}
/*!

View File

@ -82,7 +82,7 @@ Q_SIGNALS:
void qmlRunningChanged();
private:
ChildrenPrivate<StateMachine> m_children;
ChildrenPrivate<StateMachine, ChildrenMode::StateOrTransition> m_children;
bool m_completed;
bool m_running;
};