#include "scriptmodel.hpp" #include #include #include #include #include #include #include #include #include #include void ScriptModel::updateValuesUnique(const QVariantList& newValues) { this->mValues.reserve(newValues.size()); auto iter = this->mValues.begin(); auto newIter = newValues.begin(); while (true) { if (newIter == newValues.end()) { if (iter == this->mValues.end()) break; auto startIndex = static_cast(newValues.length()); auto endIndex = static_cast(this->mValues.length() - 1); this->beginRemoveRows(QModelIndex(), startIndex, endIndex); this->mValues.erase(iter, this->mValues.end()); this->endRemoveRows(); break; } else if (iter == this->mValues.end()) { // Prior branch ensures length is at least 1. auto startIndex = static_cast(this->mValues.length()); auto endIndex = static_cast(newValues.length() - 1); this->beginInsertRows(QModelIndex(), startIndex, endIndex); this->mValues.append(newValues.sliced(startIndex)); this->endInsertRows(); break; } else if (*newIter != *iter) { auto oldIter = std::find(iter, this->mValues.end(), *newIter); if (oldIter != this->mValues.end()) { if (std::find(newIter, newValues.end(), *iter) == newValues.end()) { // Remove any entries we would otherwise move around that aren't in the new list. auto startIter = iter; do { ++iter; } while (iter != this->mValues.end() && std::find(newIter, newValues.end(), *iter) == newValues.end()); auto index = static_cast(std::distance(this->mValues.begin(), iter)); auto startIndex = static_cast(std::distance(this->mValues.begin(), startIter)); this->beginRemoveRows(QModelIndex(), startIndex, index - 1); iter = this->mValues.erase(startIter, iter); this->endRemoveRows(); } else { // Advance iters to capture a whole move sequence as a single operation if possible. auto oldStartIter = oldIter; do { ++oldIter; ++newIter; } while (oldIter != this->mValues.end() && newIter != newValues.end() && *oldIter == *newIter); auto index = static_cast(std::distance(this->mValues.begin(), iter)); auto oldStartIndex = static_cast(std::distance(this->mValues.begin(), oldStartIter)); auto oldIndex = static_cast(std::distance(this->mValues.begin(), oldIter)); auto len = oldIndex - oldStartIndex; this->beginMoveRows(QModelIndex(), oldStartIndex, oldIndex - 1, QModelIndex(), index); // While it is possible to optimize this further, it is currently not worth the time. for (auto i = 0; i != len; i++) { this->mValues.move(oldStartIndex + i, index + i); } iter = this->mValues.begin() + (index + len); this->endMoveRows(); } } else { auto startNewIter = newIter; do { newIter++; } while (newIter != newValues.end() && std::find(iter, this->mValues.end(), *newIter) == this->mValues.end()); auto index = static_cast(std::distance(this->mValues.begin(), iter)); auto newIndex = static_cast(std::distance(newValues.begin(), newIter)); auto startNewIndex = static_cast(std::distance(newValues.begin(), startNewIter)); auto len = newIndex - startNewIndex; this->beginInsertRows(QModelIndex(), index, index + len - 1); #if QT_VERSION <= QT_VERSION_CHECK(6, 8, 0) this->mValues.resize(this->mValues.length() + len); #else this->mValues.resizeForOverwrite(this->mValues.length() + len); #endif iter = this->mValues.begin() + index; // invalidated std::move_backward(iter, this->mValues.end() - len, this->mValues.end()); iter = std::copy(startNewIter, newIter, iter); this->endInsertRows(); } } else { ++iter; ++newIter; } } } void ScriptModel::setValues(const QVariantList& newValues) { if (newValues == this->mValues) return; this->updateValuesUnique(newValues); emit this->valuesChanged(); } qint32 ScriptModel::rowCount(const QModelIndex& parent) const { if (parent != QModelIndex()) return 0; return static_cast(this->mValues.length()); } QVariant ScriptModel::data(const QModelIndex& index, qint32 role) const { if (role != Qt::UserRole) return QVariant(); return this->mValues.at(index.row()); } QHash ScriptModel::roleNames() const { return {{Qt::UserRole, "modelData"}}; }