/**************************************************************************** * * (c) 2009-2016 QGROUNDCONTROL PROJECT * * QGroundControl is licensed according to the terms in the file * COPYING.md in the root of the source code directory. * ****************************************************************************/ /// @file /// @author Don Gagne #include "QmlObjectListModel.h" #include #include const int QmlObjectListModel::ObjectRole = Qt::UserRole; const int QmlObjectListModel::TextRole = Qt::UserRole + 1; QmlObjectListModel::QmlObjectListModel(QObject *parent) : QAbstractListModel(parent), _dirty(false), _skipDirtyFirstItem(false) {} QmlObjectListModel::~QmlObjectListModel() {} int QmlObjectListModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent); return _objectList.count(); } QVariant QmlObjectListModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } if (index.row() < 0 || index.row() >= _objectList.count()) { return QVariant(); } if (role == ObjectRole) { return QVariant::fromValue(_objectList[index.row()]); } else if (role == TextRole) { return QVariant::fromValue(_objectList[index.row()]->objectName()); } else { return QVariant(); } } QHash QmlObjectListModel::roleNames(void) const { QHash hash; hash[ObjectRole] = "object"; hash[TextRole] = "text"; return hash; } bool QmlObjectListModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (index.isValid() && role == ObjectRole) { _objectList.replace(index.row(), value.value()); emit dataChanged(index, index); return true; } return false; } bool QmlObjectListModel::insertRows(int position, int rows, const QModelIndex &parent) { Q_UNUSED(parent); if (position < 0 || position > _objectList.count() + 1) { qWarning() << "Invalid position position:count" << position << _objectList.count(); } beginInsertRows(QModelIndex(), position, position + rows - 1); endInsertRows(); emit countChanged(count()); return true; } bool QmlObjectListModel::removeRows(int position, int rows, const QModelIndex &parent) { Q_UNUSED(parent); if (position < 0 || position >= _objectList.count()) { qWarning() << "Invalid position position:count" << position << _objectList.count(); } else if (position + rows > _objectList.count()) { qWarning() << "Invalid rows position:rows:count" << position << rows << _objectList.count(); } beginRemoveRows(QModelIndex(), position, position + rows - 1); for (int row = 0; row < rows; row++) { _objectList.removeAt(position); } endRemoveRows(); emit countChanged(count()); return true; } QObject *QmlObjectListModel::operator[](int index) { if (index < 0 || index >= _objectList.count()) { return NULL; } return _objectList[index]; } const QObject *QmlObjectListModel::operator[](int index) const { if (index < 0 || index >= _objectList.count()) { return NULL; } return _objectList[index]; } bool QmlObjectListModel::operator==(const QmlObjectListModel &other) const { if (this->count() == other.count()) { for (int i = 0; i < this->count(); ++i) { if (this->get(i) != other.get(i)) { return false; } } return true; } else { return false; } } bool QmlObjectListModel::operator!=(const QmlObjectListModel &other) const { return !this->operator==(other); } void QmlObjectListModel::clear() { while (rowCount()) { removeAt(0); } } QObject *QmlObjectListModel::removeAt(int i) { QObject *removedObject = _objectList[i]; if (removedObject) { // Look for a dirtyChanged signal on the object if (_objectList[i]->metaObject()->indexOfSignal( QMetaObject::normalizedSignature("dirtyChanged(bool)")) != -1) { if (!_skipDirtyFirstItem || i != 0) { QObject::disconnect(_objectList[i], SIGNAL(dirtyChanged(bool)), this, SLOT(_childDirtyChanged(bool))); } } } removeRows(i, 1); setDirty(true); return removedObject; } void QmlObjectListModel::insert(int i, QObject *object) { if (i < 0 || i > _objectList.count()) { qWarning() << "Invalid index index:count" << i << _objectList.count(); } QQmlEngine::setObjectOwnership(object, QQmlEngine::CppOwnership); // Look for a dirtyChanged signal on the object if (object->metaObject()->indexOfSignal( QMetaObject::normalizedSignature("dirtyChanged(bool)")) != -1) { if (!_skipDirtyFirstItem || i != 0) { QObject::connect(object, SIGNAL(dirtyChanged(bool)), this, SLOT(_childDirtyChanged(bool))); } } _objectList.insert(i, object); insertRows(i, 1); setDirty(true); } void QmlObjectListModel::insert(int i, QList objects) { if (i < 0 || i > _objectList.count()) { qWarning() << "Invalid index index:count" << i << _objectList.count(); } int j = i; for (QObject *object : objects) { QQmlEngine::setObjectOwnership(object, QQmlEngine::CppOwnership); // Look for a dirtyChanged signal on the object if (object->metaObject()->indexOfSignal( QMetaObject::normalizedSignature("dirtyChanged(bool)")) != -1) { if (!_skipDirtyFirstItem || j != 0) { QObject::connect(object, SIGNAL(dirtyChanged(bool)), this, SLOT(_childDirtyChanged(bool))); } } j++; _objectList.insert(j, object); } insertRows(i, objects.count()); setDirty(true); } void QmlObjectListModel::append(QObject *object) { insert(_objectList.count(), object); } void QmlObjectListModel::append(QList objects) { insert(_objectList.count(), objects); } QObjectList QmlObjectListModel::swapObjectList(const QObjectList &newlist) { QObjectList oldlist(_objectList); beginResetModel(); _objectList = newlist; endResetModel(); emit countChanged(count()); return oldlist; } int QmlObjectListModel::count() const { return rowCount(); } void QmlObjectListModel::setDirty(bool dirty) { if (_dirty != dirty) { _dirty = dirty; if (!dirty) { // Need to clear dirty from all children for (QObject *object : _objectList) { if (object->property("dirty").isValid()) { object->setProperty("dirty", false); } } } emit dirtyChanged(_dirty); } } void QmlObjectListModel::_childDirtyChanged(bool dirty) { _dirty |= dirty; // We want to emit dirtyChanged even if the actual value of _dirty didn't // change. It can be a useful signal to know when a child has changed dirty // state emit dirtyChanged(_dirty); } void QmlObjectListModel::deleteListAndContents() { for (int i = 0; i < _objectList.count(); i++) { _objectList[i]->deleteLater(); } deleteLater(); } void QmlObjectListModel::clearAndDeleteContents() { beginResetModel(); for (int i = 0; i < _objectList.count(); i++) { _objectList[i]->deleteLater(); } clear(); endResetModel(); } void swap(QmlObjectListModel &list1, QmlObjectListModel &list2) { using std::swap; swap(list1._objectList, list2._objectList); swap(list1._dirty, list2._dirty); swap(list1._skipDirtyFirstItem, list2._skipDirtyFirstItem); }