1 // Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
22 // File: SUIT_TreeModel.cxx
23 // Author: Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
25 #include "SUIT_TreeModel.h"
26 #include "SUIT_TreeSync.h"
27 #include "SUIT_DataObject.h"
29 #include <QApplication>
32 SUIT_AbstractModel::SUIT_AbstractModel()
36 SUIT_AbstractModel::operator const QAbstractItemModel*() const
38 return dynamic_cast<const QAbstractItemModel*>( this );
41 SUIT_AbstractModel::operator QAbstractItemModel*()
43 return dynamic_cast<QAbstractItemModel*>( this );
46 SUIT_AbstractModel::operator const QObject*() const
48 return dynamic_cast<const QObject*>( this );
57 \class SUIT_TreeModel::TreeItem
58 \brief Internal class used for tree view synchronizaton with data object tree.
62 class SUIT_TreeModel::TreeItem
65 TreeItem( SUIT_DataObject* obj, TreeItem* parent = 0, TreeItem* after = 0 );
68 void insertChild( TreeItem* child, TreeItem* after = 0 );
69 void removeChild( TreeItem* child );
70 SUIT_DataObject* dataObject() const;
71 TreeItem* parent() const;
73 int childCount() const;
74 TreeItem* child( const int i );
75 QList<TreeItem*> children() const;
76 TreeItem* nextSibling() const;
77 TreeItem* prevSibling() const;
81 QList<TreeItem*> myChildren;
82 SUIT_DataObject* myObj;
88 \param obj data object
89 \param parent parent item
90 \param after tree item after each this one should be inserted
92 SUIT_TreeModel::TreeItem::TreeItem( SUIT_DataObject* obj,
93 SUIT_TreeModel::TreeItem* parent,
94 SUIT_TreeModel::TreeItem* after )
98 // Add <this> to the parent's children list
100 myParent->insertChild( this, after );
104 \brief Destructor. Deletes all child items recursively.
107 SUIT_TreeModel::TreeItem::~TreeItem()
109 // Ensure that all children are deleted;
110 // each child removes itself from the children list
111 while( myChildren.count() )
112 delete myChildren.at( 0 );
114 // Remove this item from the parent's children list
116 myParent->removeChild( this );
120 \brief Insert child item.
122 \param child child item being inserted
123 \param after tree item after each \a child should be inserted
125 void SUIT_TreeModel::TreeItem::insertChild( SUIT_TreeModel::TreeItem* child,
126 SUIT_TreeModel::TreeItem* after )
131 int index = after ? myChildren.indexOf( after ) + 1 : 0;
132 myChildren.insert( index, child );
136 \brief Remove child item.
138 \param child child item being removed
140 void SUIT_TreeModel::TreeItem::removeChild( SUIT_TreeModel::TreeItem* child )
144 myChildren.removeAll( child );
148 \brief Get data object.
150 \return data object this item is associated to
152 SUIT_DataObject* SUIT_TreeModel::TreeItem::dataObject() const
158 \brief Get parent item.
162 SUIT_TreeModel::TreeItem* SUIT_TreeModel::TreeItem::parent() const
168 \brief Get position of this item in its parent's children list.
170 \return item position
172 int SUIT_TreeModel::TreeItem::position() const
174 return myParent ? myParent->myChildren.indexOf( (TreeItem*)this ) : -1;
178 \brief Get number of child items.
180 \return number of children
182 int SUIT_TreeModel::TreeItem::childCount() const
184 return myChildren.count();
188 \brief Get child item by specified index.
190 \param i child item index
191 \return child item or 0 if \a i is out of range
193 SUIT_TreeModel::TreeItem* SUIT_TreeModel::TreeItem::child( const int i )
195 return i >= 0 && i < myChildren.count() ? myChildren.at( i ) : 0;
199 \brief Get all child items.
201 \return list of child items
203 QList<SUIT_TreeModel::TreeItem*> SUIT_TreeModel::TreeItem::children() const
209 \brief Get next sibling item.
211 \return next sibling item or 0 if there are no any
213 SUIT_TreeModel::TreeItem* SUIT_TreeModel::TreeItem::nextSibling() const
215 return parent() ? parent()->child( position()+1 ) : 0;
219 \brief Get previous sibling item.
221 \return previous sibling item or 0 if there are no any
223 SUIT_TreeModel::TreeItem* SUIT_TreeModel::TreeItem::prevSibling() const
225 return parent() ? parent()->child( position()-1 ) : 0;
229 \class SUIT_TreeModel::TreeSync
230 \brief Functor class for synchronizing data tree and tree model
231 when the data tree is changed outside the model.
235 class SUIT_TreeModel::TreeSync
238 TreeSync( SUIT_TreeModel* );
239 bool isEqual( const ObjPtr&, const ItemPtr& ) const;
240 ObjPtr nullSrc() const;
241 ItemPtr nullTrg() const;
242 ItemPtr createItem( const ObjPtr&, const ItemPtr&, const ItemPtr& ) const;
243 void updateItem( const ObjPtr&, const ItemPtr& ) const;
244 void deleteItemWithChildren( const ItemPtr& ) const;
245 QList<ObjPtr> children( const ObjPtr& ) const;
246 QList<ItemPtr> children( const ItemPtr& ) const;
247 ItemPtr parent( const ItemPtr& ) const;
249 bool needUpdate( const ItemPtr& ) const;
250 SUIT_TreeModel* myModel;
256 \param model tree model
258 SUIT_TreeModel::TreeSync::TreeSync( SUIT_TreeModel* model )
264 \brief Check if item corresponds to the specified data object.
266 \param obj data object
267 \param item tree item
268 \return \c true if item corresponds to the data object
270 bool SUIT_TreeModel::TreeSync::isEqual( const ObjPtr& obj, const ItemPtr& item ) const
272 bool isRoot = obj == myModel->root() && item == myModel->rootItem(),
273 isEq = obj && item && item->dataObject() == obj;
274 return isRoot || ( !obj && !item ) || isEq;
278 \brief Get null data object.
280 \return null data object
282 SUIT_TreeModel::ObjPtr SUIT_TreeModel::TreeSync::nullSrc() const
288 \brief Get null tree item.
290 \return null tree item
292 SUIT_TreeModel::ItemPtr SUIT_TreeModel::TreeSync::nullTrg() const
298 \brief Create an item corresponding to the specified data object.
300 \param obj data object
301 \param parent parent tree item
302 \param after tree item after each new one should be inserted
305 SUIT_TreeModel::ItemPtr SUIT_TreeModel::TreeSync::createItem( const ObjPtr& obj,
306 const ItemPtr& parent,
307 const ItemPtr& after ) const
309 ItemPtr item = myModel ? myModel->createItem( obj, parent, after ) : 0;
311 // Additional actions that can't be performed by the model, e.g. expanded state
318 \brief Update tree item.
320 \param obj reference data object
321 \param item tree item to be updated
323 void SUIT_TreeModel::TreeSync::updateItem( const ObjPtr& obj, const ItemPtr& item ) const
327 if ( item && needUpdate( item ) )
328 myModel->updateItem( item );
332 \brief Delete item with all children recursively.
334 \param item tree item
336 void SUIT_TreeModel::TreeSync::deleteItemWithChildren( const ItemPtr& item ) const
338 // NOTE: item is deleted inside removeItem()!
339 myModel->removeItem( item );
343 \brief Get all the children of the specified data object.
345 \param obj data object
346 \return list of the children
348 QList<SUIT_TreeModel::ObjPtr> SUIT_TreeModel::TreeSync::children( const ObjPtr& obj ) const
352 ch = obj->children();
357 \brief Get all the children of the specified tree item.
359 \param item tree item
360 \return list of the children
362 QList<SUIT_TreeModel::ItemPtr> SUIT_TreeModel::TreeSync::children( const ItemPtr& item ) const
366 ch = item->children();
371 \brief Get item which is the parent for the specified item.
373 \param item tree item
376 SUIT_TreeModel::ItemPtr SUIT_TreeModel::TreeSync::parent( const ItemPtr& item ) const
378 return item ? item->parent() : 0;
382 \brief Check if the tree item needs updating.
384 \param item tree item to be checked
385 \return \c true if item needs updating
387 \todo finalize this method
389 bool SUIT_TreeModel::TreeSync::needUpdate( const ItemPtr& item ) const
393 SUIT_DataObject* obj = item->dataObject();
395 // TODO: find simplified way to check if an item is not up-to-date:
396 // - use check-sum of various item data
397 // - use "LastModified" time stamp in data objects and tree items - hardly possible, for sometimes data objects do not know that data changes...
399 update = true; // TEMPORARY!!!
401 /* update = ( item->text( 0 ) != obj->name() ) || myBrowser->needToUpdateTexts( item );
404 // 2. check pixmap (compare serialNumber()-s)
405 QPixmap objPix = obj->icon();
406 const QPixmap* itemPix = item->pixmap( 0 );
407 update = ( objPix.isNull() && ( itemPix && !itemPix->isNull() ) ) ||
408 ( !objPix.isNull() && ( !itemPix || itemPix->isNull() ) );
409 if ( !update && !objPix.isNull() && itemPix && !itemPix->isNull() ) {
410 int aIconW = objPix.width();
413 double aScale = 20.0 / aIconW;
414 aM.scale( aScale, aScale );
415 objPix = objPix.xForm( aM );
417 update = ( objPix.serialNumber() != itemPix->serialNumber() );
426 \class SUIT_TreeModel
427 \brief Implementation of the model/view API based on the tree of SUIT_DataObject class
430 The SUIT_TreeModel class does not support insertion/removal of rows. It is synchronized
431 automatically with the tree of data objects used by SUIT-based applications to
432 expose their data in a hierarchical form to the user.
437 \param parent parent object
439 SUIT_TreeModel::SUIT_TreeModel( QObject* parent )
440 : QAbstractItemModel( parent ),
443 myAutoDeleteTree( false ),
451 \param root root data object
452 \param parent parent object
454 SUIT_TreeModel::SUIT_TreeModel( SUIT_DataObject* root, QObject* parent )
455 : QAbstractItemModel( parent ),
458 myAutoDeleteTree( false ),
467 SUIT_TreeModel::~SUIT_TreeModel()
469 if ( autoDeleteTree() ) {
470 SUIT_DataObject::disconnect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
471 this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
472 SUIT_DataObject::disconnect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
473 this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
481 \brief Register new column in the model
482 \param group_id - unique data object group identificator
483 \param name - translated column name
484 \param custom_id - custom column id that should be passed into method SUIT_DataObject::data()
486 void SUIT_TreeModel::registerColumn( const int group_id, const QString& name, const int custom_id )
489 for( int i=0, n=myColumns.size(); i<n && !found; i++ )
490 if( name==myColumns[i].myName )
492 myColumns[i].myIds.insert( group_id, custom_id );
499 inf.myIds.insert( group_id, custom_id );
500 inf.myAppropriate = Qtx::Shown;
501 int n = myColumns.size();
502 myColumns.resize( n+1 );
509 \brief Remove column from the model
511 Please take into account that column is removed only for given group_id, it means
512 that information of data objects with such group_id won't be shown.
513 If there is not any registered group_id for this column after removing, the column will be hidden
514 otherwise it continue to be shown
516 \param group_id - unique data object identificator allowing the classification of objects
517 \param name - translated column name
519 void SUIT_TreeModel::unregisterColumn( const int group_id, const QString& name )
521 for( int i=0, n=myColumns.size(); i<n; i++ )
522 if( myColumns[i].myName==name )
524 myColumns[i].myIds.remove( group_id );
525 if( myColumns[i].myIds.isEmpty() )
527 myColumns.remove( i );
535 \brief Change column icon.
537 \param name - column name
538 \param icon - new icon of the specified column
540 void SUIT_TreeModel::setColumnIcon( const QString& name, const QPixmap& icon )
542 for( int i=0, n=myColumns.size(); i<n; i++ )
543 if( myColumns[i].myName==name )
545 myColumns[i].myIcon = icon;
551 \brief Get column icon.
553 \param name - column name
554 \return icon of the specified column
556 QPixmap SUIT_TreeModel::columnIcon( const QString& name ) const
559 for( int i=0, n=myColumns.size(); i<n; i++ )
560 if( myColumns[i].myName==name )
562 res = myColumns[i].myIcon;
569 \brief Change appropriate status
571 Appropriate status determines if the column should appear in the tree view header popup menu
572 (to show/hide the column).
574 If appropriate status is not specified yet, the \c Shown value is taken,
575 it means that column should be always visible.
577 \param name - column name
578 \param appr - new appropriate status
580 void SUIT_TreeModel::setAppropriate( const QString& name, const Qtx::Appropriate appr )
582 for( int i=0, n=myColumns.size(); i<n; i++ )
583 if( myColumns[i].myName==name )
585 myColumns[i].myAppropriate = appr;
586 emit headerDataChanged( Qt::Horizontal, i, i );
592 \brief Check if the column should appear in the tree view header popup menu
593 (to show/hide the column).
595 Default implementation (if appropriate status is not specified yet)
596 returns \c Shown, it means that column should be always visible.
598 \param name - column name
599 \return appropriate status
601 Qtx::Appropriate SUIT_TreeModel::appropriate( const QString& name ) const
603 Qtx::Appropriate appr = Qtx::Shown;
604 for( int i=0, n=myColumns.size(); i<n; i++ )
605 if( myColumns[i].myName==name )
607 appr = myColumns[i].myAppropriate;
615 \brief Get data tree root object.
616 \return data tree root
619 SUIT_DataObject* SUIT_TreeModel::root() const
625 \brief Set data tree root object.
626 \param r new data tree root
629 void SUIT_TreeModel::setRoot( SUIT_DataObject* r )
634 if ( autoDeleteTree() ) {
635 SUIT_DataObject::disconnect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
636 this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
637 SUIT_DataObject::disconnect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
638 this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
650 \brief Get data for the specified model index and data role.
651 \param index model index
652 \param role data role
653 \return requested data
656 QVariant SUIT_TreeModel::data( const QModelIndex& index, int role ) const
658 if ( !index.isValid() )
661 SUIT_DataObject* obj = object( index );
666 int obj_group_id = obj->groupId();
667 const ColumnInfo& inf = myColumns[index.column()];
670 if( inf.myIds.contains( 0 ) )
672 if( inf.myIds.contains( obj_group_id ) )
673 id = inf.myIds[obj_group_id];
683 // data object text for the specified column
684 val = obj->text( id );
687 // data object icon for the specified column
688 val = obj->icon( id );
691 // data object tooltip for the specified column
692 val = obj->toolTip( id );
695 // data object status tip for the specified column
696 val = obj->statusTip( id );
699 // data object what's this info for the specified column
700 val = obj->whatsThis( id );
703 // data object font for the specified column
704 val = obj->font( id );
706 case TextAlignmentRole:
707 // data object text alignment for the specified column
708 val = obj->alignment( id );
711 // data background color for the specified column
712 c = obj->color( SUIT_DataObject::Background, id );
713 if( !c.isValid() ) // default value
714 c = QApplication::palette().color( QPalette::Base );
719 // data foreground (text) color for the specified column
720 c = obj->color( SUIT_DataObject::Foreground, id );
721 if( !c.isValid() ) // default value
722 c = QApplication::palette().color( QPalette::Foreground );
726 // editor background color for the specified column
727 c = obj->color( SUIT_DataObject::Base, id );
728 if( !c.isValid() ) // default value
729 c = QApplication::palette().color( QPalette::Base );
733 // editor foreground (text) color for the specified column
734 c = obj->color( SUIT_DataObject::Text, id );
735 if( !c.isValid() ) // default value
736 c = QApplication::palette().color( QPalette::Text );
740 // adta object highlighted background color for the specified column
741 c = obj->color( SUIT_DataObject::Highlight, id );
742 if( !c.isValid() ) // default value
743 c = QApplication::palette().color( QPalette::Highlight );
746 case HighlightedTextRole:
747 // data object highlighted foreground (text) color for the specified column
748 c = obj->color( SUIT_DataObject::HighlightedText, id );
749 if( !c.isValid() ) // default value
750 c = QApplication::palette().color( QPalette::HighlightedText );
754 // data object checked state for the specified column
755 // NOTE! three-state check is not supported currently
756 if( obj->isCheckable( id ) )
757 val = obj->isOn( id ) ? Qt::Checked : Qt::Unchecked;
761 // NOTE! not supported currently
765 } // ... switch ( role ) ...
766 } // ... if ( obj ) ...
771 \brief Set data for the specified model index and data role.
772 \param index model index
773 \param value new data value
774 \param role data role
775 \return \c true if data is set
778 bool SUIT_TreeModel::setData( const QModelIndex& index,
779 const QVariant& value, int role )
781 if ( index.isValid() && value.isValid() ) {
782 SUIT_DataObject* obj = object( index );
784 // NOTE! only 'check state' data is supported by default
788 if ( obj->isCheckable( index.column() ) ) {
789 obj->setOn( value.toBool(), index.column() );
790 emit( dataChanged( index, index ) );
799 return QAbstractItemModel::setData( index, value, role );
803 \brief Get data flags for specified model index.
804 \param index model index
807 Qt::ItemFlags SUIT_TreeModel::flags( const QModelIndex& index ) const
809 if ( !index.isValid() )
812 SUIT_DataObject* obj = object( index );
816 // data object is enabled
817 if ( obj->isEnabled() )
818 f = f | Qt::ItemIsEnabled;
820 // data object is selectable
821 if ( obj->isSelectable() )
822 f = f | Qt::ItemIsSelectable;
824 // data object is checkable
825 if ( obj->isCheckable( index.column() ) )
826 f = f | Qt::ItemIsUserCheckable;
832 \brief Get header data (can be used in any data view).
833 \param column column number
834 \param orientation header orientation
835 \param role data role
838 QVariant SUIT_TreeModel::headerData( int column, Qt::Orientation orientation, int role ) const
841 // NOTE! only horizontal header is supported
842 if ( root() && orientation == Qt::Horizontal )
848 d = myColumns[column].myName;
852 d = myColumns[column].myIcon;
854 case AppropriateRole:
855 // appropriate flag (can column be hidden via context popup menu)
856 d = myColumns[column].myAppropriate;
866 \brief Create model index.
868 \param column data column
869 \param parent parent model index
872 QModelIndex SUIT_TreeModel::index( int row, int column,
873 const QModelIndex& parent ) const
875 if( hasIndex( row, column, parent ) )
877 TreeItem* parentItem = treeItem( parent );
880 TreeItem* childItem = parentItem->child( row );
882 return createIndex( row, column, childItem );
885 return QModelIndex();
889 \brief Get parent model index.
890 \param index model index
891 \return parent model index
893 QModelIndex SUIT_TreeModel::parent( const QModelIndex& index ) const
895 if ( !index.isValid() )
896 return QModelIndex();
898 TreeItem* childItem = treeItem( index );
899 TreeItem* parentItem = childItem ? childItem->parent() : 0;
901 if ( !parentItem || parentItem == rootItem() )
902 return QModelIndex();
904 return createIndex( parentItem->position(), 0, parentItem );
908 \brief Get number of data columns.
909 \param parent parent model index (not used)
910 \return data columns number
913 int SUIT_TreeModel::columnCount( const QModelIndex& /*parent*/ ) const
915 return myColumns.size();
919 \brief Get number of data rows (children of the specified model index).
920 \param parent parent model index
921 \return data rows (children) number
924 int SUIT_TreeModel::rowCount( const QModelIndex& parent ) const
926 if ( parent.column() > 0 )
929 TreeItem* parentItem = treeItem( parent );
931 return parentItem ? parentItem->childCount() : 0;
935 \brief Get data object by the specified model index.
936 \param index model index
937 \return data object corresponding to the model index
939 SUIT_DataObject* SUIT_TreeModel::object( const QModelIndex& index ) const
941 return object( treeItem( index ) );
945 \brief Get model index by the specified data object.
946 \param obj data object
947 \param column data object column
950 QModelIndex SUIT_TreeModel::index( const SUIT_DataObject* obj, int column ) const
953 return QModelIndex();
955 TreeItem* item = treeItem( obj );
957 return item ? createIndex( item->position(), column, item ) : QModelIndex();
961 \brief Get 'auto-delete data tree' flag value.
962 \return 'auto-delete data tree' flag value
963 \sa setAutoDeleteTree()
965 bool SUIT_TreeModel::autoDeleteTree() const
967 return myAutoDeleteTree;
971 \brief Set 'auto-delete data tree' flag value.
973 If this flag is set to \c true, the data tree is deleted when
974 the tree model is destroyed. Default value for this flag is \c false.
976 \param on 'auto-delete data tree' flag value
979 void SUIT_TreeModel::setAutoDeleteTree( const bool on )
981 myAutoDeleteTree = on;
985 \brief Get 'auto-update tree' flag value.
986 \return 'auto-update tree' flag value
987 \sa setAutoUpdate(), updateTree()
989 bool SUIT_TreeModel::autoUpdate() const
995 \brief Set 'auto-update tree' flag value.
997 If this flag is set to \c true (by default), the model is updated
998 automatically when data tree is changed.
1000 \param on 'auto-update tree' flag value
1001 \sa autoUpdate(), updateTree()
1003 void SUIT_TreeModel::setAutoUpdate( const bool on )
1005 if ( myAutoUpdate == on )
1008 SUIT_DataObject::disconnect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
1009 this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
1010 SUIT_DataObject::disconnect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
1011 this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
1014 if ( myAutoUpdate ) {
1015 SUIT_DataObject::connect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
1016 this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
1017 SUIT_DataObject::connect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
1018 this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
1026 \brief Check if the specified column supports custom sorting.
1027 \param column column index on which data is being sorted
1028 \return \c true if column requires custom sorting
1031 bool SUIT_TreeModel::customSorting( const int column ) const
1033 return root() ? root()->customSorting( column ) : false;
1037 \brief Compares two model indexes for the sorting purposes.
1039 This method is called only for those columns for which customSorting()
1040 method returns \c true.
1042 \param left first index to compare
1043 \param right second index to compare
1044 \return result of the comparison
1047 bool SUIT_TreeModel::lessThan( const QModelIndex& left, const QModelIndex& right ) const
1049 QVariant ldata = data( left );
1050 QVariant rdata = data( right );
1051 return root() ? root()->compare( ldata, rdata, left.column() ) : false;
1055 \brief Get item delegate for the model.
1056 \return new item delegate
1058 QAbstractItemDelegate* SUIT_TreeModel::delegate() const
1060 return new SUIT_ItemDelegate( const_cast<SUIT_TreeModel*>( this ) );
1064 \brief Update tree model.
1066 Call this method when data tree is changed outside the model.
1067 If the 'auto-update' flag is set to \c true, the model
1068 is updated automatically when the data tree is changed.
1070 \param index starting index for the updating
1073 void SUIT_TreeModel::updateTree( const QModelIndex& index )
1075 updateTree( object( index ) );
1079 \brief Update tree model.
1081 Call this method when data tree is changed outside the model.
1082 If the 'auto-update' flag is set to \c true, the model
1083 is updated automatically when the data tree is changed.
1085 \param obj starting data object for the updating
1088 void SUIT_TreeModel::updateTree( SUIT_DataObject* obj )
1093 else if ( obj->root() != root() )
1096 synchronize<ObjPtr,ItemPtr,SUIT_TreeModel::TreeSync>( obj,
1098 SUIT_TreeModel::TreeSync( this ) );
1099 emit modelUpdated();
1103 \brief Initialize tree model.
1105 void SUIT_TreeModel::initialize()
1107 SUIT_DataObject::disconnect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
1108 this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
1109 SUIT_DataObject::disconnect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
1110 this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
1111 if ( autoUpdate() ) {
1112 SUIT_DataObject::connect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
1113 this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
1114 SUIT_DataObject::connect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
1115 this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
1118 myItems.clear(); // ????? is it really necessary
1121 myRootItem = new TreeItem( 0 );
1123 registerColumn( 0, QObject::tr( "NAME_COLUMN" ), SUIT_DataObject::NameId );
1128 \brief Get root tree item.
1129 \return root tree item
1131 SUIT_TreeModel::TreeItem* SUIT_TreeModel::rootItem() const
1137 \brief Get tree item corresponding to the specified model index.
1138 \param index model index
1139 \return tree item or root item if index is invalid
1141 SUIT_TreeModel::TreeItem* SUIT_TreeModel::treeItem( const QModelIndex& index ) const
1143 return index.isValid() ? static_cast<TreeItem*>( index.internalPointer() ) : rootItem();
1147 \brief Get tree item corresponding to the specified data object.
1148 \param obj data object
1149 \return tree item or 0 if there is no tree item corresponding to \a obj
1151 SUIT_TreeModel::TreeItem* SUIT_TreeModel::treeItem( const SUIT_DataObject* obj ) const
1155 if ( obj == root() )
1157 else if ( myItems.contains( const_cast<SUIT_DataObject*>( obj ) ) )
1158 item = myItems[ const_cast<SUIT_DataObject*>( obj ) ];
1164 \brief Get data object corresponding to the specified tree item.
1165 \param item tree item
1166 \return data object or 0 if there is no data object corresponding to \a item
1168 SUIT_DataObject* SUIT_TreeModel::object( const SUIT_TreeModel::TreeItem* item ) const
1170 if ( item == rootItem() )
1173 SUIT_DataObject* obj = item ? item->dataObject() : 0;
1174 return myItems.contains( obj ) ? obj : 0;
1178 \brief Create an item corresponding to the data object.
1179 \param obj source data object
1180 \param parent parent tree item
1181 \param after tree item after which new item should be inserted
1182 \return created tree item or 0 if item could not be created
1184 SUIT_TreeModel::TreeItem* SUIT_TreeModel::createItem( SUIT_DataObject* obj,
1185 SUIT_TreeModel::TreeItem* parent,
1186 SUIT_TreeModel::TreeItem* after )
1191 SUIT_DataObject* parentObj = object( parent );
1192 QModelIndex parentIdx = index( parentObj );
1194 SUIT_DataObject* afterObj = after ? object( after ) : 0;
1195 int row = afterObj ? afterObj->position() + 1 : 0;
1197 beginInsertRows( parentIdx, row, row );
1199 myItems[ obj ] = new TreeItem( obj, parent, after );
1203 return myItems[ obj ];
1207 \brief Update tree item.
1208 \param item tree item to be updated
1210 void SUIT_TreeModel::updateItem( SUIT_TreeModel::TreeItem* item )
1215 SUIT_DataObject* obj = object( item );
1219 // update all columns corresponding to the given data object
1220 QModelIndex firstIdx = index( obj, 0 );
1221 QModelIndex lastIdx = index( obj, columnCount() - 1 );
1222 emit dataChanged( firstIdx, lastIdx );
1226 \brief Remove tree item (recursively).
1227 \param item tree item to be removed
1229 void SUIT_TreeModel::removeItem( SUIT_TreeModel::TreeItem* item )
1234 // Remove list view items from <myItems> recursively for all children.
1235 // Otherwise, "delete item" line below will destroy all item's children,
1236 // and <myItems> will contain invalid pointers
1237 while( item->childCount() )
1238 removeItem( item->child( 0 ) );
1240 SUIT_DataObject* obj = object( item );
1242 // Warning! obj can be deleted at this point!
1244 SUIT_DataObject* parentObj = object( item->parent() );
1245 QModelIndex parentIdx = index( parentObj, 0 );
1246 int row = item->position();
1248 beginRemoveRows( parentIdx, row, row );
1249 myItems.remove( obj );
1251 if ( obj == root() )
1253 else if ( item->parent() )
1254 item->parent()->removeChild( item );
1262 \brief Called when the data object is inserted to the tree.
1263 \param object data object being inserted
1264 \param parent parent data object
1266 void SUIT_TreeModel::onInserted( SUIT_DataObject* /*object*/, SUIT_DataObject* parent )
1269 updateTree( parent );
1273 \brief Called when the data object is removed from the tree.
1274 \param object data object being removed
1275 \param parent parent data object
1277 void SUIT_TreeModel::onRemoved( SUIT_DataObject* /*object*/, SUIT_DataObject* parent )
1280 updateTree( parent );
1284 \class SUIT_ProxyModel
1285 \brief Proxy model which can be used above the SUIT_TreeMovel class
1286 to enable custom sorting/filtering of the data.
1288 The SUIT_TreeModel class does not support custom sorting/filtering of the data.
1289 To use these features, the SUIT_ProxyModel class can be used as top-level
1290 wrapper for the SUIT_DataObject-based data tree model.
1295 \param parent parent object
1297 SUIT_ProxyModel::SUIT_ProxyModel( QObject* parent )
1298 : QSortFilterProxyModel( parent ),
1299 mySortingEnabled( true )
1301 SUIT_TreeModel* model = new SUIT_TreeModel( this );
1302 connect( model, SIGNAL( modelUpdated() ), this, SIGNAL( modelUpdated() ) );
1303 setSourceModel( model );
1308 \param root root data object
1309 \param parent parent object
1311 SUIT_ProxyModel::SUIT_ProxyModel( SUIT_DataObject* root, QObject* parent )
1312 : QSortFilterProxyModel( parent ),
1313 mySortingEnabled( true )
1315 SUIT_TreeModel* model = new SUIT_TreeModel( root, this );
1316 connect( model, SIGNAL( modelUpdated() ), this, SIGNAL( modelUpdated() ) );
1317 setSourceModel( model );
1322 \param model tree model
1323 \param parent parent object
1325 SUIT_ProxyModel::SUIT_ProxyModel( SUIT_AbstractModel* model, QObject* parent )
1326 : QSortFilterProxyModel( parent ),
1327 mySortingEnabled( true )
1329 connect( *model, SIGNAL( modelUpdated() ), this, SIGNAL( modelUpdated() ) );
1330 setSourceModel( *model );
1336 SUIT_ProxyModel::~SUIT_ProxyModel()
1341 \brief Get data tree root object.
1342 \return data tree root
1345 SUIT_DataObject* SUIT_ProxyModel::root() const
1347 return treeModel() ? treeModel()->root() : 0;
1351 \brief Set data tree root object.
1352 \param r new data tree root
1355 void SUIT_ProxyModel::setRoot( SUIT_DataObject* r )
1358 treeModel()->setRoot( r );
1362 \brief Get data object by the specified model index.
1363 \param index model index
1364 \return data object corresponding to the model index
1366 SUIT_DataObject* SUIT_ProxyModel::object( const QModelIndex& index ) const
1368 return treeModel() ? treeModel()->object( mapToSource( index ) ) : 0;
1372 \brief Get model index by the specified data object.
1373 \param obj data object
1374 \param column data object column
1377 QModelIndex SUIT_ProxyModel::index( const SUIT_DataObject* obj, int column ) const
1379 return treeModel() ? mapFromSource( treeModel()->index( obj, column ) ) : QModelIndex();
1383 \brief Get 'auto-delete data tree' flag value.
1384 \return 'auto-delete data tree' flag value
1385 \sa setAutoDeleteTree()
1387 bool SUIT_ProxyModel::autoDeleteTree() const
1389 return treeModel() ? treeModel()->autoDeleteTree() : false;
1393 \brief Set 'auto-delete data tree' flag value.
1395 If this flag is set to \c true, the data tree is deleted when
1396 the tree model is destroyed. Default value for this flag is \c false.
1398 \param on 'auto-delete data tree' flag value
1399 \sa autoDeleteTree()
1401 void SUIT_ProxyModel::setAutoDeleteTree( const bool on )
1404 treeModel()->setAutoDeleteTree( on );
1408 \brief Get 'auto-update tree' flag value.
1409 \return 'auto-update tree' flag value
1410 \sa setAutoUpdate(), updateTree()
1412 bool SUIT_ProxyModel::autoUpdate() const
1414 return treeModel() ? treeModel()->autoUpdate() : false;
1418 \brief Set 'auto-update tree' flag value.
1420 If this flag is set to \c true (by default), the model is updated
1421 automatically when data tree is changed.
1423 \param on 'auto-update tree' flag value
1424 \sa autoUpdate(), updateTree()
1426 void SUIT_ProxyModel::setAutoUpdate( const bool on )
1429 treeModel()->setAutoUpdate( on );
1433 \brief Check if sorting is enabled.
1434 \return \c true if sorting is enabled
1435 \sa setSortingEnabled()
1437 bool SUIT_ProxyModel::isSortingEnabled() const
1439 return mySortingEnabled;
1443 \brief Get item delegate for the model.
1444 \return new item delegate
1446 QAbstractItemDelegate* SUIT_ProxyModel::delegate() const
1448 return treeModel() ? treeModel()->delegate() : 0;
1452 \brief Update tree model.
1454 Call this method when data tree is changed outside the model.
1455 If the 'auto-update' flag is set to \c true, the model
1456 is updated automatically when the data tree is changed.
1458 \param index starting index for the updating
1461 void SUIT_ProxyModel::updateTree( const QModelIndex& index )
1464 treeModel()->updateTree( mapToSource( index ) );
1468 \brief Update tree model.
1470 Call this method when data tree is changed outside the model.
1471 If the 'auto-update' flag is set to \c true, the model
1472 is updated automatically when the data tree is changed.
1474 \param obj starting data object for the updating
1477 void SUIT_ProxyModel::updateTree( SUIT_DataObject* obj )
1480 treeModel()->updateTree( obj );
1484 \brief Compares two model indexes for the sorting purposes.
1485 \param left first index to compare
1486 \param right second index to compare
1487 \return result of the comparison
1489 bool SUIT_ProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right ) const
1491 if ( !isSortingEnabled() && left.isValid() && right.isValid() ) {
1492 return left.row() < right.row();
1494 if ( treeModel() && treeModel()->customSorting( left.column() ) ) {
1495 return treeModel()->lessThan( left, right );
1497 return QSortFilterProxyModel::lessThan( left, right );
1501 \brief Check if the specified column supports custom sorting.
1502 \param column column index on which data is being sorted
1503 \return \c true if column requires custom sorting
1506 bool SUIT_ProxyModel::customSorting( const int column ) const
1508 return treeModel() ? treeModel()->customSorting( column ) : false;
1512 \brief Enable/disable sorting.
1513 \param enabled new flag state
1514 \sa isSortingEnabled()
1516 void SUIT_ProxyModel::setSortingEnabled( bool enabled )
1518 mySortingEnabled = enabled;
1523 \brief Get tree model.
1526 SUIT_AbstractModel* SUIT_ProxyModel::treeModel() const
1528 return dynamic_cast<SUIT_AbstractModel*>( sourceModel() );
1532 \brief Register new column in the model
1533 \param group_id - unique data object identificator allowing the classification of objects
1534 \param name - translated column name
1535 \param custom_id - custom column id that should be passed into method SUIT_DataObject::data()
1537 void SUIT_ProxyModel::registerColumn( const int group_id, const QString& name, const int custom_id )
1540 treeModel()->registerColumn( group_id, name, custom_id );
1544 \brief Remove column from the model
1546 Please take into account that column is removed only for given group_id, it means
1547 that information of data objects with such group_id won't be shown.
1548 If there is not any registered group_id for this column after removing, the column will be hidden
1549 otherwise it continue to be shown
1551 \param group_id - unique data object identificator allowing the classification of objects
1552 \param name - translated column name
1554 void SUIT_ProxyModel::unregisterColumn( const int group_id, const QString& name )
1557 treeModel()->unregisterColumn( group_id, name );
1561 \brief Change column icon.
1563 \param name - column name
1564 \param icon - new icon of the specified column
1566 void SUIT_ProxyModel::setColumnIcon( const QString& name, const QPixmap& icon )
1569 treeModel()->setColumnIcon( name, icon );
1573 \brief Get column icon.
1575 \param name - column name
1576 \return icon of the specified column
1578 QPixmap SUIT_ProxyModel::columnIcon( const QString& name ) const
1580 return treeModel() ? treeModel()->columnIcon( name ) : QPixmap();
1584 \brief Change appropriate status
1586 Appropriate status determines if the column should appear in the tree view header popup menu
1587 (to show/hide the column).
1589 If appropriate status is not specified yet, the \c Shown value is taken,
1590 it means that column should be always visible.
1592 \param name - column name
1593 \param appr - new appropriate status
1595 void SUIT_ProxyModel::setAppropriate( const QString& name, const Qtx::Appropriate appr )
1598 treeModel()->setAppropriate( name, appr );
1602 \brief Check if the column should appear in the tree view header popup menu
1603 (to show/hide the column).
1605 Default implementation (if appropriate status is not specified yet)
1606 returns \c Shown, it means that column should be always visible.
1608 \param name - column name
1609 \return appropriate status
1611 Qtx::Appropriate SUIT_ProxyModel::appropriate( const QString& name ) const
1613 return treeModel() ? treeModel()->appropriate( name ) : Qtx::Shown;
1622 \class SUIT_ItemDelegate
1623 \brief An SUIT_DataObject-based item delegate class.
1625 This class can be used to render the SUIT_DataObject-based item
1626 in the widgets like QTreeView and others.
1627 Refer to the Qt 4 documentation, model/view architecture
1628 section for more details).
1633 \param parent parent object
1635 SUIT_ItemDelegate::SUIT_ItemDelegate( QObject* parent )
1636 : QItemDelegate( parent )
1641 \brief Render the item in the widget.
1643 Customizes the item colors for the specific roles.
1645 \param painter painter
1646 \param option painting option
1647 \param index model index being rendered
1649 void SUIT_ItemDelegate::paint( QPainter* painter,
1650 const QStyleOptionViewItem& option,
1651 const QModelIndex& index ) const
1653 QStyleOptionViewItem opt = option;
1654 if ( index.isValid() ) {
1655 // Note: we check into account only custom roles; other roles are process
1656 // correctly by the QItemDelegate class
1657 QVariant val = index.data( SUIT_TreeModel::BaseColorRole );
1658 if ( val.isValid() && val.value<QColor>().isValid() ) {
1659 QColor aBase = val.value<QColor>();
1660 aBase.setAlpha( 0 );
1661 opt.palette.setBrush( QPalette::Base, val.value<QColor>() );
1663 val = index.data( SUIT_TreeModel::TextColorRole );
1664 if ( val.isValid() && val.value<QColor>().isValid() )
1665 opt.palette.setBrush( QPalette::Text, val.value<QColor>() );
1666 val = index.data( SUIT_TreeModel::HighlightRole );
1667 if ( val.isValid() && val.value<QColor>().isValid() )
1668 opt.palette.setBrush( QPalette::Highlight, val.value<QColor>() );
1669 val = index.data( SUIT_TreeModel::HighlightedTextRole );
1670 if ( val.isValid() && val.value<QColor>().isValid() )
1671 opt.palette.setBrush( QPalette::HighlightedText, val.value<QColor>() );
1673 QItemDelegate::paint( painter, opt, index );