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 * $Revision$ *
45 * $LastChangedBy$ *
46 * $Date$ *
47 * *
48 \*===========================================================================*/
49 
50 #include "TreeModel.hh"
51 
52 #if QT_VERSION >= 0x050000
53  #include <QtWidgets>
54 #else
55  #include <QtGui>
56 #endif
57 
58 
61 
62 #include <ObjectTypes/Light/LightWidget.hh>
63 
64 
65 //******************************************************************************
66 
71 TreeModel::TreeModel( QObject *_parent) : QAbstractItemModel(_parent)
72 {
73  rootItem_ = new TreeItem( -1, "ROOT", DATA_UNKNOWN, 0);
74 }
75 
76 
77 //******************************************************************************
78 
83 {
84 
85 }
86 
87 
88 //******************************************************************************
89 
90 int TreeModel::columnCount(const QModelIndex &/*_parent*/) const
91 {
92  // Name,Visible,Source,Target -> 4
93  return (4);
94 }
95 
96 
97 //******************************************************************************
98 
105 QVariant TreeModel::data(const QModelIndex &_index, int _role) const
106 {
107 
108  // Skip invalid requests
109  if (!_index.isValid())
110  return QVariant();
111 
112  // Get the corresponding tree item
113  TreeItem *item = static_cast<TreeItem*>(_index.internalPointer());
114 
115  if ( item == rootItem_ ) {
116  std::cerr << "Root" << std::endl;
117  }
118 
119  // Set the background color of the objects row
120  if ( _role == Qt::BackgroundRole ) {
121  if ( !item->visible() ) {
122  return QVariant( QBrush(QColor(100,100,100) ) );
123  }
124  }
125 
126 
127 
128  switch (_index.column() ) {
129  // Name
130  case 0 :
131 
132  // If we are setting the name, also add the icon
133  if ( _role == Qt::DecorationRole ) {
134  if (item->dataType() == DATA_LIGHT)
135  {
136  LightObject* light = 0;
137  if (item->id() != -1 && PluginFunctions::getObject( item->id(), light ) ) {
138  if (light != 0 && !light->lightSource()->enabled())
139  return QVariant (QIcon (OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"LightOff.png"));
140  }
141  }
142  return QVariant( typeIcon(item->dataType()) );
143  }
144 
145  if (_role != Qt::DisplayRole && _role != Qt::EditRole )
146  return QVariant();
147 
148  return QVariant(item->name());
149 
150  break;
151  // Visible
152  case 1 :
153  if (_role == Qt::CheckStateRole ) {
154  bool visible = false;
155  // target group
156  if (item->isGroup() && item->childCount() > 0)
157  {
158  QList< TreeItem* > children = item->getLeafs();
159 
160  visible = children[0]->visible();
161  for (int i=0; i < children.size() ; ++i)
162  {
163  if (visible != children[i]->visible())
164  return QVariant(Qt::PartiallyChecked);
165  }
166  }
167  else
168  visible = item->visible();
169  return (visible) ? QVariant(Qt::Checked) : QVariant(Qt::Unchecked);
170  }
171  return QVariant();
172  // Source
173  case 2 :
174  if (_role == Qt::CheckStateRole ) {
175  bool source = false;
176  // target group
177  if (item->isGroup() && item->childCount() > 0)
178  {
179  QList< TreeItem* > children = item->getLeafs();
180 
181  source = children[0]->source();
182  for (int i=0; i < children.size() ; ++i)
183  {
184  if (source != children[i]->source())
185  return QVariant(Qt::PartiallyChecked);
186  }
187  }
188  else
189  source = item->source();
190  return (source) ? QVariant(Qt::Checked) : QVariant(Qt::Unchecked);
191  }
192  return QVariant();
193 
194  // Target
195  case 3 :
196  if (_role == Qt::CheckStateRole ) {
197  bool target = false;
198  // target group
199  if (item->isGroup() && item->childCount() > 0)
200  {
201  QList< TreeItem* > children = item->getLeafs();
202 
203  target = children[0]->target();
204  for (int i=0; i < children.size() ; ++i)
205  {
206  if (target != children[i]->target())
207  return QVariant(Qt::PartiallyChecked);
208  }
209  }
210  else
211  target = item->target();
212  return (target) ? QVariant(Qt::Checked) : QVariant(Qt::Unchecked);
213  }
214  return QVariant();
215 
216  default:
217  return QVariant();
218  }
219  return QVariant();
220 
221 }
222 
223 
224 //******************************************************************************
225 
231 Qt::ItemFlags TreeModel::flags(const QModelIndex &_index) const
232 {
233  if (!_index.isValid())
234  return 0;
235 
236  Qt::ItemFlags flags = 0;
237 
238  // Show/Source/Target
239  if ( ( _index.column() == 1 ) ||
240  ( _index.column() == 2 ) ||
241  ( _index.column() == 3 ) )
242  flags = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
243  else
244  if ( _index.column() == 0 )
245  flags = Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
246  else
247  flags = Qt::ItemIsEnabled;
248 
249  // Get the corresponding tree item
250  TreeItem *item = static_cast<TreeItem*>(_index.internalPointer());
251 
252  if ( item->isGroup() )
253  return flags | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
254  else
255  return flags | Qt::ItemIsDragEnabled;
256 }
257 
258 
259 //******************************************************************************
260 
268 QVariant TreeModel::headerData(int _section, Qt::Orientation _orientation,
269  int _role) const
270 {
271  if (_orientation == Qt::Horizontal && _role == Qt::DisplayRole) {
272 
273  switch (_section) {
274  case 0 : return QVariant("Name");
275  case 1 : return QVariant("Show");
276  case 2 : return QVariant("Source");
277  case 3 : return QVariant("Target");
278  default :
279  return QVariant();
280  }
281  }
282  return QVariant();
283 }
284 
285 
286 //******************************************************************************
287 
295 QModelIndex TreeModel::index(int _row, int _column,const QModelIndex &_parent) const
296 {
297 // if (!hasIndex(row, column, _parent))
298 // return QModelIndex();
299 
300  TreeItem *parentItem;
301 
302  if (!_parent.isValid())
303  parentItem = rootItem_;
304  else
305  parentItem = static_cast<TreeItem*>(_parent.internalPointer());
306 
307  TreeItem *childItem = parentItem->child(_row);
308  if (childItem)
309  return createIndex(_row, _column, childItem);
310  else
311  return QModelIndex();
312 }
313 
314 
315 //******************************************************************************
316 
322 QModelIndex TreeModel::parent(const QModelIndex &_index) const
323 {
324  if (!_index.isValid())
325  return QModelIndex();
326 
327  TreeItem *childItem = static_cast<TreeItem*>(_index.internalPointer());
328  TreeItem *parentItem = childItem->parent();
329 
330  if (parentItem == rootItem_)
331  return QModelIndex();
332 
333  return createIndex(parentItem->row(), 0, parentItem);
334 }
335 
336 
337 //******************************************************************************
338 
344 int TreeModel::rowCount(const QModelIndex &_parent) const
345 {
346  TreeItem *parentItem;
347  if (_parent.column() > 0)
348  return 0;
349 
350  if (!_parent.isValid())
351  parentItem = rootItem_;
352  else
353  parentItem = static_cast<TreeItem*>(_parent.internalPointer());
354 
355  return parentItem->childCount();
356 }
357 //******************************************************************************
358 
364 
365  if ( _id != -1 ){
366 
367  BaseObject* obj = 0;
368  PluginFunctions::getObject(_id, obj);
369 
370  TreeItem* item = rootItem_->childExists(_id);
371 
372  //if internal and external representation are both valid
373  if (obj != 0 && item != 0){
374  //update the name
375  bool updateRow = false;
376  if ( obj->name() != item->name() ){
377 
378  item->name( obj->name() );
379  updateRow = true;
380  }
381 
382  //update visibility
383  if ( obj->visible() != item->visible() ){
384 
385  item->visible( obj->visible() );
386  updateRow = true;
387  }
388 
389  //update source flag
390  if ( obj->source() != item->source() ){
391 
392  item->source( obj->source() );
393  updateRow = true;
394  }
395 
396  //update target flag
397  if ( obj->target() != item->target() ){
398 
399  item->target( obj->target() );
400  updateRow = true;
401  }
402  if (updateRow)
403  {
404  //TODO actually we do not need to update the whole row but single column somehow doesn't work
405  QModelIndex index0 = getModelIndex(item,0);
406  QModelIndex index1 = getModelIndex(item,3);
407 
408  if ( index0.isValid() && index1.isValid() ){
409  //the whole row has to be updated because of the grey background-color
410  emit dataChanged( index0, index1);
411  }
412  }
413 
414  //update parent
415  if ( obj->parent() == PluginFunctions::objectRoot() && isRoot( item->parent() ) ){
416  return;
417  }else if ( obj->parent() == PluginFunctions::objectRoot() && !isRoot( item->parent() ) ){
418  moveItem(item, rootItem_ );
419  }else if ( obj->parent()->id() != item->parent()->id() ){
420  TreeItem* parent = rootItem_->childExists( obj->parent()->id() );
421 
422  if (parent != 0)
423  moveItem(item, parent );
424  }
425 
426  }
427  }
428 
429 }
430 
431 
437 
438  // check if item already in model tree
439  // this function can be called by addEmpty and fileOpened
440  // both will be called by fileOpened such that the item
441  // already exists
442  if( rootItem_->childExists( _object->id() ))
443  return;
444 
445  TreeItem* parent = 0;
446  //find the parent
447  if ( _object->parent() == PluginFunctions::objectRoot() )
448  parent = rootItem_;
449  else
450  parent = rootItem_->childExists( _object->parent()->id() );
451 
452  if (parent != 0){
453  QModelIndex parentIndex = getModelIndex(parent, 0);
454 
455  beginInsertRows(parentIndex, parent->childCount(), parent->childCount()); //insert at the bottom
456 
457  TreeItem* item = new TreeItem( _object->id(), _object->name(), _object->dataType(), parent);
458 
459  parent->appendChild( item );
460 
461  endInsertRows();
462  }
463 
464  objectChanged( _object->id() );
465 }
466 
472 
473  TreeItem* item = rootItem_->childExists(_id);
474 
475  if ( item != 0 && !isRoot(item) ){
476 
477  QModelIndex itemIndex = getModelIndex(item, 0);
478  QModelIndex parentIndex = itemIndex.parent();
479 
480  beginRemoveRows( parentIndex, itemIndex.row(), itemIndex.row() );
481 
482  item->parent()->removeChild(item);
483  item->deleteSubtree();
484 
485  delete item;
486 
487  endRemoveRows();
488  }
489 }
490 
491 //******************************************************************************
492 
498 void TreeModel::moveItem(TreeItem* _item, TreeItem* _parent ){
499 
500  QModelIndex itemIndex = getModelIndex(_item, 0);
501  QModelIndex oldParentIndex = itemIndex.parent();
502  QModelIndex newParentIndex = getModelIndex(_parent, 0);
503 
504  beginMoveRows ( oldParentIndex, itemIndex.row(), itemIndex.row(), newParentIndex,0 );
505  _item->parent()->removeChild(_item);
506  _item->setParent( _parent );
507  _parent->appendChild( _item );
508  endMoveRows();
509 }
510 
511 //******************************************************************************
512 
518 TreeItem* TreeModel::getItem(const QModelIndex &_index) const
519 {
520  if (_index.isValid()) {
521  TreeItem *item = static_cast<TreeItem*>(_index.internalPointer());
522  if (item) return item;
523  }
524  return rootItem_;
525 }
526 
527 
528 //******************************************************************************
529 
535 QString TreeModel::itemName(const QModelIndex &_index) const
536 {
537  if (_index.isValid()) {
538  TreeItem *item = static_cast<TreeItem*>(_index.internalPointer());
539  if (item)
540  return item->name();
541  }
542  return "not found";
543 }
544 
545 //******************************************************************************
546 
552 int TreeModel::itemId(const QModelIndex &_index) const
553 {
554  if (_index.isValid()) {
555  TreeItem *item = static_cast<TreeItem*>(_index.internalPointer());
556  if (item)
557  return item->id();
558  }
559  return -1;
560 }
561 
562 //******************************************************************************
563 
572 QModelIndex TreeModel::getModelIndex(TreeItem* _object, int _column ){
573 
574  // root item gets an invalid QModelIndex
575  if ( _object == rootItem_ )
576  return QModelIndex();
577 
578  QModelIndex index = createIndex(_object->row(), _column, _object);
579 
580  return index;
581 }
582 
583 //******************************************************************************
584 
585 bool TreeModel::setData(const QModelIndex &_index, const QVariant &_value, int /*role*/)
586 {
587 
588  emit dataChangedInside( itemId(_index), _index.column(), _value );
589 
590 
591  return true;
592 }
593 
594 
595 //******************************************************************************
596 
603  return ( _item == rootItem_ );
604 }
605 
606 /*******************************************************************************
607  drag & drop stuff
608  *******************************************************************************/
609 
614 Qt::DropActions TreeModel::supportedDropActions() const
615 {
616  return /*Qt::CopyAction |*/ Qt::MoveAction;
617 }
618 
619 
620 //******************************************************************************
621 
626 QStringList TreeModel::mimeTypes() const
627 {
628  QStringList types;
629  types << "DataControl/dragDrop";
630  return types;
631 }
632 
633 
634 //******************************************************************************
635 
641 QMimeData* TreeModel::mimeData(const QModelIndexList& _indexes) const
642 {
643  QMimeData *mimeData = new QMimeData();
644  QByteArray encodedData;
645 
646  QDataStream stream(&encodedData, QIODevice::WriteOnly);
647 
648  QVector< int > rows;
649 
650  foreach (QModelIndex index, _indexes) {
651  if (index.isValid()) {
652 
653  if (!rows.contains( index.row() ) ){
654  TreeItem *item = getItem(index);
655  stream << item->id();
656 
657  rows.push_back( index.row() );
658  }
659  }
660  }
661 
662  mimeData->setData("DataControl/dragDrop", encodedData);
663  return mimeData;
664 }
665 
666 
667 //******************************************************************************
668 
669 bool TreeModel::dropMimeData( const QMimeData *_data,
670  Qt::DropAction _action,
671  int /*_row*/,
672  int /*_column*/,
673  const QModelIndex &_parent)
674 {
675  if (_action == Qt::IgnoreAction)
676  return true;
677 
678  if (!_data->hasFormat("DataControl/dragDrop"))
679  return false;
680 
681  QByteArray encodedData = _data->data("DataControl/dragDrop");
682  QDataStream stream(&encodedData, QIODevice::ReadOnly);
683 
684  QVector< int > ids;
685 
686  while (!stream.atEnd()) {
687  int id;
688  stream >> id;
689 
690  ids.push_back( id );
691  }
692 
693  if (ids.count() == 0)
694  return false;
695 
696  //get new parent
697  TreeItem *newParent = getItem(_parent);
698 
699  if ( newParent == 0 || !newParent->isGroup() )
700  return false;
701 
702  //and move all objects
703  for (int i = 0; i < ids.count(); i++){
704  //tell the DataControlPlugin to move the corresponding BaseObject
705  emit moveBaseObject( ids[i], newParent->id() );
706  }
707 
708  return true;
709 
710  }
711 //******************************************************************************
712 TreeItem *TreeModel::getItem(const int _id) const
713 {
714  return rootItem_->childExists(_id);
715 }
BaseObject *& objectRoot()
Get the root of the object structure.
int itemId(const QModelIndex &_index) const
Get the id of a TreeItem corresponding to a given ModelIndex.
Definition: TreeModel.cc:552
int columnCount(const QModelIndex &_parent=QModelIndex()) const
Return the number of columns.
Definition: TreeModel.cc:90
int rowCount(const QModelIndex &_parent=QModelIndex()) const
get the number of rows
Definition: TreeModel.cc:344
void deleteSubtree()
delete the whole subtree below this item ( The item itself is not touched )
Definition: TreeItem.cc:351
bool visible()
visible
Definition: TreeItem.cc:159
QModelIndex getModelIndex(TreeItem *_object, int _column)
Return the ModelIndex corresponding to a given TreeItem and Column.
Definition: TreeModel.cc:572
void objectChanged(int _id)
The object with the given id has been changed. Check if model also has to be changed.
Definition: TreeModel.cc:363
virtual bool visible()
return if object is visible
Definition: BaseObject.cc:350
QString itemName(const QModelIndex &_index) const
Get the name of a TreeItem corresponding to a given ModelIndex.
Definition: TreeModel.cc:535
bool source()
source
Definition: TreeItem.cc:147
TreeModel(QObject *_parent=0)
Constructor.
Definition: TreeModel.cc:71
TreeItem * parent()
Get the parent item ( 0 if root item )
Definition: TreeItem.cc:243
bool getObject(int _identifier, BSplineCurveObject *&_object)
LightSource * lightSource()
Definition: LightObject.cc:328
bool dataType(DataType _type) const
Definition: BaseObject.cc:232
const DataType DATA_UNKNOWN(0)
None of the other Objects.
TreeItem * childExists(int _objectId)
Check if the element exists in the subtree of this element.
Definition: TreeItem.cc:279
QString name()
name
Definition: TreeItem.cc:171
~TreeModel()
Destructor.
Definition: TreeModel.cc:82
int id() const
Definition: BaseObject.cc:201
BaseObject * parent()
Get the parent item ( 0 if rootitem )
Definition: BaseObject.cc:477
Qt::ItemFlags flags(const QModelIndex &_index) const
return the types of the corresponding entry
Definition: TreeModel.cc:231
void setParent(TreeItem *_parent)
Set the parent pointer.
Definition: TreeItem.cc:250
int id()
id
Definition: TreeItem.cc:86
bool target()
Definition: BaseObject.cc:284
QStringList mimeTypes() const
stores the mimeType for Drag & Drop
Definition: TreeModel.cc:626
#define DATA_LIGHT
Definition: Light.hh:64
void appendChild(TreeItem *child)
add a child to this node
Definition: TreeItem.cc:256
TreeItem * rootItem_
Root item of the tree.
Definition: TreeModel.hh:167
int row() const
get the row of this item from the parent
Definition: TreeItem.cc:236
TreeItem * child(int row)
return a child
Definition: TreeItem.cc:265
void removeChild(TreeItem *_item)
Remove a child from this object.
Definition: TreeItem.cc:316
int childCount() const
get the number of children
Definition: TreeItem.cc:272
QVariant data(const QModelIndex &_index, int _role) const
Get the data of the corresponding entry.
Definition: TreeModel.cc:105
void objectAdded(BaseObject *_object)
The object with the given id has been added. add it to the internal tree.
Definition: TreeModel.cc:436
QList< TreeItem * > getLeafs()
get all leafes of the tree below this object ( These will be all visible objects ) ...
Definition: TreeItem.cc:334
QModelIndex parent(const QModelIndex &_index) const
Get the parent ModelIndex.
Definition: TreeModel.cc:322
void moveItem(TreeItem *_item, TreeItem *_parent)
move the item to a new parent
Definition: TreeModel.cc:498
QString name() const
return the name of the object. The name defaults to NONAME if unset.
Definition: BaseObject.cc:741
bool isRoot(TreeItem *_item)
Check if the given item is the root item.
Definition: TreeModel.cc:602
TreeItem * getItem(const QModelIndex &_index) const
Get the TreeItem corresponding to a given ModelIndex.
Definition: TreeModel.cc:518
bool target()
target
Definition: TreeItem.cc:135
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:669
QModelIndex index(int _row, int _column, const QModelIndex &_parent=QModelIndex()) const
Get the ModelIndex at given row,column.
Definition: TreeModel.cc:295
void objectDeleted(int _id)
The object with the given id has been deleted. delete it from the internal tree.
Definition: TreeModel.cc:471
Qt::DropActions supportedDropActions() const
supported drag & Drop actions
Definition: TreeModel.cc:614
QVariant headerData(int _section, Qt::Orientation _orientation, int _role=Qt::DisplayRole) const
return the header data of the model
Definition: TreeModel.cc:268
bool source()
Definition: BaseObject.cc:302
DLLEXPORT QIcon & typeIcon(DataType _id)
Get an QIcon associated with the given DataType.
Definition: Types.cc:223
bool setData(const QModelIndex &_index, const QVariant &_value, int _role)
Set Data at &#39;index&#39; to &#39;value&#39;.
Definition: TreeModel.cc:585
bool enabled() const
Get light source status.
Definition: LightNode.cc:143
QMimeData * mimeData(const QModelIndexList &indexes) const
get the mimeData for a given ModelIndex
Definition: TreeModel.cc:641
DataType dataType()
dataType
Definition: TreeItem.cc:102