12#include <QtCore/QMetaMethod>
13#include <QtQml/QQmlEngine>
21constexpr const char* kDirtyChangedSignature =
"dirtyChanged(bool)";
22constexpr const char* kChildDirtyChangedSlotSignature =
"_childDirtyChanged(bool)";
24QMetaMethod childDirtyChangedSlot()
27 const int slotIndex = metaObject->indexOfSlot(kChildDirtyChangedSlotSignature);
28 Q_ASSERT_X(slotIndex >= 0,
"childDirtyChangedSlot",
"slot signature mismatch — update kChildDirtyChangedSlotSignature");
29 return (slotIndex >= 0) ? metaObject->method(slotIndex) : QMetaMethod();
32QMetaMethod dirtyChangedSignal(
const QObject*
object)
38 const int signalIndex =
object->metaObject()->indexOfSignal(kDirtyChangedSignature);
39 return (signalIndex >= 0) ?
object->metaObject()->method(signalIndex) : QMetaMethod();
48int QmlObjectTreeModel::TreeNode::row()
const
51 return parentNode->children.indexOf(
const_cast<TreeNode*
>(
this));
69 _deleteSubtree(&_rootNode,
false);
82 const TreeNode* parentNode =
parent.isValid() ? _nodeFromIndex(
parent) : &_rootNode;
87 return createIndex(row, 0, parentNode->children.at(row));
92 if (!
child.isValid()) {
96 const TreeNode* node = _nodeFromIndex(
child);
97 if (!node || !node->parentNode || node->parentNode == &_rootNode) {
101 return _indexForNode(node->parentNode);
106 const TreeNode* node =
parent.isValid() ? _nodeFromIndex(
parent) : &_rootNode;
107 return node ? node->children.count() : 0;
118 const TreeNode* node =
parent.isValid() ? _nodeFromIndex(
parent) : &_rootNode;
119 return node && !node->children.isEmpty();
124 if (!
index.isValid()) {
128 const TreeNode* node = _nodeFromIndex(
index);
135 return node->object ? QVariant::fromValue(node->object) :
QVariant{};
137 return node->object ? QVariant::fromValue(node->object->objectName()) :
QVariant{};
139 return QVariant::fromValue(node->nodeType);
141 if (!node->children.isEmpty()) {
144 const TreeNode* parentNode = node->parentNode;
148 return node->row() < parentNode->children.size() - 1;
161 TreeNode* node = _nodeFromIndex(
index);
167 _disconnectDirtyChanged(node->object);
170 node->object = value.value<QObject*>();
173 QQmlEngine::setObjectOwnership(node->object, QQmlEngine::CppOwnership);
174 _connectDirtyChanged(node->object);
224 if (!
index.isValid()) {
228 const TreeNode* node = _nodeFromIndex(
index);
229 return node ? node->object :
nullptr;
261 auto* node =
new TreeNode;
262 node->object = object;
263 node->parentNode = parentNode;
264 node->nodeType = nodeType;
267 QQmlEngine::setObjectOwnership(
object, QQmlEngine::CppOwnership);
268 _connectDirtyChanged(
object);
273 parentNode->children.insert(row, node);
276 parentNode->children.insert(row, node);
278 _emitSeparatorChanged(
parentIndex, row > 0 ? row - 1 : 0);
300 if (!
index.isValid()) {
305 TreeNode* node = _nodeFromIndex(
index);
306 if (!node || !node->parentNode) {
311 QObject*
object = node->object;
312 TreeNode* parentNode = node->parentNode;
313 const int row = node->row();
316 _disconnectSubtree(node);
324 parentNode->children.removeAt(row);
330 _deleteSubtree(node,
false);
335 _emitSeparatorChanged(
parentIdx, parentNode->children.count() - 1);
349 const TreeNode* node = _findNode(&_rootNode,
object);
355 if (!
index.isValid()) {
360 const TreeNode* node = _nodeFromIndex(
index);
361 while (node && node->parentNode && node->parentNode != &_rootNode) {
363 node = node->parentNode;
390 if (!parentNode || parentNode->children.isEmpty()) {
394 const int childCount = parentNode->children.count();
398 for (
const TreeNode*
child : parentNode->children) {
407 for (TreeNode*
child : parentNode->children) {
408 _disconnectSubtree(
child);
413 parentNode->children.clear();
423 _deleteSubtree(
child,
false);
430 if (_rootNode.children.isEmpty()) {
435 _disconnectSubtree(&_rootNode);
436 _deleteSubtree(&_rootNode,
false);
443 if (_rootNode.children.isEmpty()) {
448 _disconnectSubtree(&_rootNode);
449 _deleteSubtree(&_rootNode,
true);
456 return _findNode(&_rootNode,
object) !=
nullptr;
463QmlObjectTreeModel::TreeNode* QmlObjectTreeModel::_nodeFromIndex(
const QModelIndex& index)
const
465 if (!
index.isValid()) {
468 return static_cast<TreeNode*
>(
index.internalPointer());
471QModelIndex QmlObjectTreeModel::_indexForNode(
const TreeNode* node)
const
473 if (!node || node == &_rootNode) {
476 return createIndex(node->row(), 0,
const_cast<TreeNode*
>(node));
479QmlObjectTreeModel::TreeNode* QmlObjectTreeModel::_findNode(
const TreeNode* root,
const QObject*
object)
const
482 if (
child->object ==
object) {
493int QmlObjectTreeModel::_subtreeCount(
const TreeNode* node)
495 int result = node->children.count();
496 for (
const TreeNode*
child : node->children) {
502void QmlObjectTreeModel::_disconnectSubtree(TreeNode* node)
504 if (node != &_rootNode && node->object) {
505 _disconnectDirtyChanged(node->object);
507 for (TreeNode*
child : node->children) {
508 _disconnectSubtree(
child);
512void QmlObjectTreeModel::_deleteSubtree(TreeNode* node,
bool deleteObjects)
514 for (TreeNode*
child : node->children) {
517 child->object->deleteLater();
521 node->children.clear();
524void QmlObjectTreeModel::_connectDirtyChanged(QObject*
object)
533void QmlObjectTreeModel::_disconnectDirtyChanged(QObject*
object)
542void QmlObjectTreeModel::_emitSeparatorChanged(
const QModelIndex& parentIdx,
int fromRow)
544 const TreeNode* parentNode =
parentIdx.isValid() ? _nodeFromIndex(
parentIdx) : &_rootNode;
548 const int last = parentNode->children.count() - 1;
#define QGC_LOGGING_CATEGORY(name, categoryStr)
Common base for QObject*-based item models (flat lists and trees).
void endResetModel()
Depth-counted endResetModel — only the outermost call has effect.
QHash< int, QByteArray > roleNames() const override
uint _resetModelNestingCount
void beginResetModel()
Depth-counted beginResetModel — only the outermost call has effect.
void _signalCountChangedIfNotNested()
static constexpr int ObjectRole
static constexpr int TextRole
void dirtyChanged(bool dirty)
void appendChild(const QModelIndex &parentIndex, QObject *object)
void setDirty(bool dirty) override
int rowCount(const QModelIndex &parent=QModelIndex()) const override
Q_INVOKABLE int childCount(const QModelIndex &parentIndex=QModelIndex()) const
Number of direct children under parentIndex.
static constexpr int NodeTypeRole
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
int count() const override
void removeChildren(const QModelIndex &parentIndex)
Removes all children of parentIndex without removing the parent itself.
int columnCount(const QModelIndex &parent=QModelIndex()) const override
Q_INVOKABLE QModelIndex parentIndex(const QModelIndex &index) const
Convenience wrapper around parent()
Q_INVOKABLE QObject * removeItem(const QModelIndex &index)
QObject * removeAt(const QModelIndex &parentIndex, int row)
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
void appendRootItem(QObject *object)
bool insertRows(int row, int count, const QModelIndex &parent=QModelIndex()) override
Q_INVOKABLE QModelIndex indexForObject(QObject *object) const
Searches the entire tree for object and returns its QModelIndex (invalid if not found)
void clearAndDeleteContents()
Clears the tree and calls deleteLater on every QObject.
Q_INVOKABLE QModelIndex insertItem(int row, QObject *object, const QModelIndex &parentIndex=QModelIndex())
Inserts object at row under parentIndex. Returns the new item's index.
Q_INVOKABLE int depth(const QModelIndex &index) const
Returns the depth of index (0 = root-level item, -1 = invalid index)
Q_INVOKABLE QModelIndex appendItem(QObject *object, const QModelIndex &parentIndex=QModelIndex())
Appends object as the last child of parentIndex (root if invalid). Returns the new item's index.
~QmlObjectTreeModel() override
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override
bool contains(QObject *object) const
QHash< int, QByteArray > roleNames() const override
bool hasChildren(const QModelIndex &parent=QModelIndex()) const override
Q_INVOKABLE QObject * getObject(const QModelIndex &index) const
Returns the QObject* stored at index, or nullptr if invalid.
QmlObjectTreeModel(QObject *parent=nullptr)
static constexpr int SeparatorRole
bool removeRows(int row, int count, const QModelIndex &parent=QModelIndex()) override
QModelIndex parent(const QModelIndex &child) const override