QmlObjectListModel.cc 7.35 KB
Newer Older
1 2 3 4 5 6 7 8 9
/****************************************************************************
 *
 *   (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
 *
 * QGroundControl is licensed according to the terms in the file
 * COPYING.md in the root of the source code directory.
 *
 ****************************************************************************/

10 11 12 13 14 15
/// @file
///     @author Don Gagne <don@thegagnes.com>

#include "QmlObjectListModel.h"

#include <QDebug>
Don Gagne's avatar
Don Gagne committed
16
#include <QQmlEngine>
17 18

const int QmlObjectListModel::ObjectRole = Qt::UserRole;
19
const int QmlObjectListModel::TextRole = Qt::UserRole + 1;
20

21 22
QmlObjectListModel::QmlObjectListModel(QObject *parent)
    : QAbstractListModel(parent), _dirty(false), _skipDirtyFirstItem(false) {}
23

24
QmlObjectListModel::~QmlObjectListModel() {}
25

26 27 28 29
int QmlObjectListModel::rowCount(const QModelIndex &parent) const {
  Q_UNUSED(parent);

  return _objectList.count();
30 31
}

32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
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();
  }
48 49
}

50 51 52 53 54 55 56
QHash<int, QByteArray> QmlObjectListModel::roleNames(void) const {
  QHash<int, QByteArray> hash;

  hash[ObjectRole] = "object";
  hash[TextRole] = "text";

  return hash;
57 58
}

59 60 61 62 63 64 65 66 67
bool QmlObjectListModel::setData(const QModelIndex &index,
                                 const QVariant &value, int role) {
  if (index.isValid() && role == ObjectRole) {
    _objectList.replace(index.row(), value.value<QObject *>());
    emit dataChanged(index, index);
    return true;
  }

  return false;
68 69
}

70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
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;
85 86
}

87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
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;
108 109
}

110 111 112 113 114
QObject *QmlObjectListModel::operator[](int index) {
  if (index < 0 || index >= _objectList.count()) {
    return NULL;
  }
  return _objectList[index];
115 116
}

117 118 119 120 121
const QObject *QmlObjectListModel::operator[](int index) const {
  if (index < 0 || index >= _objectList.count()) {
    return NULL;
  }
  return _objectList[index];
Don Gagne's avatar
Don Gagne committed
122 123
}

124
bool QmlObjectListModel::operator==(const QmlObjectListModel &other) const {
125
  if (this->count() == other.count()) {
126
    for (int i = 0; i < this->count(); ++i) {
127 128 129
      if (this->get(i) != other.get(i)) {
        return false;
      }
Gus Grubba's avatar
Gus Grubba committed
130
    }
131 132 133 134
    return true;
  } else {
    return false;
  }
135 136
}

137
bool QmlObjectListModel::operator!=(const QmlObjectListModel &other) const {
138
  return !this->operator==(other);
139 140
}

141 142 143 144
void QmlObjectListModel::clear() {
  while (rowCount()) {
    removeAt(0);
  }
145 146
}

147 148 149
QObject *QmlObjectListModel::removeAt(int i) {
  QObject *removedObject = _objectList[i];
  if (removedObject) {
Don Gagne's avatar
Don Gagne committed
150
    // Look for a dirtyChanged signal on the object
151 152 153 154 155 156
    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)));
      }
Don Gagne's avatar
Don Gagne committed
157
    }
158 159 160 161
  }
  removeRows(i, 1);
  setDirty(true);
  return removedObject;
162 163
}

164 165 166 167 168 169 170 171 172 173 174 175 176
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)));
177
    }
178
  }
179

180 181
  _objectList.insert(i, object);
  insertRows(i, 1);
182

183 184 185 186 187 188 189
  setDirty(true);
}

void QmlObjectListModel::insert(int i, QList<QObject *> objects) {
  if (i < 0 || i > _objectList.count()) {
    qWarning() << "Invalid index index:count" << i << _objectList.count();
  }
190

191 192 193 194 195 196 197 198 199 200 201
  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)));
      }
202
    }
203
    j++;
204

205 206
    _objectList.insert(j, object);
  }
207

208
  insertRows(i, objects.count());
209

210
  setDirty(true);
211 212
}

213 214
void QmlObjectListModel::append(QObject *object) {
  insert(_objectList.count(), object);
215 216
}

217 218
void QmlObjectListModel::append(QList<QObject *> objects) {
  insert(_objectList.count(), objects);
219 220
}

221 222 223 224 225 226 227
QObjectList QmlObjectListModel::swapObjectList(const QObjectList &newlist) {
  QObjectList oldlist(_objectList);
  beginResetModel();
  _objectList = newlist;
  endResetModel();
  emit countChanged(count());
  return oldlist;
228 229
}

230 231 232 233 234 235 236 237 238 239
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);
Don Gagne's avatar
Don Gagne committed
240
        }
241
      }
Don Gagne's avatar
Don Gagne committed
242
    }
243 244
    emit dirtyChanged(_dirty);
  }
Don Gagne's avatar
Don Gagne committed
245 246
}

247 248 249 250 251 252
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);
Don Gagne's avatar
Don Gagne committed
253
}
Don Gagne's avatar
Don Gagne committed
254

255 256 257 258 259
void QmlObjectListModel::deleteListAndContents() {
  for (int i = 0; i < _objectList.count(); i++) {
    _objectList[i]->deleteLater();
  }
  deleteLater();
Don Gagne's avatar
Don Gagne committed
260
}
Don Gagne's avatar
Don Gagne committed
261

262 263 264 265 266 267 268
void QmlObjectListModel::clearAndDeleteContents() {
  beginResetModel();
  for (int i = 0; i < _objectList.count(); i++) {
    _objectList[i]->deleteLater();
  }
  clear();
  endResetModel();
Don Gagne's avatar
Don Gagne committed
269
}
270

271 272
void swap(QmlObjectListModel &list1, QmlObjectListModel &list2) {
  using std::swap;
273

274 275 276
  swap(list1._objectList, list2._objectList);
  swap(list1._dirty, list2._dirty);
  swap(list1._skipDirtyFirstItem, list2._skipDirtyFirstItem);
277
}