Salome HOME
Merge from V6_main_20120808 08Aug12
[modules/gui.git] / src / SUIT / SUIT_TreeModel.cxx
1 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
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.
7 //
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.
12 //
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
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 // File:   SUIT_TreeModel.cxx
21 // Author: Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
22
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"
28
29 #include <QApplication>
30 #include <QHash>
31 #include <QMimeData>
32
33 SUIT_AbstractModel::SUIT_AbstractModel() : mySearcher( 0 )
34 {
35 }
36
37 SUIT_AbstractModel::operator const QAbstractItemModel*() const
38 {
39   return dynamic_cast<const QAbstractItemModel*>( this );
40 }
41
42 SUIT_AbstractModel::operator QAbstractItemModel*()
43 {
44   return dynamic_cast<QAbstractItemModel*>( this );
45 }
46
47 SUIT_AbstractModel::operator const QObject*() const
48 {
49   return dynamic_cast<const QObject*>( this );
50 }
51
52 SUIT_DataSearcher* SUIT_AbstractModel::searcher() const
53 {
54   return mySearcher;
55 }
56
57 void SUIT_AbstractModel::setSearcher( SUIT_DataSearcher* s )
58 {
59   mySearcher = s;
60 }
61
62
63 /*!
64   \class SUIT_TreeModel::TreeItem
65   \brief Internal class used for tree view synchronizaton with data object tree.
66   \internal
67 */
68
69 class SUIT_TreeModel::TreeItem
70 {
71 public:
72   TreeItem( SUIT_DataObject* obj, TreeItem* parent = 0, TreeItem* after = 0 );
73   ~TreeItem();
74
75   void                  insertChild( TreeItem* child, TreeItem* after = 0 );
76   void                  removeChild( TreeItem* child );
77   SUIT_DataObject*      dataObject() const;
78   TreeItem*             parent() const;
79   int                   position() 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;
86   
87 private:
88   TreeItem*             myParent;
89   QList<TreeItem*>      myChildren;
90   SUIT_DataObject*      myObj;
91   int _position;
92 };
93
94 /*!
95   \brief Constructor.
96   \internal
97   \param obj data object
98   \param parent parent item
99   \param after tree item after each this one should be inserted
100 */
101 SUIT_TreeModel::TreeItem::TreeItem( SUIT_DataObject*          obj, 
102                                     SUIT_TreeModel::TreeItem* parent,
103                                     SUIT_TreeModel::TreeItem* after )
104 : myParent( parent ),
105   myObj( obj ),
106   _position(-1)
107 {
108   // Add <this> to the parent's children list
109   if ( myParent )
110     myParent->insertChild( this, after );
111 }
112
113 /*!
114   \brief Destructor. Deletes all child items recursively.
115   \internal
116 */
117 SUIT_TreeModel::TreeItem::~TreeItem()
118 {
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 );
123
124   // Remove this item from the parent's children list
125   if ( myParent )
126     myParent->removeChild( this );
127 }
128
129 /*!
130   \brief Insert child item.
131   \internal
132   \param child child item being inserted
133   \param after tree item after each \a child should be inserted
134 */
135 void SUIT_TreeModel::TreeItem::insertChild( SUIT_TreeModel::TreeItem* child, 
136                                             SUIT_TreeModel::TreeItem* after )
137 {
138   if ( !child )
139     return;
140
141   int index = after ? after->position() + 1 : 0;
142   myChildren.insert( index, child );
143 }
144
145 /*!
146   \brief Remove child item.
147   \internal
148   \param child child item being removed
149 */
150 void SUIT_TreeModel::TreeItem::removeChild( SUIT_TreeModel::TreeItem* child )
151 {
152   if ( !child )
153     return;
154   myChildren.removeAll( child );
155 }
156
157 /*!
158   \brief Get data object.
159   \internal
160   \return data object this item is associated to
161 */
162 SUIT_DataObject* SUIT_TreeModel::TreeItem::dataObject() const
163 {
164   return myObj;
165 }
166
167 /*!
168   \brief Get parent item.
169   \internal
170   \return parent item
171 */
172 SUIT_TreeModel::TreeItem* SUIT_TreeModel::TreeItem::parent() const
173 {
174   return myParent;
175 }
176
177 /*!
178   \brief Get position of this item in its parent's children list.
179   \internal
180   \return item position
181 */
182 int SUIT_TreeModel::TreeItem::position() const
183 {
184   return _position;
185 }
186
187 /*!
188   \brief Get number of child items.
189   \internal
190   \return number of children
191 */
192 int SUIT_TreeModel::TreeItem::childCount() const
193 {
194   return myChildren.count();
195 }
196
197 /*!
198   \brief Get child item by specified index.
199   \internal
200   \param i child item index
201   \return child item or 0 if \a i is out of range
202 */
203 SUIT_TreeModel::TreeItem* SUIT_TreeModel::TreeItem::child( const int i )
204 {
205   return i >= 0 && i < myChildren.count() ? myChildren.at( i ) : 0;
206 }
207
208 /*!
209   \brief Get all child items.
210   \internal
211   \return list of child items
212 */
213 QList<SUIT_TreeModel::TreeItem*> SUIT_TreeModel::TreeItem::children() const
214 {
215   return myChildren;
216 }
217
218 /*!
219   \brief Get next sibling item.
220   \internal
221   \return next sibling item or 0 if there are no any
222 */
223 SUIT_TreeModel::TreeItem* SUIT_TreeModel::TreeItem::nextSibling() const
224 {
225   return parent() ? parent()->child( position()+1 ) : 0;
226 }
227
228 /*!
229   \brief Get previous sibling item.
230   \internal
231   \return previous sibling item or 0 if there are no any
232 */
233 SUIT_TreeModel::TreeItem* SUIT_TreeModel::TreeItem::prevSibling() const
234 {
235   return parent() ? parent()->child( position()-1 ) : 0;
236 }
237
238 /*!
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.
242   \internal
243 */
244
245 class SUIT_TreeModel::TreeSync
246 {
247 public:
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;
258 private:
259   bool              needUpdate( const ItemPtr& ) const;
260   SUIT_TreeModel*   myModel;
261 };
262
263 /*!
264   \brief Constructor.
265   \internal
266   \param model tree model
267 */
268 SUIT_TreeModel::TreeSync::TreeSync( SUIT_TreeModel* model )
269 : myModel( model )
270 {
271 }
272
273 /*!
274   \brief Check if item corresponds to the specified data object.
275   \internal
276   \param obj data object
277   \param item tree item 
278   \return \c true if item corresponds to the data object
279 */
280 bool SUIT_TreeModel::TreeSync::isEqual( const ObjPtr& obj, const ItemPtr& item ) const
281 {
282   bool isRoot = obj == myModel->root() && item == myModel->rootItem(),
283        isEq   = obj && item && item->dataObject() == obj;
284   return isRoot || ( !obj && !item ) || isEq;
285 }
286
287 /*!
288   \brief Get null data object.
289   \internal
290   \return null data object
291 */
292 SUIT_TreeModel::ObjPtr SUIT_TreeModel::TreeSync::nullSrc() const
293 {
294   return 0;
295 }
296
297 /*!
298   \brief Get null tree item.
299   \internal
300   \return null tree item
301 */
302 SUIT_TreeModel::ItemPtr SUIT_TreeModel::TreeSync::nullTrg() const
303 {
304   return 0;
305 }
306
307 /*!
308   \brief Create an item corresponding to the specified data object.
309   \internal
310   \param obj data object
311   \param parent parent tree item
312   \param after tree item after each new one should be inserted
313   \return created item
314 */
315 SUIT_TreeModel::ItemPtr SUIT_TreeModel::TreeSync::createItem( const ObjPtr&  obj,
316                                                               const ItemPtr& parent, 
317                                                               const ItemPtr& after ) const
318 {
319   ItemPtr item = myModel ? myModel->createItem( obj, parent, after ) : 0;
320
321   // Additional actions that can't be performed by the model, e.g. expanded state
322   if( item )
323     obj->update();
324   return item;
325 }
326
327 /*!
328   \brief Update tree item.
329   \internal
330   \param obj reference data object
331   \param item tree item to be updated
332 */
333 void SUIT_TreeModel::TreeSync::updateItem( const ObjPtr& obj, const ItemPtr& item ) const
334 {
335   if( obj )
336     obj->update();
337   if ( item && needUpdate( item ) ) 
338     myModel->updateItem( item, false );
339 }
340
341 /*!
342   \brief Delete item with all children recursively.
343   \internal
344   \param item tree item
345 */
346 void SUIT_TreeModel::TreeSync::deleteItemWithChildren( const ItemPtr& item ) const
347 {
348   // NOTE: item is deleted inside removeItem()!
349   myModel->removeItem( item );
350 }
351
352 /*!
353   \brief Get all the children of the specified data object.
354   \internal
355   \param obj data object
356   \return list of the children
357 */
358 QList<SUIT_TreeModel::ObjPtr> SUIT_TreeModel::TreeSync::children( const ObjPtr& obj ) const
359 {
360   QList<ObjPtr> ch;
361   if ( obj )
362     ch = obj->children();
363   return ch;
364 }
365
366 /*!
367   \brief Get all the children of the specified tree item.
368   \internal
369   \param item tree item
370   \return list of the children
371 */
372 QList<SUIT_TreeModel::ItemPtr> SUIT_TreeModel::TreeSync::children( const ItemPtr& item ) const
373 {
374   QList<ItemPtr> ch;
375   if ( item ) 
376     ch = item->children();
377   return ch;
378 }
379
380 /*!
381   \brief Get item which is the parent for the specified item.
382   \internal
383   \param item tree item
384   \return parent item
385 */
386 SUIT_TreeModel::ItemPtr SUIT_TreeModel::TreeSync::parent( const ItemPtr& item ) const
387 {
388   return item ? item->parent() : 0;
389 }
390
391 /*!
392   \brief Check if the tree item needs updating.
393   \internal
394   \param item tree item to be checked
395   \return \c true if item needs updating
396
397   \todo finalize this method
398 */
399 bool SUIT_TreeModel::TreeSync::needUpdate( const ItemPtr& item ) const
400 {
401   bool update = false;
402   if ( item ) {
403     SUIT_DataObject* obj = item->dataObject();
404     if ( obj ) {
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...
408       // ...
409       update = true; // TEMPORARY!!!
410       // 1. check text
411 /*      update = ( item->text( 0 ) != obj->name() ) || myBrowser->needToUpdateTexts( item );
412
413       if ( !update ) { 
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();
421           if( aIconW > 20 ) {
422             QWMatrix aM;
423             double aScale = 20.0 / aIconW;
424             aM.scale( aScale, aScale );
425             objPix = objPix.xForm( aM );
426           }
427           update = ( objPix.serialNumber() != itemPix->serialNumber() );
428         }
429       }*/
430     }
431   }
432   return update;
433 }
434
435 /*!
436   \class SUIT_TreeModel
437   \brief Implementation of the model/view API based on the tree of SUIT_DataObject class
438   instances.
439
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.
443 */
444
445 /*!
446   \brief Constructor.
447   \param parent parent object
448 */
449 SUIT_TreeModel::SUIT_TreeModel( QObject* parent )
450 : QAbstractItemModel( parent ),
451   myRoot( 0 ),
452   myRootItem( 0 ),
453   myAutoDeleteTree( false ),
454   myAutoUpdate( true ),
455   myUpdateModified( false )
456 {
457   initialize();
458 }
459
460 /*!
461   \brief Constructor.
462   \param root root data object
463   \param parent parent object
464 */
465 SUIT_TreeModel::SUIT_TreeModel( SUIT_DataObject* root, QObject* parent )
466 : QAbstractItemModel( parent ),
467   myRoot( root ),
468   myRootItem( 0 ),
469   myAutoDeleteTree( false ),
470   myAutoUpdate( true ),
471   myUpdateModified( false )
472 {
473   initialize();
474 }
475
476 /*!
477   \brief Destructor
478 */
479 SUIT_TreeModel::~SUIT_TreeModel()
480 {
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     delete myRoot;
487   }
488
489   delete myRootItem;
490 }
491
492 /*!
493   \brief Register new column in the model
494   \param group_id - unique data object group identificator
495   \param name - translated column name
496   \param custom_id - custom column id that should be passed into method SUIT_DataObject::data()
497  */
498 void SUIT_TreeModel::registerColumn( const int group_id, const QString& name, const int custom_id )
499 {
500   bool found = false;
501   for ( int i=0, n=myColumns.size(); i<n && !found; i++ ) {
502     if ( name == myColumns[i].myName ) {
503       myColumns[i].myIds.insert( group_id, custom_id );
504       found = true;
505     }
506   }
507   if ( !found ) {
508     ColumnInfo inf;
509     inf.myName = name;
510     inf.myIds.insert( group_id, custom_id );
511     inf.myAppropriate = Qtx::Shown;
512     inf.myHeaderFlags = Qtx::ShowAll;
513     int n = myColumns.size();
514     myColumns.resize( n+1 );
515     myColumns[n] = inf;
516     reset();
517   }
518 }
519
520 /*!
521   \brief Remove column from the model
522
523   Please take into account that column is removed only for given group_id, it means
524   that information of data objects with such group_id won't be shown.
525   If there is not any registered group_id for this column after removing, the column will be hidden
526   otherwise it continue to be shown
527
528   \param group_id - unique data object identificator allowing the classification of objects 
529   \param name - translated column name
530  */
531 void SUIT_TreeModel::unregisterColumn( const int group_id, const QString& name )
532 {
533   for ( int i = 0, n = myColumns.size(); i < n; i++ ) {
534     if ( myColumns[i].myName == name ) {
535       myColumns[i].myIds.remove( group_id );
536       if ( myColumns[i].myIds.isEmpty() ) {
537         myColumns.remove( i );
538         reset();
539       }
540       break;
541     }
542   }
543 }
544
545 /*!
546   \brief Change column icon.
547
548   \param name - column name
549   \param icon - new icon of the specified column
550 */
551 void SUIT_TreeModel::setColumnIcon( const QString& name, const QPixmap& icon )
552 {
553   for ( int i = 0, n = myColumns.size(); i < n; i++ ) {
554     if ( myColumns[i].myName == name ) {
555       myColumns[i].myIcon = icon;
556       break;
557     }
558   }
559 }
560
561 /*!
562   \brief Get column icon.
563
564   \param name - column name
565   \return icon of the specified column
566 */
567 QPixmap SUIT_TreeModel::columnIcon( const QString& name ) const
568 {
569   QPixmap res;
570   for ( int i = 0, n = myColumns.size(); i < n; i++ ) {
571     if ( myColumns[i].myName == name ) {
572       res = myColumns[i].myIcon;
573       break;
574     }
575   }
576   return res;
577 }
578
579 /*!
580   \brief Change appropriate status
581   
582   Appropriate status determines if the column should appear in the tree view header popup menu
583   (to show/hide the column).
584
585   If appropriate status is not specified yet, the \c Shown value is taken,
586   it means that column should be always visible.
587
588   \param name - column name
589   \param appr - new appropriate status
590 */
591 void SUIT_TreeModel::setAppropriate( const QString& name, const Qtx::Appropriate appr )
592 {
593   for ( int i = 0, n = myColumns.size(); i < n; i++ ) {
594     if ( myColumns[i].myName == name && myColumns[i].myAppropriate != appr ) {
595       myColumns[i].myAppropriate = appr;
596       emit headerDataChanged( Qt::Horizontal, i, i );
597       break;
598     }
599   }
600 }
601
602 /*!
603   \brief Check if the column should appear in the tree view header popup menu
604   (to show/hide the column).
605
606   Default implementation (if appropriate status is not specified yet)
607   returns \c Shown, it means that column should be always visible.
608
609   \param name - column name
610   \return appropriate status
611 */
612 Qtx::Appropriate SUIT_TreeModel::appropriate( const QString& name ) const
613 {
614   Qtx::Appropriate appr = Qtx::Shown;
615   for ( int i = 0, n = myColumns.size(); i < n; i++ ) {
616     if ( myColumns[i].myName == name ) {
617       appr = myColumns[i].myAppropriate;
618       break;
619     }
620   }
621   return appr;
622 }
623
624
625 /*!
626   \brief Set header flags.
627   
628   These flags allow show in the header of the column text (name of the column),
629   icon or both text and icon.
630   
631   \param name - column name
632   \param flags - header flags
633
634 */
635 void SUIT_TreeModel::setHeaderFlags( const QString& name, const Qtx::HeaderViewFlags flags )
636 {
637   for ( int i = 0, n = myColumns.size(); i < n; i++ ) {
638     if ( myColumns[i].myName == name && myColumns[i].myHeaderFlags != flags ) {
639       myColumns[i].myHeaderFlags = flags;
640       emit headerDataChanged( Qt::Horizontal, i, i );
641       break;
642     }
643   }
644 }
645
646 /*!
647   \brief Get the  header flags.
648   
649   These flags allow show in the header of the column text (name of the column),
650   icon or both text and icon.
651   
652   \param name - column name
653   \return header flags
654 */
655 Qtx::HeaderViewFlags SUIT_TreeModel::headerFlags( const QString& name ) const
656 {
657   Qtx::HeaderViewFlags flags;
658   for ( int i = 0, n = myColumns.size(); i < n; i++ ) {
659     if ( myColumns[i].myName == name ) {
660       flags = myColumns[i].myHeaderFlags;
661       break;
662     }
663   }
664   return flags;
665 }
666
667 /*!
668   \brief Set visibility state of the object.
669   
670   \param id - column name
671   \param state - visible state
672 */
673 void SUIT_TreeModel::setVisibilityState( const QString& id, Qtx::VisibilityState state )
674 {
675   VisibilityMap::const_iterator it = myVisibilityMap.find( id );
676   if ( it != myVisibilityMap.end() && it.value() == state )
677     return;
678   
679   bool needSignal = false;
680   if ( state != Qtx::UnpresentableState ) {
681     myVisibilityMap.insert( id, state );
682     needSignal = true;
683   }
684   else {
685     needSignal = myVisibilityMap.remove( id ) > 0;
686   }
687   if ( needSignal ) {
688     QModelIndexList lst;
689     if ( searcher() ) {
690       SUIT_DataObject* o = searcher()->findObject( id );
691       if ( o ) lst << index( o );
692     }
693     else {
694       lst = match( index( 0, root()->customData( Qtx::IdType ).toInt() ), DisplayRole, id, 1, Qt::MatchExactly | Qt::MatchRecursive );
695     }
696     if ( !lst.isEmpty() ) {
697       QModelIndex idx = index( lst.first().row(), SUIT_DataObject::VisibilityId, lst.first().parent() );
698       emit dataChanged( idx, idx );
699     }
700   }
701 }
702
703 /*!
704   \brief Set visibility state for all objects.
705   
706   \param id - column name
707   \param state - visible state
708 */
709 void SUIT_TreeModel::setVisibilityStateForAll( Qtx::VisibilityState state )
710 {
711   if ( state != Qtx::UnpresentableState ) {
712     VisibilityMap::ConstIterator it = myVisibilityMap.begin();
713     while ( it != myVisibilityMap.end() ) {
714       if ( it.value() != state )
715         setVisibilityState( it.key(), state );
716       it++;
717     }
718   }
719   else {
720     QList<QString> anIds = myVisibilityMap.keys();
721     myVisibilityMap.clear();
722     QList<QString>::ConstIterator it = anIds.begin();
723     while ( it != anIds.end() ) {
724       QModelIndexList lst;
725       if ( searcher() ) {
726         SUIT_DataObject* o = searcher()->findObject( *it );
727         if ( o ) lst << index( o );
728       }
729       else {
730         lst = match( index( 0, root()->customData( Qtx::IdType ).toInt() ), DisplayRole, (*it), 1, Qt::MatchExactly | Qt::MatchRecursive );
731       }
732       if ( !lst.isEmpty() ) {
733         QModelIndex idx = index( lst.first().row(), SUIT_DataObject::VisibilityId ,lst.first().parent() );
734         emit dataChanged( idx, idx );
735       }
736       it++;
737     }
738   }
739 }
740
741 /*!
742   \brief Get visibility state of the object.
743   
744   \param id - column name
745   \return visible state
746 */
747 Qtx::VisibilityState SUIT_TreeModel::visibilityState( const QString& id ) const
748 {
749   VisibilityMap::const_iterator it = myVisibilityMap.find( id );
750   return it != myVisibilityMap.end() ? it.value() : Qtx::UnpresentableState;
751 }
752
753 /*!
754   \brief Get data tree root object.
755   \return data tree root
756   \sa setRoot()
757 */
758 SUIT_DataObject* SUIT_TreeModel::root() const
759 {
760   return myRoot;
761 }
762
763 /*!
764   \brief Set data tree root object.
765   \param r new data tree root
766   \sa root()
767 */
768 void SUIT_TreeModel::setRoot( SUIT_DataObject* r )
769 {
770   if ( root() == r )
771     return;
772
773   if ( autoDeleteTree() ) {
774     SUIT_DataObject::disconnect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
775                                  this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
776     SUIT_DataObject::disconnect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
777                                  this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
778     delete myRoot;
779   }
780
781   myRoot = r;
782
783   //initialize();
784   reset();
785   emit modelUpdated();
786 }
787
788 /*!
789   \brief Get data for the specified model index and data role.
790   \param index model index
791   \param role data role
792   \return requested data
793   \sa setData()
794 */
795 QVariant SUIT_TreeModel::data( const QModelIndex& index, int role ) const
796 {
797   if ( !index.isValid() )
798     return QVariant();
799
800   SUIT_DataObject* obj = object( index );
801   if ( !obj )
802     return QVariant();
803
804   QColor c;
805   QVariant val;
806
807   int obj_group_id = obj->groupId();
808   const ColumnInfo& inf = myColumns[index.column()];
809
810   int id = -1;
811   if( inf.myIds.contains( 0 ) )
812     id = inf.myIds[0];
813   if( inf.myIds.contains( obj_group_id ) )
814     id = inf.myIds[obj_group_id];
815
816   if( id<0 )
817     return QVariant();
818
819   if ( obj )
820   {
821     switch ( role )
822         {
823     case DisplayRole:
824       // data object text for the specified column
825       val = obj->text( id );
826       break;
827     case EditRole:
828       // data object text for the specified column (for editor)
829       val = obj->text( id );
830       break;
831     case DecorationRole: {
832       // icon
833       if ( id == SUIT_DataObject::VisibilityId ) {
834         // for visibility column, icon is defined specifically (using data object id)
835         QString objId = objectId( index );
836         if ( myVisibilityMap.contains( objId ) ) {
837           // visibility status is defined -> return proper icon
838           SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();      
839           val  = ( myVisibilityMap.value( objId ) == Qtx::ShownState ) ? 
840             resMgr->loadPixmap( "SUIT", tr( "ICON_DATAOBJ_VISIBLE" ) ) : 
841             resMgr->loadPixmap( "SUIT", tr( "ICON_DATAOBJ_INVISIBLE" ) );
842         } 
843         else {
844           // visibility status is undefined -> no icon
845           val = QIcon();
846         }
847       }
848       else {
849         // for other columns get icon from the object
850         val = obj->icon( id );
851       }
852       break;
853     }
854     case ToolTipRole:
855       // data object tooltip for the specified column
856       val = obj->toolTip( id ); 
857       break;
858     case StatusTipRole:
859       // data object status tip for the specified column
860       val = obj->statusTip( id ); 
861       break;
862     case WhatsThisRole:
863       // data object what's this info for the specified column
864       val = obj->whatsThis( id ); 
865       break;
866     case FontRole:
867       // data object font for the specified column
868       val = obj->font( id ); 
869       break;
870     case TextAlignmentRole:
871       // data object text alignment for the specified column
872       val = obj->alignment( id ); 
873       break;
874     case BackgroundRole:
875       // data background color for the specified column
876       c = obj->color( SUIT_DataObject::Background, id );
877       if( !c.isValid() ) // default value
878             c = QApplication::palette().color( QPalette::Base );
879       c.setAlpha( 0 );
880       val = c; 
881       break;
882     case ForegroundRole:
883       // data foreground (text) color for the specified column
884       c = obj->color( SUIT_DataObject::Foreground, id );
885       if( !c.isValid() ) // default value
886             c = QApplication::palette().color( QPalette::Foreground );
887       val = c; 
888       break;
889     case BaseColorRole:
890       // editor background color for the specified column
891       c = obj->color( SUIT_DataObject::Base, id );
892       if( !c.isValid() ) // default value
893             c = QApplication::palette().color( QPalette::Base );
894       val = c; 
895       break;
896     case TextColorRole:
897       // editor foreground (text) color for the specified column
898       c = obj->color( SUIT_DataObject::Text, id );
899       if( !c.isValid() ) // default value
900             c = QApplication::palette().color( QPalette::Text );
901       val = c; 
902       break;
903     case HighlightRole:
904       // adta object highlighted background color for the specified column
905       c = obj->color( SUIT_DataObject::Highlight, id );
906       if( !c.isValid() ) // default value
907             c = QApplication::palette().color( QPalette::Highlight );
908       val = c; 
909       break;
910     case HighlightedTextRole:
911       // data object highlighted foreground (text) color for the specified column
912       c = obj->color( SUIT_DataObject::HighlightedText, id );
913       if( !c.isValid() ) // default value
914             c = QApplication::palette().color( QPalette::HighlightedText );
915       val = c; 
916       break;
917     case CheckStateRole:
918       // data object checked state for the specified column
919       // NOTE! three-state check is not supported currently
920       if( obj->isCheckable( id ) )
921             val = obj->isOn( id ) ? Qt::Checked : Qt::Unchecked; 
922       break;
923     case SizeHintRole:
924       // data size hint
925       // NOTE! not supported currently
926       break;
927     default:
928       break;
929     } // ... switch ( role ) ...
930   } // ... if ( obj ) ...
931   return val;
932 }
933
934 /*!
935   \brief Set data for the specified model index and data role.
936   \param index model index
937   \param value new data value
938   \param role data role
939   \return \c true if data is set
940   \sa data()
941 */
942 bool SUIT_TreeModel::setData( const QModelIndex& index, 
943                               const QVariant& value, int role )
944 {
945   if ( index.isValid() && value.isValid() ) {
946     SUIT_DataObject* obj = object( index );
947     if ( obj ) {
948       // NOTE! only 'check state' data is supported by default
949       switch ( role ) {
950       case CheckStateRole:
951         // checked state
952         if ( obj->isCheckable( index.column() ) ) {
953           obj->setOn( value.toBool(), index.column() );
954           emit( dataChanged( index, index ) );
955           return true;
956         }
957         break;
958       case EditRole: {
959         QString val = value.toString();
960         if ( !val.isEmpty() && obj->setName(val) ) {
961           emit( dataChanged( index, index ) );
962           return true;
963         }
964         return false;
965         break;
966       }
967       default:
968         break;
969       }
970     }
971   }
972   return QAbstractItemModel::setData( index, value, role );
973 }
974
975 /*!
976   \brief Get data flags for specified model index.
977   \param index model index
978   \return data flags
979 */
980 Qt::ItemFlags SUIT_TreeModel::flags( const QModelIndex& index ) const
981 {
982   Qt::ItemFlags f = 0;
983
984   if (!index.isValid())
985     //return Qt::ItemIsDropEnabled; // items can be dropped into the top level of the model
986     return f;
987
988   SUIT_DataObject* obj = object(index);
989
990   if (obj) {
991     // data object is enabled
992     if (obj->isEnabled())
993       f = f | Qt::ItemIsEnabled;
994
995     // data object is selectable
996     if (obj->isSelectable())
997       f = f | Qt::ItemIsSelectable;
998
999     // data object is checkable
1000     if (obj->isCheckable(index.column()))
1001       f = f | Qt::ItemIsUserCheckable;
1002     
1003     // data object can be renamed
1004     if (obj->renameAllowed(index.column()))
1005       f = f | Qt::ItemIsEditable;
1006     
1007     // data object can be dragged
1008     if (obj->isDraggable())
1009       f = f | Qt::ItemIsDragEnabled;
1010     
1011     // another data object(s) can be dropped on this one
1012     if (obj->isDropAccepted())
1013       f = f | Qt::ItemIsDropEnabled;
1014   }
1015
1016   return f;
1017 }
1018
1019 Qt::DropActions SUIT_TreeModel::supportedDropActions() const
1020 {
1021   return Qt::CopyAction | Qt::MoveAction;
1022 }
1023
1024 /*!
1025   \brief Get header data (can be used in any data view).
1026   \param column column number
1027   \param orientation header orientation
1028   \param role data role
1029   \return header data
1030 */
1031 QVariant SUIT_TreeModel::headerData( int column, Qt::Orientation orientation, int role ) const
1032 {
1033   QVariant d;
1034   // NOTE! only horizontal header is supported
1035   if ( root() && orientation == Qt::Horizontal )
1036   {
1037     switch ( role )
1038         {
1039     case DisplayRole:
1040       // column title
1041       if((myColumns[column].myHeaderFlags & Qtx::ShowText) || 
1042          (myColumns[column].myHeaderFlags == Qtx::ShowAll)) 
1043         d = myColumns[column].myName;
1044       else
1045         d = QString();
1046       break;
1047     case DecorationRole:
1048       // column icon
1049       if((myColumns[column].myHeaderFlags & Qtx::ShowIcon) || 
1050          (myColumns[column].myHeaderFlags == Qtx::ShowAll)) 
1051         d = myColumns[column].myIcon;
1052       else
1053         d = QIcon();      
1054       break;
1055     case AppropriateRole:
1056       // appropriate flag (can column be hidden via context popup menu)
1057       d = myColumns[column].myAppropriate;
1058       break;
1059     default:
1060       break;
1061     }
1062   }
1063   return d;
1064 }
1065
1066 /*!
1067   \brief Create model index.
1068   \param row data row
1069   \param column data column
1070   \param parent parent model index
1071   \return model index
1072 */
1073 QModelIndex SUIT_TreeModel::index( int row, int column, 
1074                                    const QModelIndex& parent ) const
1075 {
1076   if( hasIndex( row, column, parent ) )
1077   {
1078     TreeItem* parentItem = treeItem( parent );
1079     if( parentItem )
1080     {
1081       TreeItem* childItem = parentItem->child( row );
1082       if( childItem )
1083         return createIndex( row, column, childItem );
1084     }
1085   }
1086   return QModelIndex();
1087 }
1088
1089 /*!
1090   \brief Get parent model index.
1091   \param index model index
1092   \return parent model index
1093 */
1094 QModelIndex SUIT_TreeModel::parent( const QModelIndex& index ) const
1095 {
1096   if ( !index.isValid() )
1097     return QModelIndex();
1098
1099   TreeItem* childItem = treeItem( index );
1100   TreeItem* parentItem = childItem ? childItem->parent() : 0;
1101
1102   if ( !parentItem || parentItem == rootItem() )
1103     return QModelIndex();
1104
1105   return createIndex( parentItem->position(), 0, parentItem );
1106 }
1107
1108 /*!
1109   \brief Get number of data columns.
1110   \param parent parent model index (not used)
1111   \return data columns number
1112   \sa rowCount()
1113 */
1114 int SUIT_TreeModel::columnCount( const QModelIndex& /*parent*/ ) const
1115 {
1116   return myColumns.size();
1117 }
1118
1119 /*!
1120   \brief Get number of data rows (children of the specified model index).
1121   \param parent parent model index
1122   \return data rows (children) number
1123   \sa columnCount()
1124 */
1125 int SUIT_TreeModel::rowCount( const QModelIndex& parent ) const
1126 {
1127   // Commented by rnv in the frame of the 
1128   // "20830: EDF 1357 GUI : Hide/Show Icon" imp
1129   // if ( parent.column() > 0 )
1130   // return 0;
1131
1132   TreeItem* parentItem = treeItem( parent );
1133
1134   return parentItem ? parentItem->childCount() : 0;
1135 }
1136
1137 /*!
1138   \brief Get data object by the specified model index.
1139   \param index model index
1140   \return data object corresponding to the model index
1141 */
1142 SUIT_DataObject* SUIT_TreeModel::object( const QModelIndex& index ) const
1143 {
1144   return object( treeItem( index ) );
1145 }
1146
1147 /*!
1148   \brief Get model index by the specified data object.
1149   \param obj data object
1150   \param column data object column
1151   \return model index
1152 */
1153 QModelIndex SUIT_TreeModel::index( const SUIT_DataObject* obj, int column ) const
1154 {
1155   if ( obj == root() )
1156     return QModelIndex();
1157
1158   TreeItem* item = treeItem( obj );
1159
1160   return item ? createIndex( item->position(), column, item ) : QModelIndex();
1161 }
1162
1163 /*!
1164   \brief Get 'auto-delete data tree' flag value.
1165   \return 'auto-delete data tree' flag value
1166   \sa setAutoDeleteTree()
1167 */
1168 bool SUIT_TreeModel::autoDeleteTree() const
1169 {
1170   return myAutoDeleteTree;
1171 }
1172
1173 /*!
1174   \brief Set 'auto-delete data tree' flag value.
1175
1176   If this flag is set to \c true, the data tree is deleted when
1177   the tree model is destroyed. Default value for this flag is \c false.
1178
1179   \param on 'auto-delete data tree' flag value
1180   \sa autoDeleteTree()
1181 */
1182 void SUIT_TreeModel::setAutoDeleteTree( const bool on )
1183 {
1184   myAutoDeleteTree = on;
1185 }
1186
1187 /*!
1188   \brief Get 'auto-update tree' flag value.
1189   \return 'auto-update tree' flag value
1190   \sa setAutoUpdate(), updateTree()
1191 */
1192 bool SUIT_TreeModel::autoUpdate() const
1193 {
1194   return myAutoUpdate;
1195 }
1196
1197 /*!
1198   \brief Set 'auto-update tree' flag value.
1199
1200   If this flag is set to \c true (by default), the model is updated
1201   automatically when data tree is changed.
1202
1203   \param on 'auto-update tree' flag value
1204   \sa autoUpdate(), updateTree()
1205 */
1206 void SUIT_TreeModel::setAutoUpdate( const bool on )
1207 {
1208   if ( myAutoUpdate == on )
1209     return;
1210
1211   SUIT_DataObject::disconnect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
1212                                this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
1213   SUIT_DataObject::disconnect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
1214                                this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
1215   myAutoUpdate = on;
1216
1217   if ( myAutoUpdate ) {
1218     SUIT_DataObject::connect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
1219                               this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
1220     SUIT_DataObject::connect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
1221                               this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
1222
1223     updateTree();
1224   }
1225 }
1226
1227 /*!
1228   \brief Get 'updateModified' flag value.
1229   \return 'updateModified' flag value
1230 */
1231 bool SUIT_TreeModel::updateModified() const
1232 {
1233   return myUpdateModified;
1234 }
1235 /*!
1236   \brief Set 'updateModified' flag value.
1237   \param on 'updateModified' flag value
1238 */
1239 void SUIT_TreeModel::setUpdateModified(const bool on)
1240 {
1241   myUpdateModified=on;
1242 }
1243
1244 /*!
1245   \brief Check if the specified column supports custom sorting.
1246   \param column column index on which data is being sorted
1247   \return \c true if column requires custom sorting
1248   \sa lessThan()
1249 */
1250 bool SUIT_TreeModel::customSorting( const int column ) const
1251 {
1252   return root() ? root()->customSorting( column ) : false;
1253 }
1254
1255 void SUIT_TreeModel::forgetObject( const SUIT_DataObject* obj )
1256 {
1257   removeItem( treeItem( obj ) );
1258 }
1259
1260 /*!
1261   \brief Compares two model indexes for the sorting purposes.
1262
1263   This method is called only for those columns for which customSorting()
1264   method returns \c true.
1265
1266   \param left first index to compare
1267   \param right second index to compare
1268   \return result of the comparison
1269   \sa customSorting()
1270 */
1271 bool SUIT_TreeModel::lessThan( const QModelIndex& left, const QModelIndex& right ) const
1272 {
1273   QVariant ldata = data( left );
1274   QVariant rdata = data( right );
1275   return root() ? root()->compare( ldata, rdata, left.column() ) : false;
1276 }
1277
1278 /*!
1279   \brief Get item delegate for the model.
1280   \return new item delegate
1281 */
1282 QAbstractItemDelegate* SUIT_TreeModel::delegate() const
1283 {
1284   return new SUIT_ItemDelegate( const_cast<SUIT_TreeModel*>( this ) );
1285 }
1286
1287
1288 void SUIT_TreeModel::emitClicked( SUIT_DataObject* obj, const QModelIndex& index) {
1289   int obj_group_id = obj->groupId();
1290   const ColumnInfo& inf = myColumns[index.column()];
1291
1292   int id = -1;
1293   if( inf.myIds.contains( 0 ) )
1294     id = inf.myIds[0];
1295   if( inf.myIds.contains( obj_group_id ) )
1296     id = inf.myIds[obj_group_id];
1297   emit clicked(obj, id);
1298 }
1299
1300 /*!
1301   \brief Update tree model.
1302
1303   Call this method when data tree is changed outside the model.
1304   If the 'auto-update' flag is set to \c true, the model
1305   is updated automatically when the data tree is changed.
1306
1307   \param index starting index for the updating
1308   \sa setAutoUpdate()
1309 */
1310 void SUIT_TreeModel::updateTree( const QModelIndex& index )
1311 {
1312   updateTree( object( index ) );
1313 }
1314
1315
1316 void SUIT_TreeModel::updateTreeModel(SUIT_DataObject* obj,TreeItem* item)
1317 {
1318   int kobj=0;
1319   int kitem=0;
1320   int nobjchild=obj->childCount();
1321   SUIT_DataObject* sobj=obj->childObject(kobj);
1322   TreeItem* sitem = item->child(kitem);
1323
1324   while(kobj < nobjchild)
1325     {
1326       if(sitem==0)
1327         {
1328           //end of item list
1329           if(kitem==0)
1330             sitem=createItemAtPos(sobj,item,0);
1331           else
1332             sitem=createItemAtPos(sobj,item,kitem);
1333           updateTreeModel(sobj,sitem);
1334           kobj++;
1335           kitem++;
1336           sobj=obj->childObject(kobj);
1337           sitem = item->child(kitem);
1338         }
1339       else if(sitem->dataObject() != sobj)
1340         {
1341           if(treeItem(sobj))
1342             {
1343               // item : to remove
1344               removeItem(sitem);
1345               sitem = item->child(kitem);
1346             }
1347           else
1348             {
1349               // obj : new object
1350               createItemAtPos(sobj,item,kitem);
1351               kobj++;
1352               kitem++;
1353               sobj=obj->childObject(kobj);
1354               sitem = item->child(kitem);
1355             }
1356         }
1357       else
1358         {
1359           //obj and item are synchronised : go to next ones
1360           updateTreeModel(sobj,sitem);
1361           if(sobj->modified()) updateItem(sitem, true);
1362           if( sobj ) sobj->update();
1363           kobj++;
1364           kitem++;
1365           sobj=obj->childObject(kobj);
1366           sitem = item->child(kitem);
1367         }
1368     }
1369   //remove remaining items
1370   for(int i = item->childCount(); i > kitem;i--)
1371     {
1372       sitem = item->child(i-1);
1373       removeItem(sitem);
1374     }
1375 }
1376
1377 /*!
1378   \brief Update tree model.
1379
1380   Call this method when data tree is changed outside the model.
1381   If the 'auto-update' flag is set to \c true, the model
1382   is updated automatically when the data tree is changed.
1383
1384   \param obj starting data object for the updating
1385   \sa setAutoUpdate()
1386 */
1387 void SUIT_TreeModel::updateTree( SUIT_DataObject* obj )
1388 {
1389   if ( !obj )
1390     obj = root();
1391
1392   else if ( obj->root() != root() )
1393     return;
1394
1395   if(updateModified())
1396     {
1397       updateTreeModel(obj,treeItem( obj ));
1398     }
1399   else
1400     {
1401       synchronize<ObjPtr,ItemPtr,SUIT_TreeModel::TreeSync>( obj,
1402                                                             treeItem( obj ),
1403                                                             SUIT_TreeModel::TreeSync( this ) );
1404     }
1405   emit modelUpdated();
1406 }
1407
1408 /*!
1409   \brief Initialize tree model.
1410 */
1411 void SUIT_TreeModel::initialize()
1412 {
1413   SUIT_DataObject::disconnect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
1414                                this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
1415   SUIT_DataObject::disconnect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
1416                                this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
1417   if ( autoUpdate() ) {
1418     SUIT_DataObject::connect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
1419                               this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
1420     SUIT_DataObject::connect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
1421                               this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
1422   }
1423
1424   myItems.clear(); // ????? is it really necessary
1425
1426   if ( !myRootItem )
1427     myRootItem = new TreeItem( 0 );
1428
1429   registerColumn( 0, QObject::tr( "NAME_COLUMN" ), SUIT_DataObject::NameId );
1430
1431   QString visCol = QObject::tr( "VISIBILITY_COLUMN" );
1432   registerColumn( 0, visCol, SUIT_DataObject::VisibilityId );
1433
1434   SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
1435   setColumnIcon( visCol, resMgr->loadPixmap( "SUIT", tr( "ICON_DATAOBJ_VISIBLE" ) ));
1436   setHeaderFlags( visCol, Qtx::ShowIcon);
1437
1438   updateTree();
1439 }
1440
1441 /*!
1442   \brief Get root tree item.
1443   \return root tree item
1444 */
1445 SUIT_TreeModel::TreeItem* SUIT_TreeModel::rootItem() const
1446 {
1447   return myRootItem;
1448 }
1449
1450 /*!
1451   \brief Get tree item corresponding to the specified model index.
1452   \param index model index
1453   \return tree item or root item if index is invalid
1454 */
1455 SUIT_TreeModel::TreeItem* SUIT_TreeModel::treeItem( const QModelIndex& index ) const
1456 {
1457   return index.isValid() ? static_cast<TreeItem*>( index.internalPointer() ) : rootItem();
1458 }
1459
1460 /*!
1461   \brief Get tree item corresponding to the specified data object.
1462   \param obj data object
1463   \return tree item or 0 if there is no tree item corresponding to \a obj
1464 */
1465 SUIT_TreeModel::TreeItem* SUIT_TreeModel::treeItem( const SUIT_DataObject* obj ) const
1466 {
1467   TreeItem* item = 0;
1468
1469   if ( obj == root() )
1470     item = rootItem();
1471   else if ( myItems.contains( const_cast<SUIT_DataObject*>( obj ) ) )
1472     item = myItems[ const_cast<SUIT_DataObject*>( obj ) ];
1473
1474   return item;
1475 }
1476
1477 /*!
1478   \brief Get data object corresponding to the specified tree item.
1479   \param item tree item
1480   \return data object or 0 if there is no data object corresponding to \a item
1481 */
1482 SUIT_DataObject* SUIT_TreeModel::object( const SUIT_TreeModel::TreeItem* item ) const
1483 {
1484   if ( item == rootItem() )
1485     return root();
1486  
1487   SUIT_DataObject* obj = item ? item->dataObject() : 0;
1488   return myItems.contains( obj ) ? obj : 0;
1489 }
1490
1491 /*!
1492   \brief Get unique object identifier
1493   
1494   Object identifier is customized via the Qtx::IdType custom data
1495
1496   \param index model index
1497   \return object identifier or null string if it isn't specified
1498   \sa SUIT_DataObject::customData()
1499 */
1500 QString SUIT_TreeModel::objectId( const QModelIndex& index ) const
1501 {
1502   QString objId;
1503   if ( index.isValid() ) {
1504     SUIT_DataObject* obj = object( index );
1505     if ( obj ) {
1506       int anId = obj->customData( Qtx::IdType ).toInt(); 
1507       objId = data( createIndex( index.row(), anId, index.internalPointer() ) ).toString();
1508     }
1509   }
1510   return objId;
1511 }
1512
1513 /*!
1514   \brief Create an item corresponding to the data object.
1515   \param obj source data object
1516   \param parent parent tree item
1517   \param after tree item after which new item should be inserted
1518   \return created tree item or 0 if item could not be created
1519 */
1520 SUIT_TreeModel::TreeItem* SUIT_TreeModel::createItem( SUIT_DataObject* obj,
1521                                                       SUIT_TreeModel::TreeItem* parent, 
1522                                                       SUIT_TreeModel::TreeItem* after )
1523 {
1524   if ( !obj )
1525     return 0;
1526
1527   SUIT_DataObject* parentObj = object( parent );
1528   QModelIndex parentIdx = index( parentObj );
1529
1530   SUIT_DataObject* afterObj = after ? object( after ) : 0;
1531   int row = afterObj ? afterObj->position() + 1 : 0;
1532
1533   beginInsertRows( parentIdx, row, row );
1534
1535   myItems[ obj ] = new TreeItem( obj, parent, after );
1536
1537   for(int pos=row;pos < parent->childCount();pos++)
1538     parent->child(pos)->setPosition(pos);
1539
1540   endInsertRows();
1541
1542   obj->setModified(false);
1543
1544   return myItems[ obj ];
1545 }
1546
1547 /*!
1548   \brief Create an item corresponding to the data object.
1549   \param obj source data object
1550   \param parent parent tree item
1551   \param pos tree item position into which new item should be inserted
1552   \return created tree item or 0 if item could not be created
1553 */
1554 SUIT_TreeModel::TreeItem* SUIT_TreeModel::createItemAtPos( SUIT_DataObject* obj,
1555                                                            SUIT_TreeModel::TreeItem* parent,
1556                                                            int pos )
1557 {
1558   if ( !obj )
1559     return 0;
1560
1561   SUIT_DataObject* parentObj = object( parent );
1562   QModelIndex parentIdx = index( parentObj );
1563
1564   int row = pos ;
1565   SUIT_TreeModel::TreeItem* after = pos>0 ? parent->child(pos-1) : 0 ;
1566
1567   beginInsertRows( parentIdx, row, row );
1568
1569   SUIT_TreeModel::TreeItem* item = new TreeItem( obj, parent, after );
1570   myItems[ obj ] = item;
1571
1572   for(int pos=row;pos < parent->childCount();pos++)
1573     parent->child(pos)->setPosition(pos);
1574
1575   endInsertRows();
1576
1577   obj->setModified(false);
1578
1579   return item;
1580 }
1581
1582 /*!
1583   \brief Update tree item.
1584   \param item tree item to be updated
1585   \param emitLayoutChanged if signal about changed layout should be emitted
1586 */
1587 void SUIT_TreeModel::updateItem( SUIT_TreeModel::TreeItem* item, bool emitLayoutChanged )
1588 {
1589   if ( !item )
1590     return;
1591   
1592   SUIT_DataObject* obj = object( item );
1593   if ( !obj )
1594     return;
1595   
1596   // update all columns corresponding to the given data object
1597   //emit layoutAboutToBeChanged(); // VSR 25/04/2011: fix crash on delete objects
1598   QModelIndex firstIdx = index( obj, 0 );
1599   QModelIndex lastIdx  = index( obj, columnCount() - 1 );
1600   emit dataChanged( firstIdx, lastIdx );
1601   obj->setModified(false);
1602   if( emitLayoutChanged )
1603     emit layoutChanged();
1604 }
1605
1606 /*!
1607   \brief Remove tree item (recursively).
1608   \param item tree item to be removed
1609 */
1610 void SUIT_TreeModel::removeItem( SUIT_TreeModel::TreeItem* item )
1611 {
1612   if ( !item )
1613     return;
1614
1615   // Remove list view items from <myItems> recursively for all children.
1616   // Otherwise, "delete item" line below will destroy all item's children,
1617   // and <myItems> will contain invalid pointers
1618   while( item->childCount() )
1619     removeItem( item->child( 0 ) );
1620
1621   SUIT_DataObject* obj = object( item );
1622   
1623   // Warning! obj can be deleted at this point!
1624
1625   TreeItem* parent=item->parent();
1626   SUIT_DataObject* parentObj = object( parent );
1627   QModelIndex parentIdx = index( parentObj, 0 );
1628   int row = item->position();
1629   
1630   beginRemoveRows( parentIdx, row, row );
1631   myItems.remove( obj );
1632
1633   if ( obj == root() )
1634     setRoot( 0 );
1635   else if ( parent )
1636     {
1637       parent->removeChild( item );
1638       for(int pos=row;pos < parent->childCount();pos++)
1639         parent->child(pos)->setPosition(pos);
1640     }
1641
1642   delete item;
1643
1644   endRemoveRows();
1645 }
1646
1647 /*!
1648   \brief Called when the data object is inserted to the tree.
1649   \param object data object being inserted
1650   \param parent parent data object
1651 */
1652 void SUIT_TreeModel::onInserted( SUIT_DataObject* /*object*/, SUIT_DataObject* parent )
1653 {
1654   if ( autoUpdate() )
1655     updateTree( parent );
1656 }
1657
1658 /*!
1659   \brief Called when the data object is removed from the tree.
1660   \param object data object being removed
1661   \param parent parent data object
1662 */
1663 void SUIT_TreeModel::onRemoved( SUIT_DataObject* /*object*/, SUIT_DataObject* parent )
1664 {
1665   if ( autoUpdate() )
1666     updateTree( parent );
1667 }
1668
1669 /*!
1670   \brief Drag and Drop support.
1671 */
1672 QStringList SUIT_TreeModel::mimeTypes() const
1673 {
1674   QStringList types;
1675   types << "application/vnd.text.list";
1676   return types;
1677 }
1678
1679 /*!
1680   \brief Called when the data objects are exported(dragged) from the tree.
1681   \param indexes the list of exported objects
1682 */
1683 QMimeData* SUIT_TreeModel::mimeData( const QModelIndexList& indexes ) const
1684 {
1685   QMimeData* mimeData = new QMimeData();
1686   QByteArray encodedData;
1687
1688   QDataStream stream( &encodedData, QIODevice::WriteOnly );
1689
1690   foreach ( QModelIndex index, indexes ) {
1691     QString id = objectId( index );
1692     // we have to check only 0 column in order to avoid repeating items in the drag object
1693     // - QTreeView tries to drag indices for all visible columns
1694     if ( index.isValid() && index.column() == 0 && !id.isEmpty() )
1695       stream << id;
1696   }
1697
1698   mimeData->setData( "application/vnd.text.list", encodedData );
1699   return mimeData;
1700 }
1701
1702 bool SUIT_TreeModel::dropMimeData( const QMimeData* data, Qt::DropAction action,
1703                                    int row, int column, const QModelIndex& parent )
1704 {
1705   if ( action == Qt::IgnoreAction )
1706     // do nothing with data
1707     return false;
1708
1709   if ( !data->hasFormat( "application/vnd.text.list" ) )
1710     // not supported data dropped
1711     return false;
1712
1713   if ( !parent.isValid() )
1714     // dropping into the top level of the model is not allowed
1715     return false;
1716
1717   // get parent object
1718   SUIT_DataObject* pobj = object( parent );
1719   if ( !pobj )
1720     // invalid parent
1721     return false;
1722
1723   // decode mime data and collect data objects being dropped
1724   QByteArray encodedData = data->data( "application/vnd.text.list" );
1725   QDataStream stream( &encodedData, QIODevice::ReadOnly );
1726   
1727   DataObjectList objects;
1728
1729   while ( !stream.atEnd() ) {
1730     QString id;
1731     stream >> id;
1732     if ( !id.isEmpty() && searcher() ) {
1733       SUIT_DataObject* obj = searcher()->findObject( id );
1734       if ( obj ) objects << obj;
1735     }
1736   }
1737
1738   // emit signal
1739   emit dropped( objects, pobj, row, action );
1740
1741   // return true if there's any to drop
1742   return !objects.isEmpty();
1743 }
1744
1745 /*!
1746   \class SUIT_ProxyModel
1747   \brief Proxy model which can be used above the SUIT_TreeModel class
1748   to enable custom sorting/filtering of the data.
1749
1750   The SUIT_TreeModel class does not support custom sorting/filtering of the data.
1751   To use these features, the SUIT_ProxyModel class can be used as top-level
1752   wrapper for the SUIT_DataObject-based data tree model.
1753 */
1754
1755 /*!
1756   \brief Constructor.
1757   \param parent parent object
1758 */
1759 SUIT_ProxyModel::SUIT_ProxyModel( QObject* parent )
1760 : QSortFilterProxyModel( parent ),
1761   mySortingEnabled( true )
1762 {
1763   SUIT_TreeModel* model = new SUIT_TreeModel( this );
1764   connect( model, SIGNAL( modelUpdated() ), this, SIGNAL( modelUpdated() ) );
1765   connect( model, SIGNAL( clicked( SUIT_DataObject*, int ) ), this, SIGNAL(clicked( SUIT_DataObject*, int ) ) );
1766   connect( model, SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ),
1767            this,  SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ) );
1768   setSourceModel( model );
1769   setDynamicSortFilter( true );
1770 }
1771
1772 /*!
1773   \brief Constructor.
1774   \param root root data object
1775   \param parent parent object
1776 */
1777 SUIT_ProxyModel::SUIT_ProxyModel( SUIT_DataObject* root, QObject* parent )
1778 : QSortFilterProxyModel( parent ),
1779   mySortingEnabled( true )
1780 {
1781   SUIT_TreeModel* model = new SUIT_TreeModel( root, this );
1782   connect( model, SIGNAL( modelUpdated() ), this, SIGNAL( modelUpdated() ) );
1783   connect( model, SIGNAL( clicked( SUIT_DataObject*, int ) ), this, SIGNAL( clicked( SUIT_DataObject*, int ) ) );
1784   connect( model, SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ),
1785            this,  SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ) );
1786   setSourceModel( model );
1787   setDynamicSortFilter( true );
1788 }
1789
1790 /*!
1791   \brief Constructor.
1792   \param model tree model
1793   \param parent parent object
1794 */
1795 SUIT_ProxyModel::SUIT_ProxyModel( SUIT_AbstractModel* model, QObject* parent )
1796 : QSortFilterProxyModel( parent ),
1797   mySortingEnabled( true )
1798 {
1799   connect( *model, SIGNAL( modelUpdated() ), this, SIGNAL( modelUpdated() ) );
1800   connect( *model, SIGNAL( clicked( SUIT_DataObject*, int ) ), this, SIGNAL( clicked( SUIT_DataObject*, int ) ) );
1801   connect( *model, SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ),
1802            this,   SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ) );
1803   setSourceModel( *model );
1804   setDynamicSortFilter( true );
1805 }
1806
1807 /*!
1808   \brief Destructor.
1809 */
1810 SUIT_ProxyModel::~SUIT_ProxyModel()
1811 {
1812 }
1813
1814 /*!
1815   \brief Get data tree root object.
1816   \return data tree root
1817   \sa setRoot()
1818 */
1819 SUIT_DataObject* SUIT_ProxyModel::root() const
1820 {
1821   return treeModel() ? treeModel()->root() : 0;
1822 }
1823
1824 /*!
1825   \brief Set data tree root object.
1826   \param r new data tree root
1827   \sa root()
1828 */
1829 void SUIT_ProxyModel::setRoot( SUIT_DataObject* r )
1830 {
1831   if ( treeModel() )
1832     treeModel()->setRoot( r );
1833 }
1834
1835 /*!
1836   \brief Get data object by the specified model index.
1837   \param index model index
1838   \return data object corresponding to the model index
1839 */
1840 SUIT_DataObject* SUIT_ProxyModel::object( const QModelIndex& index ) const
1841 {
1842   return treeModel() ? treeModel()->object( mapToSource( index ) ) : 0;
1843 }
1844
1845 /*!
1846   \brief Get model index by the specified data object.
1847   \param obj data object
1848   \param column data object column
1849   \return model index
1850 */
1851 QModelIndex SUIT_ProxyModel::index( const SUIT_DataObject* obj, int column ) const
1852 {
1853   return treeModel() ? mapFromSource( treeModel()->index( obj, column ) ) : QModelIndex();
1854 }
1855
1856 /*!
1857   \brief Get 'auto-delete data tree' flag value.
1858   \return 'auto-delete data tree' flag value
1859   \sa setAutoDeleteTree()
1860 */
1861 bool SUIT_ProxyModel::autoDeleteTree() const
1862 {
1863   return treeModel() ? treeModel()->autoDeleteTree() : false;
1864 }
1865
1866 /*!
1867   \brief Set 'auto-delete data tree' flag value.
1868
1869   If this flag is set to \c true, the data tree is deleted when
1870   the tree model is destroyed. Default value for this flag is \c false.
1871
1872   \param on 'auto-delete data tree' flag value
1873   \sa autoDeleteTree()
1874 */
1875 void SUIT_ProxyModel::setAutoDeleteTree( const bool on )
1876 {
1877   if ( treeModel() )
1878     treeModel()->setAutoDeleteTree( on );
1879 }
1880
1881 /*!
1882   \brief Get 'auto-update tree' flag value.
1883   \return 'auto-update tree' flag value
1884   \sa setAutoUpdate(), updateTree()
1885 */
1886 bool SUIT_ProxyModel::autoUpdate() const
1887 {
1888   return treeModel() ? treeModel()->autoUpdate() : false;
1889 }
1890
1891 /*!
1892   \brief Get 'updateModified' flag value.
1893   \return 'updateModified' flag value
1894 */
1895 bool SUIT_ProxyModel::updateModified() const
1896 {
1897   return treeModel() ? treeModel()->updateModified() : false;
1898 }
1899 /*!
1900   \brief Set 'updateModified' flag value.
1901
1902   If this flag is set to \c true (default=false), the model is updated by updateTreeModel that 
1903   uses the isModified flag to update only modified objects
1904
1905   \param on 'updateModified' flag value
1906 */
1907 void SUIT_ProxyModel::setUpdateModified( const bool on )
1908 {
1909   if ( treeModel() )
1910     treeModel()->setUpdateModified( on );
1911 }
1912
1913 /*!
1914   \brief Set 'auto-update tree' flag value.
1915
1916   If this flag is set to \c true (by default), the model is updated
1917   automatically when data tree is changed.
1918
1919   \param on 'auto-update tree' flag value
1920   \sa autoUpdate(), updateTree()
1921 */
1922 void SUIT_ProxyModel::setAutoUpdate( const bool on )
1923 {
1924   if ( treeModel() )
1925     treeModel()->setAutoUpdate( on );
1926 }
1927
1928 /*!
1929   \brief Check if sorting is enabled.
1930   \return \c true if sorting is enabled
1931   \sa setSortingEnabled()
1932 */
1933 bool SUIT_ProxyModel::isSortingEnabled() const
1934 {
1935   return mySortingEnabled;
1936 }
1937
1938 SUIT_DataSearcher* SUIT_ProxyModel::searcher() const
1939 {
1940   return treeModel() ? treeModel()->searcher() : 0;
1941 }
1942
1943 void SUIT_ProxyModel::setSearcher( SUIT_DataSearcher* s )
1944 {
1945   if ( treeModel() ) treeModel()->setSearcher( s );
1946 }
1947
1948 /*!
1949   \brief Get item delegate for the model.
1950   \return new item delegate
1951 */
1952 QAbstractItemDelegate* SUIT_ProxyModel::delegate() const
1953 {
1954   return treeModel() ? treeModel()->delegate() : 0;
1955 }
1956
1957 /*!
1958   \brief Update tree model.
1959
1960   Call this method when data tree is changed outside the model.
1961   If the 'auto-update' flag is set to \c true, the model
1962   is updated automatically when the data tree is changed.
1963
1964   \param index starting index for the updating
1965   \sa setAutoUpdate()
1966 */
1967 void SUIT_ProxyModel::updateTree( const QModelIndex& index )
1968 {
1969   if ( treeModel() )
1970     treeModel()->updateTree( mapToSource( index ) );
1971 }
1972
1973 /*!
1974   \brief Update tree model.
1975
1976   Call this method when data tree is changed outside the model.
1977   If the 'auto-update' flag is set to \c true, the model
1978   is updated automatically when the data tree is changed.
1979
1980   \param obj starting data object for the updating
1981   \sa setAutoUpdate()
1982 */
1983 void SUIT_ProxyModel::updateTree( SUIT_DataObject* obj )
1984 {
1985   if ( treeModel() )
1986     treeModel()->updateTree( obj );
1987 }
1988
1989 void SUIT_ProxyModel::forgetObject( const SUIT_DataObject* obj )
1990 {
1991   if ( treeModel() )
1992     treeModel()->forgetObject( obj );
1993 }
1994
1995 /*!
1996   \brief Compares two model indexes for the sorting purposes.
1997   \param left first index to compare
1998   \param right second index to compare
1999   \return result of the comparison
2000 */
2001 bool SUIT_ProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right ) const
2002 {
2003   if ( !isSortingEnabled() && left.isValid() && right.isValid() ) {
2004     return left.row() < right.row();
2005   }
2006   if ( treeModel() && treeModel()->customSorting( left.column() ) ) {
2007     return treeModel()->lessThan( left, right );
2008   }
2009   return QSortFilterProxyModel::lessThan( left, right );
2010 }
2011
2012 /*!
2013   \brief Check if the specified column supports custom sorting.
2014   \param column column index on which data is being sorted
2015   \return \c true if column requires custom sorting
2016   \sa lessThan()
2017 */
2018 bool SUIT_ProxyModel::customSorting( const int column ) const
2019 {
2020   return treeModel() ? treeModel()->customSorting( column ) : false;
2021 }
2022
2023 /*!
2024   \brief Enable/disable sorting.
2025   \param enabled new flag state
2026   \sa isSortingEnabled()
2027 */
2028 void SUIT_ProxyModel::setSortingEnabled( bool enabled )
2029 {
2030   mySortingEnabled = enabled;
2031   clear();
2032 }
2033
2034 /*
2035   \brief Get tree model.
2036   \return tree model
2037 */
2038 SUIT_AbstractModel* SUIT_ProxyModel::treeModel() const
2039 {
2040   return dynamic_cast<SUIT_AbstractModel*>( sourceModel() );
2041 }
2042
2043 /*!
2044   \brief Filter rows
2045   \param sourceRow row index of the source data model
2046   \param sourceParent parent model index of the source data model
2047   \return \c true if the specified row should be filtered out (i.e. not displayed) or \c false otherwise
2048 */
2049 bool SUIT_ProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent ) const
2050 {
2051   SUIT_DataObject* o = treeModel()->object( sourceModel()->index( sourceRow, 0, sourceParent ) );
2052   SUIT_DataObject* p = o ? o->parent() : 0;
2053   return ( !p || p->expandable() ) && o && o->isVisible();
2054 }
2055
2056 /*!
2057   \brief Register new column in the model
2058   \param group_id - unique data object identificator allowing the classification of objects 
2059   \param name - translated column name
2060   \param custom_id - custom column id that should be passed into method SUIT_DataObject::data()
2061  */
2062 void SUIT_ProxyModel::registerColumn( const int group_id, const QString& name, const int custom_id )
2063 {
2064   if( treeModel() )
2065     treeModel()->registerColumn( group_id, name, custom_id );
2066 }
2067
2068 /*!
2069   \brief Remove column from the model
2070
2071   Please take into account that column is removed only for given group_id, it means
2072   that information of data objects with such group_id won't be shown.
2073   If there is not any registered group_id for this column after removing, the column will be hidden
2074   otherwise it continue to be shown
2075
2076   \param group_id - unique data object identificator allowing the classification of objects 
2077   \param name - translated column name
2078  */
2079 void SUIT_ProxyModel::unregisterColumn( const int group_id, const QString& name )
2080 {
2081   if( treeModel() )
2082     treeModel()->unregisterColumn( group_id, name );
2083 }
2084
2085 /*!
2086   \brief Change column icon.
2087
2088   \param name - column name
2089   \param icon - new icon of the specified column
2090 */
2091 void SUIT_ProxyModel::setColumnIcon( const QString& name, const QPixmap& icon )
2092 {
2093   if( treeModel() )
2094     treeModel()->setColumnIcon( name, icon );
2095 }
2096
2097 /*!
2098   \brief Get column icon.
2099
2100   \param name - column name
2101   \return icon of the specified column
2102 */
2103 QPixmap SUIT_ProxyModel::columnIcon( const QString& name ) const
2104 {
2105   return treeModel() ? treeModel()->columnIcon( name ) : QPixmap();
2106 }
2107
2108 /*!
2109   \brief Change appropriate status
2110   
2111   Appropriate status determines if the column should appear in the tree view header popup menu
2112   (to show/hide the column).
2113
2114   If appropriate status is not specified yet, the \c Shown value is taken,
2115   it means that column should be always visible.
2116
2117   \param name - column name
2118   \param appr - new appropriate status
2119 */
2120 void SUIT_ProxyModel::setAppropriate( const QString& name, const Qtx::Appropriate appr )
2121 {
2122   if( treeModel() )
2123     treeModel()->setAppropriate( name, appr );
2124 }
2125
2126 /*!
2127   \brief Check if the column should appear in the tree view header popup menu
2128   (to show/hide the column).
2129
2130   Default implementation (if appropriate status is not specified yet)
2131   returns \c Shown, it means that column should be always visible.
2132
2133   \param name - column name
2134   \return appropriate status
2135 */
2136 Qtx::Appropriate SUIT_ProxyModel::appropriate( const QString& name ) const
2137 {
2138   return treeModel() ? treeModel()->appropriate( name ) : Qtx::Shown;
2139 }
2140
2141 /*!
2142   \brief Set header flags.
2143   
2144   These flags allow show in the header of the column text (name of the column),
2145   icon or both text and icon.
2146   
2147   \param name - column name
2148   \param flags - header flags
2149
2150 */
2151 void SUIT_ProxyModel::setHeaderFlags( const QString& name, const Qtx::HeaderViewFlags flags )
2152 {
2153   if(treeModel())
2154     treeModel()->setHeaderFlags(name, flags);
2155 }
2156
2157 /*!
2158   \brief Get the  header flags.
2159   
2160   These flags allow show in the header of the column text (name of the column),
2161   icon or both text and icon.
2162   
2163   \param name - column name
2164   \return header flags
2165 */
2166 Qtx::HeaderViewFlags SUIT_ProxyModel::headerFlags( const QString& name ) const
2167 {
2168   return treeModel() ? treeModel()->headerFlags( name ) : Qtx::ShowAll;
2169 }
2170
2171 /*!
2172   \brief Set visibility state of the object.
2173   
2174   \param id - column name
2175   \param state - visible state
2176 */
2177 void SUIT_ProxyModel::setVisibilityState(const QString& id, Qtx::VisibilityState state)
2178 {
2179   if(treeModel())
2180     treeModel()->setVisibilityState(id,state);
2181 }
2182
2183 /*!
2184   \brief Set visibility state for all objects.
2185   
2186   \param id - column name
2187   \param state - visible state
2188 */
2189 void SUIT_ProxyModel::setVisibilityStateForAll(Qtx::VisibilityState state)
2190 {
2191   if(treeModel())
2192     treeModel()->setVisibilityStateForAll(state);
2193 }
2194
2195 /*!
2196   \brief Get visibility state of the object.
2197   
2198   \param id - column name
2199   \return visible state
2200 */
2201 Qtx::VisibilityState SUIT_ProxyModel::visibilityState(const QString& id) const
2202 {
2203   return treeModel() ? treeModel()->visibilityState(id) : Qtx::UnpresentableState;
2204 }
2205
2206 void SUIT_ProxyModel::emitClicked( SUIT_DataObject* obj, const QModelIndex& index)
2207 {
2208   if(treeModel())
2209     treeModel()->emitClicked(obj,index);
2210 }
2211
2212 /*!
2213   \class SUIT_ItemDelegate
2214   \brief An SUIT_DataObject-based item delegate class.
2215
2216   This class can be used to render the SUIT_DataObject-based item
2217   in the widgets like QTreeView and others.
2218   Refer to the Qt 4 documentation, model/view architecture 
2219   section for more details).
2220 */
2221
2222 /*!
2223   \brief Constructor.
2224   \param parent parent object
2225 */
2226 SUIT_ItemDelegate::SUIT_ItemDelegate( QObject* parent )
2227 : QItemDelegate( parent )
2228 {
2229 }
2230
2231 /*!
2232   \brief Render the item in the widget.
2233
2234   Customizes the item colors for the specific roles.
2235
2236   \param painter painter
2237   \param option painting option
2238   \param index model index being rendered
2239 */
2240 void SUIT_ItemDelegate::paint( QPainter* painter, 
2241                                const QStyleOptionViewItem& option,
2242                                const QModelIndex& index ) const
2243 {
2244   QStyleOptionViewItem opt = option;
2245   if ( index.isValid() ) {
2246     // Note: we check into account only custom roles; other roles are process
2247     //       correctly by the QItemDelegate class
2248     QVariant val = index.data( SUIT_TreeModel::BaseColorRole );
2249     if ( val.isValid() && val.value<QColor>().isValid() ) {
2250       QColor aBase = val.value<QColor>();
2251       aBase.setAlpha( 0 );
2252       opt.palette.setBrush( QPalette::Base, val.value<QColor>() );
2253     }
2254     val = index.data( SUIT_TreeModel::TextColorRole );
2255     if ( val.isValid() && val.value<QColor>().isValid() )
2256       opt.palette.setBrush( QPalette::Text, val.value<QColor>() );
2257     val = index.data( SUIT_TreeModel::HighlightRole );
2258     if ( val.isValid() && val.value<QColor>().isValid() )
2259       opt.palette.setBrush( QPalette::Highlight, val.value<QColor>() );
2260     val = index.data( SUIT_TreeModel::HighlightedTextRole );
2261     if ( val.isValid() && val.value<QColor>().isValid() )
2262       opt.palette.setBrush( QPalette::HighlightedText, val.value<QColor>() );      
2263   }
2264   QItemDelegate::paint( painter, opt, index );
2265 }
2266
2267 QSize SUIT_ItemDelegate::sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const
2268 {
2269     QSize size = QItemDelegate::sizeHint ( option, index );
2270 #if QT_VERSION >= 0x040500
2271     size.setHeight( size.height() + 1 );
2272 #endif
2273     return size;
2274 }