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 
224 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
225  if (!_index.isValid())
226  return 0;
227 
228  Qt::ItemFlags flags = 0;
229 #else
230  if (!_index.isValid())
231  return Qt::ItemFlags();
232 
233  Qt::ItemFlags flags = Qt::ItemFlags();
234 #endif
235 
236 
237  // Show/Source/Target
238  if ( ( _index.column() == 1 ) ||
239  ( _index.column() == 2 ) ||
240  ( _index.column() == 3 ) )
241  flags = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
242  else
243  if ( _index.column() == 0 )
244  flags = Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
245  else
246  flags = Qt::ItemIsEnabled;
247 
248  // Get the corresponding tree item
249  TreeItem *item = static_cast<TreeItem*>(_index.internalPointer());
250 
251  if ( item->isGroup() )
252  return flags | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
253  else
254  return flags | Qt::ItemIsDragEnabled;
255 }
256 
257 
258 //******************************************************************************
259 
267 QVariant TreeModel::headerData(int _section, Qt::Orientation _orientation,
268  int _role) const
269 {
270  if (_orientation == Qt::Horizontal && _role == Qt::DisplayRole) {
271 
272  switch (_section) {
273  case 0 : return QVariant("Name");
274  case 1 : return QVariant("Show");
275  case 2 : return QVariant("Source");
276  case 3 : return QVariant("Target");
277  default :
278  return QVariant();
279  }
280  }
281  return QVariant();
282 }
283 
284 
285 //******************************************************************************
286 
294 QModelIndex TreeModel::index(int _row, int _column,const QModelIndex &_parent) const
295 {
296 // if (!hasIndex(row, column, _parent))
297 // return QModelIndex();
298 
299  TreeItem *parentItem;
300 
301  if (!_parent.isValid())
302  parentItem = rootItem_;
303  else
304  parentItem = static_cast<TreeItem*>(_parent.internalPointer());
305 
306  TreeItem *childItem = parentItem->child(_row);
307  if (childItem)
308  return createIndex(_row, _column, childItem);
309  else
310  return QModelIndex();
311 }
312 
313 
314 //******************************************************************************
315 
321 QModelIndex TreeModel::parent(const QModelIndex &_index) const
322 {
323  if (!_index.isValid())
324  return QModelIndex();
325 
326  TreeItem *childItem = static_cast<TreeItem*>(_index.internalPointer());
327  TreeItem *parentItem = childItem->parent();
328 
329  if (parentItem == rootItem_)
330  return QModelIndex();
331 
332  return createIndex(parentItem->row(), 0, parentItem);
333 }
334 
335 
336 //******************************************************************************
337 
343 int TreeModel::rowCount(const QModelIndex &_parent) const
344 {
345  TreeItem *parentItem;
346  if (_parent.column() > 0)
347  return 0;
348 
349  if (!_parent.isValid())
350  parentItem = rootItem_;
351  else
352  parentItem = static_cast<TreeItem*>(_parent.internalPointer());
353 
354  return parentItem->childCount();
355 }
356 //******************************************************************************
357 
363 
364  if ( _id != -1 ){
365 
366  BaseObject* obj = 0;
367  PluginFunctions::getObject(_id, obj);
368 
369  TreeItem* item = rootItem_->childExists(_id);
370 
371  //if internal and external representation are both valid
372  if (obj != 0 && item != 0){
373  //update the name
374  bool updateRow = false;
375  if ( obj->name() != item->name() ){
376 
377  item->name( obj->name() );
378  updateRow = true;
379  }
380 
381  //update visibility
382  if ( obj->visible() != item->visible() ){
383 
384  item->visible( obj->visible() );
385  updateRow = true;
386  }
387 
388  //update source flag
389  if ( obj->source() != item->source() ){
390 
391  item->source( obj->source() );
392  updateRow = true;
393  }
394 
395  //update target flag
396  if ( obj->target() != item->target() ){
397 
398  item->target( obj->target() );
399  updateRow = true;
400  }
401  if (updateRow)
402  {
403  //TODO actually we do not need to update the whole row but single column somehow doesn't work
404  QModelIndex index0 = getModelIndex(item,0);
405  QModelIndex index1 = getModelIndex(item,3);
406 
407  if ( index0.isValid() && index1.isValid() ){
408  //the whole row has to be updated because of the grey background-color
409  emit dataChanged( index0, index1);
410  }
411  }
412 
413  //update parent
414  if ( obj->parent() == PluginFunctions::objectRoot() && isRoot( item->parent() ) ){
415  return;
416  }else if ( obj->parent() == PluginFunctions::objectRoot() && !isRoot( item->parent() ) ){
417  moveItem(item, rootItem_ );
418  }else if ( obj->parent()->id() != item->parent()->id() ){
419  TreeItem* parent = rootItem_->childExists( obj->parent()->id() );
420 
421  if (parent != 0)
422  moveItem(item, parent );
423  }
424 
425  }
426  }
427 
428 }
429 
430 
436 
437  // check if item already in model tree
438  // this function can be called by addEmpty and fileOpened
439  // both will be called by fileOpened such that the item
440  // already exists
441  if( rootItem_->childExists( _object->id() ))
442  return;
443 
444  TreeItem* parent = 0;
445  //find the parent
446  if ( _object->parent() == PluginFunctions::objectRoot() )
447  parent = rootItem_;
448  else
449  parent = rootItem_->childExists( _object->parent()->id() );
450 
451  if (parent != 0){
452  QModelIndex parentIndex = getModelIndex(parent, 0);
453 
454  beginInsertRows(parentIndex, parent->childCount(), parent->childCount()); //insert at the bottom
455 
456  TreeItem* item = new TreeItem( _object->id(), _object->name(), _object->dataType(), parent);
457 
458  parent->appendChild( item );
459 
460  endInsertRows();
461  }
462 
463  objectChanged( _object->id() );
464 }
465 
471 
472  TreeItem* item = rootItem_->childExists(_id);
473 
474  if ( item != 0 && !isRoot(item) ){
475 
476  QModelIndex itemIndex = getModelIndex(item, 0);
477  QModelIndex parentIndex = itemIndex.parent();
478 
479  beginRemoveRows( parentIndex, itemIndex.row(), itemIndex.row() );
480 
481  item->parent()->removeChild(item);
482  item->deleteSubtree();
483 
484  delete item;
485 
486  endRemoveRows();
487  }
488 }
489 
490 //******************************************************************************
491 
497 void TreeModel::moveItem(TreeItem* _item, TreeItem* _parent ){
498 
499  QModelIndex itemIndex = getModelIndex(_item, 0);
500  QModelIndex oldParentIndex = itemIndex.parent();
501  QModelIndex newParentIndex = getModelIndex(_parent, 0);
502 
503  beginMoveRows ( oldParentIndex, itemIndex.row(), itemIndex.row(), newParentIndex,0 );
504  _item->parent()->removeChild(_item);
505  _item->setParent( _parent );
506  _parent->appendChild( _item );
507  endMoveRows();
508 }
509 
510 //******************************************************************************
511 
517 TreeItem* TreeModel::getItem(const QModelIndex &_index) const
518 {
519  if (_index.isValid()) {
520  TreeItem *item = static_cast<TreeItem*>(_index.internalPointer());
521  if (item) return item;
522  }
523  return rootItem_;
524 }
525 
526 
527 //******************************************************************************
528 
534 QString TreeModel::itemName(const QModelIndex &_index) const
535 {
536  if (_index.isValid()) {
537  TreeItem *item = static_cast<TreeItem*>(_index.internalPointer());
538  if (item)
539  return item->name();
540  }
541  return "not found";
542 }
543 
544 //******************************************************************************
545 
551 int TreeModel::itemId(const QModelIndex &_index) const
552 {
553  if (_index.isValid()) {
554  TreeItem *item = static_cast<TreeItem*>(_index.internalPointer());
555  if (item)
556  return item->id();
557  }
558  return -1;
559 }
560 
561 //******************************************************************************
562 
571 QModelIndex TreeModel::getModelIndex(TreeItem* _object, int _column ){
572 
573  // root item gets an invalid QModelIndex
574  if ( _object == rootItem_ )
575  return QModelIndex();
576 
577  QModelIndex index = createIndex(_object->row(), _column, _object);
578 
579  return index;
580 }
581 
582 //******************************************************************************
583 
584 bool TreeModel::setData(const QModelIndex &_index, const QVariant &_value, int /*role*/)
585 {
586 
587  emit dataChangedInside( itemId(_index), _index.column(), _value );
588 
589 
590  return true;
591 }
592 
593 
594 //******************************************************************************
595 
602  return ( _item == rootItem_ );
603 }
604 
605 /*******************************************************************************
606  drag & drop stuff
607  *******************************************************************************/
608 
613 Qt::DropActions TreeModel::supportedDropActions() const
614 {
615  return /*Qt::CopyAction |*/ Qt::MoveAction;
616 }
617 
618 
619 //******************************************************************************
620 
625 QStringList TreeModel::mimeTypes() const
626 {
627  QStringList types;
628  types << "DataControl/dragDrop";
629  return types;
630 }
631 
632 
633 //******************************************************************************
634 
640 QMimeData* TreeModel::mimeData(const QModelIndexList& _indexes) const
641 {
642  QMimeData *mimeData = new QMimeData();
643  QByteArray encodedData;
644 
645  QDataStream stream(&encodedData, QIODevice::WriteOnly);
646 
647  QVector< int > rows;
648 
649  foreach (QModelIndex index, _indexes) {
650  if (index.isValid()) {
651 
652  if (!rows.contains( index.row() ) ){
653  TreeItem *item = getItem(index);
654  stream << item->id();
655 
656  rows.push_back( index.row() );
657  }
658  }
659  }
660 
661  mimeData->setData("DataControl/dragDrop", encodedData);
662  return mimeData;
663 }
664 
665 
666 //******************************************************************************
667 
668 bool TreeModel::dropMimeData( const QMimeData *_data,
669  Qt::DropAction _action,
670  int /*_row*/,
671  int /*_column*/,
672  const QModelIndex &_parent)
673 {
674  if (_action == Qt::IgnoreAction)
675  return true;
676 
677  if (!_data->hasFormat("DataControl/dragDrop"))
678  return false;
679 
680  QByteArray encodedData = _data->data("DataControl/dragDrop");
681  QDataStream stream(&encodedData, QIODevice::ReadOnly);
682 
683  QVector< int > ids;
684 
685  while (!stream.atEnd()) {
686  int id;
687  stream >> id;
688 
689  ids.push_back( id );
690  }
691 
692  if (ids.count() == 0)
693  return false;
694 
695  //get new parent
696  TreeItem *newParent = getItem(_parent);
697 
698  if ( newParent == 0 || !newParent->isGroup() )
699  return false;
700 
701  //and move all objects
702  for (int i = 0; i < ids.count(); i++){
703  //tell the DataControlPlugin to move the corresponding BaseObject
704  emit moveBaseObject( ids[i], newParent->id() );
705  }
706 
707  return true;
708 
709  }
710 //******************************************************************************
711 TreeItem *TreeModel::getItem(const int _id) const
712 {
713  return rootItem_->childExists(_id);
714 }
DataType dataType()
dataType
Definition: TreeItem.cc:94
Qt::DropActions supportedDropActions() const
supported drag & Drop actions
Definition: TreeModel.cc:613
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:571
TreeItem * child(int row)
return a child
Definition: TreeItem.cc:257
TreeItem * rootItem_
Root item of the tree.
Definition: TreeModel.hh:161
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:321
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:267
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:497
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:517
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:668
int itemId(const QModelIndex &_index) const
Get the id of a TreeItem corresponding to a given ModelIndex.
Definition: TreeModel.cc:551
QModelIndex index(int _row, int _column, const QModelIndex &_parent=QModelIndex()) const
Get the ModelIndex at given row,column.
Definition: TreeModel.cc:294
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:625
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:534
bool isRoot(TreeItem *_item)
Check if the given item is the root item.
Definition: TreeModel.cc:601
QMimeData * mimeData(const QModelIndexList &indexes) const
get the mimeData for a given ModelIndex
Definition: TreeModel.cc:640
void objectDeleted(int _id)
The object with the given id has been deleted. delete it from the internal tree.
Definition: TreeModel.cc:470
void objectChanged(int _id)
The object with the given id has been changed. Check if model also has to be changed.
Definition: TreeModel.cc:362
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:343
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:435
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:584
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