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 if (_resetModelNestingCount == 0) {
114 beginInsertRows(QModelIndex(), position, position + rows - 1);
116 }
117
119
120 return true;
121}
122
123bool QmlObjectListModel::removeRows(int position, int rows, const QModelIndex& parent)
124{
126
127 if (position < 0 || position >= _objectList.count()) {
128 qCWarning(QmlObjectListModelLog) << "Invalid position - position:count" << position << _objectList.count() << this;
129 } else if (position + rows > _objectList.count()) {
130 qCWarning(QmlObjectListModelLog) << "Invalid rows - position:rows:count" << position << rows << _objectList.count() << this;
131 }
132
133 if (_resetModelNestingCount == 0) {
134 beginRemoveRows(QModelIndex(), position, position + rows - 1);
135 }
136 for (int row=0; row<rows; row++) {
137 _objectList.removeAt(position);
138 }
139 if (_resetModelNestingCount == 0) {
141 }
142
144
145 return true;
146}
147
148void QmlObjectListModel::move(int from, int to)
149{
150 if(0 <= from && from < count() && 0 <= to && to < count() && from != to) {
151 // Workaround to allow move item to the bottom. Done according to
152 // beginMoveRows() documentation and implementation specificity:
153 // https://doc.qt.io/qt-5/qabstractitemmodel.html#beginMoveRows
154 // (see 3rd picture explanation there)
155 if(from == to - 1) {
156 to = from++;
157 }
159 _objectList.move(from, to);
160 endMoveRows();
161 }
162}
163
165{
166 if (index < 0 || index >= _objectList.count()) {
167 return nullptr;
168 }
169 return _objectList[index];
170}
171
172const QObject* QmlObjectListModel::operator[](int index) const
173{
174 if (index < 0 || index >= _objectList.count()) {
175 return nullptr;
176 }
177 return _objectList[index];
178}
179
181{
183 _objectList.clear();
185}
186
188{
189 QObject* removedObject = _objectList[i];
190 if (removedObject) {
191 if (!_skipDirtyFirstItem || i != 0) {
192 disconnectDirtyChangedIfAvailable(_objectList[i], this);
193 }
194 }
195 removeRows(i, 1);
196 setDirty(true);
197 return removedObject;
198}
199
200void QmlObjectListModel::insert(int i, QObject* object)
201{
202 if (i < 0 || i > _objectList.count()) {
203 qCWarning(QmlObjectListModelLog) << "Invalid index - index:count" << i << _objectList.count() << this;
204 }
205 if (object) {
206 QQmlEngine::setObjectOwnership(object, QQmlEngine::CppOwnership);
207 if (!_skipDirtyFirstItem || i != 0) {
208 connectDirtyChangedIfAvailable(object, this);
209 }
210 }
211 _objectList.insert(i, object);
212 insertRows(i, 1);
213 setDirty(true);
214}
215
216void QmlObjectListModel::insert(int i, QList<QObject*> objects)
217{
218 if (i < 0 || i > _objectList.count()) {
219 qCWarning(QmlObjectListModelLog) << "Invalid index - index:count" << i << _objectList.count() << this;
220 }
221
222 int j = i;
223 for (QObject* object: objects) {
224 QQmlEngine::setObjectOwnership(object, QQmlEngine::CppOwnership);
225
226 if (!_skipDirtyFirstItem || j != 0) {
227 connectDirtyChangedIfAvailable(object, this);
228 }
229
230 _objectList.insert(j, object);
231 j++;
232 }
233
234 insertRows(i, objects.count());
235
236 setDirty(true);
237}
238
239void QmlObjectListModel::append(QObject* object)
240{
241 insert(_objectList.count(), object);
242}
243
244void QmlObjectListModel::append(QList<QObject*> objects)
245{
246 insert(_objectList.count(), objects);
247}
248
249QObjectList QmlObjectListModel::swapObjectList(const QObjectList& newlist)
250{
251 QObjectList oldlist(_objectList);
253 _objectList = newlist;
255 return oldlist;
256}
257
259{
260 return rowCount();
261}
262
264{
265 if (_dirty != dirty) {
266 _dirty = dirty;
267 if (!dirty) {
268 // Need to clear dirty from all children
269 for(QObject* object: _objectList) {
270 if (object->property("dirty").isValid()) {
271 object->setProperty("dirty", false);
272 }
273 }
274 }
276 }
277}
278
280{
281 for (int i=0; i<_objectList.count(); i++) {
282 _objectList[i]->deleteLater();
283 }
284 clear();
285}
#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)
Base class for flat QObject* list models. Inherits common dirty/reset/role handling from ObjectItemMo...
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
Q_INVOKABLE 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)