Salome HOME
Copyright update 2022
[modules/gui.git] / src / TreeData / TreeModel.cxx
1 // Copyright (C) 2007-2022  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 // Author: Guillaume Boulant (EDF/R&D)
21
22
23 #include "TreeItem.hxx"
24 #include "TreeModel.hxx"
25
26 TreeModel::TreeModel(const QStringList &headers, QObject *parent)
27   : QAbstractItemModel(parent)
28 {
29   QVector<QVariant> rootData;
30   foreach (QString header, headers)
31     rootData << header;
32
33   // _MEM_ We have to specify a string identifier for each item so
34   // that it could be easily retrieved by its parent. In the case of
35   // the root item, the value of the identifier doesn't matter => we
36   // choose an arbitrary value
37   //QString rootNameId = "rootItem";
38   _rootItem = new TreeItem("rootItem", rootData);
39   _rootItem->associateToModel(this);
40 }
41
42 TreeModel::~TreeModel()
43 {
44   delete _rootItem;
45 }
46
47 TreeItem * TreeModel::getRootItem() {
48   return _rootItem;
49 }
50
51 //
52 // =================================================================
53 // This part of the implementation is the standard interface required
54 // for providing an operational TreeModel. These methods are used by
55 // the TreeView for display purpose. We just have to implement how we
56 // want the items to be displayed in the view.
57 // =================================================================
58 //
59 int TreeModel::columnCount(const QModelIndex & /* parent */) const
60 {
61   return _rootItem->columnCount();
62 }
63
64 /*!
65  * This function is used by the tree model to inform the tree view of
66  * what data used for rendering of the item in the different possible
67  * role (edition, ...).
68  */
69 QVariant TreeModel::data(const QModelIndex &index, int role) const
70 {
71   if (!index.isValid())
72     return QVariant();
73
74   if (role != Qt::DisplayRole && role != Qt::EditRole)
75     return QVariant();
76
77   TreeItem *item = getItem(index);
78
79   return item->data(index.column());
80 }
81
82 Qt::ItemFlags TreeModel::flags(const QModelIndex &index) const
83 {
84   if (!index.isValid())
85     return 0;
86
87   return Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
88 }
89
90 /*!
91  * This retrieves the item asociated to the specified index.
92  */
93 TreeItem *TreeModel::getItem(const QModelIndex &index) const
94 {
95   // The item associated to an index can be retrieved using the
96   // internalPointer() function on the index object.
97   if (index.isValid()) {
98     TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
99     if (item) return item;
100   }
101   return _rootItem;
102 }
103
104 QVariant TreeModel::headerData(int section, Qt::Orientation orientation,
105                                int role) const
106 {
107   if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
108     return _rootItem->data(section);
109
110   return QVariant();
111 }
112
113 /*!
114  * This retrieves the index of the item located at (row,column) place
115  * relative to the parent specified by its index.
116  */
117 QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent) const
118 {
119   if (parent.isValid() && parent.column() != 0)
120     return QModelIndex();
121
122   TreeItem *parentItem = getItem(parent);
123
124   TreeItem *childItem = parentItem->child(row);
125   if (childItem)
126     return createIndex(row, column, childItem);
127   else
128     return QModelIndex();
129 }
130
131 QModelIndex TreeModel::parent(const QModelIndex &index) const
132 {
133   if (!index.isValid())
134     return QModelIndex();
135
136   TreeItem *childItem = getItem(index);
137   TreeItem *parentItem = childItem->parent();
138
139   if (parentItem == _rootItem)
140     return QModelIndex();
141
142   return createIndex(parentItem->rowIndex(), 0, parentItem);
143 }
144
145 int TreeModel::rowCount(const QModelIndex &parent) const
146 {
147   TreeItem *parentItem = getItem(parent);
148
149   return parentItem->childCount();
150 }
151
152 bool TreeModel::setData(const QModelIndex &index, const QVariant &value,
153                         int role)
154 {
155   if (role != Qt::EditRole)
156     return false;
157
158   TreeItem *item = getItem(index);
159   bool result = item->setData(index.column(), value);
160
161   if (result)
162     emit dataChanged(index, index);
163
164   return result;
165 }
166
167 bool TreeModel::setHeaderData(int section, Qt::Orientation orientation,
168                               const QVariant &value, int role)
169 {
170   if (role != Qt::EditRole || orientation != Qt::Horizontal)
171     return false;
172
173   bool result = _rootItem->setData(section, value);
174
175   if (result)
176     emit headerDataChanged(orientation, section, section);
177
178   return result;
179 }
180
181
182 //
183 // =================================================================
184 // This part is a specific behavior to get a TreeModel that can
185 // organize itself the tree hierarchy using data provided in a
186 // filesystem-like format:
187 //
188 // data="a/b/c" ==> creation/filling of the hierarchy a->b->c
189 // The "folder" categories are unique whereas the leaves may exists
190 // in multiple instances.
191 // =================================================================
192 //
193
194 /*
195  * The addData functions run a recurcive filling of the tree model, starting
196  * form the rootItem and descending in the tree using the recurcive
197  * function TreeItem::addData.
198  */
199
200 bool TreeModel::addData(DataObject * dataObject) {
201   QStringList path = QString(dataObject->getPath().c_str()).split(DataObject::pathsep.c_str());
202   return addData(dataObject, path);
203 }
204 bool TreeModel::addData(DataObject * dataObject, const QStringList &path) {
205   TreeItem * rootItem = this->getItem();
206   rootItem->appendChild(dataObject, path);
207   return true;
208 }
209
210 bool TreeModel::removeData(DataObject * dataObject) {
211   QStringList path = QString(dataObject->getPath().c_str()).split(DataObject::pathsep.c_str());
212   TreeItem * rootItem = this->getItem();
213   rootItem->removeChild(dataObject, path);
214   return true;
215 }