/* Copyright (c) 2009 Stephen Kelly This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef DYNAMICTREEMODEL_H #define DYNAMICTREEMODEL_H #include #include #include #include #include "indexfinder.h" #include "proxymodeltestsuite_export.h" template class QList; class ModelMoveCommand; class PROXYMODELTESTSUITE_EXPORT DynamicTreeModel : public QAbstractItemModel { Q_OBJECT public: enum Roles { DynamicTreeModelId = Qt::UserRole, LastRole }; explicit DynamicTreeModel(QObject *parent = 0); QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; QModelIndex parent(const QModelIndex &index) const; int rowCount(const QModelIndex &index = QModelIndex()) const; int columnCount(const QModelIndex &index = QModelIndex()) const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole); bool dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent); Qt::ItemFlags flags(const QModelIndex& index) const; Qt::DropActions supportedDropActions() const; QStringList mimeTypes() const; QMimeData* mimeData(const QModelIndexList& indexes) const; QModelIndexList match(const QModelIndex& start, int role, const QVariant& value, int hits = 1, Qt::MatchFlags flags = Qt::MatchFlags(Qt::MatchStartsWith | Qt::MatchWrap)) const; void clear(); QList indexToPath(const QModelIndex &idx) const; ModelMoveCommand* getMoveCommand(const QList &srcPath, int startRow, int endRow); protected slots: /** Finds the parent id of the string with id @p searchId. Returns -1 if not found. */ qint64 findParentId(qint64 searchId) const; private: QHash m_items; QHash > > m_childItems; qint64 nextId; qint64 newId() { return nextId++; }; QModelIndex m_nextParentIndex; int m_nextRow; int m_depth; int maxDepth; friend class ModelInsertCommand; friend class ModelInsertWithDescendantsCommand; friend class ModelRemoveCommand; friend class ModelDataChangeCommand; friend class ModelMoveCommand; friend class ModelMoveLayoutChangeCommand; friend class ModelResetCommand; friend class ModelLayoutChangeCommand; // friend class ModelSortIndexCommand; friend class ModelSortIndexLayoutChangeCommand; friend class ModelInsertAndRemoveQueuedCommand; }; class PROXYMODELTESTSUITE_EXPORT ModelChangeCommand : public QObject { Q_OBJECT public: ModelChangeCommand( DynamicTreeModel *model, QObject *parent = 0 ); virtual ~ModelChangeCommand() {} void setAncestorRowNumbers(const QList &rowNumbers) { m_rowNumbers = rowNumbers; } QList srcAncestors() const { return m_rowNumbers; } QModelIndex findIndex(const QList &rows) const; void setStartRow(int row) { m_startRow = row; } void setEndRow(int row) { m_endRow = row; } void setNumCols(int cols) { m_numCols = cols; } virtual void doCommand() = 0; QModelIndex parentIndex() const { return findIndex(m_rowNumbers); } int startRow() const { return m_startRow; } int endRow() const { return m_endRow; } protected: DynamicTreeModel* m_model; QList m_rowNumbers; int m_startRow; int m_endRow; int m_numCols; }; typedef QList ModelChangeCommandList; /** @brief Inserts a sub tree into the dynamictreemodel. As an alternative to setStartRow and setEndRow, the interpret command may be used. The interpret command is used to set the structure of the subtree. For example, @code cmd = new ModelInsertCommand(m_model, this); cmd->interpret( "- A" "- B" "- - C" "- D" ); @endcode Will emit an insert for 3 rows, the second of which will have a child row. The interpretation string may be complex as long as it is valid. The text at the end of each row does not need to be consistent. There is a define DUMPTREE to make this command print the tree it inserts for better readability. @code cmd->interpret( "- A" "- - B" "- - C" "- - - C" "- - C" "- - - C" "- - - C" "- - C" "- D" "- - E" "- - F" ); @endcode The string is valid if (depth of row (N + 1)) <= ( (depth of row N) + 1). For example, the following is invalid because the depth of B is 2 and the depth of A is 0. @code cmd->interpret( "- A" "- - - B" "- - C" @endcode */ class PROXYMODELTESTSUITE_EXPORT ModelInsertCommand : public ModelChangeCommand { Q_OBJECT struct Token { enum Type { Branch, Leaf }; Type type; QString content; }; public: explicit ModelInsertCommand(DynamicTreeModel *model, QObject *parent = 0 ); virtual ~ModelInsertCommand() {} void interpret(const QString &treeString); virtual void doCommand(); void doInsertTree(const QModelIndex &parent); protected: QList tokenize(const QString &treeString) const; QList getDepths(const QString &treeString) const; QString m_treeString; }; class PROXYMODELTESTSUITE_EXPORT ModelInsertAndRemoveQueuedCommand : public ModelChangeCommand { Q_OBJECT public: explicit ModelInsertAndRemoveQueuedCommand(DynamicTreeModel *model, QObject *parent = 0 ); virtual ~ModelInsertAndRemoveQueuedCommand() {} virtual void doCommand(); signals: void beginInsertRows(const QModelIndex &parent, int start, int end); void endInsertRows(); void beginRemoveRows(const QModelIndex &parent, int start, int end); void endRemoveRows(); protected slots: void queuedBeginInsertRows(const QModelIndex &parent, int start, int end); void queuedEndInsertRows(); void queuedBeginRemoveRows(const QModelIndex &parent, int start, int end); void queuedEndRemoveRows(); protected: void purgeItem(qint64 parent); }; class PROXYMODELTESTSUITE_EXPORT ModelRemoveCommand : public ModelChangeCommand { Q_OBJECT public: explicit ModelRemoveCommand(DynamicTreeModel *model, QObject *parent = 0 ); virtual ~ModelRemoveCommand() {} virtual void doCommand(); void purgeItem(qint64 parent); }; class PROXYMODELTESTSUITE_EXPORT ModelDataChangeCommand : public ModelChangeCommand { Q_OBJECT public: explicit ModelDataChangeCommand(DynamicTreeModel *model, QObject *parent = 0); virtual ~ModelDataChangeCommand() {} virtual void doCommand(); void setStartColumn(int column) { m_startColumn = column; } protected: int m_startColumn; }; class PROXYMODELTESTSUITE_EXPORT ModelMoveCommand : public ModelChangeCommand { Q_OBJECT public: explicit ModelMoveCommand(DynamicTreeModel *model, QObject *parent); virtual ~ModelMoveCommand() {} virtual bool emitPreSignal(const QModelIndex &srcParent, int srcStart, int srcEnd, const QModelIndex &destParent, int destRow); virtual void doCommand(); virtual void emitPostSignal(); void setDestAncestors( const QList &rows ) { m_destRowNumbers = rows; } QList destAncestors() const { return m_destRowNumbers; } void setDestRow(int row) { m_destRow = row; } protected: QList m_destRowNumbers; int m_destRow; }; class PROXYMODELTESTSUITE_EXPORT ModelMoveLayoutChangeCommand : public ModelMoveCommand { Q_OBJECT public: explicit ModelMoveLayoutChangeCommand(DynamicTreeModel* model, QObject* parent); virtual ~ModelMoveLayoutChangeCommand(); virtual bool emitPreSignal(const QModelIndex &srcParent, int srcStart, int srcEnd, const QModelIndex &destParent, int destRow); virtual void emitPostSignal(); void setEndOfMoveSourceAncestors(const QList &rows ) { m_endOfMoveSourceAncestors = rows; } void setEndOfMoveDestAncestors(const QList &rows ) { m_endOfMoveDestAncestors = rows; } private: QModelIndexList m_beforeMoveList; QList m_endOfMoveSourceAncestors; QList m_endOfMoveDestAncestors; }; class PROXYMODELTESTSUITE_EXPORT ModelResetCommand : public ModelChangeCommand { Q_OBJECT public: ModelResetCommand(DynamicTreeModel* model, QObject* parent = 0); virtual ~ModelResetCommand(); void setInitialTree(const QString &treeString); /* reimp */ void doCommand(); private: QString m_treeString; }; class PROXYMODELTESTSUITE_EXPORT ModelLayoutChangeCommand : public ModelChangeCommand { Q_OBJECT public: ModelLayoutChangeCommand(DynamicTreeModel* model, QObject* parent = 0); virtual ~ModelLayoutChangeCommand(); struct PersistentChange { QList oldPath; QList newPath; }; void setPersistentChanges(const QList &changes); void setInitialTree(const QString &treeString); /* reimp */ void doCommand(); private: QString m_treeString; QList m_changes; }; #endif