#include "multiverseitem.h" #include "multiversemodel.h" #include "qsacnnode.h" #include /** * @brief MultiverseModel::MultiverseModel * @param parent * @param node */ MultiverseModel::MultiverseModel(QObject *parent, QSacnNode *node) : QAbstractItemModel(parent) , node_(node) , rootItem_(new MultiverseItem()) { QMetaEnum e = QMetaEnum::fromType(); for (int k = 0; k < e.keyCount(); k++) { auto item = new MultiverseItem(rootItem_); item->setOverrideData(QString(e.key(k))); auto idx = MultiverseModel::index(k, 0, QModelIndex()); categoryIndexes.insert(static_cast (e.value(k)), idx); } connect(node, &QSacnNode::discoveryUpdates, this, &MultiverseModel::doDiscovery); connect(node, &QSacnNode::subscribing, this, &MultiverseModel::doSubscription); connect(node, &QSacnNode::unsubscribing, this, &MultiverseModel::doUnsubscribe); connect(node, &QSacnNode::creating, this, &MultiverseModel::doCreation); connect(node, &QSacnNode::terminating, this, &MultiverseModel::doTerminate); } /** * @brief MultiverseModel::~MultiverseModel */ MultiverseModel::~MultiverseModel() { delete rootItem_; } /** * @brief MultiverseModel::root * @return */ MultiverseItem * MultiverseModel::root() { return rootItem_; } /** * @brief MultiverseModel::getItem * @param index * @return */ MultiverseItem * MultiverseModel::getItem(const QModelIndex &index) const { if (index.isValid()) { auto item = static_cast(index.internalPointer()); if (item) return item; } return rootItem_; } /** * @brief MultiverseModel::headerData * @param section * @param orientation * @param role * @return */ QVariant MultiverseModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role == Qt::DisplayRole && orientation == Qt::Horizontal) { switch (static_cast(section)) { case Universe: return tr("Universe"); case Priority: return tr("Priority"); case Channels: return tr("Channels"); case SourceName: return tr("Source Name"); } } return QVariant(); } /** * @brief MultiverseModel::index * @param row * @param column * @param parent * @return */ QModelIndex MultiverseModel::index(int row, int column, const QModelIndex &parent) const { if (parent.isValid() && parent.column() != 0) return QModelIndex(); MultiverseItem *parentItem = getItem(parent); if (!parentItem) return QModelIndex(); auto childItem = parentItem->child(row); if (childItem) return createIndex(row, column, childItem); return QModelIndex(); } /** * @brief MultiverseModel::parent * @param index * @return */ QModelIndex MultiverseModel::parent(const QModelIndex &index) const { if (!checkIndex(index, CheckIndexOption::IndexIsValid | CheckIndexOption::DoNotUseParent)) return QModelIndex(); auto childItem = getItem(index); auto parentItem = childItem ? childItem->parentItem() : nullptr; if (parentItem == rootItem_ || !parentItem) return QModelIndex(); return createIndex(parentItem->row(), 0, parentItem); } /** * @brief MultiverseModel::rowCount * @param parent * @return */ int MultiverseModel::rowCount(const QModelIndex &parent) const { auto parentItem = getItem(parent); return parentItem ? parentItem->childCount() : 0; } /** * @brief MultiverseModel::columnCount * @param parent * @return */ int MultiverseModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); return QMetaEnum::fromType().keyCount(); } /** * @brief MultiverseModel::data * @param index * @param role * @return */ QVariant MultiverseModel::data(const QModelIndex &index, int role) const { if (!checkIndex(index, CheckIndexOption::IndexIsValid)) return QVariant(); return getItem(index)->data(index.column(), role); } /** * @brief MultiverseModel::setData * @param index * @param value * @param role * @return */ bool MultiverseModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (!checkIndex(index, CheckIndexOption::IndexIsValid)) return false; if (getItem(index)->setData(index.column(), value, role)) { emit dataChanged(index, index, QVector() << role); return true; } return false; } /** * @brief MultiverseModel::flags * @param index * @return */ Qt::ItemFlags MultiverseModel::flags(const QModelIndex &index) const { if (!checkIndex(index, CheckIndexOption::IndexIsValid)) return Qt::NoItemFlags; auto item = getItem(index); if (!item) return Qt::NoItemFlags; return item->flags(index.column(), QAbstractItemModel::flags(index)); } /** * @brief MultiverseModel::insert * @param universe * @param parent * @return */ void MultiverseModel::insert(const QModelIndex &parent, QSacnUniverse* universe, discoveredUniverse *discovery) { auto item = getItem(parent); beginInsertRows(parent, item->childCount(), item->childCount()); auto child = new MultiverseItem(item, universe, discovery); endInsertRows(); auto index = QPersistentModelIndex(createIndex(item->childCount() - 1, 0, child)); auto refreshRow = [this] (QPersistentModelIndex index) { auto begin = index.sibling(index.row(), 0); auto end = begin.siblingAtColumn(columnCount() - 1); emit dataChanged(begin, end); }; connect(universe, &QSacnUniverse::changed, this, [refreshRow, index](){ refreshRow(index); }); connect(universe, &QSacnUniverse::sourceListChanged, this, [this, universe, child, index, refreshRow]() { // remove the old children beginRemoveRows(index, 0, child->childCount() - 1); child->removeChildren(); endRemoveRows(); // add the new children beginInsertRows(index, 0, universe->sources().size() - 1); child->createChildren(); endInsertRows(); // refresh row of new child when data arrives for (int i = 0; i < child->childCount(); i++) { auto grandchild = child->child(i); auto index = QPersistentModelIndex(createIndex(i, 0, grandchild)); auto data = grandchild->data(Column::Universe, Qt::EditRole); if (data.metaType().id() != qMetaTypeId()) return; auto universe = data.value(); connect(universe, &QSacnUniverse::changed, this, [refreshRow, index](){ refreshRow(index); }); } }); } /** * @brief MultiverseModel::remove * @param parent * @param data */ void MultiverseModel::remove(const QModelIndex &parent, const QVariant &data) { auto item = static_cast(parent.internalPointer()); auto row = item->childRow(Column::Universe, data); if (row < 0) return; auto child = item->child(row); if (!child) return; beginRemoveRows(parent, row, row); item->removeChild(child); endRemoveRows(); } void MultiverseModel::doDiscovery() { auto parentIndex = categoryIndexes.value(MultiverseModel::Discovery); auto parent = static_cast(parentIndex.internalPointer()); beginRemoveRows(parentIndex, 0, parent->childCount() - 1); parent->removeChildren(); endRemoveRows(); beginInsertRows(parentIndex, 0, node_->discovered.size() - 1); for (auto& discovery : node_->discovered) new MultiverseItem(parent, nullptr, discovery.get()); endInsertRows(); } /** * @brief MultiverseModel::doSubscription * @param universe */ void MultiverseModel::doSubscription(QSacnUniverse* universe) { auto parentIndex = categoryIndexes.value(MultiverseModel::Receiver); insert(parentIndex, universe); } /** * @brief MultiverseModel::doUnsubscribe * @param universe */ void MultiverseModel::doUnsubscribe(QSacnUniverse* universe) { auto parentIndex = categoryIndexes.value(MultiverseModel::Receiver); remove(parentIndex, QVariant::fromValue(universe)); } /** * @brief MultiverseModel::doCreation * @param universe */ void MultiverseModel::doCreation(QSacnUniverse* universe) { auto parentIndex = categoryIndexes.value(MultiverseModel::Source); insert(parentIndex, universe); } /** * @brief MultiverseModel::doTerminate * @param universe */ void MultiverseModel::doTerminate(QSacnUniverse *universe) { auto parentIndex = categoryIndexes.value(MultiverseModel::Source); remove(parentIndex, QVariant::fromValue(universe)); }