1 /***************************************************************************
2  *   Copyright (C) 2005-2020 by the Quassel Project                        *
3  *   devel@quassel-irc.org                                                 *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) version 3.                                           *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
19  ***************************************************************************/
20 
21 #pragma once
22 
23 #include "client-export.h"
24 
25 #include <QAbstractItemModel>
26 #include <QLinkedList>  // needed for debug
27 #include <QList>
28 #include <QStringList>
29 #include <QVariant>
30 
31 /*****************************************
32  *  general item used in the Tree Model
33  *****************************************/
34 class CLIENT_EXPORT AbstractTreeItem : public QObject
35 {
36     Q_OBJECT
37 
38 public:
39     enum TreeItemFlag
40     {
41         NoTreeItemFlag = 0x00,
42         DeleteOnLastChildRemoved = 0x01
43     };
44     Q_DECLARE_FLAGS(TreeItemFlags, TreeItemFlag)
45 
46     AbstractTreeItem(AbstractTreeItem* parent = nullptr);
47 
48     bool newChild(AbstractTreeItem* child);
49     bool newChilds(const QList<AbstractTreeItem*>& items);
50 
51     bool removeChild(int row);
removeChild(AbstractTreeItem * child)52     inline bool removeChild(AbstractTreeItem* child) { return removeChild(child->row()); }
53     void removeAllChilds();
54 
55     bool reParent(AbstractTreeItem* newParent);
56 
57     AbstractTreeItem* child(int row) const;
58 
59     int childCount(int column = 0) const;
60 
61     virtual int columnCount() const = 0;
62 
63     virtual QVariant data(int column, int role) const = 0;
64     virtual bool setData(int column, const QVariant& value, int role) = 0;
65 
flags()66     virtual inline Qt::ItemFlags flags() const { return _flags; }
setFlags(Qt::ItemFlags flags)67     virtual inline void setFlags(Qt::ItemFlags flags) { _flags = flags; }
68 
treeItemFlags()69     inline AbstractTreeItem::TreeItemFlags treeItemFlags() const { return _treeItemFlags; }
setTreeItemFlags(AbstractTreeItem::TreeItemFlags flags)70     inline void setTreeItemFlags(AbstractTreeItem::TreeItemFlags flags) { _treeItemFlags = flags; }
71     int row() const;
parent()72     inline AbstractTreeItem* parent() const { return qobject_cast<AbstractTreeItem*>(QObject::parent()); }
73 
74     void dumpChildList();
75 
76 signals:
77     void dataChanged(int column = -1);
78 
79     void beginAppendChilds(int firstRow, int lastRow);
80     void endAppendChilds();
81 
82     void beginRemoveChilds(int firstRow, int lastRow);
83     void endRemoveChilds();
84 
85 protected:
86     void customEvent(QEvent* event) override;
87 
88 private:
89     QList<AbstractTreeItem*> _childItems;
90     Qt::ItemFlags _flags{};
91     TreeItemFlags _treeItemFlags{};
92 
93     void removeChildLater(AbstractTreeItem* child);
checkForDeletion()94     inline void checkForDeletion()
95     {
96         if (treeItemFlags() & DeleteOnLastChildRemoved && childCount() == 0)
97             parent()->removeChildLater(this);
98     }
99 };
100 
101 /*****************************************
102  * SimpleTreeItem
103  *****************************************/
104 class CLIENT_EXPORT SimpleTreeItem : public AbstractTreeItem
105 {
106     Q_OBJECT
107 
108 public:
109     SimpleTreeItem(QList<QVariant> data, AbstractTreeItem* parent = nullptr);
110 
111     QVariant data(int column, int role) const override;
112     bool setData(int column, const QVariant& value, int role) override;
113 
114     int columnCount() const override;
115 
116 private:
117     QList<QVariant> _itemData;
118 };
119 
120 /*****************************************
121  * PropertyMapItem
122  *****************************************/
123 class CLIENT_EXPORT PropertyMapItem : public AbstractTreeItem
124 {
125     Q_OBJECT
126 
127 public:
128     PropertyMapItem(AbstractTreeItem* parent = nullptr);
129 
130     virtual QStringList propertyOrder() const = 0;
131 
132     QVariant data(int column, int role) const override;
133     bool setData(int column, const QVariant& value, int role) override;
134 
toolTip(int column)135     virtual QString toolTip(int column) const { Q_UNUSED(column) return QString(); }
136     int columnCount() const override;
137 };
138 
139 /*****************************************
140  * TreeModel
141  *****************************************/
142 class CLIENT_EXPORT TreeModel : public QAbstractItemModel
143 {
144     Q_OBJECT
145 
146 public:
147     enum myRoles
148     {
149         SortRole = Qt::UserRole,
150         UserRole
151     };
152 
153     TreeModel(const QList<QVariant>&, QObject* parent = nullptr);
154     ~TreeModel() override;
155 
156     AbstractTreeItem* root() const;
157 
158     QVariant data(const QModelIndex& index, int role) const override;
159     bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override;
160 
161     Qt::ItemFlags flags(const QModelIndex& index) const override;
162     QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
163 
164     QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override;
165     QModelIndex indexByItem(AbstractTreeItem* item) const;
166 
167     QModelIndex parent(const QModelIndex& index) const override;
168 
169     int rowCount(const QModelIndex& parent = QModelIndex()) const override;
170     int columnCount(const QModelIndex& parent = QModelIndex()) const override;
171 
172     virtual void clear();
173 
174 private slots:
175     void itemDataChanged(int column = -1);
176 
177     void beginAppendChilds(int firstRow, int lastRow);
178     void endAppendChilds();
179 
180     void beginRemoveChilds(int firstRow, int lastRow);
181     void endRemoveChilds();
182 
183 protected:
184     AbstractTreeItem* rootItem;
185 
186 private:
187     void connectItem(AbstractTreeItem* item);
188 
189     struct ChildStatus
190     {
191         QModelIndex parent;
192         int childCount;
193         int start;
194         int end;
ChildStatusChildStatus195         inline ChildStatus(QModelIndex parent_, int cc_, int s_, int e_)
196             : parent(parent_)
197             , childCount(cc_)
198             , start(s_)
199             , end(e_){};
200     };
201     ChildStatus _childStatus;
202     int _aboutToRemoveOrInsert;
203 
204 private slots:
205     void debug_rowsAboutToBeInserted(const QModelIndex& parent, int start, int end);
206     void debug_rowsAboutToBeRemoved(const QModelIndex& parent, int start, int end);
207     void debug_rowsInserted(const QModelIndex& parent, int start, int end);
208     void debug_rowsRemoved(const QModelIndex& parent, int start, int end);
209     void debug_dataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight);
210 };
211