File indexing completed on 2025-01-05 04:59:44

0001 /*
0002  * SPDX-FileCopyrightText: 2014 Mario Bensi <mbensi@ipsquad.net>
0003  * SPDX-FileCopyrightText: 2014 Kevin Ottens <ervin@kde.org>
0004  * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005  */
0006 
0007 
0008 #include "querytreemodelbase.h"
0009 
0010 #include <QMimeData>
0011 #include <QStringList>
0012 
0013 #include <algorithm>
0014 
0015 using namespace Presentation;
0016 
0017 QueryTreeNodeBase::QueryTreeNodeBase(QueryTreeNodeBase *parent, QueryTreeModelBase *model)
0018     : m_parent(parent),
0019       m_model(model)
0020 {
0021 }
0022 
0023 QueryTreeNodeBase::~QueryTreeNodeBase()
0024 {
0025     qDeleteAll(m_childNode);
0026 }
0027 
0028 int QueryTreeNodeBase::row()
0029 {
0030     return m_parent ? m_parent->m_childNode.indexOf(this) : -1;
0031 }
0032 
0033 QueryTreeNodeBase *QueryTreeNodeBase::parent() const
0034 {
0035     return m_parent;
0036 }
0037 
0038 QueryTreeNodeBase *QueryTreeNodeBase::child(int row) const
0039 {
0040     if (row >= 0 && row < m_childNode.size())
0041         return m_childNode.value(row);
0042     else
0043         return nullptr;
0044 }
0045 
0046 void QueryTreeNodeBase::insertChild(int row, QueryTreeNodeBase *node)
0047 {
0048     m_childNode.insert(row, node);
0049 }
0050 
0051 void QueryTreeNodeBase::appendChild(QueryTreeNodeBase *node)
0052 {
0053     m_childNode.append(node);
0054 }
0055 
0056 void QueryTreeNodeBase::removeChildAt(int row)
0057 {
0058     delete m_childNode.takeAt(row);
0059 }
0060 
0061 int QueryTreeNodeBase::childCount() const
0062 {
0063     return m_childNode.size();
0064 }
0065 
0066 QModelIndex QueryTreeNodeBase::index(int row, int column, const QModelIndex &parent) const
0067 {
0068     return m_model->index(row, column, parent);
0069 }
0070 
0071 QModelIndex QueryTreeNodeBase::createIndex(int row, int column, void *data) const
0072 {
0073     return m_model->createIndex(row, column, data);
0074 }
0075 
0076 void QueryTreeNodeBase::beginInsertRows(const QModelIndex &parent, int first, int last)
0077 {
0078     m_model->beginInsertRows(parent, first, last);
0079 }
0080 
0081 void QueryTreeNodeBase::endInsertRows()
0082 {
0083     m_model->endInsertRows();
0084 }
0085 
0086 void QueryTreeNodeBase::beginRemoveRows(const QModelIndex &parent, int first, int last)
0087 {
0088     m_model->beginRemoveRows(parent, first, last);
0089 }
0090 
0091 void QueryTreeNodeBase::endRemoveRows()
0092 {
0093     m_model->endRemoveRows();
0094 }
0095 
0096 void QueryTreeNodeBase::emitDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
0097 {
0098     emit m_model->dataChanged(topLeft, bottomRight);
0099 }
0100 
0101 QueryTreeModelBase::QueryTreeModelBase(QueryTreeNodeBase *rootNode, QObject *parent)
0102     : QAbstractItemModel(parent),
0103       m_rootIndexFlag(Qt::ItemIsDropEnabled),
0104       m_rootNode(rootNode)
0105 {
0106 }
0107 
0108 QueryTreeModelBase::~QueryTreeModelBase()
0109 {
0110     delete m_rootNode;
0111 }
0112 
0113 QHash<int, QByteArray> QueryTreeModelBase::roleNames() const
0114 {
0115     auto roles = QAbstractItemModel::roleNames();
0116     roles.insert(ObjectRole, "object");
0117     roles.insert(IconNameRole, "icon");
0118     roles.insert(IsDefaultRole, "default");
0119     return roles;
0120 }
0121 
0122 Qt::ItemFlags QueryTreeModelBase::flags(const QModelIndex &index) const
0123 {
0124     if (!isModelIndexValid(index))
0125         return m_rootIndexFlag;
0126 
0127     return nodeFromIndex(index)->flags();
0128 }
0129 
0130 QModelIndex QueryTreeModelBase::index(int row, int column, const QModelIndex &parent) const
0131 {
0132     if (row < 0 || column != 0)
0133         return QModelIndex();
0134 
0135     const QueryTreeNodeBase *parentNode = nodeFromIndex(parent);
0136 
0137     if (row < parentNode->childCount()) {
0138         QueryTreeNodeBase *node = parentNode->child(row);
0139         return createIndex(row, column, node);
0140     } else {
0141         return QModelIndex();
0142     }
0143 }
0144 
0145 QModelIndex QueryTreeModelBase::parent(const QModelIndex &index) const
0146 {
0147     QueryTreeNodeBase *node = nodeFromIndex(index);
0148     if (!node->parent() || node->parent() == m_rootNode)
0149         return QModelIndex();
0150     else
0151         return createIndex(node->parent()->row(), 0, node->parent());
0152 }
0153 
0154 int QueryTreeModelBase::rowCount(const QModelIndex &index) const
0155 {
0156     return nodeFromIndex(index)->childCount();
0157 }
0158 
0159 int QueryTreeModelBase::columnCount(const QModelIndex &) const
0160 {
0161     return 1;
0162 }
0163 
0164 QVariant QueryTreeModelBase::data(const QModelIndex &index, int role) const
0165 {
0166     if (!isModelIndexValid(index)) {
0167         return QVariant();
0168     }
0169 
0170     const_cast<QueryTreeModelBase *>(this)->fetchAdditionalInfo(index);
0171 
0172     return nodeFromIndex(index)->data(role);
0173 }
0174 
0175 bool QueryTreeModelBase::setData(const QModelIndex &index, const QVariant &value, int role)
0176 {
0177     if (!isModelIndexValid(index)) {
0178         return false;
0179     }
0180 
0181     return nodeFromIndex(index)->setData(value, role);
0182 }
0183 
0184 bool QueryTreeModelBase::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
0185 {
0186     Q_UNUSED(row);
0187     Q_UNUSED(column);
0188 
0189     // If that's not holding that mime type we can't do the cycle checking
0190     // this is relevant only for internal drag and drop anyway
0191     if (data->hasFormat(QStringLiteral("application/x-zanshin-indexes"))) {
0192         const auto indexes = data->property("indexes").value<QModelIndexList>();
0193         foreach (const auto &index, indexes) {
0194             auto p = parent;
0195             while (p.isValid()) {
0196                 if (p == index) // Oops, we found a cycle (one of the indexes is parent of the drop point)
0197                     return false;
0198                 p = p.parent();
0199             }
0200         }
0201     }
0202 
0203     return nodeFromIndex(parent)->dropMimeData(data, action);
0204 }
0205 
0206 QMimeData *QueryTreeModelBase::mimeData(const QModelIndexList &indexes) const
0207 {
0208     if (indexes.isEmpty())
0209         return nullptr;
0210 
0211     auto data = createMimeData(indexes);
0212     data->setData(QStringLiteral("application/x-zanshin-indexes"), "indexes");
0213     data->setProperty("indexes", QVariant::fromValue(indexes));
0214     return data;
0215 }
0216 
0217 QStringList QueryTreeModelBase::mimeTypes() const
0218 {
0219     return QAbstractItemModel::mimeTypes() << QStringLiteral("application/x-zanshin-object")
0220                                            << QStringLiteral("application/x-zanshin-indexes");
0221 }
0222 
0223 Qt::DropActions QueryTreeModelBase::supportedDragActions() const
0224 {
0225     return Qt::MoveAction;
0226 }
0227 
0228 Qt::DropActions QueryTreeModelBase::supportedDropActions() const
0229 {
0230     return Qt::MoveAction;
0231 }
0232 
0233 QueryTreeNodeBase *QueryTreeModelBase::nodeFromIndex(const QModelIndex &index) const
0234 {
0235     return index.isValid() ? static_cast<QueryTreeNodeBase*>(index.internalPointer()) : m_rootNode;
0236 }
0237 
0238 void QueryTreeModelBase::setRootIndexFlag(Qt::ItemFlags flags)
0239 {
0240     m_rootIndexFlag = flags;
0241 }
0242 
0243 bool QueryTreeModelBase::isModelIndexValid(const QModelIndex &index) const
0244 {
0245     bool valid = index.isValid()
0246         && index.column() == 0
0247         && index.row() >= 0;
0248 
0249     if (!valid)
0250         return false;
0251 
0252     const QueryTreeNodeBase *parentNode = nodeFromIndex(index.parent());
0253     const int count = parentNode->childCount();
0254     return index.row() < count;
0255 }
0256 
0257 #include "moc_querytreemodelbase.cpp"