Salome HOME
Merge from V6_main (04/10/2012)
[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           sitem=createItemAtPos(sobj,item,kitem);
1330           updateTreeModel(sobj,sitem);
1331           kobj++;
1332           kitem++;
1333           sobj=obj->childObject(kobj);
1334           sitem = item->child(kitem);
1335         }
1336       else if(sitem->dataObject() != sobj)
1337         {
1338           if(treeItem(sobj))
1339             {
1340               // item : to remove
1341               removeItem(sitem);
1342               sitem = item->child(kitem);
1343             }
1344           else
1345             {
1346               // obj : new object
1347               sitem=createItemAtPos(sobj,item,kitem);
1348               updateTreeModel(sobj,sitem);
1349               kobj++;
1350               kitem++;
1351               sobj=obj->childObject(kobj);
1352               sitem = item->child(kitem);
1353             }
1354         }
1355       else
1356         {
1357           //obj and item are synchronised : go to next ones
1358           updateTreeModel(sobj,sitem);
1359           if(sobj->modified()) updateItem(sitem, true);
1360           sobj->update();
1361           kobj++;
1362           kitem++;
1363           sobj=obj->childObject(kobj);
1364           sitem = item->child(kitem);
1365         }
1366     }
1367   //remove remaining items
1368   for(int i = item->childCount(); i > kitem;i--)
1369     {
1370       sitem = item->child(i-1);
1371       removeItem(sitem);
1372     }
1373 }
1374
1375 /*!
1376   \brief Update tree model.
1377
1378   Call this method when data tree is changed outside the model.
1379   If the 'auto-update' flag is set to \c true, the model
1380   is updated automatically when the data tree is changed.
1381
1382   \param obj starting data object for the updating
1383   \sa setAutoUpdate()
1384 */
1385 void SUIT_TreeModel::updateTree( SUIT_DataObject* obj )
1386 {
1387   if ( !obj )
1388     obj = root();
1389
1390   else if ( obj->root() != root() )
1391     return;
1392
1393   if(updateModified())
1394     {
1395       updateTreeModel(obj,treeItem( obj ));
1396     }
1397   else
1398     {
1399       synchronize<ObjPtr,ItemPtr,SUIT_TreeModel::TreeSync>( obj,
1400                                                             treeItem( obj ),
1401                                                             SUIT_TreeModel::TreeSync( this ) );
1402     }
1403   emit modelUpdated();
1404 }
1405
1406 /*!
1407   \brief Initialize tree model.
1408 */
1409 void SUIT_TreeModel::initialize()
1410 {
1411   SUIT_DataObject::disconnect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
1412                                this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
1413   SUIT_DataObject::disconnect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
1414                                this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
1415   if ( autoUpdate() ) {
1416     SUIT_DataObject::connect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
1417                               this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
1418     SUIT_DataObject::connect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
1419                               this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
1420   }
1421
1422   myItems.clear(); // ????? is it really necessary
1423
1424   if ( !myRootItem )
1425     myRootItem = new TreeItem( 0 );
1426
1427   registerColumn( 0, QObject::tr( "NAME_COLUMN" ), SUIT_DataObject::NameId );
1428
1429   QString visCol = QObject::tr( "VISIBILITY_COLUMN" );
1430   registerColumn( 0, visCol, SUIT_DataObject::VisibilityId );
1431
1432   SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
1433   setColumnIcon( visCol, resMgr->loadPixmap( "SUIT", tr( "ICON_DATAOBJ_VISIBLE" ) ));
1434   setHeaderFlags( visCol, Qtx::ShowIcon);
1435
1436   updateTree();
1437 }
1438
1439 /*!
1440   \brief Get root tree item.
1441   \return root tree item
1442 */
1443 SUIT_TreeModel::TreeItem* SUIT_TreeModel::rootItem() const
1444 {
1445   return myRootItem;
1446 }
1447
1448 /*!
1449   \brief Get tree item corresponding to the specified model index.
1450   \param index model index
1451   \return tree item or root item if index is invalid
1452 */
1453 SUIT_TreeModel::TreeItem* SUIT_TreeModel::treeItem( const QModelIndex& index ) const
1454 {
1455   return index.isValid() ? static_cast<TreeItem*>( index.internalPointer() ) : rootItem();
1456 }
1457
1458 /*!
1459   \brief Get tree item corresponding to the specified data object.
1460   \param obj data object
1461   \return tree item or 0 if there is no tree item corresponding to \a obj
1462 */
1463 SUIT_TreeModel::TreeItem* SUIT_TreeModel::treeItem( const SUIT_DataObject* obj ) const
1464 {
1465   TreeItem* item = 0;
1466
1467   if ( obj == root() )
1468     item = rootItem();
1469   else if ( myItems.contains( const_cast<SUIT_DataObject*>( obj ) ) )
1470     item = myItems[ const_cast<SUIT_DataObject*>( obj ) ];
1471
1472   return item;
1473 }
1474
1475 /*!
1476   \brief Get data object corresponding to the specified tree item.
1477   \param item tree item
1478   \return data object or 0 if there is no data object corresponding to \a item
1479 */
1480 SUIT_DataObject* SUIT_TreeModel::object( const SUIT_TreeModel::TreeItem* item ) const
1481 {
1482   if ( item == rootItem() )
1483     return root();
1484  
1485   SUIT_DataObject* obj = item ? item->dataObject() : 0;
1486   return myItems.contains( obj ) ? obj : 0;
1487 }
1488
1489 /*!
1490   \brief Get unique object identifier
1491   
1492   Object identifier is customized via the Qtx::IdType custom data
1493
1494   \param index model index
1495   \return object identifier or null string if it isn't specified
1496   \sa SUIT_DataObject::customData()
1497 */
1498 QString SUIT_TreeModel::objectId( const QModelIndex& index ) const
1499 {
1500   QString objId;
1501   if ( index.isValid() ) {
1502     SUIT_DataObject* obj = object( index );
1503     if ( obj ) {
1504       int anId = obj->customData( Qtx::IdType ).toInt(); 
1505       objId = data( createIndex( index.row(), anId, index.internalPointer() ) ).toString();
1506     }
1507   }
1508   return objId;
1509 }
1510
1511 /*!
1512   \brief Create an item corresponding to the data object.
1513   \param obj source data object
1514   \param parent parent tree item
1515   \param after tree item after which new item should be inserted
1516   \return created tree item or 0 if item could not be created
1517 */
1518 SUIT_TreeModel::TreeItem* SUIT_TreeModel::createItem( SUIT_DataObject* obj,
1519                                                       SUIT_TreeModel::TreeItem* parent, 
1520                                                       SUIT_TreeModel::TreeItem* after )
1521 {
1522   if ( !obj )
1523     return 0;
1524
1525   SUIT_DataObject* parentObj = object( parent );
1526   QModelIndex parentIdx = index( parentObj );
1527
1528   SUIT_DataObject* afterObj = after ? object( after ) : 0;
1529   int row = afterObj ? afterObj->position() + 1 : 0;
1530
1531   beginInsertRows( parentIdx, row, row );
1532
1533   myItems[ obj ] = new TreeItem( obj, parent, after );
1534
1535   for(int pos=row;pos < parent->childCount();pos++)
1536     parent->child(pos)->setPosition(pos);
1537
1538   endInsertRows();
1539
1540   obj->setModified(false);
1541
1542   return myItems[ obj ];
1543 }
1544
1545 /*!
1546   \brief Create an item corresponding to the data object.
1547   \param obj source data object
1548   \param parent parent tree item
1549   \param pos tree item position into which new item should be inserted
1550   \return created tree item or 0 if item could not be created
1551 */
1552 SUIT_TreeModel::TreeItem* SUIT_TreeModel::createItemAtPos( SUIT_DataObject* obj,
1553                                                            SUIT_TreeModel::TreeItem* parent,
1554                                                            int pos )
1555 {
1556   if ( !obj )
1557     return 0;
1558
1559   SUIT_DataObject* parentObj = object( parent );
1560   QModelIndex parentIdx = index( parentObj );
1561
1562   int row = pos ;
1563   SUIT_TreeModel::TreeItem* after = pos>0 ? parent->child(pos-1) : 0 ;
1564
1565   beginInsertRows( parentIdx, row, row );
1566
1567   SUIT_TreeModel::TreeItem* item = new TreeItem( obj, parent, after );
1568   myItems[ obj ] = item;
1569
1570   for(int ppos=row;ppos < parent->childCount();ppos++)
1571     parent->child(ppos)->setPosition(ppos);
1572
1573   endInsertRows();
1574
1575   obj->setModified(false);
1576
1577   return item;
1578 }
1579
1580 /*!
1581   \brief Update tree item.
1582   \param item tree item to be updated
1583   \param emitLayoutChanged if signal about changed layout should be emitted
1584 */
1585 void SUIT_TreeModel::updateItem( SUIT_TreeModel::TreeItem* item, bool emitLayoutChanged )
1586 {
1587   if ( !item )
1588     return;
1589   
1590   SUIT_DataObject* obj = object( item );
1591   if ( !obj )
1592     return;
1593   
1594   // update all columns corresponding to the given data object
1595   //emit layoutAboutToBeChanged(); // VSR 25/04/2011: fix crash on delete objects
1596   QModelIndex firstIdx = index( obj, 0 );
1597   QModelIndex lastIdx  = index( obj, columnCount() - 1 );
1598   emit dataChanged( firstIdx, lastIdx );
1599   obj->setModified(false);
1600   if( emitLayoutChanged )
1601     emit layoutChanged();
1602 }
1603
1604 /*!
1605   \brief Remove tree item (recursively).
1606   \param item tree item to be removed
1607 */
1608 void SUIT_TreeModel::removeItem( SUIT_TreeModel::TreeItem* item )
1609 {
1610   if ( !item )
1611     return;
1612
1613   // Remove list view items from <myItems> recursively for all children.
1614   // Otherwise, "delete item" line below will destroy all item's children,
1615   // and <myItems> will contain invalid pointers
1616   while( item->childCount() )
1617     removeItem( item->child( 0 ) );
1618
1619   SUIT_DataObject* obj = object( item );
1620   
1621   // Warning! obj can be deleted at this point!
1622
1623   TreeItem* parent=item->parent();
1624   SUIT_DataObject* parentObj = object( parent );
1625   QModelIndex parentIdx = index( parentObj, 0 );
1626   int row = item->position();
1627   
1628   beginRemoveRows( parentIdx, row, row );
1629   myItems.remove( obj );
1630
1631   if ( obj == root() )
1632     setRoot( 0 );
1633   else if ( parent )
1634     {
1635       parent->removeChild( item );
1636       for(int pos=row;pos < parent->childCount();pos++)
1637         parent->child(pos)->setPosition(pos);
1638     }
1639
1640   delete item;
1641
1642   endRemoveRows();
1643 }
1644
1645 /*!
1646   \brief Called when the data object is inserted to the tree.
1647   \param object data object being inserted
1648   \param parent parent data object
1649 */
1650 void SUIT_TreeModel::onInserted( SUIT_DataObject* /*object*/, SUIT_DataObject* parent )
1651 {
1652   if ( autoUpdate() )
1653     updateTree( parent );
1654 }
1655
1656 /*!
1657   \brief Called when the data object is removed from the tree.
1658   \param object data object being removed
1659   \param parent parent data object
1660 */
1661 void SUIT_TreeModel::onRemoved( SUIT_DataObject* /*object*/, SUIT_DataObject* parent )
1662 {
1663   if ( autoUpdate() )
1664     updateTree( parent );
1665 }
1666
1667 /*!
1668   \brief Drag and Drop support.
1669 */
1670 QStringList SUIT_TreeModel::mimeTypes() const
1671 {
1672   QStringList types;
1673   types << "application/vnd.text.list";
1674   return types;
1675 }
1676
1677 /*!
1678   \brief Called when the data objects are exported(dragged) from the tree.
1679   \param indexes the list of exported objects
1680 */
1681 QMimeData* SUIT_TreeModel::mimeData( const QModelIndexList& indexes ) const
1682 {
1683   QMimeData* mimeData = new QMimeData();
1684   QByteArray encodedData;
1685
1686   QDataStream stream( &encodedData, QIODevice::WriteOnly );
1687
1688   foreach ( QModelIndex index, indexes ) {
1689     QString id = objectId( index );
1690     // we have to check only 0 column in order to avoid repeating items in the drag object
1691     // - QTreeView tries to drag indices for all visible columns
1692     if ( index.isValid() && index.column() == 0 && !id.isEmpty() )
1693       stream << id;
1694   }
1695
1696   mimeData->setData( "application/vnd.text.list", encodedData );
1697   return mimeData;
1698 }
1699
1700 bool SUIT_TreeModel::dropMimeData( const QMimeData* data, Qt::DropAction action,
1701                                    int row, int column, const QModelIndex& parent )
1702 {
1703   if ( action == Qt::IgnoreAction )
1704     // do nothing with data
1705     return false;
1706
1707   if ( !data->hasFormat( "application/vnd.text.list" ) )
1708     // not supported data dropped
1709     return false;
1710
1711   if ( !parent.isValid() )
1712     // dropping into the top level of the model is not allowed
1713     return false;
1714
1715   // get parent object
1716   SUIT_DataObject* pobj = object( parent );
1717   if ( !pobj )
1718     // invalid parent
1719     return false;
1720
1721   // decode mime data and collect data objects being dropped
1722   QByteArray encodedData = data->data( "application/vnd.text.list" );
1723   QDataStream stream( &encodedData, QIODevice::ReadOnly );
1724   
1725   DataObjectList objects;
1726
1727   while ( !stream.atEnd() ) {
1728     QString id;
1729     stream >> id;
1730     if ( !id.isEmpty() && searcher() ) {
1731       SUIT_DataObject* obj = searcher()->findObject( id );
1732       if ( obj ) objects << obj;
1733     }
1734   }
1735
1736   // emit signal
1737   emit dropped( objects, pobj, row, action );
1738
1739   // return true if there's any to drop
1740   return !objects.isEmpty();
1741 }
1742
1743 /*!
1744   \class SUIT_ProxyModel
1745   \brief Proxy model which can be used above the SUIT_TreeModel class
1746   to enable custom sorting/filtering of the data.
1747
1748   The SUIT_TreeModel class does not support custom sorting/filtering of the data.
1749   To use these features, the SUIT_ProxyModel class can be used as top-level
1750   wrapper for the SUIT_DataObject-based data tree model.
1751 */
1752
1753 /*!
1754   \brief Constructor.
1755   \param parent parent object
1756 */
1757 SUIT_ProxyModel::SUIT_ProxyModel( QObject* parent )
1758 : QSortFilterProxyModel( parent ),
1759   mySortingEnabled( true )
1760 {
1761   SUIT_TreeModel* model = new SUIT_TreeModel( this );
1762   connect( model, SIGNAL( modelUpdated() ), this, SIGNAL( modelUpdated() ) );
1763   connect( model, SIGNAL( clicked( SUIT_DataObject*, int ) ), this, SIGNAL(clicked( SUIT_DataObject*, int ) ) );
1764   connect( model, SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ),
1765            this,  SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ) );
1766   setSourceModel( model );
1767   setDynamicSortFilter( true );
1768 }
1769
1770 /*!
1771   \brief Constructor.
1772   \param root root data object
1773   \param parent parent object
1774 */
1775 SUIT_ProxyModel::SUIT_ProxyModel( SUIT_DataObject* root, QObject* parent )
1776 : QSortFilterProxyModel( parent ),
1777   mySortingEnabled( true )
1778 {
1779   SUIT_TreeModel* model = new SUIT_TreeModel( root, this );
1780   connect( model, SIGNAL( modelUpdated() ), this, SIGNAL( modelUpdated() ) );
1781   connect( model, SIGNAL( clicked( SUIT_DataObject*, int ) ), this, SIGNAL( clicked( SUIT_DataObject*, int ) ) );
1782   connect( model, SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ),
1783            this,  SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ) );
1784   setSourceModel( model );
1785   setDynamicSortFilter( true );
1786 }
1787
1788 /*!
1789   \brief Constructor.
1790   \param model tree model
1791   \param parent parent object
1792 */
1793 SUIT_ProxyModel::SUIT_ProxyModel( SUIT_AbstractModel* model, QObject* parent )
1794 : QSortFilterProxyModel( parent ),
1795   mySortingEnabled( true )
1796 {
1797   connect( *model, SIGNAL( modelUpdated() ), this, SIGNAL( modelUpdated() ) );
1798   connect( *model, SIGNAL( clicked( SUIT_DataObject*, int ) ), this, SIGNAL( clicked( SUIT_DataObject*, int ) ) );
1799   connect( *model, SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ),
1800            this,   SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ) );
1801   setSourceModel( *model );
1802   setDynamicSortFilter( true );
1803 }
1804
1805 /*!
1806   \brief Destructor.
1807 */
1808 SUIT_ProxyModel::~SUIT_ProxyModel()
1809 {
1810 }
1811
1812 /*!
1813   \brief Get data tree root object.
1814   \return data tree root
1815   \sa setRoot()
1816 */
1817 SUIT_DataObject* SUIT_ProxyModel::root() const
1818 {
1819   return treeModel() ? treeModel()->root() : 0;
1820 }
1821
1822 /*!
1823   \brief Set data tree root object.
1824   \param r new data tree root
1825   \sa root()
1826 */
1827 void SUIT_ProxyModel::setRoot( SUIT_DataObject* r )
1828 {
1829   if ( treeModel() )
1830     treeModel()->setRoot( r );
1831 }
1832
1833 /*!
1834   \brief Get data object by the specified model index.
1835   \param index model index
1836   \return data object corresponding to the model index
1837 */
1838 SUIT_DataObject* SUIT_ProxyModel::object( const QModelIndex& index ) const
1839 {
1840   return treeModel() ? treeModel()->object( mapToSource( index ) ) : 0;
1841 }
1842
1843 /*!
1844   \brief Get model index by the specified data object.
1845   \param obj data object
1846   \param column data object column
1847   \return model index
1848 */
1849 QModelIndex SUIT_ProxyModel::index( const SUIT_DataObject* obj, int column ) const
1850 {
1851   return treeModel() ? mapFromSource( treeModel()->index( obj, column ) ) : QModelIndex();
1852 }
1853
1854 /*!
1855   \brief Get 'auto-delete data tree' flag value.
1856   \return 'auto-delete data tree' flag value
1857   \sa setAutoDeleteTree()
1858 */
1859 bool SUIT_ProxyModel::autoDeleteTree() const
1860 {
1861   return treeModel() ? treeModel()->autoDeleteTree() : false;
1862 }
1863
1864 /*!
1865   \brief Set 'auto-delete data tree' flag value.
1866
1867   If this flag is set to \c true, the data tree is deleted when
1868   the tree model is destroyed. Default value for this flag is \c false.
1869
1870   \param on 'auto-delete data tree' flag value
1871   \sa autoDeleteTree()
1872 */
1873 void SUIT_ProxyModel::setAutoDeleteTree( const bool on )
1874 {
1875   if ( treeModel() )
1876     treeModel()->setAutoDeleteTree( on );
1877 }
1878
1879 /*!
1880   \brief Get 'auto-update tree' flag value.
1881   \return 'auto-update tree' flag value
1882   \sa setAutoUpdate(), updateTree()
1883 */
1884 bool SUIT_ProxyModel::autoUpdate() const
1885 {
1886   return treeModel() ? treeModel()->autoUpdate() : false;
1887 }
1888
1889 /*!
1890   \brief Get 'updateModified' flag value.
1891   \return 'updateModified' flag value
1892 */
1893 bool SUIT_ProxyModel::updateModified() const
1894 {
1895   return treeModel() ? treeModel()->updateModified() : false;
1896 }
1897 /*!
1898   \brief Set 'updateModified' flag value.
1899
1900   If this flag is set to \c true (default=false), the model is updated by updateTreeModel that 
1901   uses the isModified flag to update only modified objects
1902
1903   \param on 'updateModified' flag value
1904 */
1905 void SUIT_ProxyModel::setUpdateModified( const bool on )
1906 {
1907   if ( treeModel() )
1908     treeModel()->setUpdateModified( on );
1909 }
1910
1911 /*!
1912   \brief Set 'auto-update tree' flag value.
1913
1914   If this flag is set to \c true (by default), the model is updated
1915   automatically when data tree is changed.
1916
1917   \param on 'auto-update tree' flag value
1918   \sa autoUpdate(), updateTree()
1919 */
1920 void SUIT_ProxyModel::setAutoUpdate( const bool on )
1921 {
1922   if ( treeModel() )
1923     treeModel()->setAutoUpdate( on );
1924 }
1925
1926 /*!
1927   \brief Check if sorting is enabled.
1928   \return \c true if sorting is enabled
1929   \sa setSortingEnabled()
1930 */
1931 bool SUIT_ProxyModel::isSortingEnabled() const
1932 {
1933   return mySortingEnabled;
1934 }
1935
1936 SUIT_DataSearcher* SUIT_ProxyModel::searcher() const
1937 {
1938   return treeModel() ? treeModel()->searcher() : 0;
1939 }
1940
1941 void SUIT_ProxyModel::setSearcher( SUIT_DataSearcher* s )
1942 {
1943   if ( treeModel() ) treeModel()->setSearcher( s );
1944 }
1945
1946 /*!
1947   \brief Get item delegate for the model.
1948   \return new item delegate
1949 */
1950 QAbstractItemDelegate* SUIT_ProxyModel::delegate() const
1951 {
1952   return treeModel() ? treeModel()->delegate() : 0;
1953 }
1954
1955 /*!
1956   \brief Update tree model.
1957
1958   Call this method when data tree is changed outside the model.
1959   If the 'auto-update' flag is set to \c true, the model
1960   is updated automatically when the data tree is changed.
1961
1962   \param index starting index for the updating
1963   \sa setAutoUpdate()
1964 */
1965 void SUIT_ProxyModel::updateTree( const QModelIndex& index )
1966 {
1967   if ( treeModel() )
1968     treeModel()->updateTree( mapToSource( index ) );
1969 }
1970
1971 /*!
1972   \brief Update tree model.
1973
1974   Call this method when data tree is changed outside the model.
1975   If the 'auto-update' flag is set to \c true, the model
1976   is updated automatically when the data tree is changed.
1977
1978   \param obj starting data object for the updating
1979   \sa setAutoUpdate()
1980 */
1981 void SUIT_ProxyModel::updateTree( SUIT_DataObject* obj )
1982 {
1983   if ( treeModel() )
1984     treeModel()->updateTree( obj );
1985 }
1986
1987 void SUIT_ProxyModel::forgetObject( const SUIT_DataObject* obj )
1988 {
1989   if ( treeModel() )
1990     treeModel()->forgetObject( obj );
1991 }
1992
1993 /*!
1994   \brief Compares two model indexes for the sorting purposes.
1995   \param left first index to compare
1996   \param right second index to compare
1997   \return result of the comparison
1998 */
1999 bool SUIT_ProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right ) const
2000 {
2001   if ( !isSortingEnabled() && left.isValid() && right.isValid() ) {
2002     return left.row() < right.row();
2003   }
2004   if ( treeModel() && treeModel()->customSorting( left.column() ) ) {
2005     return treeModel()->lessThan( left, right );
2006   }
2007   return QSortFilterProxyModel::lessThan( left, right );
2008 }
2009
2010 /*!
2011   \brief Check if the specified column supports custom sorting.
2012   \param column column index on which data is being sorted
2013   \return \c true if column requires custom sorting
2014   \sa lessThan()
2015 */
2016 bool SUIT_ProxyModel::customSorting( const int column ) const
2017 {
2018   return treeModel() ? treeModel()->customSorting( column ) : false;
2019 }
2020
2021 /*!
2022   \brief Enable/disable sorting.
2023   \param enabled new flag state
2024   \sa isSortingEnabled()
2025 */
2026 void SUIT_ProxyModel::setSortingEnabled( bool enabled )
2027 {
2028   mySortingEnabled = enabled;
2029   clear();
2030 }
2031
2032 /*
2033   \brief Get tree model.
2034   \return tree model
2035 */
2036 SUIT_AbstractModel* SUIT_ProxyModel::treeModel() const
2037 {
2038   return dynamic_cast<SUIT_AbstractModel*>( sourceModel() );
2039 }
2040
2041 /*!
2042   \brief Filter rows
2043   \param sourceRow row index of the source data model
2044   \param sourceParent parent model index of the source data model
2045   \return \c true if the specified row should be filtered out (i.e. not displayed) or \c false otherwise
2046 */
2047 bool SUIT_ProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent ) const
2048 {
2049   SUIT_DataObject* o = treeModel()->object( sourceModel()->index( sourceRow, 0, sourceParent ) );
2050   SUIT_DataObject* p = o ? o->parent() : 0;
2051   return ( !p || p->expandable() ) && o && o->isVisible();
2052 }
2053
2054 /*!
2055   \brief Register new column in the model
2056   \param group_id - unique data object identificator allowing the classification of objects 
2057   \param name - translated column name
2058   \param custom_id - custom column id that should be passed into method SUIT_DataObject::data()
2059  */
2060 void SUIT_ProxyModel::registerColumn( const int group_id, const QString& name, const int custom_id )
2061 {
2062   if( treeModel() )
2063     treeModel()->registerColumn( group_id, name, custom_id );
2064 }
2065
2066 /*!
2067   \brief Remove column from the model
2068
2069   Please take into account that column is removed only for given group_id, it means
2070   that information of data objects with such group_id won't be shown.
2071   If there is not any registered group_id for this column after removing, the column will be hidden
2072   otherwise it continue to be shown
2073
2074   \param group_id - unique data object identificator allowing the classification of objects 
2075   \param name - translated column name
2076  */
2077 void SUIT_ProxyModel::unregisterColumn( const int group_id, const QString& name )
2078 {
2079   if( treeModel() )
2080     treeModel()->unregisterColumn( group_id, name );
2081 }
2082
2083 /*!
2084   \brief Change column icon.
2085
2086   \param name - column name
2087   \param icon - new icon of the specified column
2088 */
2089 void SUIT_ProxyModel::setColumnIcon( const QString& name, const QPixmap& icon )
2090 {
2091   if( treeModel() )
2092     treeModel()->setColumnIcon( name, icon );
2093 }
2094
2095 /*!
2096   \brief Get column icon.
2097
2098   \param name - column name
2099   \return icon of the specified column
2100 */
2101 QPixmap SUIT_ProxyModel::columnIcon( const QString& name ) const
2102 {
2103   return treeModel() ? treeModel()->columnIcon( name ) : QPixmap();
2104 }
2105
2106 /*!
2107   \brief Change appropriate status
2108   
2109   Appropriate status determines if the column should appear in the tree view header popup menu
2110   (to show/hide the column).
2111
2112   If appropriate status is not specified yet, the \c Shown value is taken,
2113   it means that column should be always visible.
2114
2115   \param name - column name
2116   \param appr - new appropriate status
2117 */
2118 void SUIT_ProxyModel::setAppropriate( const QString& name, const Qtx::Appropriate appr )
2119 {
2120   if( treeModel() )
2121     treeModel()->setAppropriate( name, appr );
2122 }
2123
2124 /*!
2125   \brief Check if the column should appear in the tree view header popup menu
2126   (to show/hide the column).
2127
2128   Default implementation (if appropriate status is not specified yet)
2129   returns \c Shown, it means that column should be always visible.
2130
2131   \param name - column name
2132   \return appropriate status
2133 */
2134 Qtx::Appropriate SUIT_ProxyModel::appropriate( const QString& name ) const
2135 {
2136   return treeModel() ? treeModel()->appropriate( name ) : Qtx::Shown;
2137 }
2138
2139 /*!
2140   \brief Set header flags.
2141   
2142   These flags allow show in the header of the column text (name of the column),
2143   icon or both text and icon.
2144   
2145   \param name - column name
2146   \param flags - header flags
2147
2148 */
2149 void SUIT_ProxyModel::setHeaderFlags( const QString& name, const Qtx::HeaderViewFlags flags )
2150 {
2151   if(treeModel())
2152     treeModel()->setHeaderFlags(name, flags);
2153 }
2154
2155 /*!
2156   \brief Get the  header flags.
2157   
2158   These flags allow show in the header of the column text (name of the column),
2159   icon or both text and icon.
2160   
2161   \param name - column name
2162   \return header flags
2163 */
2164 Qtx::HeaderViewFlags SUIT_ProxyModel::headerFlags( const QString& name ) const
2165 {
2166   return treeModel() ? treeModel()->headerFlags( name ) : Qtx::ShowAll;
2167 }
2168
2169 /*!
2170   \brief Set visibility state of the object.
2171   
2172   \param id - column name
2173   \param state - visible state
2174 */
2175 void SUIT_ProxyModel::setVisibilityState(const QString& id, Qtx::VisibilityState state)
2176 {
2177   if(treeModel())
2178     treeModel()->setVisibilityState(id,state);
2179 }
2180
2181 /*!
2182   \brief Set visibility state for all objects.
2183   
2184   \param id - column name
2185   \param state - visible state
2186 */
2187 void SUIT_ProxyModel::setVisibilityStateForAll(Qtx::VisibilityState state)
2188 {
2189   if(treeModel())
2190     treeModel()->setVisibilityStateForAll(state);
2191 }
2192
2193 /*!
2194   \brief Get visibility state of the object.
2195   
2196   \param id - column name
2197   \return visible state
2198 */
2199 Qtx::VisibilityState SUIT_ProxyModel::visibilityState(const QString& id) const
2200 {
2201   return treeModel() ? treeModel()->visibilityState(id) : Qtx::UnpresentableState;
2202 }
2203
2204 void SUIT_ProxyModel::emitClicked( SUIT_DataObject* obj, const QModelIndex& index)
2205 {
2206   if(treeModel())
2207     treeModel()->emitClicked(obj,index);
2208 }
2209
2210 /*!
2211   \class SUIT_ItemDelegate
2212   \brief An SUIT_DataObject-based item delegate class.
2213
2214   This class can be used to render the SUIT_DataObject-based item
2215   in the widgets like QTreeView and others.
2216   Refer to the Qt 4 documentation, model/view architecture 
2217   section for more details).
2218 */
2219
2220 /*!
2221   \brief Constructor.
2222   \param parent parent object
2223 */
2224 SUIT_ItemDelegate::SUIT_ItemDelegate( QObject* parent )
2225 : QItemDelegate( parent )
2226 {
2227 }
2228
2229 /*!
2230   \brief Render the item in the widget.
2231
2232   Customizes the item colors for the specific roles.
2233
2234   \param painter painter
2235   \param option painting option
2236   \param index model index being rendered
2237 */
2238 void SUIT_ItemDelegate::paint( QPainter* painter, 
2239                                const QStyleOptionViewItem& option,
2240                                const QModelIndex& index ) const
2241 {
2242   QStyleOptionViewItem opt = option;
2243   if ( index.isValid() ) {
2244     // Note: we check into account only custom roles; other roles are process
2245     //       correctly by the QItemDelegate class
2246     QVariant val = index.data( SUIT_TreeModel::BaseColorRole );
2247     if ( val.isValid() && val.value<QColor>().isValid() ) {
2248       QColor aBase = val.value<QColor>();
2249       aBase.setAlpha( 0 );
2250       opt.palette.setBrush( QPalette::Base, val.value<QColor>() );
2251     }
2252     val = index.data( SUIT_TreeModel::TextColorRole );
2253     if ( val.isValid() && val.value<QColor>().isValid() )
2254       opt.palette.setBrush( QPalette::Text, val.value<QColor>() );
2255     val = index.data( SUIT_TreeModel::HighlightRole );
2256     if ( val.isValid() && val.value<QColor>().isValid() )
2257       opt.palette.setBrush( QPalette::Highlight, val.value<QColor>() );
2258     val = index.data( SUIT_TreeModel::HighlightedTextRole );
2259     if ( val.isValid() && val.value<QColor>().isValid() )
2260       opt.palette.setBrush( QPalette::HighlightedText, val.value<QColor>() );      
2261   }
2262   QItemDelegate::paint( painter, opt, index );
2263 }
2264
2265 QSize SUIT_ItemDelegate::sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const
2266 {
2267     QSize size = QItemDelegate::sizeHint ( option, index );
2268 #if QT_VERSION >= 0x040500
2269     size.setHeight( size.height() + 1 );
2270 #endif
2271     return size;
2272 }