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);
151 TreeNode* node = _nodeFromIndex(
index);
157 _disconnectDirtyChanged(node->object);
160 node->object = value.value<QObject*>();
163 QQmlEngine::setObjectOwnership(node->object, QQmlEngine::CppOwnership);
164 _connectDirtyChanged(node->object);
213 if (!
index.isValid()) {
217 const TreeNode* node = _nodeFromIndex(
index);
218 return node ? node->object :
nullptr;
250 auto* node =
new TreeNode;
251 node->object = object;
252 node->parentNode = parentNode;
253 node->nodeType = nodeType;
256 QQmlEngine::setObjectOwnership(
object, QQmlEngine::CppOwnership);
257 _connectDirtyChanged(
object);
262 parentNode->children.insert(row, node);
265 parentNode->children.insert(row, node);
288 if (!
index.isValid()) {
293 TreeNode* node = _nodeFromIndex(
index);
294 if (!node || !node->parentNode) {
299 QObject*
object = node->object;
300 TreeNode* parentNode = node->parentNode;
301 const int row = node->row();
304 _disconnectSubtree(node);
310 parentNode->children.removeAt(row);
314 _deleteSubtree(node,
false);
330 const TreeNode* node = _findNode(&_rootNode,
object);
336 if (!
index.isValid()) {
341 const TreeNode* node = _nodeFromIndex(
index);
342 while (node && node->parentNode && node->parentNode != &_rootNode) {
344 node = node->parentNode;
371 if (!parentNode || parentNode->children.isEmpty()) {
375 const int childCount = parentNode->children.count();
379 for (
const TreeNode*
child : parentNode->children) {
387 for (TreeNode*
child : parentNode->children) {
388 _disconnectSubtree(
child);
389 _deleteSubtree(
child,
false);
392 parentNode->children.clear();
404 if (_rootNode.children.isEmpty()) {
409 _disconnectSubtree(&_rootNode);
410 _deleteSubtree(&_rootNode,
false);
417 if (_rootNode.children.isEmpty()) {
422 _disconnectSubtree(&_rootNode);
423 _deleteSubtree(&_rootNode,
true);
430 return _findNode(&_rootNode,
object) !=
nullptr;
437QmlObjectTreeModel::TreeNode* QmlObjectTreeModel::_nodeFromIndex(
const QModelIndex& index)
const
439 if (!
index.isValid()) {
442 return static_cast<TreeNode*
>(
index.internalPointer());
445QModelIndex QmlObjectTreeModel::_indexForNode(
const TreeNode* node)
const
447 if (!node || node == &_rootNode) {
450 return createIndex(node->row(), 0,
const_cast<TreeNode*
>(node));
453QmlObjectTreeModel::TreeNode* QmlObjectTreeModel::_findNode(
const TreeNode* root,
const QObject*
object)
const
456 if (
child->object ==
object) {
467int QmlObjectTreeModel::_subtreeCount(
const TreeNode* node)
469 int result = node->children.count();
470 for (
const TreeNode*
child : node->children) {
476void QmlObjectTreeModel::_disconnectSubtree(TreeNode* node)
478 if (node != &_rootNode && node->object) {
479 _disconnectDirtyChanged(node->object);
481 for (TreeNode*
child : node->children) {
482 _disconnectSubtree(
child);
486void QmlObjectTreeModel::_deleteSubtree(TreeNode* node,
bool deleteObjects)
488 for (TreeNode*
child : node->children) {
491 child->object->deleteLater();
495 node->children.clear();
498void QmlObjectTreeModel::_connectDirtyChanged(QObject*
object)
507void QmlObjectTreeModel::_disconnectDirtyChanged(QObject*
object)
#define QGC_LOGGING_CATEGORY(name, categoryStr)
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
QModelIndex parentIndex(const QModelIndex &index) const
Convenience wrapper around parent()
int rowCount(const QModelIndex &parent=QModelIndex()) const override
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
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
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.
QModelIndex insertItem(int row, QObject *object, const QModelIndex &parentIndex=QModelIndex())
Inserts object at row under parentIndex. Returns the new item's index.
int depth(const QModelIndex &index) const
Returns the depth of index (0 = root-level item, -1 = invalid index)
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
QObject * getObject(const QModelIndex &index) const
Returns the QObject* stored at index, or nullptr if invalid.
QmlObjectTreeModel(QObject *parent=nullptr)
bool removeRows(int row, int count, const QModelIndex &parent=QModelIndex()) override
QModelIndex parent(const QModelIndex &child) const override
int childCount(const QModelIndex &parentIndex=QModelIndex()) const
Number of direct children under parentIndex.