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