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 #include "TreeModel.hh"
45 
46  #include <QtWidgets>
47 
48 
51 
52 #include <ObjectTypes/Light/LightWidget.hh>
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  // Name,Visible,Source,Target -> 4
83  return (4);
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(100,100,100) ) );
113  }
114  }
115 
116 
117 
118  switch (_index.column() ) {
119  // Name
120  case 0 :
121 
122  // If we are setting the name, also add the icon
123  if ( _role == Qt::DecorationRole ) {
124  if (item->dataType() == DATA_LIGHT)
125  {
126  LightObject* light = 0;
127  if (item->id() != -1 && PluginFunctions::getObject( item->id(), light ) ) {
128  if (light != 0 && !light->lightSource()->enabled())
129  return QVariant (QIcon (OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"LightOff.png"));
130  }
131  }
132  return QVariant( typeIcon(item->dataType()) );
133  }
134 
135  if (_role != Qt::DisplayRole && _role != Qt::EditRole )
136  return QVariant();
137 
138  return QVariant(item->name());
139 
140  break;
141  // Visible
142  case 1 :
143  if (_role == Qt::CheckStateRole ) {
144  bool visible = false;
145  // target group
146  if (item->isGroup() && item->childCount() > 0)
147  {
148  QList< TreeItem* > children = item->getLeafs();
149 
150  visible = children[0]->visible();
151  for (int i=0; i < children.size() ; ++i)
152  {
153  if (visible != children[i]->visible())
154  return QVariant(Qt::PartiallyChecked);
155  }
156  }
157  else
158  visible = item->visible();
159  return (visible) ? QVariant(Qt::Checked) : QVariant(Qt::Unchecked);
160  }
161  return QVariant();
162  // Source
163  case 2 :
164  if (_role == Qt::CheckStateRole ) {
165  bool source = false;
166  // target group
167  if (item->isGroup() && item->childCount() > 0)
168  {
169  QList< TreeItem* > children = item->getLeafs();
170 
171  source = children[0]->source();
172  for (int i=0; i < children.size() ; ++i)
173  {
174  if (source != children[i]->source())
175  return QVariant(Qt::PartiallyChecked);
176  }
177  }
178  else
179  source = item->source();
180  return (source) ? QVariant(Qt::Checked) : QVariant(Qt::Unchecked);
181  }
182  return QVariant();
183 
184  // Target
185  case 3 :
186  if (_role == Qt::CheckStateRole ) {
187  bool target = false;
188  // target group
189  if (item->isGroup() && item->childCount() > 0)
190  {
191  QList< TreeItem* > children = item->getLeafs();
192 
193  target = children[0]->target();
194  for (int i=0; i < children.size() ; ++i)
195  {
196  if (target != children[i]->target())
197  return QVariant(Qt::PartiallyChecked);
198  }
199  }
200  else
201  target = item->target();
202  return (target) ? QVariant(Qt::Checked) : QVariant(Qt::Unchecked);
203  }
204  return QVariant();
205 
206  default:
207  return QVariant();
208  }
209  return QVariant();
210 
211 }
212 
213 
214 //******************************************************************************
215 
221 Qt::ItemFlags TreeModel::flags(const QModelIndex &_index) const
222 {
223  if (!_index.isValid())
224  return 0;
225 
226  Qt::ItemFlags flags = 0;
227 
228  // Show/Source/Target
229  if ( ( _index.column() == 1 ) ||
230  ( _index.column() == 2 ) ||
231  ( _index.column() == 3 ) )
232  flags = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
233  else
234  if ( _index.column() == 0 )
235  flags = Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
236  else
237  flags = Qt::ItemIsEnabled;
238 
239  // Get the corresponding tree item
240  TreeItem *item = static_cast<TreeItem*>(_index.internalPointer());
241 
242  if ( item->isGroup() )
243  return flags | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
244  else
245  return flags | Qt::ItemIsDragEnabled;
246 }
247 
248 
249 //******************************************************************************
250 
258 QVariant TreeModel::headerData(int _section, Qt::Orientation _orientation,
259  int _role) const
260 {
261  if (_orientation == Qt::Horizontal && _role == Qt::DisplayRole) {
262 
263  switch (_section) {
264  case 0 : return QVariant("Name");
265  case 1 : return QVariant("Show");
266  case 2 : return QVariant("Source");
267  case 3 : return QVariant("Target");
268  default :
269  return QVariant();
270  }
271  }
272  return QVariant();
273 }
274 
275 
276 //******************************************************************************
277 
285 QModelIndex TreeModel::index(int _row, int _column,const QModelIndex &_parent) const
286 {
287 // if (!hasIndex(row, column, _parent))
288 // return QModelIndex();
289 
290  TreeItem *parentItem;
291 
292  if (!_parent.isValid())
293  parentItem = rootItem_;
294  else
295  parentItem = static_cast<TreeItem*>(_parent.internalPointer());
296 
297  TreeItem *childItem = parentItem->child(_row);
298  if (childItem)
299  return createIndex(_row, _column, childItem);
300  else
301  return QModelIndex();
302 }
303 
304 
305 //******************************************************************************
306 
312 QModelIndex TreeModel::parent(const QModelIndex &_index) const
313 {
314  if (!_index.isValid())
315  return QModelIndex();
316 
317  TreeItem *childItem = static_cast<TreeItem*>(_index.internalPointer());
318  TreeItem *parentItem = childItem->parent();
319 
320  if (parentItem == rootItem_)
321  return QModelIndex();
322 
323  return createIndex(parentItem->row(), 0, parentItem);
324 }
325 
326 
327 //******************************************************************************
328 
334 int TreeModel::rowCount(const QModelIndex &_parent) const
335 {
336  TreeItem *parentItem;
337  if (_parent.column() > 0)
338  return 0;
339 
340  if (!_parent.isValid())
341  parentItem = rootItem_;
342  else
343  parentItem = static_cast<TreeItem*>(_parent.internalPointer());
344 
345  return parentItem->childCount();
346 }
347 //******************************************************************************
348 
354 
355  if ( _id != -1 ){
356 
357  BaseObject* obj = 0;
358  PluginFunctions::getObject(_id, obj);
359 
360  TreeItem* item = rootItem_->childExists(_id);
361 
362  //if internal and external representation are both valid
363  if (obj != 0 && item != 0){
364  //update the name
365  bool updateRow = false;
366  if ( obj->name() != item->name() ){
367 
368  item->name( obj->name() );
369  updateRow = true;
370  }
371 
372  //update visibility
373  if ( obj->visible() != item->visible() ){
374 
375  item->visible( obj->visible() );
376  updateRow = true;
377  }
378 
379  //update source flag
380  if ( obj->source() != item->source() ){
381 
382  item->source( obj->source() );
383  updateRow = true;
384  }
385 
386  //update target flag
387  if ( obj->target() != item->target() ){
388 
389  item->target( obj->target() );
390  updateRow = true;
391  }
392  if (updateRow)
393  {
394  //TODO actually we do not need to update the whole row but single column somehow doesn't work
395  QModelIndex index0 = getModelIndex(item,0);
396  QModelIndex index1 = getModelIndex(item,3);
397 
398  if ( index0.isValid() && index1.isValid() ){
399  //the whole row has to be updated because of the grey background-color
400  emit dataChanged( index0, index1);
401  }
402  }
403 
404  //update parent
405  if ( obj->parent() == PluginFunctions::objectRoot() && isRoot( item->parent() ) ){
406  return;
407  }else if ( obj->parent() == PluginFunctions::objectRoot() && !isRoot( item->parent() ) ){
408  moveItem(item, rootItem_ );
409  }else if ( obj->parent()->id() != item->parent()->id() ){
410  TreeItem* parent = rootItem_->childExists( obj->parent()->id() );
411 
412  if (parent != 0)
413  moveItem(item, parent );
414  }
415 
416  }
417  }
418 
419 }
420 
421 
427 
428  // check if item already in model tree
429  // this function can be called by addEmpty and fileOpened
430  // both will be called by fileOpened such that the item
431  // already exists
432  if( rootItem_->childExists( _object->id() ))
433  return;
434 
435  TreeItem* parent = 0;
436  //find the parent
437  if ( _object->parent() == PluginFunctions::objectRoot() )
438  parent = rootItem_;
439  else
440  parent = rootItem_->childExists( _object->parent()->id() );
441 
442  if (parent != 0){
443  QModelIndex parentIndex = getModelIndex(parent, 0);
444 
445  beginInsertRows(parentIndex, parent->childCount(), parent->childCount()); //insert at the bottom
446 
447  TreeItem* item = new TreeItem( _object->id(), _object->name(), _object->dataType(), parent);
448 
449  parent->appendChild( item );
450 
451  endInsertRows();
452  }
453 
454  objectChanged( _object->id() );
455 }
456 
462 
463  TreeItem* item = rootItem_->childExists(_id);
464 
465  if ( item != 0 && !isRoot(item) ){
466 
467  QModelIndex itemIndex = getModelIndex(item, 0);
468  QModelIndex parentIndex = itemIndex.parent();
469 
470  beginRemoveRows( parentIndex, itemIndex.row(), itemIndex.row() );
471 
472  item->parent()->removeChild(item);
473  item->deleteSubtree();
474 
475  delete item;
476 
477  endRemoveRows();
478  }
479 }
480 
481 //******************************************************************************
482 
488 void TreeModel::moveItem(TreeItem* _item, TreeItem* _parent ){
489 
490  QModelIndex itemIndex = getModelIndex(_item, 0);
491  QModelIndex oldParentIndex = itemIndex.parent();
492  QModelIndex newParentIndex = getModelIndex(_parent, 0);
493 
494  beginMoveRows ( oldParentIndex, itemIndex.row(), itemIndex.row(), newParentIndex,0 );
495  _item->parent()->removeChild(_item);
496  _item->setParent( _parent );
497  _parent->appendChild( _item );
498  endMoveRows();
499 }
500 
501 //******************************************************************************
502 
508 TreeItem* TreeModel::getItem(const QModelIndex &_index) const
509 {
510  if (_index.isValid()) {
511  TreeItem *item = static_cast<TreeItem*>(_index.internalPointer());
512  if (item) return item;
513  }
514  return rootItem_;
515 }
516 
517 
518 //******************************************************************************
519 
525 QString TreeModel::itemName(const QModelIndex &_index) const
526 {
527  if (_index.isValid()) {
528  TreeItem *item = static_cast<TreeItem*>(_index.internalPointer());
529  if (item)
530  return item->name();
531  }
532  return "not found";
533 }
534 
535 //******************************************************************************
536 
542 int TreeModel::itemId(const QModelIndex &_index) const
543 {
544  if (_index.isValid()) {
545  TreeItem *item = static_cast<TreeItem*>(_index.internalPointer());
546  if (item)
547  return item->id();
548  }
549  return -1;
550 }
551 
552 //******************************************************************************
553 
562 QModelIndex TreeModel::getModelIndex(TreeItem* _object, int _column ){
563 
564  // root item gets an invalid QModelIndex
565  if ( _object == rootItem_ )
566  return QModelIndex();
567 
568  QModelIndex index = createIndex(_object->row(), _column, _object);
569 
570  return index;
571 }
572 
573 //******************************************************************************
574 
575 bool TreeModel::setData(const QModelIndex &_index, const QVariant &_value, int /*role*/)
576 {
577 
578  emit dataChangedInside( itemId(_index), _index.column(), _value );
579 
580 
581  return true;
582 }
583 
584 
585 //******************************************************************************
586 
593  return ( _item == rootItem_ );
594 }
595 
596 /*******************************************************************************
597  drag & drop stuff
598  *******************************************************************************/
599 
604 Qt::DropActions TreeModel::supportedDropActions() const
605 {
606  return /*Qt::CopyAction |*/ Qt::MoveAction;
607 }
608 
609 
610 //******************************************************************************
611 
616 QStringList TreeModel::mimeTypes() const
617 {
618  QStringList types;
619  types << "DataControl/dragDrop";
620  return types;
621 }
622 
623 
624 //******************************************************************************
625 
631 QMimeData* TreeModel::mimeData(const QModelIndexList& _indexes) const
632 {
633  QMimeData *mimeData = new QMimeData();
634  QByteArray encodedData;
635 
636  QDataStream stream(&encodedData, QIODevice::WriteOnly);
637 
638  QVector< int > rows;
639 
640  foreach (QModelIndex index, _indexes) {
641  if (index.isValid()) {
642 
643  if (!rows.contains( index.row() ) ){
644  TreeItem *item = getItem(index);
645  stream << item->id();
646 
647  rows.push_back( index.row() );
648  }
649  }
650  }
651 
652  mimeData->setData("DataControl/dragDrop", encodedData);
653  return mimeData;
654 }
655 
656 
657 //******************************************************************************
658 
659 bool TreeModel::dropMimeData( const QMimeData *_data,
660  Qt::DropAction _action,
661  int /*_row*/,
662  int /*_column*/,
663  const QModelIndex &_parent)
664 {
665  if (_action == Qt::IgnoreAction)
666  return true;
667 
668  if (!_data->hasFormat("DataControl/dragDrop"))
669  return false;
670 
671  QByteArray encodedData = _data->data("DataControl/dragDrop");
672  QDataStream stream(&encodedData, QIODevice::ReadOnly);
673 
674  QVector< int > ids;
675 
676  while (!stream.atEnd()) {
677  int id;
678  stream >> id;
679 
680  ids.push_back( id );
681  }
682 
683  if (ids.count() == 0)
684  return false;
685 
686  //get new parent
687  TreeItem *newParent = getItem(_parent);
688 
689  if ( newParent == 0 || !newParent->isGroup() )
690  return false;
691 
692  //and move all objects
693  for (int i = 0; i < ids.count(); i++){
694  //tell the DataControlPlugin to move the corresponding BaseObject
695  emit moveBaseObject( ids[i], newParent->id() );
696  }
697 
698  return true;
699 
700  }
701 //******************************************************************************
702 TreeItem *TreeModel::getItem(const int _id) const
703 {
704  return rootItem_->childExists(_id);
705 }
DataType dataType()
dataType
Definition: TreeItem.cc:94
Qt::DropActions supportedDropActions() const
supported drag & Drop actions
Definition: TreeModel.cc:604
LightSource * lightSource()
Definition: LightObject.cc:326
~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
bool enabled() const
Get light source status.
Definition: LightNode.cc:137
bool target()
target
Definition: TreeItem.cc:127
bool source()
Definition: BaseObject.cc:291
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
bool target()
Definition: BaseObject.cc:273
TreeItem * parent()
Get the parent item ( 0 if root item )
Definition: TreeItem.cc:235
QList< TreeItem *> getLeafs()
get all leafes of the tree below this object ( These will be all visible objects ) ...
Definition: TreeItem.cc:326
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
bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
This is called when mimeData is dropped.
Definition: TreeModel.cc:659
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
bool source()
source
Definition: TreeItem.cc:139
QStringList mimeTypes() const
stores the mimeType for Drag & Drop
Definition: TreeModel.cc:616
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
QMimeData * mimeData(const QModelIndexList &indexes) const
get the mimeData for a given ModelIndex
Definition: TreeModel.cc:631
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
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
#define DATA_LIGHT
Definition: Light.hh:58
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.
DLLEXPORT QIcon & typeIcon(DataType _id)
Get an QIcon associated with the given DataType.
Definition: Types.cc:212