File indexing completed on 2024-05-12 03:48:21

0001 /*
0002     File                 : TreeModel.cpp
0003     Project              : LabPlot
0004     Description          : This is an abstract treemodel which can be used by a treeview
0005     --------------------------------------------------------------------
0006     SPDX-FileCopyrightText: 2019 Martin Marmsoler <martin.marmsoler@gmail.com>
0007 
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 
0011 #include "TreeModel.h"
0012 
0013 // ##########################################################
0014 //  TreeItem ###############################################
0015 // ##########################################################
0016 
0017 TreeItem::TreeItem(const QVector<QVariant>& data, TreeItem* parent)
0018     : itemData(data)
0019     , parentItem(parent) {
0020 }
0021 
0022 TreeItem::~TreeItem() {
0023     qDeleteAll(childItems);
0024 }
0025 
0026 TreeItem* TreeItem::child(int number) {
0027     return childItems.value(number);
0028 }
0029 
0030 int TreeItem::childCount() const {
0031     return childItems.count();
0032 }
0033 
0034 int TreeItem::childNumber() const {
0035     if (parentItem)
0036         return parentItem->childItems.indexOf(const_cast<TreeItem*>(this));
0037 
0038     return 0;
0039 }
0040 
0041 int TreeItem::columnCount() const {
0042     return itemData.count();
0043 }
0044 
0045 QVariant TreeItem::data(int column) const {
0046     return itemData.value(column);
0047 }
0048 
0049 QVariant TreeItem::backgroundColor() const {
0050     return m_backgroundColor;
0051 }
0052 
0053 bool TreeItem::insertChildren(int position, int count, int columns) {
0054     if (position < 0 || position > childItems.size())
0055         return false;
0056 
0057     for (int row = 0; row < count; ++row) {
0058         QVector<QVariant> data(columns);
0059         auto* item = new TreeItem(data, this);
0060         childItems.insert(position, item);
0061     }
0062 
0063     return true;
0064 }
0065 
0066 bool TreeItem::insertColumns(int position, int columns) {
0067     if (position < 0 || position > itemData.size())
0068         return false;
0069 
0070     for (int column = 0; column < columns; ++column)
0071         itemData.insert(position, QVariant());
0072 
0073     for (auto* child : childItems)
0074         child->insertColumns(position, columns);
0075 
0076     return true;
0077 }
0078 
0079 TreeItem* TreeItem::parent() {
0080     return parentItem;
0081 }
0082 
0083 bool TreeItem::removeChildren(int position, int count) {
0084     if (position < 0 || position + count > childItems.size())
0085         return false;
0086 
0087     for (int row = 0; row < count; ++row)
0088         delete childItems.takeAt(position);
0089 
0090     return true;
0091 }
0092 
0093 bool TreeItem::removeColumns(int position, int columns) {
0094     if (position < 0 || position + columns > itemData.size())
0095         return false;
0096 
0097     for (int column = 0; column < columns; ++column)
0098         itemData.remove(position);
0099 
0100     for (auto* child : childItems)
0101         child->removeColumns(position, columns);
0102 
0103     return true;
0104 }
0105 
0106 bool TreeItem::setData(int column, const QVariant& value) {
0107     if (column < 0 || column >= itemData.size())
0108         return false;
0109 
0110     itemData[column] = value;
0111     return true;
0112 }
0113 
0114 bool TreeItem::setBackgroundColor(int column, const QVariant& value) {
0115     if (column < 0 || column >= itemData.size())
0116         return false;
0117 
0118     m_backgroundColor = value.value<QColor>();
0119     return true;
0120 }
0121 
0122 // ##########################################################
0123 //  TreeModel ###############################################
0124 // ##########################################################
0125 
0126 TreeModel::TreeModel(const QStringList& headers, QObject* parent)
0127     : QAbstractItemModel(parent) {
0128     QVector<QVariant> rootData;
0129     for (auto& header : headers)
0130         rootData << header;
0131 
0132     rootItem = new TreeItem(rootData);
0133 }
0134 
0135 TreeModel::~TreeModel() {
0136     delete rootItem;
0137 }
0138 
0139 int TreeModel::columnCount(const QModelIndex& /* parent */) const {
0140     return rootItem->columnCount();
0141 }
0142 
0143 QVariant TreeModel::treeData(const int row, const int column, const QModelIndex& parent, const int role) {
0144     QModelIndex currentIndex = index(row, column, parent);
0145     return data(currentIndex, role);
0146 }
0147 
0148 QVariant TreeModel::data(const QModelIndex& index, int role) const {
0149     if (!index.isValid())
0150         return {};
0151 
0152     if (role != Qt::DisplayRole && role != Qt::EditRole && role != Qt::BackgroundRole)
0153         return {};
0154 
0155     TreeItem* item = getItem(index);
0156 
0157     if (role != Qt::BackgroundRole)
0158         return item->data(index.column());
0159 
0160     return item->backgroundColor();
0161 }
0162 
0163 Qt::ItemFlags TreeModel::flags(const QModelIndex& index) const {
0164     if (!index.isValid())
0165         return Qt::NoItemFlags;
0166 
0167     return Qt::ItemIsEditable | QAbstractItemModel::flags(index);
0168 }
0169 
0170 TreeItem* TreeModel::getItem(const QModelIndex& index) const {
0171     if (index.isValid()) {
0172         auto* item = static_cast<TreeItem*>(index.internalPointer());
0173         if (item)
0174             return item;
0175     }
0176     return rootItem;
0177 }
0178 
0179 QVariant TreeModel::headerData(int section, Qt::Orientation orientation, int role) const {
0180     if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
0181         return rootItem->data(section);
0182 
0183     return {};
0184 }
0185 
0186 QModelIndex TreeModel::index(int row, int column, const QModelIndex& parent) const {
0187     if (parent.isValid() && parent.column() != 0)
0188         return {};
0189 
0190     TreeItem* parentItem = getItem(parent);
0191 
0192     TreeItem* childItem = parentItem->child(row);
0193     if (childItem)
0194         return createIndex(row, column, childItem);
0195     else
0196         return {};
0197 }
0198 
0199 bool TreeModel::insertColumns(int position, int columns, const QModelIndex& parent) {
0200     bool success;
0201 
0202     beginInsertColumns(parent, position, position + columns - 1);
0203     success = rootItem->insertColumns(position, columns);
0204     endInsertColumns();
0205 
0206     return success;
0207 }
0208 
0209 bool TreeModel::insertRows(int position, int rows, const QModelIndex& parent) {
0210     TreeItem* parentItem = getItem(parent);
0211     bool success;
0212 
0213     beginInsertRows(parent, position, position + rows - 1);
0214     success = parentItem->insertChildren(position, rows, rootItem->columnCount());
0215     endInsertRows();
0216 
0217     return success;
0218 }
0219 
0220 QModelIndex TreeModel::parent(const QModelIndex& index) const {
0221     if (!index.isValid())
0222         return {};
0223 
0224     TreeItem* childItem = getItem(index);
0225     TreeItem* parentItem = childItem->parent();
0226 
0227     if (parentItem == rootItem)
0228         return {};
0229 
0230     return createIndex(parentItem->childNumber(), 0, parentItem);
0231 }
0232 
0233 bool TreeModel::removeColumns(int position, int columns, const QModelIndex& parent) {
0234     bool success;
0235 
0236     beginRemoveColumns(parent, position, position + columns - 1);
0237     success = rootItem->removeColumns(position, columns);
0238     endRemoveColumns();
0239 
0240     if (rootItem->columnCount() == 0)
0241         removeRows(0, rowCount());
0242 
0243     return success;
0244 }
0245 
0246 bool TreeModel::removeRows(int position, int rows, const QModelIndex& parent) {
0247     TreeItem* parentItem = getItem(parent);
0248 
0249     beginRemoveRows(parent, position, position + rows - 1);
0250     bool success = parentItem->removeChildren(position, rows);
0251     endRemoveRows();
0252 
0253     return success;
0254 }
0255 
0256 int TreeModel::rowCount(const QModelIndex& parent) const {
0257     TreeItem* parentItem = getItem(parent);
0258 
0259     return parentItem->childCount();
0260 }
0261 
0262 bool TreeModel::setTreeData(const QVariant& data, const int row, const int column, const QModelIndex& parent, int role) {
0263     QModelIndex curveIndex = index(row, column, parent);
0264     return setData(curveIndex, data, role);
0265 }
0266 
0267 bool TreeModel::setData(const QModelIndex& index, const QVariant& value, int role) {
0268     if (role == Qt::EditRole || role == Qt::DisplayRole) {
0269         TreeItem* item = getItem(index);
0270         bool result = item->setData(index.column(), value);
0271 
0272         if (result)
0273             Q_EMIT dataChanged(index, index);
0274 
0275         return result;
0276     } else if (role == Qt::BackgroundRole) {
0277         TreeItem* item = getItem(index);
0278         bool result = item->setBackgroundColor(index.column(), value);
0279 
0280         if (result)
0281             Q_EMIT dataChanged(index, index);
0282     }
0283 
0284     return false;
0285 }
0286 
0287 bool TreeModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant& value, int role) {
0288     if (role != Qt::EditRole && role != Qt::DisplayRole && orientation != Qt::Horizontal)
0289         return false;
0290 
0291     bool result = rootItem->setData(section, value);
0292 
0293     if (result)
0294         Q_EMIT headerDataChanged(orientation, section, section);
0295 
0296     return result;
0297 }
0298 
0299 int TreeModel::compareStrings(const QString& value, const int row, const int column, const QModelIndex& parent) {
0300     QModelIndex plotIndex = index(row, column, parent);
0301     return plotIndex.data().toString().compare(value);
0302 }