]> SALOME platform Git repositories - modules/gui.git/blob - src/SUIT/SUIT_TreeModel.cxx
Salome HOME
Merge branch 'master' of https://git.salome-platform.org/git/modules/gui into pre...
[modules/gui.git] / src / SUIT / SUIT_TreeModel.cxx
1 // Copyright (C) 2007-2014  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         if ( !val.isEmpty() && obj->setName(val) ) {
946           emit( dataChanged( index, index ) );
947           return true;
948         }
949         return false;
950         break;
951       }
952       default:
953         break;
954       }
955     }
956   }
957   return QAbstractItemModel::setData( index, value, role );
958 }
959
960 /*!
961   \brief Get data flags for specified model index.
962   \param index model index
963   \return data flags
964 */
965 Qt::ItemFlags SUIT_TreeModel::flags( const QModelIndex& index ) const
966 {
967   Qt::ItemFlags f = 0;
968
969   if (!index.isValid())
970     //return Qt::ItemIsDropEnabled; // items can be dropped into the top level of the model
971     return f;
972
973   SUIT_DataObject* obj = object(index);
974
975   if (obj) {
976     // data object is enabled
977     if (obj->isEnabled())
978       f = f | Qt::ItemIsEnabled;
979
980     // data object is selectable
981     if (obj->isSelectable())
982       f = f | Qt::ItemIsSelectable;
983
984     // data object is checkable
985     if (obj->isCheckable(index.column()))
986       f = f | Qt::ItemIsUserCheckable;
987     
988     // data object can be renamed
989     if (obj->renameAllowed(index.column()))
990       f = f | Qt::ItemIsEditable;
991     
992     // data object can be dragged
993     if (obj->isDraggable())
994       f = f | Qt::ItemIsDragEnabled;
995     
996     // another data object(s) can be dropped on this one
997     if (obj->isDropAccepted())
998       f = f | Qt::ItemIsDropEnabled;
999   }
1000
1001   return f;
1002 }
1003
1004 Qt::DropActions SUIT_TreeModel::supportedDropActions() const
1005 {
1006   return Qt::CopyAction | Qt::MoveAction;
1007 }
1008
1009 /*!
1010   \brief Get header data (can be used in any data view).
1011   \param column column number
1012   \param orientation header orientation
1013   \param role data role
1014   \return header data
1015 */
1016 QVariant SUIT_TreeModel::headerData( int column, Qt::Orientation orientation, int role ) const
1017 {
1018   QVariant d;
1019   // NOTE! only horizontal header is supported
1020   if ( root() && orientation == Qt::Horizontal )
1021   {
1022     switch ( role )
1023         {
1024     case DisplayRole:
1025       // column title
1026       if((myColumns[column].myHeaderFlags & Qtx::ShowText) || 
1027          (myColumns[column].myHeaderFlags == Qtx::ShowAll)) 
1028         d = myColumns[column].myName;
1029       else
1030         d = QString();
1031       break;
1032     case DecorationRole:
1033       // column icon
1034       if((myColumns[column].myHeaderFlags & Qtx::ShowIcon) || 
1035          (myColumns[column].myHeaderFlags == Qtx::ShowAll)) 
1036         d = myColumns[column].myIcon;
1037       else
1038         d = QIcon();      
1039       break;
1040     case AppropriateRole:
1041       // appropriate flag (can column be hidden via context popup menu)
1042       d = myColumns[column].myAppropriate;
1043       break;
1044     default:
1045       break;
1046     }
1047   }
1048   return d;
1049 }
1050
1051 /*!
1052   \brief Create model index.
1053   \param row data row
1054   \param column data column
1055   \param parent parent model index
1056   \return model index
1057 */
1058 QModelIndex SUIT_TreeModel::index( int row, int column, 
1059                                    const QModelIndex& parent ) const
1060 {
1061   if( hasIndex( row, column, parent ) )
1062   {
1063     TreeItem* parentItem = treeItem( parent );
1064     if( parentItem )
1065     {
1066       TreeItem* childItem = parentItem->child( row );
1067       if( childItem )
1068         return createIndex( row, column, childItem );
1069     }
1070   }
1071   return QModelIndex();
1072 }
1073
1074 /*!
1075   \brief Get parent model index.
1076   \param index model index
1077   \return parent model index
1078 */
1079 QModelIndex SUIT_TreeModel::parent( const QModelIndex& index ) const
1080 {
1081   if ( !index.isValid() )
1082     return QModelIndex();
1083
1084   TreeItem* childItem = treeItem( index );
1085   TreeItem* parentItem = childItem ? childItem->parent() : 0;
1086
1087   if ( !parentItem || parentItem == rootItem() )
1088     return QModelIndex();
1089
1090   return createIndex( parentItem->position(), 0, parentItem );
1091 }
1092
1093 /*!
1094   \brief Get number of data columns.
1095   \param parent parent model index (not used)
1096   \return data columns number
1097   \sa rowCount()
1098 */
1099 int SUIT_TreeModel::columnCount( const QModelIndex& /*parent*/ ) const
1100 {
1101   return myColumns.size();
1102 }
1103
1104 /*!
1105   \brief Get number of data rows (children of the specified model index).
1106   \param parent parent model index
1107   \return data rows (children) number
1108   \sa columnCount()
1109 */
1110 int SUIT_TreeModel::rowCount( const QModelIndex& parent ) const
1111 {
1112   // Commented by rnv in the frame of the 
1113   // "20830: EDF 1357 GUI : Hide/Show Icon" imp
1114   // if ( parent.column() > 0 )
1115   // return 0;
1116
1117   TreeItem* parentItem = treeItem( parent );
1118
1119   return parentItem ? parentItem->childCount() : 0;
1120 }
1121
1122 /*!
1123   \brief Get data object by the specified model index.
1124   \param index model index
1125   \return data object corresponding to the model index
1126 */
1127 SUIT_DataObject* SUIT_TreeModel::object( const QModelIndex& index ) const
1128 {
1129   return object( treeItem( index ) );
1130 }
1131
1132 /*!
1133   \brief Get model index by the specified data object.
1134   \param obj data object
1135   \param column data object column
1136   \return model index
1137 */
1138 QModelIndex SUIT_TreeModel::index( const SUIT_DataObject* obj, int column ) const
1139 {
1140   if ( obj == root() )
1141     return QModelIndex();
1142
1143   TreeItem* item = treeItem( obj );
1144
1145   return item ? createIndex( item->position(), column, item ) : QModelIndex();
1146 }
1147
1148 /*!
1149   \brief Get 'auto-delete data tree' flag value.
1150   \return 'auto-delete data tree' flag value
1151   \sa setAutoDeleteTree()
1152 */
1153 bool SUIT_TreeModel::autoDeleteTree() const
1154 {
1155   return myAutoDeleteTree;
1156 }
1157
1158 /*!
1159   \brief Set 'auto-delete data tree' flag value.
1160
1161   If this flag is set to \c true, the data tree is deleted when
1162   the tree model is destroyed. Default value for this flag is \c false.
1163
1164   \param on 'auto-delete data tree' flag value
1165   \sa autoDeleteTree()
1166 */
1167 void SUIT_TreeModel::setAutoDeleteTree( const bool on )
1168 {
1169   myAutoDeleteTree = on;
1170 }
1171
1172 /*!
1173   \brief Get 'auto-update tree' flag value.
1174   \return 'auto-update tree' flag value
1175   \sa setAutoUpdate(), updateTree()
1176 */
1177 bool SUIT_TreeModel::autoUpdate() const
1178 {
1179   return myAutoUpdate;
1180 }
1181
1182 /*!
1183   \brief Set 'auto-update tree' flag value.
1184
1185   If this flag is set to \c true (by default), the model is updated
1186   automatically when data tree is changed.
1187
1188   \param on 'auto-update tree' flag value
1189   \sa autoUpdate(), updateTree()
1190 */
1191 void SUIT_TreeModel::setAutoUpdate( const bool on )
1192 {
1193   if ( myAutoUpdate == on )
1194     return;
1195
1196   SUIT_DataObject::disconnect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
1197                                this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
1198   SUIT_DataObject::disconnect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
1199                                this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
1200   SUIT_DataObject::disconnect( SIGNAL( modified( SUIT_DataObject* ) ),
1201                                this, SLOT( onModified( SUIT_DataObject* ) ) );
1202   myAutoUpdate = on;
1203
1204   if ( myAutoUpdate ) {
1205     SUIT_DataObject::connect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
1206                               this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
1207     SUIT_DataObject::connect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
1208                               this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
1209     SUIT_DataObject::connect( SIGNAL( modified( SUIT_DataObject* ) ),
1210                               this, SLOT( onModified( SUIT_DataObject* ) ) );
1211
1212     updateTree();
1213   }
1214 }
1215
1216 /*!
1217   \brief Get 'updateModified' flag value.
1218   \return 'updateModified' flag value
1219 */
1220 bool SUIT_TreeModel::updateModified() const
1221 {
1222   return myUpdateModified;
1223 }
1224 /*!
1225   \brief Set 'updateModified' flag value.
1226   \param on 'updateModified' flag value
1227 */
1228 void SUIT_TreeModel::setUpdateModified(const bool on)
1229 {
1230   myUpdateModified=on;
1231 }
1232
1233 /*!
1234   \brief Check if the specified column supports custom sorting.
1235   \param column column index on which data is being sorted
1236   \return \c true if column requires custom sorting
1237   \sa lessThan()
1238 */
1239 bool SUIT_TreeModel::customSorting( const int column ) const
1240 {
1241   return root() ? root()->customSorting( column ) : false;
1242 }
1243
1244 void SUIT_TreeModel::forgetObject( const SUIT_DataObject* obj )
1245 {
1246   removeItem( treeItem( obj ) );
1247 }
1248
1249 /*!
1250   \brief Compares two model indexes for the sorting purposes.
1251
1252   This method is called only for those columns for which customSorting()
1253   method returns \c true.
1254
1255   \param left first index to compare
1256   \param right second index to compare
1257   \return result of the comparison
1258   \sa customSorting()
1259 */
1260 bool SUIT_TreeModel::lessThan( const QModelIndex& left, const QModelIndex& right ) const
1261 {
1262   QVariant ldata = data( left );
1263   QVariant rdata = data( right );
1264   return root() ? root()->compare( ldata, rdata, left.column() ) : false;
1265 }
1266
1267 /*!
1268   \brief Get item delegate for the model.
1269   \return new item delegate
1270 */
1271 QAbstractItemDelegate* SUIT_TreeModel::delegate() const
1272 {
1273   return new SUIT_ItemDelegate( const_cast<SUIT_TreeModel*>( this ) );
1274 }
1275
1276
1277 void SUIT_TreeModel::emitClicked( SUIT_DataObject* obj, const QModelIndex& index) {
1278   int obj_group_id = obj->groupId();
1279   const ColumnInfo& inf = myColumns[index.column()];
1280
1281   int id = -1;
1282   if( inf.myIds.contains( 0 ) )
1283     id = inf.myIds[0];
1284   if( inf.myIds.contains( obj_group_id ) )
1285     id = inf.myIds[obj_group_id];
1286   emit clicked(obj, id);
1287 }
1288
1289 /*!
1290   \brief Update tree model.
1291
1292   Call this method when data tree is changed outside the model.
1293   If the 'auto-update' flag is set to \c true, the model
1294   is updated automatically when the data tree is changed.
1295
1296   \param index starting index for the updating
1297   \sa setAutoUpdate()
1298 */
1299 void SUIT_TreeModel::updateTree( const QModelIndex& index )
1300 {
1301   updateTree( object( index ) );
1302 }
1303
1304
1305 void SUIT_TreeModel::updateTreeModel(SUIT_DataObject* obj,TreeItem* item)
1306 {
1307   int kobj=0;
1308   int kitem=0;
1309   int nobjchild=obj->childCount();
1310   SUIT_DataObject* sobj=obj->childObject(kobj);
1311   TreeItem* sitem = item->child(kitem);
1312
1313   while(kobj < nobjchild)
1314     {
1315       if(sitem==0)
1316         {
1317           //end of item list
1318           sitem=createItemAtPos(sobj,item,kitem);
1319           updateTreeModel(sobj,sitem);
1320           kobj++;
1321           kitem++;
1322           sobj=obj->childObject(kobj);
1323           sitem = item->child(kitem);
1324         }
1325       else if(sitem->dataObject() != sobj)
1326         {
1327           if(treeItem(sobj))
1328             {
1329               // item : to remove
1330               removeItem(sitem);
1331               sitem = item->child(kitem);
1332             }
1333           else
1334             {
1335               // obj : new object
1336               sitem=createItemAtPos(sobj,item,kitem);
1337               updateTreeModel(sobj,sitem);
1338               kobj++;
1339               kitem++;
1340               sobj=obj->childObject(kobj);
1341               sitem = item->child(kitem);
1342             }
1343         }
1344       else
1345         {
1346           //obj and item are synchronised : go to next ones
1347           updateTreeModel(sobj,sitem);
1348           if(sobj->modified()) updateItem(sitem, true);
1349           sobj->update();
1350           kobj++;
1351           kitem++;
1352           sobj=obj->childObject(kobj);
1353           sitem = item->child(kitem);
1354         }
1355     }
1356   //remove remaining items
1357   for(int i = item->childCount(); i > kitem;i--)
1358     {
1359       sitem = item->child(i-1);
1360       removeItem(sitem);
1361     }
1362 }
1363
1364 /*!
1365   \brief Update tree model.
1366
1367   Call this method when data tree is changed outside the model.
1368   If the 'auto-update' flag is set to \c true, the model
1369   is updated automatically when the data tree is changed.
1370
1371   \param obj starting data object for the updating
1372   \sa setAutoUpdate()
1373 */
1374 void SUIT_TreeModel::updateTree( SUIT_DataObject* obj )
1375 {
1376   if ( !obj )
1377     obj = root();
1378
1379   else if ( obj->root() != root() )
1380     return;
1381
1382   if(updateModified())
1383     {
1384       updateTreeModel(obj,treeItem( obj ));
1385     }
1386   else
1387     {
1388       synchronize<ObjPtr,ItemPtr,SUIT_TreeModel::TreeSync>( obj,
1389                                                             treeItem( obj ),
1390                                                             SUIT_TreeModel::TreeSync( this ) );
1391     }
1392   emit modelUpdated();
1393 }
1394
1395 /*!
1396   \brief Initialize tree model.
1397 */
1398 void SUIT_TreeModel::initialize()
1399 {
1400   SUIT_DataObject::disconnect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
1401                                this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
1402   SUIT_DataObject::disconnect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
1403                                this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
1404   SUIT_DataObject::disconnect( SIGNAL( modified( SUIT_DataObject* ) ),
1405                                this, SLOT( onModified( SUIT_DataObject* ) ) );
1406   if ( autoUpdate() ) {
1407     SUIT_DataObject::connect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
1408                               this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
1409     SUIT_DataObject::connect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
1410                               this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
1411     SUIT_DataObject::connect( SIGNAL( modified( SUIT_DataObject* ) ),
1412                               this, SLOT( onModified( SUIT_DataObject* ) ) );
1413   }
1414
1415   myItems.clear(); // ????? is it really necessary
1416
1417   if ( !myRootItem )
1418     myRootItem = new TreeItem( 0 );
1419
1420   registerColumn( 0, QObject::tr( "NAME_COLUMN" ), SUIT_DataObject::NameId );
1421
1422   QString visCol = QObject::tr( "VISIBILITY_COLUMN" );
1423   registerColumn( 0, visCol, SUIT_DataObject::VisibilityId );
1424
1425   SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
1426   setColumnIcon( visCol, resMgr->loadPixmap( "SUIT", tr( "ICON_DATAOBJ_VISIBLE" ) ));
1427   setHeaderFlags( visCol, Qtx::ShowIcon);
1428
1429   updateTree();
1430 }
1431
1432 /*!
1433   \brief Get root tree item.
1434   \return root tree item
1435 */
1436 SUIT_TreeModel::TreeItem* SUIT_TreeModel::rootItem() const
1437 {
1438   return myRootItem;
1439 }
1440
1441 /*!
1442   \brief Get tree item corresponding to the specified model index.
1443   \param index model index
1444   \return tree item or root item if index is invalid
1445 */
1446 SUIT_TreeModel::TreeItem* SUIT_TreeModel::treeItem( const QModelIndex& index ) const
1447 {
1448   return index.isValid() ? static_cast<TreeItem*>( index.internalPointer() ) : rootItem();
1449 }
1450
1451 /*!
1452   \brief Get tree item corresponding to the specified data object.
1453   \param obj data object
1454   \return tree item or 0 if there is no tree item corresponding to \a obj
1455 */
1456 SUIT_TreeModel::TreeItem* SUIT_TreeModel::treeItem( const SUIT_DataObject* obj ) const
1457 {
1458   TreeItem* item = 0;
1459
1460   if ( obj == root() )
1461     item = rootItem();
1462   else if ( myItems.contains( const_cast<SUIT_DataObject*>( obj ) ) )
1463     item = myItems[ const_cast<SUIT_DataObject*>( obj ) ];
1464
1465   return item;
1466 }
1467
1468 /*!
1469   \brief Get data object corresponding to the specified tree item.
1470   \param item tree item
1471   \return data object or 0 if there is no data object corresponding to \a item
1472 */
1473 SUIT_DataObject* SUIT_TreeModel::object( const SUIT_TreeModel::TreeItem* item ) const
1474 {
1475   if ( item == rootItem() )
1476     return root();
1477  
1478   SUIT_DataObject* obj = item ? item->dataObject() : 0;
1479   return myItems.contains( obj ) ? obj : 0;
1480 }
1481
1482 /*!
1483   \brief Get unique object identifier
1484   
1485   Object identifier is customized via the Qtx::IdType custom data
1486
1487   \param index model index
1488   \return object identifier or null string if it isn't specified
1489   \sa SUIT_DataObject::customData()
1490 */
1491 QString SUIT_TreeModel::objectId( const QModelIndex& index ) const
1492 {
1493   QString objId;
1494   if ( index.isValid() ) {
1495     SUIT_DataObject* obj = object( index );
1496     if ( obj ) {
1497       int anId = obj->customData( Qtx::IdType ).toInt(); 
1498       objId = data( createIndex( index.row(), anId, index.internalPointer() ) ).toString();
1499     }
1500   }
1501   return objId;
1502 }
1503
1504 /*!
1505   \brief Create an item corresponding to the data object.
1506   \param obj source data object
1507   \param parent parent tree item
1508   \param after tree item after which new item should be inserted
1509   \return created tree item or 0 if item could not be created
1510 */
1511 SUIT_TreeModel::TreeItem* SUIT_TreeModel::createItem( SUIT_DataObject* obj,
1512                                                       SUIT_TreeModel::TreeItem* parent, 
1513                                                       SUIT_TreeModel::TreeItem* after )
1514 {
1515   if ( !obj )
1516     return 0;
1517
1518   SUIT_DataObject* parentObj = object( parent );
1519   QModelIndex parentIdx = index( parentObj );
1520
1521   SUIT_DataObject* afterObj = after ? object( after ) : 0;
1522   int row = afterObj ? afterObj->position() + 1 : 0;
1523
1524   beginInsertRows( parentIdx, row, row );
1525
1526   myItems[ obj ] = new TreeItem( obj, parent, after );
1527
1528   for(int pos=row;pos < parent->childCount();pos++)
1529     parent->child(pos)->setPosition(pos);
1530
1531   endInsertRows();
1532
1533   obj->setModified(false);
1534
1535   return myItems[ obj ];
1536 }
1537
1538 /*!
1539   \brief Create an item corresponding to the data object.
1540   \param obj source data object
1541   \param parent parent tree item
1542   \param pos tree item position into which new item should be inserted
1543   \return created tree item or 0 if item could not be created
1544 */
1545 SUIT_TreeModel::TreeItem* SUIT_TreeModel::createItemAtPos( SUIT_DataObject* obj,
1546                                                            SUIT_TreeModel::TreeItem* parent,
1547                                                            int pos )
1548 {
1549   if ( !obj )
1550     return 0;
1551
1552   SUIT_DataObject* parentObj = object( parent );
1553   QModelIndex parentIdx = index( parentObj );
1554
1555   int row = pos ;
1556   SUIT_TreeModel::TreeItem* after = pos>0 ? parent->child(pos-1) : 0 ;
1557
1558   beginInsertRows( parentIdx, row, row );
1559
1560   SUIT_TreeModel::TreeItem* item = new TreeItem( obj, parent, after );
1561   myItems[ obj ] = item;
1562
1563   for(int ppos=row;ppos < parent->childCount();ppos++)
1564     parent->child(ppos)->setPosition(ppos);
1565
1566   endInsertRows();
1567
1568   obj->setModified(false);
1569
1570   return item;
1571 }
1572
1573 /*!
1574   \brief Update tree item.
1575   \param item tree item to be updated
1576   \param emitLayoutChanged if signal about changed layout should be emitted
1577 */
1578 void SUIT_TreeModel::updateItem( SUIT_TreeModel::TreeItem* item, bool emitLayoutChanged )
1579 {
1580   if ( !item )
1581     return;
1582   
1583   SUIT_DataObject* obj = object( item );
1584   if ( !obj )
1585     return;
1586   
1587   // update all columns corresponding to the given data object
1588   /*To avoid crashes we should update any persistent model indexes before emitting layoutChanged(). In other words, when the structure changes:
1589       -  emit layoutAboutToBeChanged
1590       - Remember the QModelIndex that will change
1591       - call changePersistentIndex()
1592       - emit layoutChanged
1593   */
1594
1595     emit layoutAboutToBeChanged();
1596
1597     // Remember the QModelIndex that will change
1598     QModelIndexList fromIndexes;
1599     QModelIndexList toIndexes;
1600     for (int i = 0; i < columnCount() - 1; ++i) {
1601         fromIndexes.append( index( obj, i ));
1602         toIndexes.append(QModelIndex());
1603     }
1604     //changePersistentIndexList(fromIndexes, toIndexes); // Limitation: can lead to loss of selection
1605
1606     emit dataChanged( toIndexes.first(), toIndexes.last() );
1607     obj->setModified(false);
1608     if ( emitLayoutChanged )
1609       emit layoutChanged();
1610 }
1611
1612 /*!
1613   \brief Remove tree item (recursively).
1614   \param item tree item to be removed
1615 */
1616 void SUIT_TreeModel::removeItem( SUIT_TreeModel::TreeItem* item )
1617 {
1618   if ( !item )
1619     return;
1620
1621   // Remove list view items from <myItems> recursively for all children.
1622   // Otherwise, "delete item" line below will destroy all item's children,
1623   // and <myItems> will contain invalid pointers
1624   while( item->childCount() )
1625     removeItem( item->child( 0 ) );
1626
1627   SUIT_DataObject* obj = object( item );
1628   
1629   // Warning! obj can be deleted at this point!
1630
1631   TreeItem* parent=item->parent();
1632   SUIT_DataObject* parentObj = object( parent );
1633   QModelIndex parentIdx = index( parentObj, 0 );
1634   int row = item->position();
1635   
1636   beginRemoveRows( parentIdx, row, row );
1637   myItems.remove( obj );
1638
1639   if ( obj == root() )
1640     setRoot( 0 );
1641   else if ( parent )
1642     {
1643       parent->removeChild( item );
1644       for(int pos=row;pos < parent->childCount();pos++)
1645         parent->child(pos)->setPosition(pos);
1646     }
1647
1648   delete item;
1649
1650   endRemoveRows();
1651 }
1652
1653 /*!
1654   \brief Called when the data object is inserted to the tree.
1655   \param object data object being inserted
1656   \param parent parent data object
1657 */
1658 void SUIT_TreeModel::onInserted( SUIT_DataObject* /*object*/, SUIT_DataObject* parent )
1659 {
1660   if ( autoUpdate() )
1661     updateTree( parent );
1662 }
1663
1664 /*!
1665   \brief Called when the data object is removed from the tree.
1666   \param object data object being removed
1667   \param parent parent data object
1668 */
1669 void SUIT_TreeModel::onRemoved( SUIT_DataObject* /*object*/, SUIT_DataObject* parent )
1670 {
1671   if ( autoUpdate() )
1672     updateTree( parent );
1673 }
1674
1675 /*!
1676   \brief Called when the data object is modified. TreeSync is not used here for maximum efficiency.
1677   It is assumed that it is up to the application to decide when its data objects are modified.
1678   \param obj data object that has been modified
1679 */
1680 void SUIT_TreeModel::onModified( SUIT_DataObject* obj )
1681 {
1682   if ( autoUpdate() )
1683   {
1684     QModelIndex firstIdx = index( obj, 0 );
1685     QModelIndex lastIdx  = index( obj, columnCount() - 1 );
1686     emit dataChanged( firstIdx, lastIdx );
1687     obj->setModified(false);
1688   }
1689 }
1690
1691 /*!
1692   \brief Drag and Drop support.
1693 */
1694 QStringList SUIT_TreeModel::mimeTypes() const
1695 {
1696   QStringList types;
1697   types << "application/vnd.text.list";
1698   return types;
1699 }
1700
1701 /*!
1702   \brief Called when the data objects are exported(dragged) from the tree.
1703   \param indexes the list of exported objects
1704 */
1705 QMimeData* SUIT_TreeModel::mimeData( const QModelIndexList& indexes ) const
1706 {
1707   QMimeData* mimeData = new QMimeData();
1708   QByteArray encodedData;
1709
1710   QDataStream stream( &encodedData, QIODevice::WriteOnly );
1711
1712   foreach ( QModelIndex index, indexes ) {
1713     QString id = objectId( index );
1714     // we have to check only 0 column in order to avoid repeating items in the drag object
1715     // - QTreeView tries to drag indices for all visible columns
1716     if ( index.isValid() && index.column() == 0 && !id.isEmpty() )
1717       stream << id;
1718   }
1719
1720   mimeData->setData( "application/vnd.text.list", encodedData );
1721   return mimeData;
1722 }
1723
1724 bool SUIT_TreeModel::dropMimeData( const QMimeData* data, Qt::DropAction action,
1725                                    int row, int column, const QModelIndex& parent )
1726 {
1727   if ( action == Qt::IgnoreAction )
1728     // do nothing with data
1729     return false;
1730
1731   if ( !data->hasFormat( "application/vnd.text.list" ) )
1732     // not supported data dropped
1733     return false;
1734
1735   if ( !parent.isValid() )
1736     // dropping into the top level of the model is not allowed
1737     return false;
1738
1739   // get parent object
1740   SUIT_DataObject* pobj = object( parent );
1741   if ( !pobj )
1742     // invalid parent
1743     return false;
1744
1745   // decode mime data and collect data objects being dropped
1746   QByteArray encodedData = data->data( "application/vnd.text.list" );
1747   QDataStream stream( &encodedData, QIODevice::ReadOnly );
1748   
1749   DataObjectList objects;
1750
1751   while ( !stream.atEnd() ) {
1752     QString id;
1753     stream >> id;
1754     if ( !id.isEmpty() && searcher() ) {
1755       SUIT_DataObject* obj = searcher()->findObject( id );
1756       if ( obj ) objects << obj;
1757     }
1758   }
1759
1760   // emit signal
1761   emit dropped( objects, pobj, row, action );
1762
1763   // return true if there's any to drop
1764   return !objects.isEmpty();
1765 }
1766
1767 /*!
1768   \class SUIT_ProxyModel
1769   \brief Proxy model which can be used above the SUIT_TreeModel class
1770   to enable custom sorting/filtering of the data.
1771
1772   The SUIT_TreeModel class does not support custom sorting/filtering of the data.
1773   To use these features, the SUIT_ProxyModel class can be used as top-level
1774   wrapper for the SUIT_DataObject-based data tree model.
1775 */
1776
1777 /*!
1778   \brief Constructor.
1779   \param parent parent object
1780 */
1781 SUIT_ProxyModel::SUIT_ProxyModel( QObject* parent )
1782 : QSortFilterProxyModel( parent ),
1783   mySortingEnabled( true )
1784 {
1785   SUIT_TreeModel* model = new SUIT_TreeModel( this );
1786   connect( model, SIGNAL( modelUpdated() ), this, SIGNAL( modelUpdated() ) );
1787   connect( model, SIGNAL( clicked( SUIT_DataObject*, int ) ), this, SIGNAL(clicked( SUIT_DataObject*, int ) ) );
1788   connect( model, SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ),
1789            this,  SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ) );
1790   setSourceModel( model );
1791   setDynamicSortFilter( true );
1792 }
1793
1794 /*!
1795   \brief Constructor.
1796   \param root root data object
1797   \param parent parent object
1798 */
1799 SUIT_ProxyModel::SUIT_ProxyModel( SUIT_DataObject* root, QObject* parent )
1800 : QSortFilterProxyModel( parent ),
1801   mySortingEnabled( true )
1802 {
1803   SUIT_TreeModel* model = new SUIT_TreeModel( root, this );
1804   connect( model, SIGNAL( modelUpdated() ), this, SIGNAL( modelUpdated() ) );
1805   connect( model, SIGNAL( clicked( SUIT_DataObject*, int ) ), this, SIGNAL( clicked( SUIT_DataObject*, int ) ) );
1806   connect( model, SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ),
1807            this,  SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ) );
1808   setSourceModel( model );
1809   setDynamicSortFilter( true );
1810 }
1811
1812 /*!
1813   \brief Constructor.
1814   \param model tree model
1815   \param parent parent object
1816 */
1817 SUIT_ProxyModel::SUIT_ProxyModel( SUIT_AbstractModel* model, QObject* parent )
1818 : QSortFilterProxyModel( parent ),
1819   mySortingEnabled( true )
1820 {
1821   connect( *model, SIGNAL( modelUpdated() ), this, SIGNAL( modelUpdated() ) );
1822   connect( *model, SIGNAL( clicked( SUIT_DataObject*, int ) ), this, SIGNAL( clicked( SUIT_DataObject*, int ) ) );
1823   connect( *model, SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ),
1824            this,   SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ) );
1825   setSourceModel( *model );
1826   setDynamicSortFilter( true );
1827 }
1828
1829 /*!
1830   \brief Destructor.
1831 */
1832 SUIT_ProxyModel::~SUIT_ProxyModel()
1833 {
1834 }
1835
1836 /*!
1837   \brief Get data tree root object.
1838   \return data tree root
1839   \sa setRoot()
1840 */
1841 SUIT_DataObject* SUIT_ProxyModel::root() const
1842 {
1843   return treeModel() ? treeModel()->root() : 0;
1844 }
1845
1846 /*!
1847   \brief Set data tree root object.
1848   \param r new data tree root
1849   \sa root()
1850 */
1851 void SUIT_ProxyModel::setRoot( SUIT_DataObject* r )
1852 {
1853   if ( treeModel() )
1854     treeModel()->setRoot( r );
1855 }
1856
1857 /*!
1858   \brief Get data object by the specified model index.
1859   \param index model index
1860   \return data object corresponding to the model index
1861 */
1862 SUIT_DataObject* SUIT_ProxyModel::object( const QModelIndex& index ) const
1863 {
1864   return treeModel() ? treeModel()->object( mapToSource( index ) ) : 0;
1865 }
1866
1867 /*!
1868   \brief Get model index by the specified data object.
1869   \param obj data object
1870   \param column data object column
1871   \return model index
1872 */
1873 QModelIndex SUIT_ProxyModel::index( const SUIT_DataObject* obj, int column ) const
1874 {
1875   return treeModel() ? mapFromSource( treeModel()->index( obj, column ) ) : QModelIndex();
1876 }
1877
1878 /*!
1879   \brief Get 'auto-delete data tree' flag value.
1880   \return 'auto-delete data tree' flag value
1881   \sa setAutoDeleteTree()
1882 */
1883 bool SUIT_ProxyModel::autoDeleteTree() const
1884 {
1885   return treeModel() ? treeModel()->autoDeleteTree() : false;
1886 }
1887
1888 /*!
1889   \brief Set 'auto-delete data tree' flag value.
1890
1891   If this flag is set to \c true, the data tree is deleted when
1892   the tree model is destroyed. Default value for this flag is \c false.
1893
1894   \param on 'auto-delete data tree' flag value
1895   \sa autoDeleteTree()
1896 */
1897 void SUIT_ProxyModel::setAutoDeleteTree( const bool on )
1898 {
1899   if ( treeModel() )
1900     treeModel()->setAutoDeleteTree( on );
1901 }
1902
1903 /*!
1904   \brief Get 'auto-update tree' flag value.
1905   \return 'auto-update tree' flag value
1906   \sa setAutoUpdate(), updateTree()
1907 */
1908 bool SUIT_ProxyModel::autoUpdate() const
1909 {
1910   return treeModel() ? treeModel()->autoUpdate() : false;
1911 }
1912
1913 /*!
1914   \brief Get 'updateModified' flag value.
1915   \return 'updateModified' flag value
1916 */
1917 bool SUIT_ProxyModel::updateModified() const
1918 {
1919   return treeModel() ? treeModel()->updateModified() : false;
1920 }
1921 /*!
1922   \brief Set 'updateModified' flag value.
1923
1924   If this flag is set to \c true (default=false), the model is updated by updateTreeModel that 
1925   uses the isModified flag to update only modified objects
1926
1927   \param on 'updateModified' flag value
1928 */
1929 void SUIT_ProxyModel::setUpdateModified( const bool on )
1930 {
1931   if ( treeModel() )
1932     treeModel()->setUpdateModified( on );
1933 }
1934
1935 /*!
1936   \brief Set 'auto-update tree' flag value.
1937
1938   If this flag is set to \c true (by default), the model is updated
1939   automatically when data tree is changed.
1940
1941   \param on 'auto-update tree' flag value
1942   \sa autoUpdate(), updateTree()
1943 */
1944 void SUIT_ProxyModel::setAutoUpdate( const bool on )
1945 {
1946   if ( treeModel() )
1947     treeModel()->setAutoUpdate( on );
1948 }
1949
1950 /*!
1951   \brief Check if sorting is enabled.
1952   \return \c true if sorting is enabled
1953   \sa setSortingEnabled()
1954 */
1955 bool SUIT_ProxyModel::isSortingEnabled() const
1956 {
1957   return mySortingEnabled;
1958 }
1959
1960 SUIT_DataSearcher* SUIT_ProxyModel::searcher() const
1961 {
1962   return treeModel() ? treeModel()->searcher() : 0;
1963 }
1964
1965 void SUIT_ProxyModel::setSearcher( SUIT_DataSearcher* s )
1966 {
1967   if ( treeModel() ) treeModel()->setSearcher( s );
1968 }
1969
1970 /*!
1971   \brief Get item delegate for the model.
1972   \return new item delegate
1973 */
1974 QAbstractItemDelegate* SUIT_ProxyModel::delegate() const
1975 {
1976   return treeModel() ? treeModel()->delegate() : 0;
1977 }
1978
1979 /*!
1980   \brief Update tree model.
1981
1982   Call this method when data tree is changed outside the model.
1983   If the 'auto-update' flag is set to \c true, the model
1984   is updated automatically when the data tree is changed.
1985
1986   \param index starting index for the updating
1987   \sa setAutoUpdate()
1988 */
1989 void SUIT_ProxyModel::updateTree( const QModelIndex& index )
1990 {
1991   if ( treeModel() )
1992     treeModel()->updateTree( mapToSource( index ) );
1993 }
1994
1995 /*!
1996   \brief Update tree model.
1997
1998   Call this method when data tree is changed outside the model.
1999   If the 'auto-update' flag is set to \c true, the model
2000   is updated automatically when the data tree is changed.
2001
2002   \param obj starting data object for the updating
2003   \sa setAutoUpdate()
2004 */
2005 void SUIT_ProxyModel::updateTree( SUIT_DataObject* obj )
2006 {
2007   if ( treeModel() )
2008     treeModel()->updateTree( obj );
2009 }
2010
2011 void SUIT_ProxyModel::forgetObject( const SUIT_DataObject* obj )
2012 {
2013   if ( treeModel() )
2014     treeModel()->forgetObject( obj );
2015 }
2016
2017 /*!
2018   \brief Compares two model indexes for the sorting purposes.
2019   \param left first index to compare
2020   \param right second index to compare
2021   \return result of the comparison
2022 */
2023 bool SUIT_ProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right ) const
2024 {
2025   if ( !isSortingEnabled() && left.isValid() && right.isValid() ) {
2026     return left.row() < right.row();
2027   }
2028   if ( treeModel() && treeModel()->customSorting( left.column() ) ) {
2029     return treeModel()->lessThan( left, right );
2030   }
2031   return QSortFilterProxyModel::lessThan( left, right );
2032 }
2033
2034 /*!
2035   \brief Check if the specified column supports custom sorting.
2036   \param column column index on which data is being sorted
2037   \return \c true if column requires custom sorting
2038   \sa lessThan()
2039 */
2040 bool SUIT_ProxyModel::customSorting( const int column ) const
2041 {
2042   return treeModel() ? treeModel()->customSorting( column ) : false;
2043 }
2044
2045 /*!
2046   \brief Enable/disable sorting.
2047   \param enabled new flag state
2048   \sa isSortingEnabled()
2049 */
2050 void SUIT_ProxyModel::setSortingEnabled( bool enabled )
2051 {
2052   mySortingEnabled = enabled;
2053   clear();
2054 }
2055
2056 /*
2057   \brief Get tree model.
2058   \return tree model
2059 */
2060 SUIT_AbstractModel* SUIT_ProxyModel::treeModel() const
2061 {
2062   return dynamic_cast<SUIT_AbstractModel*>( sourceModel() );
2063 }
2064
2065 /*!
2066   \brief Filter rows
2067   \param sourceRow row index of the source data model
2068   \param sourceParent parent model index of the source data model
2069   \return \c true if the specified row should be filtered out (i.e. not displayed) or \c false otherwise
2070 */
2071 bool SUIT_ProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent ) const
2072 {
2073   SUIT_DataObject* o = treeModel()->object( sourceModel()->index( sourceRow, 0, sourceParent ) );
2074   SUIT_DataObject* p = o ? o->parent() : 0;
2075   return ( !p || p->expandable() ) && o && o->isVisible();
2076 }
2077
2078 /*!
2079   \brief Register new column in the model
2080   \param group_id - unique data object identificator allowing the classification of objects 
2081   \param name - translated column name
2082   \param custom_id - custom column id that should be passed into method SUIT_DataObject::data()
2083  */
2084 void SUIT_ProxyModel::registerColumn( const int group_id, const QString& name, const int custom_id )
2085 {
2086   if( treeModel() )
2087     treeModel()->registerColumn( group_id, name, custom_id );
2088 }
2089
2090 /*!
2091   \brief Remove column from the model
2092
2093   Please take into account that column is removed only for given group_id, it means
2094   that information of data objects with such group_id won't be shown.
2095   If there is not any registered group_id for this column after removing, the column will be hidden
2096   otherwise it continue to be shown
2097
2098   \param group_id - unique data object identificator allowing the classification of objects 
2099   \param name - translated column name
2100  */
2101 void SUIT_ProxyModel::unregisterColumn( const int group_id, const QString& name )
2102 {
2103   if( treeModel() )
2104     treeModel()->unregisterColumn( group_id, name );
2105 }
2106
2107 /*!
2108   \brief Change column icon.
2109
2110   \param name - column name
2111   \param icon - new icon of the specified column
2112 */
2113 void SUIT_ProxyModel::setColumnIcon( const QString& name, const QPixmap& icon )
2114 {
2115   if( treeModel() )
2116     treeModel()->setColumnIcon( name, icon );
2117 }
2118
2119 /*!
2120   \brief Get column icon.
2121
2122   \param name - column name
2123   \return icon of the specified column
2124 */
2125 QPixmap SUIT_ProxyModel::columnIcon( const QString& name ) const
2126 {
2127   return treeModel() ? treeModel()->columnIcon( name ) : QPixmap();
2128 }
2129
2130 /*!
2131   \brief Change appropriate status
2132   
2133   Appropriate status determines if the column should appear in the tree view header popup menu
2134   (to show/hide the column).
2135
2136   If appropriate status is not specified yet, the \c Shown value is taken,
2137   it means that column should be always visible.
2138
2139   \param name - column name
2140   \param appr - new appropriate status
2141 */
2142 void SUIT_ProxyModel::setAppropriate( const QString& name, const Qtx::Appropriate appr )
2143 {
2144   if( treeModel() )
2145     treeModel()->setAppropriate( name, appr );
2146 }
2147
2148 /*!
2149   \brief Check if the column should appear in the tree view header popup menu
2150   (to show/hide the column).
2151
2152   Default implementation (if appropriate status is not specified yet)
2153   returns \c Shown, it means that column should be always visible.
2154
2155   \param name - column name
2156   \return appropriate status
2157 */
2158 Qtx::Appropriate SUIT_ProxyModel::appropriate( const QString& name ) const
2159 {
2160   return treeModel() ? treeModel()->appropriate( name ) : Qtx::Shown;
2161 }
2162
2163 /*!
2164   \brief Set header flags.
2165   
2166   These flags allow show in the header of the column text (name of the column),
2167   icon or both text and icon.
2168   
2169   \param name - column name
2170   \param flags - header flags
2171
2172 */
2173 void SUIT_ProxyModel::setHeaderFlags( const QString& name, const Qtx::HeaderViewFlags flags )
2174 {
2175   if(treeModel())
2176     treeModel()->setHeaderFlags(name, flags);
2177 }
2178
2179 /*!
2180   \brief Get the  header flags.
2181   
2182   These flags allow show in the header of the column text (name of the column),
2183   icon or both text and icon.
2184   
2185   \param name - column name
2186   \return header flags
2187 */
2188 Qtx::HeaderViewFlags SUIT_ProxyModel::headerFlags( const QString& name ) const
2189 {
2190   return treeModel() ? treeModel()->headerFlags( name ) : Qtx::ShowAll;
2191 }
2192
2193 /*!
2194   \brief Set visibility state of the object.
2195   
2196   \param id - column name
2197   \param state - visible state
2198   \param emitChanged - if set to false, blocks dataChanged() signal, this can be used to
2199   prevent emitting dataChanged() several times for the same data object
2200 */
2201 void SUIT_ProxyModel::setVisibilityState(const QString& id, Qtx::VisibilityState state, bool emitChanged ) {
2202   if(treeModel())
2203     treeModel()->setVisibilityState(id,state,emitChanged);
2204 }
2205
2206 /*!
2207   \brief Set visibility state for all objects.
2208   
2209   \param id - column name
2210   \param state - visible state
2211 */
2212 void SUIT_ProxyModel::setVisibilityStateForAll(Qtx::VisibilityState state)
2213 {
2214   if(treeModel())
2215     treeModel()->setVisibilityStateForAll(state);
2216 }
2217
2218 /*!
2219   \brief Get visibility state of the object.
2220   
2221   \param id - column name
2222   \return visible state
2223 */
2224 Qtx::VisibilityState SUIT_ProxyModel::visibilityState(const QString& id) const
2225 {
2226   return treeModel() ? treeModel()->visibilityState(id) : Qtx::UnpresentableState;
2227 }
2228
2229 void SUIT_ProxyModel::emitClicked( SUIT_DataObject* obj, const QModelIndex& index)
2230 {
2231   if(treeModel())
2232     treeModel()->emitClicked(obj,index);
2233 }
2234
2235 /*!
2236   \class SUIT_ItemDelegate
2237   \brief An SUIT_DataObject-based item delegate class.
2238
2239   This class can be used to render the SUIT_DataObject-based item
2240   in the widgets like QTreeView and others.
2241   Refer to the Qt 4 documentation, model/view architecture 
2242   section for more details).
2243 */
2244
2245 /*!
2246   \brief Constructor.
2247   \param parent parent object
2248 */
2249 SUIT_ItemDelegate::SUIT_ItemDelegate( QObject* parent )
2250 : QItemDelegate( parent )
2251 {
2252 }
2253
2254 /*!
2255   \brief Render the item in the widget.
2256
2257   Customizes the item colors for the specific roles.
2258
2259   \param painter painter
2260   \param option painting option
2261   \param index model index being rendered
2262 */
2263 void SUIT_ItemDelegate::paint( QPainter* painter, 
2264                                const QStyleOptionViewItem& option,
2265                                const QModelIndex& index ) const
2266 {
2267   QStyleOptionViewItem opt = option;
2268   if ( index.isValid() ) {
2269     // Note: we check into account only custom roles; other roles are process
2270     //       correctly by the QItemDelegate class
2271     QVariant val = index.data( SUIT_TreeModel::BaseColorRole );
2272     if ( val.isValid() && val.value<QColor>().isValid() ) {
2273       QColor aBase = val.value<QColor>();
2274       aBase.setAlpha( 0 );
2275       opt.palette.setBrush( QPalette::Base, val.value<QColor>() );
2276     }
2277     val = index.data( SUIT_TreeModel::TextColorRole );
2278     if ( val.isValid() && val.value<QColor>().isValid() )
2279       opt.palette.setBrush( QPalette::Text, val.value<QColor>() );
2280     val = index.data( SUIT_TreeModel::HighlightRole );
2281     if ( val.isValid() && val.value<QColor>().isValid() )
2282       opt.palette.setBrush( QPalette::Highlight, val.value<QColor>() );
2283     val = index.data( SUIT_TreeModel::HighlightedTextRole );
2284     if ( val.isValid() && val.value<QColor>().isValid() )
2285       opt.palette.setBrush( QPalette::HighlightedText, val.value<QColor>() );      
2286   }
2287   QItemDelegate::paint( painter, opt, index );
2288 }
2289
2290 QSize SUIT_ItemDelegate::sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const
2291 {
2292     QSize size = QItemDelegate::sizeHint ( option, index );
2293 #if QT_VERSION >= 0x040500
2294     size.setHeight( size.height() + 1 );
2295 #endif
2296     return size;
2297 }