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 
55 //******************************************************************************
56 
61 TreeModel::TreeModel( QObject *_parent) : QAbstractItemModel(_parent)
62 {
63  rootItem_ = new TreeItem( -1, "ROOT", DATA_UNKNOWN, 0);
64 }
65 
66 
67 //******************************************************************************
68 
73 {
74 
75 }
76 
77 
78 //******************************************************************************
79 
80 int TreeModel::columnCount(const QModelIndex &/*_parent*/) const
81 {
82  // Id, Name -> 2
83  return (2);
84 }
85 
86 
87 //******************************************************************************
88 
95 QVariant TreeModel::data(const QModelIndex &_index, int _role) const
96 {
97 
98  // Skip invalid requests
99  if (!_index.isValid())
100  return QVariant();
101 
102  // Get the corresponding tree item
103  TreeItem *item = static_cast<TreeItem*>(_index.internalPointer());
104 
105  if ( item == rootItem_ ) {
106  std::cerr << "Root" << std::endl;
107  }
108 
109  // Set the background color of the objects row
110  if ( _role == Qt::BackgroundRole ) {
111  if ( !item->visible() ) {
112  return QVariant (QBrush (QColor (192, 192, 192)));
113  }
114  }
115 
116  if (_role == Qt::DisplayRole)
117  {
118  switch (_index.column ())
119  {
120  case 0:
121  return QVariant(item->id());
122  case 1:
123  return QVariant(item->name());
124  default:
125  return QVariant ();
126  }
127  }
128  else
129  return QVariant ();
130 }
131 
132 
133 //******************************************************************************
134 
140 Qt::ItemFlags TreeModel::flags(const QModelIndex &_index) const
141 {
142  if (!_index.isValid())
143  return 0;
144 
145  Qt::ItemFlags flags = 0;
146 
147  // Show/Source/Target
148  if ( _index.column() == 0 || _index.column() == 1 )
149  flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
150  else
151  flags = Qt::ItemIsEnabled;
152 
153  return flags;
154 }
155 
156 
157 //******************************************************************************
158 
166 QVariant TreeModel::headerData(int _section, Qt::Orientation _orientation,
167  int _role) const
168 {
169  if (_orientation == Qt::Horizontal && _role == Qt::DisplayRole) {
170 
171  if (_section == 0)
172  return QVariant("ID");
173  else if (_section == 1)
174  return QVariant("Name");
175  else
176  return QVariant();
177 
178  }
179  return QVariant();
180 }
181 
182 
183 //******************************************************************************
184 
192 QModelIndex TreeModel::index(int _row, int _column, const QModelIndex &_parent) const
193 {
194  TreeItem *parentItem;
195 
196  if (!_parent.isValid())
197  parentItem = rootItem_;
198  else
199  parentItem = static_cast<TreeItem*>(_parent.internalPointer());
200 
201  TreeItem *childItem = parentItem->child(_row);
202  if (childItem)
203  return createIndex(_row, _column, childItem);
204  else
205  return QModelIndex();
206 }
207 
208 
209 //******************************************************************************
210 
216 QModelIndex TreeModel::parent(const QModelIndex &_index) const
217 {
218  if (!_index.isValid())
219  return QModelIndex();
220 
221  TreeItem *childItem = static_cast<TreeItem*>(_index.internalPointer());
222  TreeItem *parentItem = childItem->parent();
223 
224  if (parentItem == rootItem_)
225  return QModelIndex();
226 
227  return createIndex(parentItem->row(), 0, parentItem);
228 }
229 
230 
231 //******************************************************************************
232 
238 int TreeModel::rowCount(const QModelIndex &_parent) const
239 {
240  TreeItem *parentItem;
241  if (_parent.column() > 0)
242  return 0;
243 
244  if (!_parent.isValid())
245  parentItem = rootItem_;
246  else
247  parentItem = static_cast<TreeItem*>(_parent.internalPointer());
248 
249  return parentItem->childCount();
250 }
251 
252 
253 //******************************************************************************
254 
259 void TreeModel::objectChanged(int _id) {
260 
261  if ( _id != -1 ){
262 
263  BaseObject* obj = 0;
264  PluginFunctions::getObject(_id, obj);
265 
266  TreeItem* item = rootItem_->childExists(_id);
267 
268  //if internal and external representation are both valid
269  if (obj != 0 && item != 0){
270  //update the name
271  if ( obj->name() != item->name() ){
272 
273  item->name( obj->name() );
274 
275  QModelIndex index = getModelIndex(item,0);
276  if ( index.isValid() )
277  emit dataChanged( index, index);
278  }
279 
280  //update visibility
281  if ( obj->visible() != item->visible() || obj->isGroup() ){
282 
283  item->visible( obj->visible() );
284 
285  QModelIndex index0 = getModelIndex(item,0);
286  QModelIndex index1 = getModelIndex(item,3);
287 
288  if ( index0.isValid() && index1.isValid() ){
289  //the whole row has to be updated because of the grey background-color
290  emit dataChanged( index0, index1);
291  propagateUpwards(item->parent(), 1, obj->visible() );
292  }
293 
294  if ( obj->isGroup() )
295  propagateDownwards(item, 1 );
296  }
297 
298  //update parent
299  if ( obj->parent() == PluginFunctions::objectRoot() && isRoot( item->parent() ) ){
300  return;
301  }else if ( obj->parent() == PluginFunctions::objectRoot() && !isRoot( item->parent() ) ){
302  moveItem(item, rootItem_ );
303  }else if ( obj->parent()->id() != item->parent()->id() ){
304  TreeItem* parent = rootItem_->childExists( obj->parent()->id() );
305 
306  if (parent != 0)
307  moveItem(item, parent );
308  }
309  }
310  }
311 }
312 
313 
318 void TreeModel::objectAdded(BaseObject* _object){
319 
320  objectAdded (_object, _object->parent());
321 }
322 
329 
330  if (rootItem_->childExists(_object->id()))
331  return;
332 
333  TreeItem* parent = 0;
334  //find the parent
335  if ( _parent == PluginFunctions::objectRoot() )
336  parent = rootItem_;
337  else
338  parent = rootItem_->childExists( _parent->id() );
339 
340  if (!parent)
341  {
342  objectAdded(_parent);
343  parent = rootItem_->childExists( _parent->id() );
344  }
345 
346  QModelIndex parentIndex = getModelIndex(parent, 0);
347 
348  beginInsertRows(parentIndex, parent->childCount(), parent->childCount()); //insert at the bottom
349 
350  TreeItem* item = new TreeItem( _object->id(), _object->name(), _object->dataType(), parent);
351 
352  parent->appendChild( item );
353 
354  endInsertRows();
355 
356  objectChanged( _object->id() );
357 }
358 
363 void TreeModel::objectDeleted(int _id){
364 
365  TreeItem* item = rootItem_->childExists(_id);
366 
367  if ( item != 0 && !isRoot(item) ){
368 
369  QModelIndex itemIndex = getModelIndex(item, 0);
370  QModelIndex parentIndex = itemIndex.parent();
371 
372  beginRemoveRows( parentIndex, itemIndex.row(), itemIndex.row() );
373 
374  item->parent()->removeChild(item);
375  item->deleteSubtree();
376 
377  delete item;
378 
379  endRemoveRows();
380  }
381 }
382 
383 //******************************************************************************
384 
390 void TreeModel::moveItem(TreeItem* _item, TreeItem* _parent ){
391 
392  QModelIndex itemIndex = getModelIndex(_item, 0);
393  QModelIndex oldParentIndex = itemIndex.parent();
394  QModelIndex newParentIndex = getModelIndex(_parent, 0);
395 
396  //delete everything at the old location
397  beginRemoveRows( oldParentIndex, itemIndex.row(), itemIndex.row() );
398 
399  _item->parent()->removeChild(_item);
400 
401  endRemoveRows();
402 
403  //insert it at the new location
404  beginInsertRows(newParentIndex, _parent->childCount(), _parent->childCount() ); //insert at the bottom
405  _item->setParent( _parent );
406  _parent->appendChild( _item );
407  endInsertRows();
408 
409  emit layoutChanged();
410 }
411 
412 //******************************************************************************
413 
419 TreeItem* TreeModel::getItem(const QModelIndex &_index) const
420 {
421  if (_index.isValid()) {
422  TreeItem *item = static_cast<TreeItem*>(_index.internalPointer());
423  if (item) return item;
424  }
425  return rootItem_;
426 }
427 
428 
429 //******************************************************************************
430 
436 QString TreeModel::itemName(const QModelIndex &_index) const
437 {
438  if (_index.isValid()) {
439  TreeItem *item = static_cast<TreeItem*>(_index.internalPointer());
440  if (item)
441  return item->name();
442  }
443  return "not found";
444 }
445 
446 //******************************************************************************
447 
453 int TreeModel::itemId(const QModelIndex &_index) const
454 {
455  if (_index.isValid()) {
456  TreeItem *item = static_cast<TreeItem*>(_index.internalPointer());
457  if (item)
458  return item->id();
459  }
460  return -1;
461 }
462 
463 //******************************************************************************
464 
473 QModelIndex TreeModel::getModelIndex(TreeItem* _object, int _column ){
474 
475  // root item gets an invalid QModelIndex
476  if ( _object == rootItem_ )
477  return QModelIndex();
478 
479  QModelIndex index = createIndex(_object->row(), _column, _object);
480 
481  return index;
482 }
483 
484 //******************************************************************************
485 
494 QModelIndex TreeModel::getModelIndex(int _id, int _column ){
495 
496  TreeItem *obj = rootItem_->childExists(_id);
497 
498  if (obj)
499  return getModelIndex (obj, _column);
500 
501  return QModelIndex();
502 }
503 
504 
505 //******************************************************************************
506 
513 void TreeModel::propagateUpwards(TreeItem* _item, int _column, bool _value ){
514 
515  if ( isRoot(_item) || (!_item->isGroup()) )
516  return;
517 
518  if (_column == 1){ //visibility
519  _item->visible( _value );
520 
521  //the whole row has to be updated because of the grey background-color
522  QModelIndex index0 = getModelIndex(_item,0);
523  QModelIndex index1 = getModelIndex(_item,3);
524 
525  emit dataChanged( index0, index1);
526 
527  } else {
528 
529  QModelIndex index = getModelIndex(_item,_column);
530  emit dataChanged(index, index);
531  }
532 
533  propagateUpwards( _item->parent(), _column, _value );
534 }
535 
536 //******************************************************************************
537 
543 void TreeModel::propagateDownwards(TreeItem* _item, int _column ){
544 
545  for (int i=0; i < _item->childCount(); i++){
546 
547  TreeItem* current = _item->child(i);
548 
549  bool changed = false;
550 
551  switch ( _column ){
552 
553  case 1: //VISIBILTY
554 
555  if ( current->visible() != _item->visible() ){
556 
557  current->visible( _item->visible() );
558  changed = true;
559  }
560  break;
561 
562  default:
563  break;
564  }
565 
566  if (changed){
567  QModelIndex index = getModelIndex(current,_column);
568  emit dataChanged(index, index);
569  }
570 
571  if ( current->isGroup() )
572  propagateDownwards(current, _column);
573  }
574 }
575 
576 //******************************************************************************
577 
578 bool TreeModel::setData(const QModelIndex &_index, const QVariant &_value, int /*role*/)
579 {
580 
581  emit dataChangedInside( itemId(_index), _index.column(), _value );
582 
583  return true;
584 }
585 
586 
587 //******************************************************************************
588 
594 bool TreeModel::isRoot(TreeItem * _item) {
595  return ( _item == rootItem_ );
596 }
~TreeModel()
Destructor.
Definition: TreeModel.cc:72
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
QModelIndex getModelIndex(TreeItem *_object, int _column)
Return the ModelIndex corresponding to a given TreeItem and Column.
Definition: TreeModel.cc:562
TreeItem * child(int row)
return a child
Definition: TreeItem.cc:257
TreeItem * childExists(int _objectId)
Check if the element exists in the subtree of this element.
Definition: TreeItem.cc:271
int columnCount(const QModelIndex &_parent=QModelIndex()) const
Return the number of columns.
Definition: TreeModel.cc:80
QModelIndex parent(const QModelIndex &_index) const
Get the parent ModelIndex.
Definition: TreeModel.cc:312
bool getObject(const int _identifier, BaseObject *&_object)
Get the object which has the given identifier.
BaseObject *& objectRoot()
Get the root of the object structure.
bool visible()
visible
Definition: TreeItem.cc:151
Qt::ItemFlags flags(const QModelIndex &_index) const
return the types of the corresponding entry
Definition: TreeModel.cc:221
QVariant headerData(int _section, Qt::Orientation _orientation, int _role=Qt::DisplayRole) const
return the header data of the model
Definition: TreeModel.cc:258
void setParent(TreeItem *_parent)
Set the parent pointer.
Definition: TreeItem.cc:242
void moveItem(TreeItem *_item, TreeItem *_parent)
move the item to a new parent
Definition: TreeModel.cc:488
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
TreeItem * getItem(const QModelIndex &_index) const
Get the TreeItem corresponding to a given ModelIndex.
Definition: TreeModel.cc:508
bool dataType(DataType _type) const
Definition: BaseObject.cc:221
QVariant data(const QModelIndex &_index, int _role) const
Get the data of the corresponding entry.
Definition: TreeModel.cc:95
int itemId(const QModelIndex &_index) const
Get the id of a TreeItem corresponding to a given ModelIndex.
Definition: TreeModel.cc:542
QModelIndex index(int _row, int _column, const QModelIndex &_parent=QModelIndex()) const
Get the ModelIndex at given row,column.
Definition: TreeModel.cc:285
BaseObject * parent()
Get the parent item ( 0 if rootitem )
Definition: BaseObject.cc:466
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
QString itemName(const QModelIndex &_index) const
Get the name of a TreeItem corresponding to a given ModelIndex.
Definition: TreeModel.cc:525
bool isRoot(TreeItem *_item)
Check if the given item is the root item.
Definition: TreeModel.cc:592
void propagateDownwards(TreeItem *_obj, int _column)
Recursively update a column up to the root of the tree.
Definition: TreeModel.cc:543
bool isGroup() const
Check if object is a group.
Definition: BaseObject.cc:619
void objectDeleted(int _id)
The object with the given id has been deleted. delete it from the internal tree.
Definition: TreeModel.cc:461
void objectChanged(int _id)
The object with the given id has been changed. Check if model also has to be changed.
Definition: TreeModel.cc:353
void propagateUpwards(TreeItem *_obj, int _column, bool _value)
Recursively update a column up to the root of the tree.
Definition: TreeModel.cc:513
virtual bool visible()
return if object is visible
Definition: BaseObject.cc:339
int rowCount(const QModelIndex &_parent=QModelIndex()) const
get the number of rows
Definition: TreeModel.cc:334
TreeModel(QObject *_parent=0)
Constructor.
Definition: TreeModel.cc:61
void objectAdded(BaseObject *_object)
The object with the given id has been added. add it to the internal tree.
Definition: TreeModel.cc:426
TreeItem * rootItem_
Root item of the tree.
Definition: TreeModel.hh:161
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
bool setData(const QModelIndex &_index, const QVariant &_value, int _role)
Set Data at &#39;index&#39; to &#39;value&#39;.
Definition: TreeModel.cc:575
const DataType DATA_UNKNOWN(0)
None of the other Objects.