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