File indexing completed on 2024-05-26 05:56:50
0001 /* 0002 This file is part of the Okteta Kasten Framework, made within the KDE community. 0003 0004 SPDX-FileCopyrightText: 2009, 2010, 2011 Alex Richardson <alex.richardson@gmx.de> 0005 0006 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0007 */ 0008 0009 #include "structuretreemodel.hpp" 0010 #include "structurestool.hpp" 0011 #include <structureslogging.hpp> 0012 #include "datatypes/datainformationwithchildren.hpp" 0013 #include "datatypes/topleveldatainformation.hpp" 0014 #include "datatypes/array/arraydatainformation.hpp" 0015 // Qt 0016 #include <QFont> 0017 #include <QMimeData> 0018 0019 namespace Kasten { 0020 0021 StructureTreeModel::StructureTreeModel(StructuresTool* tool, QObject* parent) 0022 : QAbstractItemModel(parent) 0023 , mTool(tool) 0024 , mLastSender(nullptr) 0025 , mLastStartIndex(0) 0026 , mLastEndIndex(0) 0027 { 0028 connect(mTool, &StructuresTool::dataChanged, this, &StructureTreeModel::onToolDataChange); 0029 connect(mTool, &StructuresTool::dataCleared, this, &StructureTreeModel::onToolDataClear); 0030 connect(mTool, &StructuresTool::childrenAboutToBeInserted, 0031 this, &StructureTreeModel::onChildrenAboutToBeInserted); 0032 connect(mTool, &StructuresTool::childrenAboutToBeRemoved, 0033 this, &StructureTreeModel::onChildrenAboutToBeRemoved); 0034 connect(mTool, &StructuresTool::childrenInserted, 0035 this, &StructureTreeModel::onChildrenInserted); 0036 connect(mTool, &StructuresTool::childrenRemoved, 0037 this, &StructureTreeModel::onChildrenRemoved); 0038 0039 } 0040 0041 StructureTreeModel::~StructureTreeModel() = default; 0042 0043 void StructureTreeModel::onChildrenRemoved(const DataInformation* sender, uint startIndex, 0044 uint endIndex) 0045 { 0046 Q_ASSERT(sender == mLastSender); 0047 Q_ASSERT(startIndex == mLastStartIndex); 0048 Q_ASSERT(endIndex == mLastEndIndex); 0049 Q_UNUSED(sender) 0050 Q_UNUSED(startIndex) 0051 Q_UNUSED(endIndex) 0052 endRemoveRows(); 0053 } 0054 0055 void StructureTreeModel::onChildrenInserted(const DataInformation* sender, uint startIndex, 0056 uint endIndex) 0057 { 0058 Q_ASSERT(sender == mLastSender); 0059 Q_ASSERT(startIndex == mLastStartIndex); 0060 Q_ASSERT(endIndex == mLastEndIndex); 0061 Q_UNUSED(sender) 0062 Q_UNUSED(startIndex) 0063 Q_UNUSED(endIndex) 0064 endInsertRows(); 0065 } 0066 0067 void StructureTreeModel::onChildrenAboutToBeRemoved(DataInformation* sender, uint startIndex, 0068 uint endIndex) 0069 { 0070 // qCDebug(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "data information" << sender->fullObjectPath() << ": removing " 0071 // "children from index" << startIndex << "to" << endIndex; 0072 QModelIndex idx = findItemInModel(sender); 0073 Q_ASSERT(idx.isValid()); 0074 mLastSender = sender; 0075 mLastStartIndex = startIndex; 0076 mLastEndIndex = endIndex; 0077 beginRemoveRows(idx, startIndex, endIndex); 0078 } 0079 0080 void StructureTreeModel::onChildrenAboutToBeInserted(DataInformation* sender, uint startIndex, 0081 uint endIndex) 0082 { 0083 // qCDebug(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "data information" << sender->fullObjectPath() << ": inserting " 0084 // "children from index" << startIndex << "to" << endIndex; 0085 QModelIndex idx = findItemInModel(sender); 0086 Q_ASSERT(idx.isValid()); 0087 mLastSender = sender; 0088 mLastStartIndex = startIndex; 0089 mLastEndIndex = endIndex; 0090 beginInsertRows(idx, startIndex, endIndex); 0091 } 0092 0093 int StructureTreeModel::columnCount(const QModelIndex& parent) const 0094 { 0095 Q_UNUSED(parent) 0096 return DataInformation::COLUMN_COUNT; 0097 } 0098 0099 QVariant StructureTreeModel::data(const QModelIndex& index, int role) const 0100 { 0101 if (!index.isValid()) { 0102 return {}; 0103 } 0104 0105 auto* item = static_cast<DataInformation*> (index.internalPointer()); 0106 0107 if (role == DataInformationRole) { 0108 // Using ArrayDataInformation::childAt() needed with DataInformationWithDummyChildren for updated dummy 0109 if (item->parent()->isArray()) { 0110 ArrayDataInformation* array = item->parent()->asArray(); 0111 item = array->childAt(index.row()); 0112 } 0113 return QVariant::fromValue(item); 0114 } 0115 0116 const int column = index.column(); 0117 if (role == Qt::FontRole) { 0118 if (column == 0 && item->parent()->isTopLevel()) { 0119 // TODO: ideally here we would not take the default application font 0120 // (as given by QFont()) but the default of the view 0121 QFont font; 0122 font.setBold(true); 0123 return font; 0124 } 0125 return {}; 0126 } 0127 if (item->parent()->isArray()) { 0128 ArrayDataInformation* array = item->parent()->asArray(); 0129 return array->childData(index.row(), column, role); 0130 } 0131 return item->data(column, role); 0132 } 0133 0134 bool StructureTreeModel::setData(const QModelIndex& index, const QVariant& value, 0135 int role) 0136 { 0137 if (!index.isValid()) { 0138 return false; 0139 } 0140 0141 auto* item = index.data(StructureTreeModel::DataInformationRole).value<DataInformation*>(); 0142 if (!item) { 0143 qCDebug(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "item == NULL"; 0144 return false; 0145 } 0146 0147 bool change = mTool->setData(value, role, item, index.row()); 0148 0149 return change; 0150 } 0151 0152 Qt::ItemFlags StructureTreeModel::flags(const QModelIndex& index) const 0153 { 0154 if (!index.isValid()) { 0155 return Qt::NoItemFlags; 0156 } 0157 auto* item = static_cast<DataInformation*> (index.internalPointer()); 0158 Qt::ItemFlags flags = item->flags(index.column(), mTool->isFileLoaded()); 0159 if (item->wasAbleToRead()) { 0160 flags |= Qt::ItemIsDragEnabled; 0161 } 0162 0163 return flags; 0164 } 0165 0166 QMimeData* StructureTreeModel::mimeData(const QModelIndexList& indexes) const 0167 { 0168 if (indexes.isEmpty()) { 0169 return nullptr; 0170 } 0171 0172 const QModelIndex index = indexes.first(); 0173 0174 auto* item = index.data(StructureTreeModel::DataInformationRole).value<DataInformation*>(); 0175 0176 auto* mimeData = new QMimeData; 0177 0178 mimeData->setText(item->valueString()); 0179 mimeData->setData(QStringLiteral("application/octet-stream"), mTool->bytes(item)); 0180 0181 return mimeData; 0182 } 0183 0184 QStringList StructureTreeModel::mimeTypes() const 0185 { 0186 return { 0187 QStringLiteral("application/octet-stream"), 0188 QStringLiteral("text/plain"), 0189 }; 0190 } 0191 0192 QVariant StructureTreeModel::headerData(int section, Qt::Orientation orientation, 0193 int role) const 0194 { 0195 if (orientation == Qt::Horizontal) { 0196 return mTool->headerData(section, role); 0197 } 0198 return {}; 0199 } 0200 0201 QModelIndex StructureTreeModel::index(int row, int column, const QModelIndex& parent) const 0202 { 0203 if (!hasIndex(row, column, parent)) { 0204 return {}; 0205 } 0206 0207 DataInformation* childItem = nullptr; 0208 0209 if (!parent.isValid()) { 0210 childItem = mTool->childAt(row); 0211 } else { 0212 if (parent.column() != 0) { 0213 return {}; 0214 } 0215 auto* parentItem = static_cast<DataInformation*> (parent.internalPointer()); 0216 childItem = parentItem->childAt(row); 0217 } 0218 if (childItem) { 0219 return createIndex(row, column, childItem); 0220 } 0221 0222 return {}; 0223 } 0224 0225 QModelIndex StructureTreeModel::parent(const QModelIndex& index) const 0226 { 0227 if (!index.isValid()) { 0228 return {}; 0229 } 0230 0231 auto* childItem = static_cast<DataInformation*> (index.internalPointer()); 0232 0233 DataInformationBase* parentObj = childItem->parent(); 0234 0235 if (!parentObj || parentObj->isTopLevel()) { 0236 return {}; 0237 } 0238 0239 // not null, not topleveldatainformation-> must be datainformation 0240 DataInformation* parent = parentObj->asDataInformation(); 0241 return createIndex(parent->row(), 0, parent); 0242 } 0243 0244 int StructureTreeModel::rowCount(const QModelIndex& parent) const 0245 { 0246 if (!parent.isValid()) { 0247 return mTool->childCount(); 0248 } 0249 if (parent.column() != 0) { 0250 return 0; 0251 } 0252 auto* parentItem = static_cast<DataInformation*> (parent.internalPointer()); 0253 if (!parentItem) { 0254 qCDebug(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "parentItem is NULL"; 0255 return mTool->childCount(); 0256 } 0257 return parentItem->childCount(); 0258 } 0259 0260 bool StructureTreeModel::hasChildren(const QModelIndex& parent) const 0261 { 0262 if (!parent.isValid()) { 0263 return mTool->childCount() > 0; 0264 } 0265 auto* parentItem = static_cast<DataInformation*> (parent.internalPointer()); 0266 if (!parentItem) { 0267 return false; 0268 } 0269 return parentItem->childCount() > 0; 0270 } 0271 0272 QModelIndex StructureTreeModel::findItemInModel(DataInformationBase* data) const 0273 { 0274 Q_CHECK_PTR(data); 0275 if (!data || data->isTopLevel()) { 0276 return {}; // invalid object 0277 } 0278 return createIndex(data->asDataInformation()->row(), 0, data); 0279 } 0280 0281 void StructureTreeModel::onToolDataChange(int row, void* data) 0282 { 0283 Q_EMIT dataChanged(createIndex(row, 0, data), createIndex(row, 2, data)); 0284 } 0285 0286 void StructureTreeModel::onToolDataClear() 0287 { 0288 beginResetModel(); 0289 endResetModel(); 0290 } 0291 0292 } 0293 0294 #include "moc_structuretreemodel.cpp"