1 // Copyright (C) 2007-2014 CEA/DEN, EDF R&D, OPEN CASCADE
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 // File: SUIT_TreeModel.cxx
21 // Author: Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
23 #include "SUIT_Session.h"
24 #include "SUIT_TreeModel.h"
25 #include "SUIT_TreeSync.h"
26 #include "SUIT_DataObject.h"
27 #include "SUIT_ResourceMgr.h"
29 #include <QApplication>
33 SUIT_AbstractModel::SUIT_AbstractModel() : mySearcher( 0 )
37 SUIT_AbstractModel::operator const QAbstractItemModel*() const
39 return dynamic_cast<const QAbstractItemModel*>( this );
42 SUIT_AbstractModel::operator QAbstractItemModel*()
44 return dynamic_cast<QAbstractItemModel*>( this );
47 SUIT_AbstractModel::operator const QObject*() const
49 return dynamic_cast<const QObject*>( this );
52 SUIT_DataSearcher* SUIT_AbstractModel::searcher() const
57 void SUIT_AbstractModel::setSearcher( SUIT_DataSearcher* s )
64 \class SUIT_TreeModel::TreeItem
65 \brief Internal class used for tree view synchronizaton with data object tree.
69 class SUIT_TreeModel::TreeItem
72 TreeItem( SUIT_DataObject* obj, TreeItem* parent = 0, TreeItem* after = 0 );
75 void insertChild( TreeItem* child, TreeItem* after = 0 );
76 void removeChild( TreeItem* child );
77 SUIT_DataObject* dataObject() const;
78 TreeItem* parent() const;
80 void setPosition(int position) {_position=position;};
81 int childCount() const;
82 TreeItem* child( const int i );
83 QList<TreeItem*> children() const;
84 TreeItem* nextSibling() const;
85 TreeItem* prevSibling() const;
89 QList<TreeItem*> myChildren;
90 SUIT_DataObject* myObj;
97 \param obj data object
98 \param parent parent item
99 \param after tree item after each this one should be inserted
101 SUIT_TreeModel::TreeItem::TreeItem( SUIT_DataObject* obj,
102 SUIT_TreeModel::TreeItem* parent,
103 SUIT_TreeModel::TreeItem* after )
104 : myParent( parent ),
108 // Add <this> to the parent's children list
110 myParent->insertChild( this, after );
114 \brief Destructor. Deletes all child items recursively.
117 SUIT_TreeModel::TreeItem::~TreeItem()
119 // Ensure that all children are deleted;
120 // each child removes itself from the children list
121 while( myChildren.count() )
122 delete myChildren.at( 0 );
124 // Remove this item from the parent's children list
126 myParent->removeChild( this );
130 \brief Insert child item.
132 \param child child item being inserted
133 \param after tree item after each \a child should be inserted
135 void SUIT_TreeModel::TreeItem::insertChild( SUIT_TreeModel::TreeItem* child,
136 SUIT_TreeModel::TreeItem* after )
141 int index = after ? after->position() + 1 : 0;
142 myChildren.insert( index, child );
146 \brief Remove child item.
148 \param child child item being removed
150 void SUIT_TreeModel::TreeItem::removeChild( SUIT_TreeModel::TreeItem* child )
154 myChildren.removeAll( child );
158 \brief Get data object.
160 \return data object this item is associated to
162 SUIT_DataObject* SUIT_TreeModel::TreeItem::dataObject() const
168 \brief Get parent item.
172 SUIT_TreeModel::TreeItem* SUIT_TreeModel::TreeItem::parent() const
178 \brief Get position of this item in its parent's children list.
180 \return item position
182 int SUIT_TreeModel::TreeItem::position() const
188 \brief Get number of child items.
190 \return number of children
192 int SUIT_TreeModel::TreeItem::childCount() const
194 return myChildren.count();
198 \brief Get child item by specified index.
200 \param i child item index
201 \return child item or 0 if \a i is out of range
203 SUIT_TreeModel::TreeItem* SUIT_TreeModel::TreeItem::child( const int i )
205 return i >= 0 && i < myChildren.count() ? myChildren.at( i ) : 0;
209 \brief Get all child items.
211 \return list of child items
213 QList<SUIT_TreeModel::TreeItem*> SUIT_TreeModel::TreeItem::children() const
219 \brief Get next sibling item.
221 \return next sibling item or 0 if there are no any
223 SUIT_TreeModel::TreeItem* SUIT_TreeModel::TreeItem::nextSibling() const
225 return parent() ? parent()->child( position()+1 ) : 0;
229 \brief Get previous sibling item.
231 \return previous sibling item or 0 if there are no any
233 SUIT_TreeModel::TreeItem* SUIT_TreeModel::TreeItem::prevSibling() const
235 return parent() ? parent()->child( position()-1 ) : 0;
239 \class SUIT_TreeModel::TreeSync
240 \brief Functor class for synchronizing data tree and tree model
241 when the data tree is changed outside the model.
245 class SUIT_TreeModel::TreeSync
248 TreeSync( SUIT_TreeModel* );
249 bool isEqual( const ObjPtr&, const ItemPtr& ) const;
250 ObjPtr nullSrc() const;
251 ItemPtr nullTrg() const;
252 ItemPtr createItem( const ObjPtr&, const ItemPtr&, const ItemPtr& ) const;
253 void updateItem( const ObjPtr&, const ItemPtr& ) const;
254 void deleteItemWithChildren( const ItemPtr& ) const;
255 QList<ObjPtr> children( const ObjPtr& ) const;
256 QList<ItemPtr> children( const ItemPtr& ) const;
257 ItemPtr parent( const ItemPtr& ) const;
259 bool needUpdate( const ItemPtr& ) const;
260 SUIT_TreeModel* myModel;
266 \param model tree model
268 SUIT_TreeModel::TreeSync::TreeSync( SUIT_TreeModel* model )
274 \brief Check if item corresponds to the specified data object.
276 \param obj data object
277 \param item tree item
278 \return \c true if item corresponds to the data object
280 bool SUIT_TreeModel::TreeSync::isEqual( const ObjPtr& obj, const ItemPtr& item ) const
282 bool isRoot = obj == myModel->root() && item == myModel->rootItem(),
283 isEq = obj && item && item->dataObject() == obj;
284 return isRoot || ( !obj && !item ) || isEq;
288 \brief Get null data object.
290 \return null data object
292 SUIT_TreeModel::ObjPtr SUIT_TreeModel::TreeSync::nullSrc() const
298 \brief Get null tree item.
300 \return null tree item
302 SUIT_TreeModel::ItemPtr SUIT_TreeModel::TreeSync::nullTrg() const
308 \brief Create an item corresponding to the specified data object.
310 \param obj data object
311 \param parent parent tree item
312 \param after tree item after each new one should be inserted
315 SUIT_TreeModel::ItemPtr SUIT_TreeModel::TreeSync::createItem( const ObjPtr& obj,
316 const ItemPtr& parent,
317 const ItemPtr& after ) const
319 ItemPtr item = myModel ? myModel->createItem( obj, parent, after ) : 0;
321 // Additional actions that can't be performed by the model, e.g. expanded state
328 \brief Update tree item.
330 \param obj reference data object
331 \param item tree item to be updated
333 void SUIT_TreeModel::TreeSync::updateItem( const ObjPtr& obj, const ItemPtr& item ) const
337 if ( item && needUpdate( item ) )
338 myModel->updateItem( item, false );
342 \brief Delete item with all children recursively.
344 \param item tree item
346 void SUIT_TreeModel::TreeSync::deleteItemWithChildren( const ItemPtr& item ) const
348 // NOTE: item is deleted inside removeItem()!
349 myModel->removeItem( item );
353 \brief Get all the children of the specified data object.
355 \param obj data object
356 \return list of the children
358 QList<SUIT_TreeModel::ObjPtr> SUIT_TreeModel::TreeSync::children( const ObjPtr& obj ) const
362 ch = obj->children();
367 \brief Get all the children of the specified tree item.
369 \param item tree item
370 \return list of the children
372 QList<SUIT_TreeModel::ItemPtr> SUIT_TreeModel::TreeSync::children( const ItemPtr& item ) const
376 ch = item->children();
381 \brief Get item which is the parent for the specified item.
383 \param item tree item
386 SUIT_TreeModel::ItemPtr SUIT_TreeModel::TreeSync::parent( const ItemPtr& item ) const
388 return item ? item->parent() : 0;
392 \brief Check if the tree item needs updating.
394 \param item tree item to be checked
395 \return \c true if item needs updating
397 \todo finalize this method
399 bool SUIT_TreeModel::TreeSync::needUpdate( const ItemPtr& item ) const
403 SUIT_DataObject* obj = item->dataObject();
405 // TODO: find simplified way to check if an item is not up-to-date:
406 // - use check-sum of various item data
407 // - use "LastModified" time stamp in data objects and tree items - hardly possible, for sometimes data objects do not know that data changes...
409 update = true; // TEMPORARY!!!
411 /* update = ( item->text( 0 ) != obj->name() ) || myBrowser->needToUpdateTexts( item );
414 // 2. check pixmap (compare serialNumber()-s)
415 QPixmap objPix = obj->icon();
416 const QPixmap* itemPix = item->pixmap( 0 );
417 update = ( objPix.isNull() && ( itemPix && !itemPix->isNull() ) ) ||
418 ( !objPix.isNull() && ( !itemPix || itemPix->isNull() ) );
419 if ( !update && !objPix.isNull() && itemPix && !itemPix->isNull() ) {
420 int aIconW = objPix.width();
423 double aScale = 20.0 / aIconW;
424 aM.scale( aScale, aScale );
425 objPix = objPix.xForm( aM );
427 update = ( objPix.serialNumber() != itemPix->serialNumber() );
436 \class SUIT_TreeModel
437 \brief Implementation of the model/view API based on the tree of SUIT_DataObject class
440 The SUIT_TreeModel class does not support insertion/removal of rows. It is synchronized
441 automatically with the tree of data objects used by SUIT-based applications to
442 expose their data in a hierarchical form to the user.
447 \param parent parent object
449 SUIT_TreeModel::SUIT_TreeModel( QObject* parent )
450 : QAbstractItemModel( parent ),
453 myAutoDeleteTree( false ),
454 myAutoUpdate( true ),
455 myUpdateModified( false )
462 \param root root data object
463 \param parent parent object
465 SUIT_TreeModel::SUIT_TreeModel( SUIT_DataObject* root, QObject* parent )
466 : QAbstractItemModel( parent ),
469 myAutoDeleteTree( false ),
470 myAutoUpdate( true ),
471 myUpdateModified( false )
479 SUIT_TreeModel::~SUIT_TreeModel()
481 if ( autoDeleteTree() ) {
482 SUIT_DataObject::disconnect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
483 this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
484 SUIT_DataObject::disconnect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
485 this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
486 SUIT_DataObject::disconnect( SIGNAL( modifed( SUIT_DataObject* ) ),
487 this, SLOT( onModified( SUIT_DataObject* ) ) );
495 \brief Register new column in the model
496 \param group_id - unique data object group identificator
497 \param name - translated column name
498 \param custom_id - custom column id that should be passed into method SUIT_DataObject::data()
500 void SUIT_TreeModel::registerColumn( const int group_id, const QString& name, const int custom_id )
503 for ( int i=0, n=myColumns.size(); i<n && !found; i++ ) {
504 if ( name == myColumns[i].myName ) {
505 myColumns[i].myIds.insert( group_id, custom_id );
512 inf.myIds.insert( group_id, custom_id );
513 inf.myAppropriate = Qtx::Shown;
514 inf.myHeaderFlags = Qtx::ShowAll;
515 int n = myColumns.size();
516 myColumns.resize( n+1 );
523 \brief Remove column from the model
525 Please take into account that column is removed only for given group_id, it means
526 that information of data objects with such group_id won't be shown.
527 If there is not any registered group_id for this column after removing, the column will be hidden
528 otherwise it continue to be shown
530 \param group_id - unique data object identificator allowing the classification of objects
531 \param name - translated column name
533 void SUIT_TreeModel::unregisterColumn( const int group_id, const QString& name )
535 for ( int i = 0, n = myColumns.size(); i < n; i++ ) {
536 if ( myColumns[i].myName == name ) {
537 myColumns[i].myIds.remove( group_id );
538 if ( myColumns[i].myIds.isEmpty() ) {
539 myColumns.remove( i );
548 \brief Change column icon.
550 \param name - column name
551 \param icon - new icon of the specified column
553 void SUIT_TreeModel::setColumnIcon( const QString& name, const QPixmap& icon )
555 for ( int i = 0, n = myColumns.size(); i < n; i++ ) {
556 if ( myColumns[i].myName == name ) {
557 myColumns[i].myIcon = icon;
564 \brief Get column icon.
566 \param name - column name
567 \return icon of the specified column
569 QPixmap SUIT_TreeModel::columnIcon( const QString& name ) const
572 for ( int i = 0, n = myColumns.size(); i < n; i++ ) {
573 if ( myColumns[i].myName == name ) {
574 res = myColumns[i].myIcon;
582 \brief Change appropriate status
584 Appropriate status determines if the column should appear in the tree view header popup menu
585 (to show/hide the column).
587 If appropriate status is not specified yet, the \c Shown value is taken,
588 it means that column should be always visible.
590 \param name - column name
591 \param appr - new appropriate status
593 void SUIT_TreeModel::setAppropriate( const QString& name, const Qtx::Appropriate appr )
595 for ( int i = 0, n = myColumns.size(); i < n; i++ ) {
596 if ( myColumns[i].myName == name && myColumns[i].myAppropriate != appr ) {
597 myColumns[i].myAppropriate = appr;
598 emit headerDataChanged( Qt::Horizontal, i, i );
605 \brief Check if the column should appear in the tree view header popup menu
606 (to show/hide the column).
608 Default implementation (if appropriate status is not specified yet)
609 returns \c Shown, it means that column should be always visible.
611 \param name - column name
612 \return appropriate status
614 Qtx::Appropriate SUIT_TreeModel::appropriate( const QString& name ) const
616 Qtx::Appropriate appr = Qtx::Shown;
617 for ( int i = 0, n = myColumns.size(); i < n; i++ ) {
618 if ( myColumns[i].myName == name ) {
619 appr = myColumns[i].myAppropriate;
628 \brief Set header flags.
630 These flags allow show in the header of the column text (name of the column),
631 icon or both text and icon.
633 \param name - column name
634 \param flags - header flags
637 void SUIT_TreeModel::setHeaderFlags( const QString& name, const Qtx::HeaderViewFlags flags )
639 for ( int i = 0, n = myColumns.size(); i < n; i++ ) {
640 if ( myColumns[i].myName == name && myColumns[i].myHeaderFlags != flags ) {
641 myColumns[i].myHeaderFlags = flags;
642 emit headerDataChanged( Qt::Horizontal, i, i );
649 \brief Get the header flags.
651 These flags allow show in the header of the column text (name of the column),
652 icon or both text and icon.
654 \param name - column name
657 Qtx::HeaderViewFlags SUIT_TreeModel::headerFlags( const QString& name ) const
659 Qtx::HeaderViewFlags flags;
660 for ( int i = 0, n = myColumns.size(); i < n; i++ ) {
661 if ( myColumns[i].myName == name ) {
662 flags = myColumns[i].myHeaderFlags;
670 \brief Set visibility state of the object.
672 \param id - column name
673 \param state - visible state
674 \param emitChanged - if set to false, blocks dataChanged() signal, this can be used to
675 prevent emitting dataChanged() several times for the same data object
677 void SUIT_TreeModel::setVisibilityState( const QString& id, Qtx::VisibilityState state, bool emitChanged )
679 VisibilityMap::const_iterator it = myVisibilityMap.find( id );
680 if ( it != myVisibilityMap.end() && it.value() == state )
683 bool needSignal = false;
684 if ( state != Qtx::UnpresentableState ) {
685 myVisibilityMap.insert( id, state );
689 needSignal = myVisibilityMap.remove( id ) > 0;
691 if ( emitChanged && needSignal ) {
694 SUIT_DataObject* o = searcher()->findObject( id );
695 if ( o ) lst << index( o );
698 lst = match( index( 0, root()->customData( Qtx::IdType ).toInt() ), DisplayRole, id, 1, Qt::MatchExactly | Qt::MatchRecursive );
700 if ( !lst.isEmpty() ) {
701 QModelIndex idx = index( lst.first().row(), SUIT_DataObject::VisibilityId, lst.first().parent() );
702 emit dataChanged( idx, idx );
708 \brief Set visibility state for all objects.
710 \param state - visible state
712 void SUIT_TreeModel::setVisibilityStateForAll( Qtx::VisibilityState state )
714 foreach( QString id, myVisibilityMap.keys() )
715 setVisibilityState( id, state );
719 \brief Get visibility state of the object.
721 \param id - column name
722 \return visible state
724 Qtx::VisibilityState SUIT_TreeModel::visibilityState( const QString& id ) const
726 VisibilityMap::const_iterator it = myVisibilityMap.find( id );
727 return it != myVisibilityMap.end() ? it.value() : Qtx::UnpresentableState;
731 \brief Get data tree root object.
732 \return data tree root
735 SUIT_DataObject* SUIT_TreeModel::root() const
741 \brief Set data tree root object.
742 \param r new data tree root
745 void SUIT_TreeModel::setRoot( SUIT_DataObject* r )
750 if ( autoDeleteTree() ) {
751 SUIT_DataObject::disconnect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
752 this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
753 SUIT_DataObject::disconnect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
754 this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
755 SUIT_DataObject::disconnect( SIGNAL( modified( SUIT_DataObject* ) ),
756 this, SLOT( onModified( SUIT_DataObject* ) ) );
760 QList<TreeItem*> items = myRootItem->children();
761 for ( QList<TreeItem*>::iterator anIt = items.begin(); anIt != items.end(); anIt++ )
774 \brief Get data for the specified model index and data role.
775 \param index model index
776 \param role data role
777 \return requested data
780 QVariant SUIT_TreeModel::data( const QModelIndex& index, int role ) const
782 if ( !index.isValid() )
785 SUIT_DataObject* obj = object( index );
792 int obj_group_id = obj->groupId();
793 const ColumnInfo& inf = myColumns[index.column()];
796 if( inf.myIds.contains( 0 ) )
798 if( inf.myIds.contains( obj_group_id ) )
799 id = inf.myIds[obj_group_id];
809 // data object text for the specified column
810 val = obj->text( id );
813 // data object text for the specified column (for editor)
814 val = obj->text( id );
816 case DecorationRole: {
818 if ( id == SUIT_DataObject::VisibilityId ) {
819 // for visibility column, icon is defined specifically (using data object id)
820 QString objId = objectId( index );
821 if ( myVisibilityMap.contains( objId ) ) {
822 // visibility status is defined -> return proper icon
823 SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
824 val = ( myVisibilityMap.value( objId ) == Qtx::ShownState ) ?
825 resMgr->loadPixmap( "SUIT", tr( "ICON_DATAOBJ_VISIBLE" ) ) :
826 resMgr->loadPixmap( "SUIT", tr( "ICON_DATAOBJ_INVISIBLE" ) );
829 // visibility status is undefined -> no icon
834 // for other columns get icon from the object
835 val = obj->icon( id );
840 // data object tooltip for the specified column
841 val = obj->toolTip( id );
844 // data object status tip for the specified column
845 val = obj->statusTip( id );
848 // data object what's this info for the specified column
849 val = obj->whatsThis( id );
852 // data object font for the specified column
853 val = obj->font( id );
855 case TextAlignmentRole:
856 // data object text alignment for the specified column
857 val = obj->alignment( id );
860 // data background color for the specified column
861 c = obj->color( SUIT_DataObject::Background, id );
862 if( !c.isValid() ) // default value
863 c = QApplication::palette().color( QPalette::Base );
868 // data foreground (text) color for the specified column
869 c = obj->color( SUIT_DataObject::Foreground, id );
870 if( !c.isValid() ) // default value
871 c = QApplication::palette().color( QPalette::Foreground );
875 // editor background color for the specified column
876 c = obj->color( SUIT_DataObject::Base, id );
877 if( !c.isValid() ) // default value
878 c = QApplication::palette().color( QPalette::Base );
882 // editor foreground (text) color for the specified column
883 c = obj->color( SUIT_DataObject::Text, id );
884 if( !c.isValid() ) // default value
885 c = QApplication::palette().color( QPalette::Text );
889 // adta object highlighted background color for the specified column
890 c = obj->color( SUIT_DataObject::Highlight, id );
891 if( !c.isValid() ) // default value
892 c = QApplication::palette().color( QPalette::Highlight );
895 case HighlightedTextRole:
896 // data object highlighted foreground (text) color for the specified column
897 c = obj->color( SUIT_DataObject::HighlightedText, id );
898 if( !c.isValid() ) // default value
899 c = QApplication::palette().color( QPalette::HighlightedText );
903 // data object checked state for the specified column
904 // NOTE! three-state check is not supported currently
905 if( obj->isCheckable( id ) )
906 val = obj->isOn( id ) ? Qt::Checked : Qt::Unchecked;
910 // NOTE! not supported currently
914 } // ... switch ( role ) ...
915 } // ... if ( obj ) ...
920 \brief Set data for the specified model index and data role.
921 \param index model index
922 \param value new data value
923 \param role data role
924 \return \c true if data is set
927 bool SUIT_TreeModel::setData( const QModelIndex& index,
928 const QVariant& value, int role )
930 if ( index.isValid() && value.isValid() ) {
931 SUIT_DataObject* obj = object( index );
933 // NOTE! only 'check state' data is supported by default
937 if ( obj->isCheckable( index.column() ) ) {
938 obj->setOn( value.toBool(), index.column() );
939 emit( dataChanged( index, index ) );
944 QString val = value.toString();
945 if ( !val.isEmpty() && obj->setName(val) ) {
946 emit( dataChanged( index, index ) );
957 return QAbstractItemModel::setData( index, value, role );
961 \brief Get data flags for specified model index.
962 \param index model index
965 Qt::ItemFlags SUIT_TreeModel::flags( const QModelIndex& index ) const
969 if (!index.isValid())
970 //return Qt::ItemIsDropEnabled; // items can be dropped into the top level of the model
973 SUIT_DataObject* obj = object(index);
976 // data object is enabled
977 if (obj->isEnabled())
978 f = f | Qt::ItemIsEnabled;
980 // data object is selectable
981 if (obj->isSelectable())
982 f = f | Qt::ItemIsSelectable;
984 // data object is checkable
985 if (obj->isCheckable(index.column()))
986 f = f | Qt::ItemIsUserCheckable;
988 // data object can be renamed
989 if (obj->renameAllowed(index.column()))
990 f = f | Qt::ItemIsEditable;
992 // data object can be dragged
993 if (obj->isDraggable())
994 f = f | Qt::ItemIsDragEnabled;
996 // another data object(s) can be dropped on this one
997 if (obj->isDropAccepted())
998 f = f | Qt::ItemIsDropEnabled;
1004 Qt::DropActions SUIT_TreeModel::supportedDropActions() const
1006 return Qt::CopyAction | Qt::MoveAction;
1010 \brief Get header data (can be used in any data view).
1011 \param column column number
1012 \param orientation header orientation
1013 \param role data role
1016 QVariant SUIT_TreeModel::headerData( int column, Qt::Orientation orientation, int role ) const
1019 // NOTE! only horizontal header is supported
1020 if ( root() && orientation == Qt::Horizontal )
1026 if((myColumns[column].myHeaderFlags & Qtx::ShowText) ||
1027 (myColumns[column].myHeaderFlags == Qtx::ShowAll))
1028 d = myColumns[column].myName;
1032 case DecorationRole:
1034 if((myColumns[column].myHeaderFlags & Qtx::ShowIcon) ||
1035 (myColumns[column].myHeaderFlags == Qtx::ShowAll))
1036 d = myColumns[column].myIcon;
1040 case AppropriateRole:
1041 // appropriate flag (can column be hidden via context popup menu)
1042 d = myColumns[column].myAppropriate;
1052 \brief Create model index.
1054 \param column data column
1055 \param parent parent model index
1058 QModelIndex SUIT_TreeModel::index( int row, int column,
1059 const QModelIndex& parent ) const
1061 if( hasIndex( row, column, parent ) )
1063 TreeItem* parentItem = treeItem( parent );
1066 TreeItem* childItem = parentItem->child( row );
1068 return createIndex( row, column, childItem );
1071 return QModelIndex();
1075 \brief Get parent model index.
1076 \param index model index
1077 \return parent model index
1079 QModelIndex SUIT_TreeModel::parent( const QModelIndex& index ) const
1081 if ( !index.isValid() )
1082 return QModelIndex();
1084 TreeItem* childItem = treeItem( index );
1085 TreeItem* parentItem = childItem ? childItem->parent() : 0;
1087 if ( !parentItem || parentItem == rootItem() )
1088 return QModelIndex();
1090 return createIndex( parentItem->position(), 0, parentItem );
1094 \brief Get number of data columns.
1095 \param parent parent model index (not used)
1096 \return data columns number
1099 int SUIT_TreeModel::columnCount( const QModelIndex& /*parent*/ ) const
1101 return myColumns.size();
1105 \brief Get number of data rows (children of the specified model index).
1106 \param parent parent model index
1107 \return data rows (children) number
1110 int SUIT_TreeModel::rowCount( const QModelIndex& parent ) const
1112 // Commented by rnv in the frame of the
1113 // "20830: EDF 1357 GUI : Hide/Show Icon" imp
1114 // if ( parent.column() > 0 )
1117 TreeItem* parentItem = treeItem( parent );
1119 return parentItem ? parentItem->childCount() : 0;
1123 \brief Get data object by the specified model index.
1124 \param index model index
1125 \return data object corresponding to the model index
1127 SUIT_DataObject* SUIT_TreeModel::object( const QModelIndex& index ) const
1129 return object( treeItem( index ) );
1133 \brief Get model index by the specified data object.
1134 \param obj data object
1135 \param column data object column
1138 QModelIndex SUIT_TreeModel::index( const SUIT_DataObject* obj, int column ) const
1140 if ( obj == root() )
1141 return QModelIndex();
1143 TreeItem* item = treeItem( obj );
1145 return item ? createIndex( item->position(), column, item ) : QModelIndex();
1149 \brief Get 'auto-delete data tree' flag value.
1150 \return 'auto-delete data tree' flag value
1151 \sa setAutoDeleteTree()
1153 bool SUIT_TreeModel::autoDeleteTree() const
1155 return myAutoDeleteTree;
1159 \brief Set 'auto-delete data tree' flag value.
1161 If this flag is set to \c true, the data tree is deleted when
1162 the tree model is destroyed. Default value for this flag is \c false.
1164 \param on 'auto-delete data tree' flag value
1165 \sa autoDeleteTree()
1167 void SUIT_TreeModel::setAutoDeleteTree( const bool on )
1169 myAutoDeleteTree = on;
1173 \brief Get 'auto-update tree' flag value.
1174 \return 'auto-update tree' flag value
1175 \sa setAutoUpdate(), updateTree()
1177 bool SUIT_TreeModel::autoUpdate() const
1179 return myAutoUpdate;
1183 \brief Set 'auto-update tree' flag value.
1185 If this flag is set to \c true (by default), the model is updated
1186 automatically when data tree is changed.
1188 \param on 'auto-update tree' flag value
1189 \sa autoUpdate(), updateTree()
1191 void SUIT_TreeModel::setAutoUpdate( const bool on )
1193 if ( myAutoUpdate == on )
1196 SUIT_DataObject::disconnect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
1197 this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
1198 SUIT_DataObject::disconnect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
1199 this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
1200 SUIT_DataObject::disconnect( SIGNAL( modified( SUIT_DataObject* ) ),
1201 this, SLOT( onModified( SUIT_DataObject* ) ) );
1204 if ( myAutoUpdate ) {
1205 SUIT_DataObject::connect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
1206 this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
1207 SUIT_DataObject::connect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
1208 this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
1209 SUIT_DataObject::connect( SIGNAL( modified( SUIT_DataObject* ) ),
1210 this, SLOT( onModified( SUIT_DataObject* ) ) );
1217 \brief Get 'updateModified' flag value.
1218 \return 'updateModified' flag value
1220 bool SUIT_TreeModel::updateModified() const
1222 return myUpdateModified;
1225 \brief Set 'updateModified' flag value.
1226 \param on 'updateModified' flag value
1228 void SUIT_TreeModel::setUpdateModified(const bool on)
1230 myUpdateModified=on;
1234 \brief Check if the specified column supports custom sorting.
1235 \param column column index on which data is being sorted
1236 \return \c true if column requires custom sorting
1239 bool SUIT_TreeModel::customSorting( const int column ) const
1241 return root() ? root()->customSorting( column ) : false;
1244 void SUIT_TreeModel::forgetObject( const SUIT_DataObject* obj )
1246 removeItem( treeItem( obj ) );
1250 \brief Compares two model indexes for the sorting purposes.
1252 This method is called only for those columns for which customSorting()
1253 method returns \c true.
1255 \param left first index to compare
1256 \param right second index to compare
1257 \return result of the comparison
1260 bool SUIT_TreeModel::lessThan( const QModelIndex& left, const QModelIndex& right ) const
1262 QVariant ldata = data( left );
1263 QVariant rdata = data( right );
1264 return root() ? root()->compare( ldata, rdata, left.column() ) : false;
1268 \brief Get item delegate for the model.
1269 \return new item delegate
1271 QAbstractItemDelegate* SUIT_TreeModel::delegate() const
1273 return new SUIT_ItemDelegate( const_cast<SUIT_TreeModel*>( this ) );
1277 void SUIT_TreeModel::emitClicked( SUIT_DataObject* obj, const QModelIndex& index) {
1278 int obj_group_id = obj->groupId();
1279 const ColumnInfo& inf = myColumns[index.column()];
1282 if( inf.myIds.contains( 0 ) )
1284 if( inf.myIds.contains( obj_group_id ) )
1285 id = inf.myIds[obj_group_id];
1286 emit clicked(obj, id);
1290 \brief Update tree model.
1292 Call this method when data tree is changed outside the model.
1293 If the 'auto-update' flag is set to \c true, the model
1294 is updated automatically when the data tree is changed.
1296 \param index starting index for the updating
1299 void SUIT_TreeModel::updateTree( const QModelIndex& index )
1301 updateTree( object( index ) );
1305 void SUIT_TreeModel::updateTreeModel(SUIT_DataObject* obj,TreeItem* item)
1309 int nobjchild=obj->childCount();
1310 SUIT_DataObject* sobj=obj->childObject(kobj);
1311 TreeItem* sitem = item->child(kitem);
1313 while(kobj < nobjchild)
1318 sitem=createItemAtPos(sobj,item,kitem);
1319 updateTreeModel(sobj,sitem);
1322 sobj=obj->childObject(kobj);
1323 sitem = item->child(kitem);
1325 else if(sitem->dataObject() != sobj)
1331 sitem = item->child(kitem);
1336 sitem=createItemAtPos(sobj,item,kitem);
1337 updateTreeModel(sobj,sitem);
1340 sobj=obj->childObject(kobj);
1341 sitem = item->child(kitem);
1346 //obj and item are synchronised : go to next ones
1347 updateTreeModel(sobj,sitem);
1348 if(sobj->modified()) updateItem(sitem, true);
1352 sobj=obj->childObject(kobj);
1353 sitem = item->child(kitem);
1356 //remove remaining items
1357 for(int i = item->childCount(); i > kitem;i--)
1359 sitem = item->child(i-1);
1365 \brief Update tree model.
1367 Call this method when data tree is changed outside the model.
1368 If the 'auto-update' flag is set to \c true, the model
1369 is updated automatically when the data tree is changed.
1371 \param obj starting data object for the updating
1374 void SUIT_TreeModel::updateTree( SUIT_DataObject* obj )
1379 else if ( obj->root() != root() )
1382 if(updateModified())
1384 updateTreeModel(obj,treeItem( obj ));
1388 synchronize<ObjPtr,ItemPtr,SUIT_TreeModel::TreeSync>( obj,
1390 SUIT_TreeModel::TreeSync( this ) );
1392 emit modelUpdated();
1396 \brief Initialize tree model.
1398 void SUIT_TreeModel::initialize()
1400 SUIT_DataObject::disconnect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
1401 this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
1402 SUIT_DataObject::disconnect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
1403 this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
1404 SUIT_DataObject::disconnect( SIGNAL( modified( SUIT_DataObject* ) ),
1405 this, SLOT( onModified( SUIT_DataObject* ) ) );
1406 if ( autoUpdate() ) {
1407 SUIT_DataObject::connect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
1408 this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
1409 SUIT_DataObject::connect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
1410 this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
1411 SUIT_DataObject::connect( SIGNAL( modified( SUIT_DataObject* ) ),
1412 this, SLOT( onModified( SUIT_DataObject* ) ) );
1415 myItems.clear(); // ????? is it really necessary
1418 myRootItem = new TreeItem( 0 );
1420 registerColumn( 0, QObject::tr( "NAME_COLUMN" ), SUIT_DataObject::NameId );
1422 QString visCol = QObject::tr( "VISIBILITY_COLUMN" );
1423 registerColumn( 0, visCol, SUIT_DataObject::VisibilityId );
1425 SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
1426 setColumnIcon( visCol, resMgr->loadPixmap( "SUIT", tr( "ICON_DATAOBJ_VISIBLE" ) ));
1427 setHeaderFlags( visCol, Qtx::ShowIcon);
1433 \brief Get root tree item.
1434 \return root tree item
1436 SUIT_TreeModel::TreeItem* SUIT_TreeModel::rootItem() const
1442 \brief Get tree item corresponding to the specified model index.
1443 \param index model index
1444 \return tree item or root item if index is invalid
1446 SUIT_TreeModel::TreeItem* SUIT_TreeModel::treeItem( const QModelIndex& index ) const
1448 return index.isValid() ? static_cast<TreeItem*>( index.internalPointer() ) : rootItem();
1452 \brief Get tree item corresponding to the specified data object.
1453 \param obj data object
1454 \return tree item or 0 if there is no tree item corresponding to \a obj
1456 SUIT_TreeModel::TreeItem* SUIT_TreeModel::treeItem( const SUIT_DataObject* obj ) const
1460 if ( obj == root() )
1462 else if ( myItems.contains( const_cast<SUIT_DataObject*>( obj ) ) )
1463 item = myItems[ const_cast<SUIT_DataObject*>( obj ) ];
1469 \brief Get data object corresponding to the specified tree item.
1470 \param item tree item
1471 \return data object or 0 if there is no data object corresponding to \a item
1473 SUIT_DataObject* SUIT_TreeModel::object( const SUIT_TreeModel::TreeItem* item ) const
1475 if ( item == rootItem() )
1478 SUIT_DataObject* obj = item ? item->dataObject() : 0;
1479 return myItems.contains( obj ) ? obj : 0;
1483 \brief Get unique object identifier
1485 Object identifier is customized via the Qtx::IdType custom data
1487 \param index model index
1488 \return object identifier or null string if it isn't specified
1489 \sa SUIT_DataObject::customData()
1491 QString SUIT_TreeModel::objectId( const QModelIndex& index ) const
1494 if ( index.isValid() ) {
1495 SUIT_DataObject* obj = object( index );
1497 int anId = obj->customData( Qtx::IdType ).toInt();
1498 objId = data( createIndex( index.row(), anId, index.internalPointer() ) ).toString();
1505 \brief Create an item corresponding to the data object.
1506 \param obj source data object
1507 \param parent parent tree item
1508 \param after tree item after which new item should be inserted
1509 \return created tree item or 0 if item could not be created
1511 SUIT_TreeModel::TreeItem* SUIT_TreeModel::createItem( SUIT_DataObject* obj,
1512 SUIT_TreeModel::TreeItem* parent,
1513 SUIT_TreeModel::TreeItem* after )
1518 SUIT_DataObject* parentObj = object( parent );
1519 QModelIndex parentIdx = index( parentObj );
1521 SUIT_DataObject* afterObj = after ? object( after ) : 0;
1522 int row = afterObj ? afterObj->position() + 1 : 0;
1524 beginInsertRows( parentIdx, row, row );
1526 myItems[ obj ] = new TreeItem( obj, parent, after );
1528 for(int pos=row;pos < parent->childCount();pos++)
1529 parent->child(pos)->setPosition(pos);
1533 obj->setModified(false);
1535 return myItems[ obj ];
1539 \brief Create an item corresponding to the data object.
1540 \param obj source data object
1541 \param parent parent tree item
1542 \param pos tree item position into which new item should be inserted
1543 \return created tree item or 0 if item could not be created
1545 SUIT_TreeModel::TreeItem* SUIT_TreeModel::createItemAtPos( SUIT_DataObject* obj,
1546 SUIT_TreeModel::TreeItem* parent,
1552 SUIT_DataObject* parentObj = object( parent );
1553 QModelIndex parentIdx = index( parentObj );
1556 SUIT_TreeModel::TreeItem* after = pos>0 ? parent->child(pos-1) : 0 ;
1558 beginInsertRows( parentIdx, row, row );
1560 SUIT_TreeModel::TreeItem* item = new TreeItem( obj, parent, after );
1561 myItems[ obj ] = item;
1563 for(int ppos=row;ppos < parent->childCount();ppos++)
1564 parent->child(ppos)->setPosition(ppos);
1568 obj->setModified(false);
1574 \brief Update tree item.
1575 \param item tree item to be updated
1576 \param emitLayoutChanged if signal about changed layout should be emitted
1578 void SUIT_TreeModel::updateItem( SUIT_TreeModel::TreeItem* item, bool emitLayoutChanged )
1583 SUIT_DataObject* obj = object( item );
1587 // update all columns corresponding to the given data object
1588 /*To avoid crashes we should update any persistent model indexes before emitting layoutChanged(). In other words, when the structure changes:
1589 - emit layoutAboutToBeChanged
1590 - Remember the QModelIndex that will change
1591 - call changePersistentIndex()
1592 - emit layoutChanged
1595 emit layoutAboutToBeChanged();
1597 // Remember the QModelIndex that will change
1598 QModelIndexList fromIndexes;
1599 QModelIndexList toIndexes;
1600 for (int i = 0; i < columnCount() - 1; ++i) {
1601 fromIndexes.append( index( obj, i ));
1602 toIndexes.append(QModelIndex());
1604 //changePersistentIndexList(fromIndexes, toIndexes); // Limitation: can lead to loss of selection
1606 emit dataChanged( toIndexes.first(), toIndexes.last() );
1607 obj->setModified(false);
1608 if ( emitLayoutChanged )
1609 emit layoutChanged();
1613 \brief Remove tree item (recursively).
1614 \param item tree item to be removed
1616 void SUIT_TreeModel::removeItem( SUIT_TreeModel::TreeItem* item )
1621 // Remove list view items from <myItems> recursively for all children.
1622 // Otherwise, "delete item" line below will destroy all item's children,
1623 // and <myItems> will contain invalid pointers
1624 while( item->childCount() )
1625 removeItem( item->child( 0 ) );
1627 SUIT_DataObject* obj = object( item );
1629 // Warning! obj can be deleted at this point!
1631 TreeItem* parent=item->parent();
1632 SUIT_DataObject* parentObj = object( parent );
1633 QModelIndex parentIdx = index( parentObj, 0 );
1634 int row = item->position();
1636 beginRemoveRows( parentIdx, row, row );
1637 myItems.remove( obj );
1639 if ( obj == root() )
1643 parent->removeChild( item );
1644 for(int pos=row;pos < parent->childCount();pos++)
1645 parent->child(pos)->setPosition(pos);
1654 \brief Called when the data object is inserted to the tree.
1655 \param object data object being inserted
1656 \param parent parent data object
1658 void SUIT_TreeModel::onInserted( SUIT_DataObject* /*object*/, SUIT_DataObject* parent )
1661 updateTree( parent );
1665 \brief Called when the data object is removed from the tree.
1666 \param object data object being removed
1667 \param parent parent data object
1669 void SUIT_TreeModel::onRemoved( SUIT_DataObject* /*object*/, SUIT_DataObject* parent )
1672 updateTree( parent );
1676 \brief Called when the data object is modified. TreeSync is not used here for maximum efficiency.
1677 It is assumed that it is up to the application to decide when its data objects are modified.
1678 \param obj data object that has been modified
1680 void SUIT_TreeModel::onModified( SUIT_DataObject* obj )
1684 QModelIndex firstIdx = index( obj, 0 );
1685 QModelIndex lastIdx = index( obj, columnCount() - 1 );
1686 emit dataChanged( firstIdx, lastIdx );
1687 obj->setModified(false);
1692 \brief Drag and Drop support.
1694 QStringList SUIT_TreeModel::mimeTypes() const
1697 types << "application/vnd.text.list";
1702 \brief Called when the data objects are exported(dragged) from the tree.
1703 \param indexes the list of exported objects
1705 QMimeData* SUIT_TreeModel::mimeData( const QModelIndexList& indexes ) const
1707 QMimeData* mimeData = new QMimeData();
1708 QByteArray encodedData;
1710 QDataStream stream( &encodedData, QIODevice::WriteOnly );
1712 foreach ( QModelIndex index, indexes ) {
1713 QString id = objectId( index );
1714 // we have to check only 0 column in order to avoid repeating items in the drag object
1715 // - QTreeView tries to drag indices for all visible columns
1716 if ( index.isValid() && index.column() == 0 && !id.isEmpty() )
1720 mimeData->setData( "application/vnd.text.list", encodedData );
1724 bool SUIT_TreeModel::dropMimeData( const QMimeData* data, Qt::DropAction action,
1725 int row, int column, const QModelIndex& parent )
1727 if ( action == Qt::IgnoreAction )
1728 // do nothing with data
1731 if ( !data->hasFormat( "application/vnd.text.list" ) )
1732 // not supported data dropped
1735 if ( !parent.isValid() )
1736 // dropping into the top level of the model is not allowed
1739 // get parent object
1740 SUIT_DataObject* pobj = object( parent );
1745 // decode mime data and collect data objects being dropped
1746 QByteArray encodedData = data->data( "application/vnd.text.list" );
1747 QDataStream stream( &encodedData, QIODevice::ReadOnly );
1749 DataObjectList objects;
1751 while ( !stream.atEnd() ) {
1754 if ( !id.isEmpty() && searcher() ) {
1755 SUIT_DataObject* obj = searcher()->findObject( id );
1756 if ( obj ) objects << obj;
1761 emit dropped( objects, pobj, row, action );
1763 // return true if there's any to drop
1764 return !objects.isEmpty();
1768 \class SUIT_ProxyModel
1769 \brief Proxy model which can be used above the SUIT_TreeModel class
1770 to enable custom sorting/filtering of the data.
1772 The SUIT_TreeModel class does not support custom sorting/filtering of the data.
1773 To use these features, the SUIT_ProxyModel class can be used as top-level
1774 wrapper for the SUIT_DataObject-based data tree model.
1779 \param parent parent object
1781 SUIT_ProxyModel::SUIT_ProxyModel( QObject* parent )
1782 : QSortFilterProxyModel( parent ),
1783 mySortingEnabled( true )
1785 SUIT_TreeModel* model = new SUIT_TreeModel( this );
1786 connect( model, SIGNAL( modelUpdated() ), this, SIGNAL( modelUpdated() ) );
1787 connect( model, SIGNAL( clicked( SUIT_DataObject*, int ) ), this, SIGNAL(clicked( SUIT_DataObject*, int ) ) );
1788 connect( model, SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ),
1789 this, SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ) );
1790 setSourceModel( model );
1791 setDynamicSortFilter( true );
1796 \param root root data object
1797 \param parent parent object
1799 SUIT_ProxyModel::SUIT_ProxyModel( SUIT_DataObject* root, QObject* parent )
1800 : QSortFilterProxyModel( parent ),
1801 mySortingEnabled( true )
1803 SUIT_TreeModel* model = new SUIT_TreeModel( root, this );
1804 connect( model, SIGNAL( modelUpdated() ), this, SIGNAL( modelUpdated() ) );
1805 connect( model, SIGNAL( clicked( SUIT_DataObject*, int ) ), this, SIGNAL( clicked( SUIT_DataObject*, int ) ) );
1806 connect( model, SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ),
1807 this, SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ) );
1808 setSourceModel( model );
1809 setDynamicSortFilter( true );
1814 \param model tree model
1815 \param parent parent object
1817 SUIT_ProxyModel::SUIT_ProxyModel( SUIT_AbstractModel* model, QObject* parent )
1818 : QSortFilterProxyModel( parent ),
1819 mySortingEnabled( true )
1821 connect( *model, SIGNAL( modelUpdated() ), this, SIGNAL( modelUpdated() ) );
1822 connect( *model, SIGNAL( clicked( SUIT_DataObject*, int ) ), this, SIGNAL( clicked( SUIT_DataObject*, int ) ) );
1823 connect( *model, SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ),
1824 this, SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ) );
1825 setSourceModel( *model );
1826 setDynamicSortFilter( true );
1832 SUIT_ProxyModel::~SUIT_ProxyModel()
1837 \brief Get data tree root object.
1838 \return data tree root
1841 SUIT_DataObject* SUIT_ProxyModel::root() const
1843 return treeModel() ? treeModel()->root() : 0;
1847 \brief Set data tree root object.
1848 \param r new data tree root
1851 void SUIT_ProxyModel::setRoot( SUIT_DataObject* r )
1854 treeModel()->setRoot( r );
1858 \brief Get data object by the specified model index.
1859 \param index model index
1860 \return data object corresponding to the model index
1862 SUIT_DataObject* SUIT_ProxyModel::object( const QModelIndex& index ) const
1864 return treeModel() ? treeModel()->object( mapToSource( index ) ) : 0;
1868 \brief Get model index by the specified data object.
1869 \param obj data object
1870 \param column data object column
1873 QModelIndex SUIT_ProxyModel::index( const SUIT_DataObject* obj, int column ) const
1875 return treeModel() ? mapFromSource( treeModel()->index( obj, column ) ) : QModelIndex();
1879 \brief Get 'auto-delete data tree' flag value.
1880 \return 'auto-delete data tree' flag value
1881 \sa setAutoDeleteTree()
1883 bool SUIT_ProxyModel::autoDeleteTree() const
1885 return treeModel() ? treeModel()->autoDeleteTree() : false;
1889 \brief Set 'auto-delete data tree' flag value.
1891 If this flag is set to \c true, the data tree is deleted when
1892 the tree model is destroyed. Default value for this flag is \c false.
1894 \param on 'auto-delete data tree' flag value
1895 \sa autoDeleteTree()
1897 void SUIT_ProxyModel::setAutoDeleteTree( const bool on )
1900 treeModel()->setAutoDeleteTree( on );
1904 \brief Get 'auto-update tree' flag value.
1905 \return 'auto-update tree' flag value
1906 \sa setAutoUpdate(), updateTree()
1908 bool SUIT_ProxyModel::autoUpdate() const
1910 return treeModel() ? treeModel()->autoUpdate() : false;
1914 \brief Get 'updateModified' flag value.
1915 \return 'updateModified' flag value
1917 bool SUIT_ProxyModel::updateModified() const
1919 return treeModel() ? treeModel()->updateModified() : false;
1922 \brief Set 'updateModified' flag value.
1924 If this flag is set to \c true (default=false), the model is updated by updateTreeModel that
1925 uses the isModified flag to update only modified objects
1927 \param on 'updateModified' flag value
1929 void SUIT_ProxyModel::setUpdateModified( const bool on )
1932 treeModel()->setUpdateModified( on );
1936 \brief Set 'auto-update tree' flag value.
1938 If this flag is set to \c true (by default), the model is updated
1939 automatically when data tree is changed.
1941 \param on 'auto-update tree' flag value
1942 \sa autoUpdate(), updateTree()
1944 void SUIT_ProxyModel::setAutoUpdate( const bool on )
1947 treeModel()->setAutoUpdate( on );
1951 \brief Check if sorting is enabled.
1952 \return \c true if sorting is enabled
1953 \sa setSortingEnabled()
1955 bool SUIT_ProxyModel::isSortingEnabled() const
1957 return mySortingEnabled;
1960 SUIT_DataSearcher* SUIT_ProxyModel::searcher() const
1962 return treeModel() ? treeModel()->searcher() : 0;
1965 void SUIT_ProxyModel::setSearcher( SUIT_DataSearcher* s )
1967 if ( treeModel() ) treeModel()->setSearcher( s );
1971 \brief Get item delegate for the model.
1972 \return new item delegate
1974 QAbstractItemDelegate* SUIT_ProxyModel::delegate() const
1976 return treeModel() ? treeModel()->delegate() : 0;
1980 \brief Update tree model.
1982 Call this method when data tree is changed outside the model.
1983 If the 'auto-update' flag is set to \c true, the model
1984 is updated automatically when the data tree is changed.
1986 \param index starting index for the updating
1989 void SUIT_ProxyModel::updateTree( const QModelIndex& index )
1992 treeModel()->updateTree( mapToSource( index ) );
1996 \brief Update tree model.
1998 Call this method when data tree is changed outside the model.
1999 If the 'auto-update' flag is set to \c true, the model
2000 is updated automatically when the data tree is changed.
2002 \param obj starting data object for the updating
2005 void SUIT_ProxyModel::updateTree( SUIT_DataObject* obj )
2008 treeModel()->updateTree( obj );
2011 void SUIT_ProxyModel::forgetObject( const SUIT_DataObject* obj )
2014 treeModel()->forgetObject( obj );
2018 \brief Compares two model indexes for the sorting purposes.
2019 \param left first index to compare
2020 \param right second index to compare
2021 \return result of the comparison
2023 bool SUIT_ProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right ) const
2025 if ( !isSortingEnabled() && left.isValid() && right.isValid() ) {
2026 return left.row() < right.row();
2028 if ( treeModel() && treeModel()->customSorting( left.column() ) ) {
2029 return treeModel()->lessThan( left, right );
2031 return QSortFilterProxyModel::lessThan( left, right );
2035 \brief Check if the specified column supports custom sorting.
2036 \param column column index on which data is being sorted
2037 \return \c true if column requires custom sorting
2040 bool SUIT_ProxyModel::customSorting( const int column ) const
2042 return treeModel() ? treeModel()->customSorting( column ) : false;
2046 \brief Enable/disable sorting.
2047 \param enabled new flag state
2048 \sa isSortingEnabled()
2050 void SUIT_ProxyModel::setSortingEnabled( bool enabled )
2052 mySortingEnabled = enabled;
2057 \brief Get tree model.
2060 SUIT_AbstractModel* SUIT_ProxyModel::treeModel() const
2062 return dynamic_cast<SUIT_AbstractModel*>( sourceModel() );
2067 \param sourceRow row index of the source data model
2068 \param sourceParent parent model index of the source data model
2069 \return \c true if the specified row should be filtered out (i.e. not displayed) or \c false otherwise
2071 bool SUIT_ProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent ) const
2073 SUIT_DataObject* o = treeModel()->object( sourceModel()->index( sourceRow, 0, sourceParent ) );
2074 SUIT_DataObject* p = o ? o->parent() : 0;
2075 return ( !p || p->expandable() ) && o && o->isVisible();
2079 \brief Register new column in the model
2080 \param group_id - unique data object identificator allowing the classification of objects
2081 \param name - translated column name
2082 \param custom_id - custom column id that should be passed into method SUIT_DataObject::data()
2084 void SUIT_ProxyModel::registerColumn( const int group_id, const QString& name, const int custom_id )
2087 treeModel()->registerColumn( group_id, name, custom_id );
2091 \brief Remove column from the model
2093 Please take into account that column is removed only for given group_id, it means
2094 that information of data objects with such group_id won't be shown.
2095 If there is not any registered group_id for this column after removing, the column will be hidden
2096 otherwise it continue to be shown
2098 \param group_id - unique data object identificator allowing the classification of objects
2099 \param name - translated column name
2101 void SUIT_ProxyModel::unregisterColumn( const int group_id, const QString& name )
2104 treeModel()->unregisterColumn( group_id, name );
2108 \brief Change column icon.
2110 \param name - column name
2111 \param icon - new icon of the specified column
2113 void SUIT_ProxyModel::setColumnIcon( const QString& name, const QPixmap& icon )
2116 treeModel()->setColumnIcon( name, icon );
2120 \brief Get column icon.
2122 \param name - column name
2123 \return icon of the specified column
2125 QPixmap SUIT_ProxyModel::columnIcon( const QString& name ) const
2127 return treeModel() ? treeModel()->columnIcon( name ) : QPixmap();
2131 \brief Change appropriate status
2133 Appropriate status determines if the column should appear in the tree view header popup menu
2134 (to show/hide the column).
2136 If appropriate status is not specified yet, the \c Shown value is taken,
2137 it means that column should be always visible.
2139 \param name - column name
2140 \param appr - new appropriate status
2142 void SUIT_ProxyModel::setAppropriate( const QString& name, const Qtx::Appropriate appr )
2145 treeModel()->setAppropriate( name, appr );
2149 \brief Check if the column should appear in the tree view header popup menu
2150 (to show/hide the column).
2152 Default implementation (if appropriate status is not specified yet)
2153 returns \c Shown, it means that column should be always visible.
2155 \param name - column name
2156 \return appropriate status
2158 Qtx::Appropriate SUIT_ProxyModel::appropriate( const QString& name ) const
2160 return treeModel() ? treeModel()->appropriate( name ) : Qtx::Shown;
2164 \brief Set header flags.
2166 These flags allow show in the header of the column text (name of the column),
2167 icon or both text and icon.
2169 \param name - column name
2170 \param flags - header flags
2173 void SUIT_ProxyModel::setHeaderFlags( const QString& name, const Qtx::HeaderViewFlags flags )
2176 treeModel()->setHeaderFlags(name, flags);
2180 \brief Get the header flags.
2182 These flags allow show in the header of the column text (name of the column),
2183 icon or both text and icon.
2185 \param name - column name
2186 \return header flags
2188 Qtx::HeaderViewFlags SUIT_ProxyModel::headerFlags( const QString& name ) const
2190 return treeModel() ? treeModel()->headerFlags( name ) : Qtx::ShowAll;
2194 \brief Set visibility state of the object.
2196 \param id - column name
2197 \param state - visible state
2198 \param emitChanged - if set to false, blocks dataChanged() signal, this can be used to
2199 prevent emitting dataChanged() several times for the same data object
2201 void SUIT_ProxyModel::setVisibilityState(const QString& id, Qtx::VisibilityState state, bool emitChanged ) {
2203 treeModel()->setVisibilityState(id,state,emitChanged);
2207 \brief Set visibility state for all objects.
2209 \param id - column name
2210 \param state - visible state
2212 void SUIT_ProxyModel::setVisibilityStateForAll(Qtx::VisibilityState state)
2215 treeModel()->setVisibilityStateForAll(state);
2219 \brief Get visibility state of the object.
2221 \param id - column name
2222 \return visible state
2224 Qtx::VisibilityState SUIT_ProxyModel::visibilityState(const QString& id) const
2226 return treeModel() ? treeModel()->visibilityState(id) : Qtx::UnpresentableState;
2229 void SUIT_ProxyModel::emitClicked( SUIT_DataObject* obj, const QModelIndex& index)
2232 treeModel()->emitClicked(obj,index);
2236 \class SUIT_ItemDelegate
2237 \brief An SUIT_DataObject-based item delegate class.
2239 This class can be used to render the SUIT_DataObject-based item
2240 in the widgets like QTreeView and others.
2241 Refer to the Qt 4 documentation, model/view architecture
2242 section for more details).
2247 \param parent parent object
2249 SUIT_ItemDelegate::SUIT_ItemDelegate( QObject* parent )
2250 : QItemDelegate( parent )
2255 \brief Render the item in the widget.
2257 Customizes the item colors for the specific roles.
2259 \param painter painter
2260 \param option painting option
2261 \param index model index being rendered
2263 void SUIT_ItemDelegate::paint( QPainter* painter,
2264 const QStyleOptionViewItem& option,
2265 const QModelIndex& index ) const
2267 QStyleOptionViewItem opt = option;
2268 if ( index.isValid() ) {
2269 // Note: we check into account only custom roles; other roles are process
2270 // correctly by the QItemDelegate class
2271 QVariant val = index.data( SUIT_TreeModel::BaseColorRole );
2272 if ( val.isValid() && val.value<QColor>().isValid() ) {
2273 QColor aBase = val.value<QColor>();
2274 aBase.setAlpha( 0 );
2275 opt.palette.setBrush( QPalette::Base, val.value<QColor>() );
2277 val = index.data( SUIT_TreeModel::TextColorRole );
2278 if ( val.isValid() && val.value<QColor>().isValid() )
2279 opt.palette.setBrush( QPalette::Text, val.value<QColor>() );
2280 val = index.data( SUIT_TreeModel::HighlightRole );
2281 if ( val.isValid() && val.value<QColor>().isValid() )
2282 opt.palette.setBrush( QPalette::Highlight, val.value<QColor>() );
2283 val = index.data( SUIT_TreeModel::HighlightedTextRole );
2284 if ( val.isValid() && val.value<QColor>().isValid() )
2285 opt.palette.setBrush( QPalette::HighlightedText, val.value<QColor>() );
2287 QItemDelegate::paint( painter, opt, index );
2290 QSize SUIT_ItemDelegate::sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const
2292 QSize size = QItemDelegate::sizeHint ( option, index );
2293 #if QT_VERSION >= 0x040500
2294 size.setHeight( size.height() + 1 );