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 }