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"