Salome HOME
updated copyright message
[modules/gui.git] / src / TreeData / TreeItem.cxx
1 // Copyright (C) 2007-2023  CEA, EDF, 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 <QStringList>
24 #include "TreeItem.hxx"
25
26 TreeItem::TreeItem(const QString &nameId,
27                    const QVector<QVariant> &columnValues,
28                    TreeItem *parent)
29 {
30   this->initialize(nameId, columnValues, parent);
31 }
32
33 /*!
34  * This initializes the tree item. Called by the constructors.
35  */
36 void TreeItem::initialize(const QString &nameId,
37                           const QVector<QVariant> &columnValues,
38                           TreeItem *parent) {
39   _itemNameId = nameId;
40   _itemData   = columnValues;
41   _parentItem = parent;
42
43   // An item is associated to the model of its parent. It can't be
44   //done automatically in the case where the item has no parent. Then
45   //the function associatedToModel has to be called explicitely from
46   //within the user code (for exemple at construction of the model,
47   //when creating the root item).
48   if ( parent != NULL ) {
49     this->associateToModel(parent->associatedModel());
50   }
51 }
52
53 TreeItem::~TreeItem()
54 {
55   qDeleteAll(_childItems);
56   qDeleteAll(_childItemsMapById);
57   qDeleteAll(_childItemsMapByLabel);
58 }
59
60 /*!
61  * This must be used to specified which model this item belongs to. It
62  * is required because the item sometimes requests its model for
63  * global informations about the data tree. In standard usage, this
64  * function is automatically set when the item is instantiated by
65  * requested the parent item. Then only the root item needs a manual
66  * setting.
67  */
68 void TreeItem::associateToModel(TreeModel * model) {
69   _associatedModel = model;
70 }
71
72 TreeModel * TreeItem::associatedModel() {
73   return _associatedModel;
74 }
75
76 /*!
77  * This provide an identifier for this item
78  */
79 QString TreeItem::nameId() {
80   return _itemNameId;
81 }
82
83 /*!
84  * This creates an item from the specified dataObject and put it in
85  * the decendency of this item at the specified relativePath. The
86  * created item could not be a direct child of this item in the case
87  * where the relative path is not null. Note that no reference on the
88  * dataObject is kept in this instance. Only the identifier is used to
89  * set the item identifier, and the properties may be used to set the
90  * values of the item (stored in columns).
91  */
92 void TreeItem::appendChild(DataObject * dataObject,
93                            const QStringList &relativePath) {
94   // Definition of the nameId
95   QString nameId = QString(dataObject->getNameId().c_str());
96
97   // Definition of columns data values
98   QVector<QVariant> columnValues;
99   columnValues << QString(dataObject->getLabel().c_str());
100   columnValues << "No value"; // We could use the dataObject properties
101
102   // Append the item at the specified location with the specified values:
103   this->appendChild(nameId, columnValues, relativePath);
104 }
105
106 void TreeItem::appendChild(const QString &nameId,
107                            const QVector<QVariant> &columnValues,
108                            const QStringList &relativePath) {
109
110   if ( relativePath.isEmpty() ) {
111     // It is a direct child => just create and append to this.
112     TreeItem * child = new TreeItem(nameId, columnValues, this);
113     this->appendChild(child);
114     return;
115   }
116
117   // The child is embedded in a sub-folder (to be created if doesn't
118   // exist).
119   // We first check if the sub-folder already exist:
120   TreeItem * folder = this->childByLabel(relativePath[0]);
121   if ( folder == NULL ) {
122     // The folder does not exist. It must be created before going any
123     // further. By convention we choose the folder name as
124     // identifier.
125     QString folderNameId = relativePath[0];
126     QVector<QVariant> folderColumnValues;
127     folderColumnValues << relativePath[0] << "No value";
128     folder = new TreeItem(folderNameId, folderColumnValues, this);
129     this->appendChild(folder);
130   }
131
132   // We create the relative path of the next iteration (delete the
133   // first folder path).
134   QStringList nextRelativePath;
135   for (int i = 1; i < relativePath.size(); ++i)
136     nextRelativePath << relativePath[i];
137
138   folder->appendChild(nameId, columnValues, nextRelativePath);
139 }
140
141 /*!
142  * This appends the specified child to this item. This item is the
143  * direct parent of the specified child.
144  */
145 void TreeItem::appendChild(TreeItem *item)
146 {
147   TreeModel * model = this->associatedModel();
148
149   int position = this->childCount();
150   model->beginInsertRows(this->modelIndex(), position, position);
151   _childItems.append(item);
152   _childItemsMapById[item->nameId()] = item;
153   _childItemsMapByLabel[item->data(0).toString()] = item;
154   model->endInsertRows();
155 }
156
157 /*!
158  * This removes the specified child to this item. This item is the
159  * direct parent of the specified child.
160  */
161 void TreeItem::removeChild(TreeItem *item)
162 {
163   TreeModel * model = this->associatedModel();
164
165   int position = this->childCount();
166   model->beginRemoveRows(this->modelIndex(), position, position);
167   _childItems.removeOne(item);
168   _childItemsMapById.remove(item->nameId());
169   _childItemsMapByLabel.remove(item->data(0).toString());
170   model->endRemoveRows();
171 }
172
173 void TreeItem::removeChild(DataObject * dataObject, const QStringList &relativePath) {
174   if ( relativePath.isEmpty() ) {
175     // It is a direct child => just remove it.
176     QString nameId = QString(dataObject->getNameId().c_str());
177     TreeItem * child = this->childById(nameId);
178     if (child != NULL)
179       this->removeChild(child);
180     return;
181   }
182
183   // The child is embedded in a sub-folder.
184   // We first check if the sub-folder already exist:
185   TreeItem * folder = this->childByLabel(relativePath[0]);
186   if ( folder == NULL )
187     return;
188
189   // Go down into subfolder, if any.
190   QStringList nextRelativePath;
191   for (int i = 1; i < relativePath.size(); ++i)
192     nextRelativePath << relativePath[i];
193
194   folder->removeChild(dataObject, nextRelativePath);
195
196   if (folder->childCount() == 0)
197     this->removeChild(folder);
198 }
199
200 /*!
201  * The child() function returns the child that corresponds to the
202  * specified row number in the item's list of child items.
203  */
204 TreeItem *TreeItem::child(int row)
205 {
206   return _childItems.value(row);
207 }
208
209 TreeItem *TreeItem::childById(const QString &nameId)
210 {
211   QMap <QString, TreeItem*>::iterator it;
212   it = _childItemsMapById.find ( nameId );
213
214   if ( it != _childItemsMapById.end() ) {
215     return it.value();
216   }
217   return NULL;
218 }
219
220 TreeItem *TreeItem::childByLabel(const QString &label)
221 {
222   QMap <QString, TreeItem*>::iterator it;
223   it = _childItemsMapByLabel.find ( label );
224
225   if ( it != _childItemsMapByLabel.end() ) {
226     return it.value();
227   }
228   return NULL;
229 }
230
231
232
233 int TreeItem::childCount() const
234 {
235   return _childItems.count();
236 }
237
238 /*!
239  * The rowIndex() function reports the item's location within its
240  * parent's list of items.
241  */
242 int TreeItem::rowIndex() const
243 {
244   if (_parentItem)
245     return _parentItem->_childItems.indexOf(const_cast<TreeItem*>(this));
246
247   return 0;
248 }
249
250 int TreeItem::columnCount() const
251 {
252   return _itemData.count();
253 }
254
255 QVariant TreeItem::data(int column) const
256 {
257   return _itemData.value(column);
258 }
259
260 TreeItem *TreeItem::parent()
261 {
262   return _parentItem;
263 }
264
265 bool TreeItem::setData(int column, const QVariant &value)
266 {
267   if (column < 0 || column >= _itemData.size())
268     return false;
269
270   _itemData[column] = value;
271   return true;
272 }
273
274 QModelIndex TreeItem::modelIndex(int column)
275 {
276   TreeModel * model = this->associatedModel();
277   if (_parentItem && (_parentItem != model->getRootItem()))
278     return model->index(rowIndex(),
279                         column,
280                         _parentItem->modelIndex());
281   else
282     return model->index(rowIndex(),
283                         column,
284                         QModelIndex());
285 }