Developer Documentation
TreeModel.cc
1 /*===========================================================================*\
2 * *
3 * OpenFlipper *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openflipper.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenFlipper. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39 * *
40 \*===========================================================================*/
41 
42 
43 
44 
45 
46 #include "TreeModel.hh"
47 
48 
50 
51 
52 #include <QtWidgets>
53 
54 namespace VSI {
55 
56 //******************************************************************************
57 
62 TreeModel::TreeModel( QObject *_parent) : QAbstractItemModel(_parent)
63 {
64  rootItem_ = new TreeItem( -1, "ROOT", DATA_UNKNOWN, 0);
65 }
66 
67 
68 //******************************************************************************
69 
74 {
75 
76 }
77 
78 
79 //******************************************************************************
80 
81 int TreeModel::columnCount(const QModelIndex &/*_parent*/) const
82 {
83  // Id, Name -> 2
84  return (2);
85 }
86 
87 
88 //******************************************************************************
89 
96 QVariant TreeModel::data(const QModelIndex &_index, int _role) const
97 {
98 
99  // Skip invalid requests
100  if (!_index.isValid())
101  return QVariant();
102 
103  // Get the corresponding tree item
104  TreeItem *item = static_cast<TreeItem*>(_index.internalPointer());
105 
106  if ( item == rootItem_ ) {
107  std::cerr << "Root" << std::endl;
108  }
109 
110  // Set the background color of the objects row
111  if ( _role == Qt::BackgroundRole ) {
112  if ( !item->visible() ) {
113  return QVariant (QBrush (QColor (192, 192, 192)));
114  }
115  }
116 
117  if (_role == Qt::DisplayRole)
118  {
119  switch (_index.column ())
120  {
121  case 0:
122  return QVariant(item->id());
123  case 1:
124  return QVariant(item->name());
125  default:
126  return QVariant ();
127  }
128  }
129  else
130  return QVariant ();
131 }
132 
133 
134 //******************************************************************************
135 
141 Qt::ItemFlags TreeModel::flags(const QModelIndex &_index) const
142 {
143 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
144  if (!_index.isValid())
145  return 0;
146 
147  Qt::ItemFlags flags = 0;
148 #else
149  if (!_index.isValid())
150  return Qt::ItemFlags();
151 
152  Qt::ItemFlags flags = Qt::ItemFlags();
153 #endif
154 
155  // Show/Source/Target
156  if ( _index.column() == 0 || _index.column() == 1 )
157  flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
158  else
159  flags = Qt::ItemIsEnabled;
160 
161  return flags;
162 }
163 
164 
165 //******************************************************************************
166 
174 QVariant TreeModel::headerData(int _section, Qt::Orientation _orientation,
175  int _role) const
176 {
177  if (_orientation == Qt::Horizontal && _role == Qt::DisplayRole) {
178 
179  if (_section == 0)
180  return QVariant("ID");
181  else if (_section == 1)
182  return QVariant("Name");
183  else
184  return QVariant();
185 
186  }
187  return QVariant();
188 }
189 
190 
191 //******************************************************************************
192 
200 QModelIndex TreeModel::index(int _row, int _column, const QModelIndex &_parent) const
201 {
202  TreeItem *parentItem;
203 
204  if (!_parent.isValid())
205  parentItem = rootItem_;
206  else
207  parentItem = static_cast<TreeItem*>(_parent.internalPointer());
208 
209  TreeItem *childItem = parentItem->child(_row);
210  if (childItem)
211  return createIndex(_row, _column, childItem);
212  else
213  return QModelIndex();
214 }
215 
216 
217 //******************************************************************************
218 
224 QModelIndex TreeModel::parent(const QModelIndex &_index) const
225 {
226  if (!_index.isValid())
227  return QModelIndex();
228 
229  TreeItem *childItem = static_cast<TreeItem*>(_index.internalPointer());
230  TreeItem *parentItem = childItem->parent();
231 
232  if (parentItem == rootItem_)
233  return QModelIndex();
234 
235  return createIndex(parentItem->row(), 0, parentItem);
236 }
237 
238 
239 //******************************************************************************
240 
246 int TreeModel::rowCount(const QModelIndex &_parent) const
247 {
248  TreeItem *parentItem;
249  if (_parent.column() > 0)
250  return 0;
251 
252  if (!_parent.isValid())
253  parentItem = rootItem_;
254  else
255  parentItem = static_cast<TreeItem*>(_parent.internalPointer());
256 
257  return parentItem->childCount();
258 }
259 
260 
261 //******************************************************************************
262 
268 
269  if ( _id != -1 ){
270 
271  BaseObject* obj = 0;
272  PluginFunctions::getObject(_id, obj);
273 
274  TreeItem* item = rootItem_->childExists(_id);
275 
276  //if internal and external representation are both valid
277  if (obj != 0 && item != 0){
278  //update the name
279  if ( obj->name() != item->name() ){
280 
281  item->name( obj->name() );
282 
283  QModelIndex index = getModelIndex(item,0);
284  if ( index.isValid() )
285  emit dataChanged( index, index);
286  }
287 
288  //update visibility
289  if ( obj->visible() != item->visible() || obj->isGroup() ){
290 
291  item->visible( obj->visible() );
292 
293  QModelIndex index0 = getModelIndex(item,0);
294  QModelIndex index1 = getModelIndex(item,3);
295 
296  if ( index0.isValid() && index1.isValid() ){
297  //the whole row has to be updated because of the grey background-color
298  emit dataChanged( index0, index1);
299  propagateUpwards(item->parent(), 1, obj->visible() );
300  }
301 
302  if ( obj->isGroup() )
303  propagateDownwards(item, 1 );
304  }
305 
306  //update parent
307  if ( obj->parent() == PluginFunctions::objectRoot() && isRoot( item->parent() ) ){
308  return;
309  }else if ( obj->parent() == PluginFunctions::objectRoot() && !isRoot( item->parent() ) ){
310  moveItem(item, rootItem_ );
311  }else if ( obj->parent()->id() != item->parent()->id() ){
312  TreeItem* parent = rootItem_->childExists( obj->parent()->id() );
313 
314  if (parent != 0)
315  moveItem(item, parent );
316  }
317  }
318  }
319 }
320 
321 
327 
328  objectAdded (_object, _object->parent());
329 }
330 
337 
338  if (rootItem_->childExists(_object->id()))
339  return;
340 
341  TreeItem* parent = 0;
342  //find the parent
343  if ( _parent == PluginFunctions::objectRoot() )
344  parent = rootItem_;
345  else
346  parent = rootItem_->childExists( _parent->id() );
347 
348  if (!parent)
349  {
350  objectAdded(_parent);
351  parent = rootItem_->childExists( _parent->id() );
352  }
353 
354  QModelIndex parentIndex = getModelIndex(parent, 0);
355 
356  beginInsertRows(parentIndex, parent->childCount(), parent->childCount()); //insert at the bottom
357 
358  TreeItem* item = new TreeItem( _object->id(), _object->name(), _object->dataType(), parent);
359 
360  parent->appendChild( item );
361 
362  endInsertRows();
363 
364  objectChanged( _object->id() );
365 }
366 
372 
373  TreeItem* item = rootItem_->childExists(_id);
374 
375  if ( item != 0 && !isRoot(item) ){
376 
377  QModelIndex itemIndex = getModelIndex(item, 0);
378  QModelIndex parentIndex = itemIndex.parent();
379 
380  beginRemoveRows( parentIndex, itemIndex.row(), itemIndex.row() );
381 
382  item->parent()->removeChild(item);
383  item->deleteSubtree();
384 
385  delete item;
386 
387  endRemoveRows();
388  }
389 }
390 
391 //******************************************************************************
392 
398 void TreeModel::moveItem(TreeItem* _item, TreeItem* _parent ){
399 
400  QModelIndex itemIndex = getModelIndex(_item, 0);
401  QModelIndex oldParentIndex = itemIndex.parent();
402  QModelIndex newParentIndex = getModelIndex(_parent, 0);
403 
404  //delete everything at the old location
405  beginRemoveRows( oldParentIndex, itemIndex.row(), itemIndex.row() );
406 
407  _item->parent()->removeChild(_item);
408 
409  endRemoveRows();
410 
411  //insert it at the new location
412  beginInsertRows(newParentIndex, _parent->childCount(), _parent->childCount() ); //insert at the bottom
413  _item->setParent( _parent );
414  _parent->appendChild( _item );
415  endInsertRows();
416 
417  emit layoutChanged();
418 }
419 
420 //******************************************************************************
421 
427 TreeItem* TreeModel::getItem(const QModelIndex &_index) const
428 {
429  if (_index.isValid()) {
430  TreeItem *item = static_cast<TreeItem*>(_index.internalPointer());
431  if (item) return item;
432  }
433  return rootItem_;
434 }
435 
436 
437 //******************************************************************************
438 
444 QString TreeModel::itemName(const QModelIndex &_index) const
445 {
446  if (_index.isValid()) {
447  TreeItem *item = static_cast<TreeItem*>(_index.internalPointer());
448  if (item)
449  return item->name();
450  }
451  return "not found";
452 }
453 
454 //******************************************************************************
455 
461 int TreeModel::itemId(const QModelIndex &_index) const
462 {
463  if (_index.isValid()) {
464  TreeItem *item = static_cast<TreeItem*>(_index.internalPointer());
465  if (item)
466  return item->id();
467  }
468  return -1;
469 }
470 
471 //******************************************************************************
472 
481 QModelIndex TreeModel::getModelIndex(TreeItem* _object, int _column ){
482 
483  // root item gets an invalid QModelIndex
484  if ( _object == rootItem_ )
485  return QModelIndex();
486 
487  QModelIndex index = createIndex(_object->row(), _column, _object);
488 
489  return index;
490 }
491 
492 //******************************************************************************
493 
502 QModelIndex TreeModel::getModelIndex(int _id, int _column ){
503 
504  TreeItem *obj = rootItem_->childExists(_id);
505 
506  if (obj)
507  return getModelIndex (obj, _column);
508 
509  return QModelIndex();
510 }
511 
512 
513 //******************************************************************************
514 
521 void TreeModel::propagateUpwards(TreeItem* _item, int _column, bool _value ){
522 
523  if ( isRoot(_item) || (!_item->isGroup()) )
524  return;
525 
526  if (_column == 1){ //visibility
527  _item->visible( _value );
528 
529  //the whole row has to be updated because of the grey background-color
530  QModelIndex index0 = getModelIndex(_item,0);
531  QModelIndex index1 = getModelIndex(_item,3);
532 
533  emit dataChanged( index0, index1);
534 
535  } else {
536 
537  QModelIndex index = getModelIndex(_item,_column);
538  emit dataChanged(index, index);
539  }
540 
541  propagateUpwards( _item->parent(), _column, _value );
542 }
543 
544 //******************************************************************************
545 
551 void TreeModel::propagateDownwards(TreeItem* _item, int _column ){
552 
553  for (int i=0; i < _item->childCount(); i++){
554 
555  TreeItem* current = _item->child(i);
556 
557  bool changed = false;
558 
559  switch ( _column ){
560 
561  case 1: //VISIBILTY
562 
563  if ( current->visible() != _item->visible() ){
564 
565  current->visible( _item->visible() );
566  changed = true;
567  }
568  break;
569 
570  default:
571  break;
572  }
573 
574  if (changed){
575  QModelIndex index = getModelIndex(current,_column);
576  emit dataChanged(index, index);
577  }
578 
579  if ( current->isGroup() )
580  propagateDownwards(current, _column);
581  }
582 }
583 
584 //******************************************************************************
585 
586 bool TreeModel::setData(const QModelIndex &_index, const QVariant &_value, int /*role*/)
587 {
588 
589  emit dataChangedInside( itemId(_index), _index.column(), _value );
590 
591  return true;
592 }
593 
594 
595 //******************************************************************************
596 
603  return ( _item == rootItem_ );
604 }
605 
606 
607 } // namespace VSI
int itemId(const QModelIndex &_index) const
Get the id of a TreeItem corresponding to a given ModelIndex.
Definition: TreeModel.cc:461
QString itemName(const QModelIndex &_index) const
Get the name of a TreeItem corresponding to a given ModelIndex.
Definition: TreeModel.cc:444
int row() const
get the row of this item from the parent
Definition: TreeItem.cc:228
void deleteSubtree()
delete the whole subtree below this item ( The item itself is not touched )
Definition: TreeItem.cc:343
void moveItem(TreeItem *_item, TreeItem *_parent)
move the item to a new parent
Definition: TreeModel.cc:398
TreeItem * child(int row)
return a child
Definition: TreeItem.cc:257
TreeModel(QObject *_parent=0)
Constructor.
Definition: TreeModel.cc:62
TreeItem * childExists(int _objectId)
Check if the element exists in the subtree of this element.
Definition: TreeItem.cc:271
bool getObject(const int _identifier, BaseObject *&_object)
Get the object which has the given identifier.
BaseObject *& objectRoot()
Get the root of the object structure.
int columnCount(const QModelIndex &_parent=QModelIndex()) const
Return the number of columns.
Definition: TreeModel.cc:81
bool visible()
visible
Definition: TreeItem.cc:151
void objectDeleted(int id_)
The object with the given id has been deleted. delete it from the internal tree.
Definition: TreeModel.cc:371
void setParent(TreeItem *_parent)
Set the parent pointer.
Definition: TreeItem.cc:242
bool setData(const QModelIndex &_index, const QVariant &_value, int _role)
Set Data at &#39;index&#39; to &#39;value&#39;.
Definition: TreeModel.cc:586
QVariant headerData(int _section, Qt::Orientation _orientation, int _role=Qt::DisplayRole) const
return the header data of the model
Definition: TreeModel.cc:174
TreeItem * parent()
Get the parent item ( 0 if root item )
Definition: TreeItem.cc:235
void appendChild(TreeItem *child)
add a child to this node
Definition: TreeItem.cc:248
int id() const
Definition: BaseObject.cc:190
bool dataType(DataType _type) const
Definition: BaseObject.cc:221
QModelIndex parent(const QModelIndex &_index) const
Get the parent ModelIndex.
Definition: TreeModel.cc:224
BaseObject * parent()
Get the parent item ( 0 if rootitem )
Definition: BaseObject.cc:466
~TreeModel()
Destructor.
Definition: TreeModel.cc:73
void objectAdded(BaseObject *_object)
The object with the given id has been added. add it to the internal tree.
Definition: TreeModel.cc:326
int id()
id
Definition: TreeItem.cc:78
QString name() const
return the name of the object. The name defaults to NONAME if unset.
Definition: BaseObject.cc:730
QString name()
name
Definition: TreeItem.cc:163
void objectChanged(int id_)
The object with the given id has been changed. Check if model also has to be changed.
Definition: TreeModel.cc:267
QModelIndex index(int _row, int _column, const QModelIndex &_parent=QModelIndex()) const
Get the ModelIndex at given row,column.
Definition: TreeModel.cc:200
bool isGroup() const
Check if object is a group.
Definition: BaseObject.cc:619
QVariant data(const QModelIndex &_index, int _role) const
Get the data of the corresponding entry.
Definition: TreeModel.cc:96
void propagateUpwards(TreeItem *_obj, int _column, bool _value)
Recursively update a column up to the root of the tree.
Definition: TreeModel.cc:521
Qt::ItemFlags flags(const QModelIndex &_index) const
return the types of the corresponding entry
Definition: TreeModel.cc:141
void propagateDownwards(TreeItem *_obj, int _column)
Recursively update a column up to the root of the tree.
Definition: TreeModel.cc:551
bool isRoot(TreeItem *_item)
Check if the given item is the root item.
Definition: TreeModel.cc:602
virtual bool visible()
return if object is visible
Definition: BaseObject.cc:339
TreeItem * getItem(const QModelIndex &_index) const
Get the TreeItem corresponding to a given ModelIndex.
Definition: TreeModel.cc:427
int rowCount(const QModelIndex &_parent=QModelIndex()) const
get the number of rows
Definition: TreeModel.cc:246
QModelIndex getModelIndex(TreeItem *_object, int _column)
Return the ModelIndex corresponding to a given TreeItem and Column.
Definition: TreeModel.cc:481
TreeItem * rootItem_
Rootitem of the tree.
Definition: TreeModel.hh:163
void removeChild(TreeItem *_item)
Remove a child from this object.
Definition: TreeItem.cc:308
int childCount() const
get the number of children
Definition: TreeItem.cc:264
const DataType DATA_UNKNOWN(0)
None of the other Objects.