File indexing completed on 2024-05-19 04:56:28

0001 /**
0002  * \file checkablelistmodel.h
0003  * Proxy model to use QAbstractItemModel with QML.
0004  *
0005  * \b Project: Kid3
0006  * \author Urs Fleisch
0007  * \date 23 Sep 2014
0008  *
0009  * Copyright (C) 2014-2024  Urs Fleisch
0010  *
0011  * This file is part of Kid3.
0012  *
0013  * Kid3 is free software; you can redistribute it and/or modify
0014  * it under the terms of the GNU General Public License as published by
0015  * the Free Software Foundation; either version 2 of the License, or
0016  * (at your option) any later version.
0017  *
0018  * Kid3 is distributed in the hope that it will be useful,
0019  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0020  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0021  * GNU General Public License for more details.
0022  *
0023  * You should have received a copy of the GNU General Public License
0024  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
0025  */
0026 
0027 #pragma once
0028 
0029 #include <QAbstractProxyModel>
0030 #include <QItemSelectionModel>
0031 
0032 /**
0033  * Proxy model to map a hierarchical item model to a list model suitable for
0034  * QML.
0035  *
0036  * Compared with VisualDataModel, this model has a selectionModel property,
0037  * which can be used to have multi selection and queried from delegates using
0038  * the checkState role. Other functions help to improve the support of
0039  * QAbstractItemModel in QML.
0040  */
0041 class CheckableListModel : public QAbstractProxyModel {
0042   Q_OBJECT
0043   /** Source model, equivalent to the model property of VisualDataModel. */
0044   Q_PROPERTY(QObject* sourceModel
0045              READ sourceModel WRITE setSourceModelObject
0046              NOTIFY sourceModelChanged)
0047   /** Selection model used to store the selections with the checkState role. */
0048   Q_PROPERTY(QObject* selectionModel
0049              READ selectionModel WRITE setSelectionModelObject
0050              NOTIFY selectionModelChanged)
0051   /** Root node in the hierarchical source model. */
0052   Q_PROPERTY(QModelIndex rootIndex READ rootIndex WRITE setRootIndex
0053              NOTIFY rootIndexChanged)
0054   /** Current row. */
0055   Q_PROPERTY(int currentRow READ currentRow WRITE setCurrentRow
0056              NOTIFY currentRowChanged)
0057 public:
0058   /**
0059    * Constructor.
0060    * @param parent parent object
0061    */
0062   explicit CheckableListModel(QObject* parent = nullptr);
0063 
0064   /**
0065    * Destructor.
0066    */
0067   ~CheckableListModel() override = default;
0068 
0069   /**
0070    * Get selection model.
0071    * @return selection model.
0072    */
0073   QItemSelectionModel* selectionModel() const;
0074 
0075   /**
0076    * Set selection model.
0077    * @param selModel selection model to use
0078    */
0079   void setSelectionModel(QItemSelectionModel* selModel);
0080 
0081   /**
0082    * Get root node in hierarchical source model.
0083    * @return root model index.
0084    */
0085   QModelIndex rootIndex() const;
0086 
0087   /**
0088    * Set root node in hierarchical source model.
0089    * @param rootIndex root model index
0090    */
0091   void setRootIndex(const QModelIndex& rootIndex);
0092 
0093   /**
0094    * Get data for @a roleName and @a row from model.
0095    * @param row model row
0096    * @param roleName role name as used in scripting languages
0097    * @return model data.
0098    */
0099   Q_INVOKABLE QVariant getDataValue(int row, const QByteArray& roleName) const;
0100 
0101   /**
0102    * Set data for @a roleName and @a row in model.
0103    * This method can be used to assign values in the model because this is not
0104    * supported by the role properties available in the delegate.
0105    *
0106    * @param row model row
0107    * @param roleName role name as used in scripting languages
0108    * @param value model data
0109    * @return true if ok.
0110    */
0111   Q_INVOKABLE bool setDataValue(int row, const QByteArray& roleName,
0112                                 const QVariant& value);
0113 
0114   /**
0115    * Get model index in the source model.
0116    * @param row model row
0117    * @return model index.
0118    */
0119   Q_INVOKABLE QModelIndex modelIndex(int row) const;
0120 
0121   /**
0122    * Get parent of the current root index.
0123    * This can be used to go up in the hierarchy.
0124    * @return model index of parent.
0125    */
0126   Q_INVOKABLE QModelIndex parentModelIndex() const;
0127 
0128   /**
0129    * Check if a row has children in the source model.
0130    * This can be used to go down in the hierarchy using modelIndex().
0131    * @param row model row
0132    * @return true if the node has children.
0133    */
0134   Q_INVOKABLE bool hasModelChildren(int row) const;
0135 
0136   /**
0137    * Get the current row.
0138    * @return model row.
0139    */
0140   int currentRow() const;
0141 
0142   /**
0143    * Clear the selection and select @a row as the current index.
0144    * @param row row to select
0145    */
0146   void setCurrentRow(int row);
0147 
0148   /** Set item flags. */
0149   Qt::ItemFlags flags(const QModelIndex& index) const override;
0150 
0151   /** Get data for a given role. */
0152   QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
0153 
0154   /** Set data for a given role. */
0155   bool setData(const QModelIndex& index, const QVariant& value,
0156                int role = Qt::EditRole) override;
0157 
0158   /** Set source model. */
0159   void setSourceModel(QAbstractItemModel* srcModel) override;
0160 
0161   /** Get index in model. */
0162   QModelIndex index(int row, int column,
0163                     const QModelIndex& parent = QModelIndex()) const override;
0164 
0165   /** Get parent model index. */
0166   QModelIndex parent(const QModelIndex& child) const override;
0167 
0168   /** Get number of rows under given @a parent. */
0169   int rowCount(const QModelIndex& parent = QModelIndex()) const override;
0170 
0171   /** Get number of columns under given @a parent. */
0172   int columnCount(const QModelIndex& parent = QModelIndex()) const override;
0173 
0174   /** Map proxy index to index of source model. */
0175   QModelIndex mapToSource(const QModelIndex& proxyIndex) const override;
0176 
0177   /** Map index of source model to proxy index. */
0178   QModelIndex mapFromSource(const QModelIndex& srcIndex) const override;
0179 
0180 signals:
0181   /** Emitted when source model is changed. */
0182   void sourceModelChanged();
0183 
0184   /** Emitted when selection model is changed. */
0185   void selectionModelChanged();
0186 
0187   /** Emitted when root index is changed. */
0188   void rootIndexChanged();
0189 
0190   /** Emitted when the current row is changed. */
0191   void currentRowChanged(int row);
0192 
0193 private slots:
0194   void onModelAboutToBeReset();
0195   void onModelReset();
0196   void onDataChanged(const QModelIndex& topLeft,
0197                      const QModelIndex& bottomRight);
0198   void onRowsAboutToBeRemoved(const QModelIndex& parent, int first, int last);
0199   void onRowsRemoved(const QModelIndex &parent, int first, int last);
0200   void onRowsAboutToBeInserted(const QModelIndex& parent, int first, int last);
0201   void onRowsInserted(const QModelIndex& parent, int first, int last);
0202   void onSelectionChanged(const QItemSelection& selected,
0203                           const QItemSelection& deselected);
0204   void onCurrentChanged(const QModelIndex& current,
0205                         const QModelIndex& previous);
0206 
0207 private:
0208   void setSourceModelObject(QObject* obj);
0209   void setSelectionModelObject(QObject* obj);
0210 
0211   QItemSelectionModel* m_selModel;
0212   QPersistentModelIndex m_rootIndex;
0213 };