QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
QmlObjectListModel.cc
Go to the documentation of this file.
2
3#include <QtCore/QMetaMethod>
4#include <QtQml/QQmlEngine>
5
7
8QGC_LOGGING_CATEGORY(QmlObjectListModelLog, "API.QmlObjectListModel")
9
10namespace {
11
12constexpr const char* kDirtyChangedSignature = "dirtyChanged(bool)";
13constexpr const char* kChildDirtyChangedSlotSignature = "_childDirtyChanged(bool)";
14
15QMetaMethod childDirtyChangedSlot()
16{
17 const QMetaObject* metaObject = &ObjectListModelBase::staticMetaObject;
18 const int slotIndex = metaObject->indexOfSlot(kChildDirtyChangedSlotSignature);
19 Q_ASSERT_X(slotIndex >= 0, "childDirtyChangedSlot", "slot signature mismatch — update kChildDirtyChangedSlotSignature");
20 return (slotIndex >= 0) ? metaObject->method(slotIndex) : QMetaMethod();
21}
22
23QMetaMethod dirtyChangedSignal(const QObject* object)
24{
25 if (!object) {
26 return QMetaMethod();
27 }
28
29 const int signalIndex = object->metaObject()->indexOfSignal(kDirtyChangedSignature);
30 return (signalIndex >= 0) ? object->metaObject()->method(signalIndex) : QMetaMethod();
31}
32
33void connectDirtyChangedIfAvailable(QObject* object, ObjectListModelBase* receiver)
34{
35 const QMetaMethod signal = dirtyChangedSignal(object);
36 const QMetaMethod slot = childDirtyChangedSlot();
37 if (signal.isValid() && slot.isValid()) {
38 QObject::connect(object, signal, receiver, slot);
39 }
40}
41
42void disconnectDirtyChangedIfAvailable(QObject* object, ObjectListModelBase* receiver)
43{
44 const QMetaMethod signal = dirtyChangedSignal(object);
45 const QMetaMethod slot = childDirtyChangedSlot();
46 if (signal.isValid() && slot.isValid()) {
47 QObject::disconnect(object, signal, receiver, slot);
48 }
49}
50
51} // namespace
52
54 : ObjectListModelBase(parent)
55{
56
57}
58
59QObject* QmlObjectListModel::get(int index)
60{
61 if (index < 0 || index >= _objectList.count()) {
62 qCWarning(QmlObjectListModelLog) << "InternalError: Invalid index - index:count" << index << _objectList.count() << this;
63 return nullptr;
64 }
65 return _objectList[index];
66}
67
68int QmlObjectListModel::rowCount(const QModelIndex& parent) const
69{
71
72 return _objectList.count();
73}
74
75QVariant QmlObjectListModel::data(const QModelIndex &index, int role) const
76{
77 if (!index.isValid()) {
78 return QVariant();
79 }
80
81 if (index.row() < 0 || index.row() >= _objectList.count()) {
82 return QVariant();
83 }
84
85 if (role == ObjectRole) {
86 return QVariant::fromValue(_objectList[index.row()]);
87 } else if (role == TextRole) {
88 return QVariant::fromValue(_objectList[index.row()]->objectName());
89 } else {
90 return QVariant();
91 }
92}
93
94bool QmlObjectListModel::setData(const QModelIndex& index, const QVariant& value, int role)
95{
96 if (index.isValid() && role == ObjectRole) {
97 _objectList.replace(index.row(), value.value<QObject*>());
99 return true;
100 }
101
102 return false;
103}
104
105bool QmlObjectListModel::insertRows(int position, int rows, const QModelIndex& parent)
106{
108
109 if (position < 0 || position > _objectList.count() + 1) {
110 qCWarning(QmlObjectListModelLog) << "Invalid position - position:count" << position << _objectList.count() << this;
111 }
112
113 beginInsertRows(QModelIndex(), position, position + rows - 1);
115
117
118 return true;
119}
120
121bool QmlObjectListModel::removeRows(int position, int rows, const QModelIndex& parent)
122{
124
125 if (position < 0 || position >= _objectList.count()) {
126 qCWarning(QmlObjectListModelLog) << "Invalid position - position:count" << position << _objectList.count() << this;
127 } else if (position + rows > _objectList.count()) {
128 qCWarning(QmlObjectListModelLog) << "Invalid rows - position:rows:count" << position << rows << _objectList.count() << this;
129 }
130
131 beginRemoveRows(QModelIndex(), position, position + rows - 1);
132 for (int row=0; row<rows; row++) {
133 _objectList.removeAt(position);
134 }
136
138
139 return true;
140}
141
142void QmlObjectListModel::move(int from, int to)
143{
144 if(0 <= from && from < count() && 0 <= to && to < count() && from != to) {
145 // Workaround to allow move item to the bottom. Done according to
146 // beginMoveRows() documentation and implementation specificity:
147 // https://doc.qt.io/qt-5/qabstractitemmodel.html#beginMoveRows
148 // (see 3rd picture explanation there)
149 if(from == to - 1) {
150 to = from++;
151 }
153 _objectList.move(from, to);
154 endMoveRows();
155 }
156}
157
159{
160 if (index < 0 || index >= _objectList.count()) {
161 return nullptr;
162 }
163 return _objectList[index];
164}
165
166const QObject* QmlObjectListModel::operator[](int index) const
167{
168 if (index < 0 || index >= _objectList.count()) {
169 return nullptr;
170 }
171 return _objectList[index];
172}
173
175{
177 _objectList.clear();
179}
180
182{
183 QObject* removedObject = _objectList[i];
184 if (removedObject) {
185 if (!_skipDirtyFirstItem || i != 0) {
186 disconnectDirtyChangedIfAvailable(_objectList[i], this);
187 }
188 }
189 removeRows(i, 1);
190 setDirty(true);
191 return removedObject;
192}
193
194void QmlObjectListModel::insert(int i, QObject* object)
195{
196 if (i < 0 || i > _objectList.count()) {
197 qCWarning(QmlObjectListModelLog) << "Invalid index - index:count" << i << _objectList.count() << this;
198 }
199 if (object) {
200 QQmlEngine::setObjectOwnership(object, QQmlEngine::CppOwnership);
201 if (!_skipDirtyFirstItem || i != 0) {
202 connectDirtyChangedIfAvailable(object, this);
203 }
204 }
205 _objectList.insert(i, object);
206 insertRows(i, 1);
207 setDirty(true);
208}
209
210void QmlObjectListModel::insert(int i, QList<QObject*> objects)
211{
212 if (i < 0 || i > _objectList.count()) {
213 qCWarning(QmlObjectListModelLog) << "Invalid index - index:count" << i << _objectList.count() << this;
214 }
215
216 int j = i;
217 for (QObject* object: objects) {
218 QQmlEngine::setObjectOwnership(object, QQmlEngine::CppOwnership);
219
220 if (!_skipDirtyFirstItem || j != 0) {
221 connectDirtyChangedIfAvailable(object, this);
222 }
223
224 _objectList.insert(j, object);
225 j++;
226 }
227
228 insertRows(i, objects.count());
229
230 setDirty(true);
231}
232
233void QmlObjectListModel::append(QObject* object)
234{
235 insert(_objectList.count(), object);
236}
237
238void QmlObjectListModel::append(QList<QObject*> objects)
239{
240 insert(_objectList.count(), objects);
241}
242
243QObjectList QmlObjectListModel::swapObjectList(const QObjectList& newlist)
244{
245 QObjectList oldlist(_objectList);
247 _objectList = newlist;
249 return oldlist;
250}
251
253{
254 return rowCount();
255}
256
258{
259 if (_dirty != dirty) {
260 _dirty = dirty;
261 if (!dirty) {
262 // Need to clear dirty from all children
263 for(QObject* object: _objectList) {
264 if (object->property("dirty").isValid()) {
265 object->setProperty("dirty", false);
266 }
267 }
268 }
270 }
271}
272
274{
275 for (int i=0; i<_objectList.count(); i++) {
276 _objectList[i]->deleteLater();
277 }
278 clear();
279}
#define QGC_LOGGING_CATEGORY(name, categoryStr)
void endResetModel()
Depth-counted endResetModel — only the outermost call has effect.
void beginResetModel()
Depth-counted beginResetModel — only the outermost call has effect.
static constexpr int ObjectRole
static constexpr int TextRole
void dirtyChanged(bool dirty)
QModelIndex index(int row, int column=0, const QModelIndex &parent=QModelIndex()) const override
QModelIndex parent(const QModelIndex &child) const override
void append(QObject *object)
Caller maintains responsibility for object ownership and deletion.
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override
T value(int index) const
void move(int from, int to)
void setDirty(bool dirty) override final
QObject * get(int index)
bool removeRows(int position, int rows, const QModelIndex &index=QModelIndex()) override
QObject * removeAt(int index)
int rowCount(const QModelIndex &parent=QModelIndex()) const override
QObject * operator[](int index)
int count() const override final
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
void clear() override final
bool insertRows(int position, int rows, const QModelIndex &index=QModelIndex()) override
void clearAndDeleteContents() override final
Clears the list and calls deleteLater on each entry.
QObjectList swapObjectList(const QObjectList &newlist)
void insert(int index, QObject *object)
QmlObjectListModel(QObject *parent=nullptr)