/
friendlyperch
/
QGrid
Обзор
Документация
Войти
/
friendlyperch
/
QGrid
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
dev-ver1
src/models/UniversalTableModel.cpp
581 строка
14 KB
FriendlyPerch
prepare for deploy
17 янв 2026, 15:26
17 янв 2026, 15:26
d7fce50
Код
Авторство
О чём код?
#include "UniversalTableModel.h" #include <algorithm> #include <QDebug> #include <QMetaProperty> #include <QtGlobal> #include "common/NullableBase.h" UniversalTableModel::UniversalTableModel(QObject *parent) : QAbstractTableModel(parent) { onObjectPropertyChangedMethod = findOnObjectPropertyChangedMethod(); } int UniversalTableModel::rowCount(const QModelIndex &index) const { Q_UNUSED(index); if (!datasource) return 0; return datasource->count(); } int UniversalTableModel::columnCount(const QModelIndex &index) const { Q_UNUSED(index); return std::count_if(columns.begin(), columns.end(), [](GridColumn *column) { return column->getVisible(); }); } QVariant UniversalTableModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); if (index.row() >= datasource->count()) return QVariant(); int actualColumn = getColumnIndexByVisualIndex(index.column()); if (actualColumn < 0 || actualColumn >= columns.count()) return QVariant(); GridColumn *column = columns.at(actualColumn); if (column->getCheckable() && column->getFieldName().isEmpty()) { if (role == Qt::CheckStateRole) { return mSelectedRows.contains(index.row()) ? Qt::Checked : Qt::Unchecked; } if (role == Qt::DisplayRole) { return QVariant(); } return QVariant(); } QVariant result; QString fieldName = column->getFieldName(); QVariant currentValue; if (!fieldName.isEmpty() && datasource->qobjectValue(index.row())) { currentValue = datasource->qobjectValue(index.row())->property(fieldName.toStdString().data()); } switch (role) { case Qt::DisplayRole: { if (!column->getCheckable()) { if (column->getValueFunc() != nullptr) { if (!currentValue.isNull() && currentValue.isValid()) result = column->getValueFunc()(currentValue); } else { result = currentValue; } } } break; case Qt::EditRole: { result = currentValue; } break; case Qt::CheckStateRole: { if (column->getCheckable()) result = currentValue.toBool() ? Qt::Checked : Qt::Unchecked; } break; case Qt::TextAlignmentRole: { result = static_cast<int>(column->getTextAlignment()); } break; default: break; } return result; } Qt::ItemFlags UniversalTableModel::flags(const QModelIndex &index) const { if (!index.isValid()) return Qt::ItemIsEnabled; int actualColumn = getColumnIndexByVisualIndex(index.column()); if (actualColumn < 0 || actualColumn >= columns.count()) return Qt::ItemIsEnabled; GridColumn *column = columns.at(actualColumn); Qt::ItemFlags flags = QAbstractItemModel::flags(index); if (column->getCheckable()) flags |= Qt::ItemIsUserCheckable; if (column->getEditable()) flags |= Qt::ItemIsEditable; return flags; } bool UniversalTableModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (!index.isValid()) return false; int actualColumn = getColumnIndexByVisualIndex(index.column()); if (actualColumn < 0 || actualColumn >= columns.count()) return false; GridColumn *column = columns.at(actualColumn); if (role == Qt::CheckStateRole) { if (column->getCheckable()) { if (column->getFieldName().isEmpty()) { Qt::CheckState checkState = static_cast<Qt::CheckState>(value.toInt()); bool selected = (checkState == Qt::Checked); setRowSelected(index.row(), selected); emit dataChanged(index, index); return true; } else { auto obj = datasource->qobjectValue(index.row()); if (obj) { Qt::CheckState checkState = static_cast<Qt::CheckState>(value.toInt()); bool boolValue = (checkState == Qt::Checked); QString fieldName = column->getFieldName(); if (!fieldName.isEmpty() && !fieldName.isNull()) { obj->setProperty(fieldName.toStdString().data(), boolValue); } } emit dataChanged(index, index); return true; } } return false; } if (role == Qt::EditRole) { if (column->getFieldName().isEmpty()) { return false; } if (!column->getEditable()) { return false; } auto obj = datasource->qobjectValue(index.row()); if (obj) { QString fieldName = column->getFieldName(); if (!fieldName.isEmpty() && !fieldName.isNull()) { obj->setProperty(fieldName.toStdString().data(), value); } } emit dataChanged(index, index); return true; } return false; } QVariant UniversalTableModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal) { int actualSection = getColumnIndexByVisualIndex(section); if (actualSection >= 0 && actualSection < columns.count()) { GridColumn *column = columns.at(actualSection); if (role == Qt::DecorationRole) { QIcon icon = column->getHeaderIcon(); if (!icon.isNull()) return icon; return QVariant(); } if (role == Qt::DisplayRole) { if (!column->getHeader().isEmpty() && !column->getHeader().isNull()) return column->getHeader(); } } return QVariant(); } else { if (role == Qt::DisplayRole) return section + 1; return QVariant(); } } ActiveListBase *UniversalTableModel::getDatasource() const { return datasource; } void UniversalTableModel::setDatasource(ActiveListBase *value) { if (datasource != value) { beginResetModel(); datasource = value; endResetModel(); subscribeToAllObject(value); auto conn = connect(value, &ActiveListBase::countChanged, this, &UniversalTableModel::reloadDatasource, Qt::UniqueConnection); if (!conn) { qWarning() << "Failed to connect to countChanged signal"; } conn = connect(value, &ActiveListBase::inserted, this, &UniversalTableModel::onDatasourceInsert, Qt::UniqueConnection); if (!conn) { qWarning() << "Failed to connect to inserted signal"; } conn = connect(value, &ActiveListBase::removed, this, &UniversalTableModel::onDatasourceRemove, Qt::UniqueConnection); if (!conn) { qWarning() << "Failed to connect to removed signal"; } emit datasourceChanged(); } } GridColumn *UniversalTableModel::getColumn(int index) const { if(columns.empty()) return nullptr; return columns.at(index); } QObject *UniversalTableModel::getObjectByIndex(int index) { return datasource->qobjectValue(index); } QMetaMethod UniversalTableModel::findOnObjectPropertyChangedMethod() { QMetaMethod result; for (int m = 0; m < this->metaObject()->methodCount(); m++) { QMetaMethod method = this->metaObject()->method(m); if (QString(method.name()) == "onObjectPropertyChanged" && method.parameterCount() == 0) { result = method; } } return result; } QString UniversalTableModel::getPropertyName(QObject *sender, int senderSignalIndex) { QMetaMethod senderSignal = sender->metaObject()->method(senderSignalIndex); QMetaProperty senderProperty; const QMetaObject *senderMeta = sender->metaObject(); for (int i = 0; i < senderMeta->propertyCount(); i++) { if (senderMeta->property(i).hasNotifySignal()) { if (senderMeta->property(i).notifySignal() == senderSignal) { senderProperty = senderMeta->property(i); break; } } } return QString(senderProperty.name()); } void UniversalTableModel::subscribeToObjectProperties(QObject *obj) { if (!obj) return; for (auto col : columns) { QString fieldName = col->getFieldName(); if (fieldName.isEmpty()) continue; int propertyIndex = obj->metaObject()->indexOfProperty(fieldName.toStdString().data()); if (propertyIndex > -1) { if (obj->metaObject()->property(propertyIndex).hasNotifySignal()) { connect(obj, obj->metaObject()->property(propertyIndex).notifySignal(), this, onObjectPropertyChangedMethod); } } } } void UniversalTableModel::unsubscribeFromObjectProperties(QObject *obj) { if (!obj) return; for (auto col : columns) { QString fieldName = col->getFieldName(); if (fieldName.isEmpty()) continue; int propertyIndex = obj->metaObject()->indexOfProperty(fieldName.toStdString().data()); if (propertyIndex > -1) { if (obj->metaObject()->property(propertyIndex).hasNotifySignal()) { disconnect(obj, obj->metaObject()->property(propertyIndex).notifySignal(), this, onObjectPropertyChangedMethod); } } } } void UniversalTableModel::subscribeToAllObject(ActiveListBase *value) { if (!value) return; for (int i = 0; i < value->count(); ++i) { QObject *obj = value->qobjectValue(i); subscribeToObjectProperties(obj); } } void UniversalTableModel::unsubscribeFromAllObjects(ActiveListBase *value) { if (!value) return; for (int i = 0; i < value->count(); ++i) { QObject *obj = value->qobjectValue(i); unsubscribeFromObjectProperties(obj); } } void UniversalTableModel::setFilters(QMap<QString, QVariant> value) { filters = value; } void UniversalTableModel::reloadDatasource() { beginResetModel(); endResetModel(); emit datasourceChanged(); // subscribeToAllObject(); } void UniversalTableModel::onDatasourceCountChanged() { } void UniversalTableModel::onDatasourceInsert(size_t index, size_t count) { int startIndex = static_cast<int>(index); int endIndex = static_cast<int>(index + count - 1); beginInsertRows(QModelIndex(), startIndex, endIndex); insertRows(static_cast<int>(index), static_cast<int>(count)); endInsertRows(); if (datasource) { for (size_t i = index; i < index + count; ++i) { QObject *obj = datasource->qobjectValue(static_cast<int>(i)); subscribeToObjectProperties(obj); } } } void UniversalTableModel::onDatasourceRemove(size_t index, size_t count) { if (datasource) { for (size_t i = index; i < index + count; ++i) { QObject *obj = datasource->qobjectValue(static_cast<int>(i)); unsubscribeFromObjectProperties(obj); } } int startIndex = static_cast<int>(index); int endIndex = static_cast<int>(index + count - 1); beginRemoveRows(QModelIndex(), startIndex, endIndex); removeRows(static_cast<int>(index), static_cast<int>(count)); endRemoveRows(); } void UniversalTableModel::onObjectPropertyChanged() { QObject *sender = this->sender(); if (sender) { QString senderPropertyName = getPropertyName(sender, senderSignalIndex()); auto rowIndexOpt = datasource->qobjectIndexOf(sender); if (!rowIndexOpt.has_value()) return; int rowIndex = static_cast<int>(rowIndexOpt.value()); GridColumn *col = nullptr; for (GridColumn *c : columns) { if (c->getFieldName() == senderPropertyName) { col = c; break; } } int columnIndex = columns.indexOf(col); QModelIndex modelIndex = index(rowIndex, columnIndex); emit dataChanged(modelIndex, modelIndex); } } QVector<GridColumn *> UniversalTableModel::getColumns() const { return columns; } void UniversalTableModel::setColumns(const QVector<GridColumn *> &value) { if (datasource) { unsubscribeFromAllObjects(datasource); } beginResetModel(); columns = value; for (auto column : value) if (column->getIsId()) idColumn = column; endResetModel(); if (datasource) { subscribeToAllObject(datasource); } } Mode UniversalTableModel::getMode() const { return mode; } void UniversalTableModel::setMode(const Mode &value) { mode = value; } void UniversalTableModel::setCheckableSelectionEnabled(bool enabled) { if (mCheckableSelectionEnabled != enabled) { beginResetModel(); mCheckableSelectionEnabled = enabled; if (!enabled) { mSelectedRows.clear(); } endResetModel(); } } bool UniversalTableModel::getCheckableSelectionEnabled() const { return mCheckableSelectionEnabled; } void UniversalTableModel::setRowSelected(int row, bool selected) { if (selected) { mSelectedRows.insert(row); } else { mSelectedRows.remove(row); } if (mSelectionChangedCallback) { mSelectionChangedCallback(row, selected); } } bool UniversalTableModel::isRowSelected(int row) const { return mSelectedRows.contains(row); } QSet<int> UniversalTableModel::getSelectedRows() const { return mSelectedRows; } void UniversalTableModel::setSelectionChangedCallback(std::function<void(int, bool)> callback) { mSelectionChangedCallback = callback; } int UniversalTableModel::getColumnIndexByVisualIndex(int visualIndex) const { if (visualIndex < 0) return -1; int visibleCount = 0; for (int i = 0; i < columns.count(); ++i) { if (columns[i]->getVisible()) { if (visibleCount == visualIndex) { return i; } visibleCount++; } } return -1; }