Developer Documentation
Loading...
Searching...
No Matches
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
61TreeModel::TreeModel( QObject *_parent) : QAbstractItemModel(_parent)
62{
63 rootItem_ = new TreeItem( -1, "ROOT", DATA_UNKNOWN, 0);
64}
65
66
67//******************************************************************************
68
76
77
78//******************************************************************************
79
80int TreeModel::columnCount(const QModelIndex &/*_parent*/) const
81{
82 // Name,Visible,Source,Target -> 4
83 return (4);
84}
85
86
87//******************************************************************************
88
95QVariant 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
221Qt::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
267QVariant 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
294QModelIndex 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
321QModelIndex 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
343int 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;
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() )
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
497void 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
517TreeItem* 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
534QString 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
551int 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
571QModelIndex 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
584bool 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
613Qt::DropActions TreeModel::supportedDropActions() const
614{
615 return /*Qt::CopyAction |*/ Qt::MoveAction;
616}
617
618
619//******************************************************************************
620
625QStringList TreeModel::mimeTypes() const
626{
627 QStringList types;
628 types << "DataControl/dragDrop";
629 return types;
630}
631
632
633//******************************************************************************
634
640QMimeData* 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
668bool 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//******************************************************************************
711TreeItem *TreeModel::getItem(const int _id) const
712{
713 return rootItem_->childExists(_id);
714}
DLLEXPORT QIcon & typeIcon(DataType _id)
Get an QIcon associated with the given DataType.
Definition Types.cc:212
const DataType DATA_UNKNOWN(0)
None of the other Objects.
#define DATA_LIGHT
Definition Light.hh:58
bool enabled() const
Get light source status.
Definition LightNode.cc:137
QString name() const
return the name of the object. The name defaults to NONAME if unset.
BaseObject * parent()
Get the parent item ( 0 if rootitem )
bool dataType(DataType _type) const
bool source()
bool target()
int id() const
virtual bool visible()
return if object is visible
LightSource * lightSource()
int childCount() const
get the number of children
Definition TreeItem.cc:264
QList< TreeItem * > getLeafs()
get all leafes of the tree below this object ( These will be all visible objects )
Definition TreeItem.cc:326
int id()
id
Definition TreeItem.cc:78
TreeItem * parent()
Get the parent item ( 0 if root item )
Definition TreeItem.cc:235
bool target()
target
Definition TreeItem.cc:127
QString name()
name
Definition TreeItem.cc:163
DataType dataType()
dataType
Definition TreeItem.cc:94
bool visible()
visible
Definition TreeItem.cc:151
TreeItem * child(int row)
return a child
Definition TreeItem.cc:257
void deleteSubtree()
delete the whole subtree below this item ( The item itself is not touched )
Definition TreeItem.cc:343
int row() const
get the row of this item from the parent
Definition TreeItem.cc:228
void appendChild(TreeItem *child)
add a child to this node
Definition TreeItem.cc:248
void setParent(TreeItem *_parent)
Set the parent pointer.
Definition TreeItem.cc:242
void removeChild(TreeItem *_item)
Remove a child from this object.
Definition TreeItem.cc:308
bool source()
source
Definition TreeItem.cc:139
TreeItem * childExists(int _objectId)
Check if the element exists in the subtree of this element.
Definition TreeItem.cc:271
bool isRoot(TreeItem *_item)
Check if the given item is the root item.
Definition TreeModel.cc:601
QStringList mimeTypes() const
stores the mimeType for Drag & Drop
Definition TreeModel.cc:625
QString itemName(const QModelIndex &_index) const
Get the name of a TreeItem corresponding to a given ModelIndex.
Definition TreeModel.cc:534
bool setData(const QModelIndex &_index, const QVariant &_value, int _role)
Set Data at 'index' to 'value'.
Definition TreeModel.cc:584
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
TreeModel(QObject *_parent=0)
Constructor.
Definition TreeModel.cc:61
int rowCount(const QModelIndex &_parent=QModelIndex()) const
get the number of rows
Definition TreeModel.cc:343
void objectDeleted(int _id)
The object with the given id has been deleted. delete it from the internal tree.
Definition TreeModel.cc:470
QVariant headerData(int _section, Qt::Orientation _orientation, int _role=Qt::DisplayRole) const
return the header data of the model
Definition TreeModel.cc:267
QMimeData * mimeData(const QModelIndexList &indexes) const
get the mimeData for a given ModelIndex
Definition TreeModel.cc:640
void moveItem(TreeItem *_item, TreeItem *_parent)
move the item to a new parent
Definition TreeModel.cc:497
int itemId(const QModelIndex &_index) const
Get the id of a TreeItem corresponding to a given ModelIndex.
Definition TreeModel.cc:551
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
TreeItem * rootItem_
Root item of the tree.
Definition TreeModel.hh:161
QVariant data(const QModelIndex &_index, int _role) const
Get the data of the corresponding entry.
Definition TreeModel.cc:95
Qt::DropActions supportedDropActions() const
supported drag & Drop actions
Definition TreeModel.cc:613
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
void objectAdded(BaseObject *_object)
The object with the given id has been added. add it to the internal tree.
Definition TreeModel.cc:435
TreeItem * getItem(const QModelIndex &_index) const
Get the TreeItem corresponding to a given ModelIndex.
Definition TreeModel.cc:517
Qt::ItemFlags flags(const QModelIndex &_index) const
return the types of the corresponding entry
Definition TreeModel.cc:221
~TreeModel()
Destructor.
Definition TreeModel.cc:72
QModelIndex getModelIndex(TreeItem *_object, int _column)
Return the ModelIndex corresponding to a given TreeItem and Column.
Definition TreeModel.cc:571
QModelIndex index(int _row, int _column, const QModelIndex &_parent=QModelIndex()) const
Get the ModelIndex at given row,column.
Definition TreeModel.cc:294
bool getObject(const int _identifier, BaseObject *&_object)
Get the object which has the given identifier.
BaseObject *& objectRoot()
Get the root of the object structure.