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