diff --git a/src/presentation/querytreemodelbase.cpp b/src/presentation/querytreemodelbase.cpp index c1fb84e4..4b6a48c9 100644 --- a/src/presentation/querytreemodelbase.cpp +++ b/src/presentation/querytreemodelbase.cpp @@ -1,262 +1,267 @@ /* This file is part of Zanshin Copyright 2014 Mario Bensi Copyright 2014 Kevin Ottens This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "querytreemodelbase.h" #include #include #include using namespace Presentation; QueryTreeNodeBase::QueryTreeNodeBase(QueryTreeNodeBase *parent, QueryTreeModelBase *model) : m_parent(parent), m_model(model) { } QueryTreeNodeBase::~QueryTreeNodeBase() { qDeleteAll(m_childNode); } int QueryTreeNodeBase::row() { return m_parent ? m_parent->m_childNode.indexOf(this) : -1; } QueryTreeNodeBase *QueryTreeNodeBase::parent() const { return m_parent; } QueryTreeNodeBase *QueryTreeNodeBase::child(int row) const { if (row >= 0 && row < m_childNode.size()) return m_childNode.value(row); else return Q_NULLPTR; } void QueryTreeNodeBase::insertChild(int row, QueryTreeNodeBase *node) { m_childNode.insert(row, node); } void QueryTreeNodeBase::appendChild(QueryTreeNodeBase *node) { m_childNode.append(node); } void QueryTreeNodeBase::removeChildAt(int row) { delete m_childNode.takeAt(row); } int QueryTreeNodeBase::childCount() const { return m_childNode.size(); } QModelIndex QueryTreeNodeBase::index(int row, int column, const QModelIndex &parent) const { return m_model->index(row, column, parent); } QModelIndex QueryTreeNodeBase::createIndex(int row, int column, void *data) const { return m_model->createIndex(row, column, data); } void QueryTreeNodeBase::beginInsertRows(const QModelIndex &parent, int first, int last) { m_model->beginInsertRows(parent, first, last); } void QueryTreeNodeBase::endInsertRows() { m_model->endInsertRows(); } void QueryTreeNodeBase::beginRemoveRows(const QModelIndex &parent, int first, int last) { m_model->beginRemoveRows(parent, first, last); } void QueryTreeNodeBase::endRemoveRows() { m_model->endRemoveRows(); } void QueryTreeNodeBase::emitDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) { emit m_model->dataChanged(topLeft, bottomRight); } QueryTreeModelBase::QueryTreeModelBase(QueryTreeNodeBase *rootNode, QObject *parent) : QAbstractItemModel(parent), m_rootIndexFlag(Qt::ItemIsDropEnabled), m_rootNode(rootNode) { auto roles = roleNames(); roles.insert(ObjectRole, "object"); roles.insert(IconNameRole, "icon"); roles.insert(IsDefaultRole, "default"); setRoleNames(roles); } QueryTreeModelBase::~QueryTreeModelBase() { delete m_rootNode; } Qt::ItemFlags QueryTreeModelBase::flags(const QModelIndex &index) const { if (!isModelIndexValid(index)) return m_rootIndexFlag; return nodeFromIndex(index)->flags(); } QModelIndex QueryTreeModelBase::index(int row, int column, const QModelIndex &parent) const { if (row < 0 || column != 0) return QModelIndex(); const QueryTreeNodeBase *parentNode = nodeFromIndex(parent); if (row < parentNode->childCount()) { QueryTreeNodeBase *node = parentNode->child(row); return createIndex(row, column, node); } else { return QModelIndex(); } } QModelIndex QueryTreeModelBase::parent(const QModelIndex &index) const { QueryTreeNodeBase *node = nodeFromIndex(index); if (!node->parent() || node->parent() == m_rootNode) return QModelIndex(); else return createIndex(node->parent()->row(), 0, node->parent()); } int QueryTreeModelBase::rowCount(const QModelIndex &index) const { return nodeFromIndex(index)->childCount(); } int QueryTreeModelBase::columnCount(const QModelIndex &) const { return 1; } QVariant QueryTreeModelBase::data(const QModelIndex &index, int role) const { if (!isModelIndexValid(index)) { return QVariant(); } return nodeFromIndex(index)->data(role); } bool QueryTreeModelBase::setData(const QModelIndex &index, const QVariant &value, int role) { if (!isModelIndexValid(index)) { return false; } return nodeFromIndex(index)->setData(value, role); } bool QueryTreeModelBase::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) { Q_UNUSED(row); Q_UNUSED(column); // If that's not holding that mime type we can't do the cycle checking // this is relevant only for internal drag and drop anyway if (data->hasFormat(QStringLiteral("application/x-zanshin-indexes"))) { const auto indexes = data->property("indexes").value(); foreach (const auto &index, indexes) { auto p = parent; while (p.isValid()) { if (p == index) // Oops, we found a cycle (one of the indexes is parent of the drop point) return false; p = p.parent(); } } } return nodeFromIndex(parent)->dropMimeData(data, action); } QMimeData *QueryTreeModelBase::mimeData(const QModelIndexList &indexes) const { if (indexes.isEmpty()) return Q_NULLPTR; auto data = createMimeData(indexes); data->setData(QStringLiteral("application/x-zanshin-indexes"), "indexes"); data->setProperty("indexes", QVariant::fromValue(indexes)); return data; } QStringList QueryTreeModelBase::mimeTypes() const { return QAbstractItemModel::mimeTypes() << QStringLiteral("application/x-zanshin-object") << QStringLiteral("application/x-zanshin-indexes"); } +Qt::DropActions QueryTreeModelBase::supportedDragActions() const +{ + return Qt::MoveAction; +} + Qt::DropActions QueryTreeModelBase::supportedDropActions() const { return Qt::MoveAction; } QueryTreeNodeBase *QueryTreeModelBase::nodeFromIndex(const QModelIndex &index) const { return index.isValid() ? static_cast(index.internalPointer()) : m_rootNode; } void QueryTreeModelBase::setRootIndexFlag(Qt::ItemFlags flags) { m_rootIndexFlag = flags; } bool QueryTreeModelBase::isModelIndexValid(const QModelIndex &index) const { bool valid = index.isValid() && index.column() == 0 && index.row() >= 0; if (!valid) return false; const QueryTreeNodeBase *parentNode = nodeFromIndex(index.parent()); const int count = parentNode->childCount(); return index.row() < count; } diff --git a/src/presentation/querytreemodelbase.h b/src/presentation/querytreemodelbase.h index c380cd37..95b3694e 100644 --- a/src/presentation/querytreemodelbase.h +++ b/src/presentation/querytreemodelbase.h @@ -1,114 +1,115 @@ /* This file is part of Zanshin Copyright 2014 Mario Bensi Copyright 2014 Kevin Ottens This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef PRESENTATION_QUERYTREEMODELBASE_H #define PRESENTATION_QUERYTREEMODELBASE_H #include namespace Presentation { class QueryTreeModelBase; class QueryTreeNodeBase { public: QueryTreeNodeBase(QueryTreeNodeBase *parent, QueryTreeModelBase *model); virtual ~QueryTreeNodeBase(); virtual Qt::ItemFlags flags() const = 0; virtual QVariant data(int role) const = 0; virtual bool setData(const QVariant &value, int role) = 0; virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action) = 0; int row(); QueryTreeNodeBase *parent() const; QueryTreeNodeBase *child(int row) const; void insertChild(int row, QueryTreeNodeBase *node); void appendChild(QueryTreeNodeBase *node); void removeChildAt(int row); int childCount() const; protected: QModelIndex index(int row, int column, const QModelIndex &parent) const; QModelIndex createIndex(int row, int column, void *data) const; void beginInsertRows(const QModelIndex &parent, int first, int last); void endInsertRows(); void beginRemoveRows(const QModelIndex &parent, int first, int last); void endRemoveRows(); void emitDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); private: QueryTreeNodeBase *m_parent; QList m_childNode; QueryTreeModelBase *m_model; }; class QueryTreeModelBase : public QAbstractItemModel { Q_OBJECT public: enum { ObjectRole = Qt::UserRole + 1, IconNameRole, IsDefaultRole, UserRole }; ~QueryTreeModelBase(); Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE; QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; QModelIndex parent(const QModelIndex &index) const Q_DECL_OVERRIDE; int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) Q_DECL_OVERRIDE; bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) Q_DECL_OVERRIDE; QMimeData *mimeData(const QModelIndexList &indexes) const Q_DECL_OVERRIDE; QStringList mimeTypes() const Q_DECL_OVERRIDE; + Qt::DropActions supportedDragActions() const Q_DECL_OVERRIDE; Qt::DropActions supportedDropActions() const Q_DECL_OVERRIDE; // TODO Qt5: Remove but needed in Qt4, so that we can trigger it from the outside using QAbstractItemModel::dataChanged; protected: explicit QueryTreeModelBase(QueryTreeNodeBase *rootNode, QObject *parent = Q_NULLPTR); virtual QMimeData *createMimeData(const QModelIndexList &indexes) const = 0; QueryTreeNodeBase *nodeFromIndex(const QModelIndex &index) const; void setRootIndexFlag(Qt::ItemFlags flags); private: friend class QueryTreeNodeBase; bool isModelIndexValid(const QModelIndex &index) const; Qt::ItemFlags m_rootIndexFlag; QueryTreeNodeBase *m_rootNode; }; } #endif // PRESENTATION_QUERYTREEMODELBASE_H