]> SALOME platform Git repositories - modules/gui.git/blob - src/SUIT/SUIT_TreeModel.cxx
Salome HOME
Merge remote-tracking branch 'origin/vsr/fix_single_study_pb' into pre/fix_single_study
[modules/gui.git] / src / SUIT / SUIT_TreeModel.cxx
1 // Copyright (C) 2007-2014  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 // File:   SUIT_TreeModel.cxx
21 // Author: Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
22
23 #include "SUIT_Session.h"
24 #include "SUIT_TreeModel.h"
25 #include "SUIT_TreeSync.h"
26 #include "SUIT_DataObject.h"
27 #include "SUIT_ResourceMgr.h"
28
29 #include <QApplication>
30 #include <QHash>
31 #include <QMimeData>
32
33 SUIT_AbstractModel::SUIT_AbstractModel() : mySearcher( 0 )
34 {
35 }
36
37 SUIT_AbstractModel::operator const QAbstractItemModel*() const
38 {
39   return dynamic_cast<const QAbstractItemModel*>( this );
40 }
41
42 SUIT_AbstractModel::operator QAbstractItemModel*()
43 {
44   return dynamic_cast<QAbstractItemModel*>( this );
45 }
46
47 SUIT_AbstractModel::operator const QObject*() const
48 {
49   return dynamic_cast<const QObject*>( this );
50 }
51
52 SUIT_DataSearcher* SUIT_AbstractModel::searcher() const
53 {
54   return mySearcher;
55 }
56
57 void SUIT_AbstractModel::setSearcher( SUIT_DataSearcher* s )
58 {
59   mySearcher = s;
60 }
61
62
63 /*!
64   \class SUIT_TreeModel::TreeItem
65   \brief Internal class used for tree view synchronizaton with data object tree.
66   \internal
67 */
68
69 class SUIT_TreeModel::TreeItem
70 {
71 public:
72   TreeItem( SUIT_DataObject* obj, TreeItem* parent = 0, TreeItem* after = 0 );
73   ~TreeItem();
74
75   void                  insertChild( TreeItem* child, TreeItem* after = 0 );
76   void                  removeChild( TreeItem* child );
77   SUIT_DataObject*      dataObject() const;
78   TreeItem*             parent() const;
79   int                   position() const;
80   void                  setPosition(int position) {_position=position;};
81   int                   childCount() const;
82   TreeItem*             child( const int i );
83   QList<TreeItem*>      children() const;
84   TreeItem*             nextSibling() const;
85   TreeItem*             prevSibling() const;
86   
87 private:
88   TreeItem*             myParent;
89   QList<TreeItem*>      myChildren;
90   SUIT_DataObject*      myObj;
91   int _position;
92 };
93
94 /*!
95   \brief Constructor.
96   \internal
97   \param obj data object
98   \param parent parent item
99   \param after tree item after each this one should be inserted
100 */
101 SUIT_TreeModel::TreeItem::TreeItem( SUIT_DataObject*          obj, 
102                                     SUIT_TreeModel::TreeItem* parent,
103                                     SUIT_TreeModel::TreeItem* after )
104 : myParent( parent ),
105   myObj( obj ),
106   _position(-1)
107 {
108   // Add <this> to the parent's children list
109   if ( myParent )
110     myParent->insertChild( this, after );
111 }
112
113 /*!
114   \brief Destructor. Deletes all child items recursively.
115   \internal
116 */
117 SUIT_TreeModel::TreeItem::~TreeItem()
118 {
119   // Ensure that all children are deleted;
120   // each child removes itself from the children list
121   while( myChildren.count() )
122     delete myChildren.at( 0 );
123
124   // Remove this item from the parent's children list
125   if ( myParent )
126     myParent->removeChild( this );
127 }
128
129 /*!
130   \brief Insert child item.
131   \internal
132   \param child child item being inserted
133   \param after tree item after each \a child should be inserted
134 */
135 void SUIT_TreeModel::TreeItem::insertChild( SUIT_TreeModel::TreeItem* child, 
136                                             SUIT_TreeModel::TreeItem* after )
137 {
138   if ( !child )
139     return;
140
141   int index = after ? after->position() + 1 : 0;
142   myChildren.insert( index, child );
143 }
144
145 /*!
146   \brief Remove child item.
147   \internal
148   \param child child item being removed
149 */
150 void SUIT_TreeModel::TreeItem::removeChild( SUIT_TreeModel::TreeItem* child )
151 {
152   if ( !child )
153     return;
154   myChildren.removeAll( child );
155 }
156
157 /*!
158   \brief Get data object.
159   \internal
160   \return data object this item is associated to
161 */
162 SUIT_DataObject* SUIT_TreeModel::TreeItem::dataObject() const
163 {
164   return myObj;
165 }
166
167 /*!
168   \brief Get parent item.
169   \internal
170   \return parent item
171 */
172 SUIT_TreeModel::TreeItem* SUIT_TreeModel::TreeItem::parent() const
173 {
174   return myParent;
175 }
176
177 /*!
178   \brief Get position of this item in its parent's children list.
179   \internal
180   \return item position
181 */
182 int SUIT_TreeModel::TreeItem::position() const
183 {
184   return _position;
185 }
186
187 /*!
188   \brief Get number of child items.
189   \internal
190   \return number of children
191 */
192 int SUIT_TreeModel::TreeItem::childCount() const
193 {
194   return myChildren.count();
195 }
196
197 /*!
198   \brief Get child item by specified index.
199   \internal
200   \param i child item index
201   \return child item or 0 if \a i is out of range
202 */
203 SUIT_TreeModel::TreeItem* SUIT_TreeModel::TreeItem::child( const int i )
204 {
205   return i >= 0 && i < myChildren.count() ? myChildren.at( i ) : 0;
206 }
207
208 /*!
209   \brief Get all child items.
210   \internal
211   \return list of child items
212 */
213 QList<SUIT_TreeModel::TreeItem*> SUIT_TreeModel::TreeItem::children() const
214 {
215   return myChildren;
216 }
217
218 /*!
219   \brief Get next sibling item.
220   \internal
221   \return next sibling item or 0 if there are no any
222 */
223 SUIT_TreeModel::TreeItem* SUIT_TreeModel::TreeItem::nextSibling() const
224 {
225   return parent() ? parent()->child( position()+1 ) : 0;
226 }
227
228 /*!
229   \brief Get previous sibling item.
230   \internal
231   \return previous sibling item or 0 if there are no any
232 */
233 SUIT_TreeModel::TreeItem* SUIT_TreeModel::TreeItem::prevSibling() const
234 {
235   return parent() ? parent()->child( position()-1 ) : 0;
236 }
237
238 /*!
239   \class SUIT_TreeModel::TreeSync
240   \brief Functor class for synchronizing data tree and tree model 
241          when the data tree is changed outside the model.
242   \internal
243 */
244
245 class SUIT_TreeModel::TreeSync
246 {
247 public:
248   TreeSync( SUIT_TreeModel* );
249   bool              isEqual( const ObjPtr&, const ItemPtr& ) const;
250   ObjPtr            nullSrc() const;
251   ItemPtr           nullTrg() const;
252   ItemPtr           createItem( const ObjPtr&, const ItemPtr&, const ItemPtr& ) const;
253   void              updateItem( const ObjPtr&, const ItemPtr& ) const;
254   void              deleteItemWithChildren( const ItemPtr& ) const;
255   QList<ObjPtr>     children( const ObjPtr& ) const;
256   QList<ItemPtr>    children( const ItemPtr& ) const;
257   ItemPtr           parent( const ItemPtr& ) const;
258 private:
259   bool              needUpdate( const ItemPtr& ) const;
260   SUIT_TreeModel*   myModel;
261 };
262
263 /*!
264   \brief Constructor.
265   \internal
266   \param model tree model
267 */
268 SUIT_TreeModel::TreeSync::TreeSync( SUIT_TreeModel* model )
269 : myModel( model )
270 {
271 }
272
273 /*!
274   \brief Check if item corresponds to the specified data object.
275   \internal
276   \param obj data object
277   \param item tree item 
278   \return \c true if item corresponds to the data object
279 */
280 bool SUIT_TreeModel::TreeSync::isEqual( const ObjPtr& obj, const ItemPtr& item ) const
281 {
282   bool isRoot = obj == myModel->root() && item == myModel->rootItem(),
283        isEq   = obj && item && item->dataObject() == obj;
284   return isRoot || ( !obj && !item ) || isEq;
285 }
286
287 /*!
288   \brief Get null data object.
289   \internal
290   \return null data object
291 */
292 SUIT_TreeModel::ObjPtr SUIT_TreeModel::TreeSync::nullSrc() const
293 {
294   return 0;
295 }
296
297 /*!
298   \brief Get null tree item.
299   \internal
300   \return null tree item
301 */
302 SUIT_TreeModel::ItemPtr SUIT_TreeModel::TreeSync::nullTrg() const
303 {
304   return 0;
305 }
306
307 /*!
308   \brief Create an item corresponding to the specified data object.
309   \internal
310   \param obj data object
311   \param parent parent tree item
312   \param after tree item after each new one should be inserted
313   \return created item
314 */
315 SUIT_TreeModel::ItemPtr SUIT_TreeModel::TreeSync::createItem( const ObjPtr&  obj,
316                                                               const ItemPtr& parent, 
317                                                               const ItemPtr& after ) const
318 {
319   ItemPtr item = myModel ? myModel->createItem( obj, parent, after ) : 0;
320
321   // Additional actions that can't be performed by the model, e.g. expanded state
322   if( item )
323     obj->update();
324   return item;
325 }
326
327 /*!
328   \brief Update tree item.
329   \internal
330   \param obj reference data object
331   \param item tree item to be updated
332 */
333 void SUIT_TreeModel::TreeSync::updateItem( const ObjPtr& obj, const ItemPtr& item ) const
334 {
335   if( obj )
336     obj->update();
337   if ( item && needUpdate( item ) ) 
338     myModel->updateItem( item, false );
339 }
340
341 /*!
342   \brief Delete item with all children recursively.
343   \internal
344   \param item tree item
345 */
346 void SUIT_TreeModel::TreeSync::deleteItemWithChildren( const ItemPtr& item ) const
347 {
348   // NOTE: item is deleted inside removeItem()!
349   myModel->removeItem( item );
350 }
351
352 /*!
353   \brief Get all the children of the specified data object.
354   \internal
355   \param obj data object
356   \return list of the children
357 */
358 QList<SUIT_TreeModel::ObjPtr> SUIT_TreeModel::TreeSync::children( const ObjPtr& obj ) const
359 {
360   QList<ObjPtr> ch;
361   if ( obj )
362     ch = obj->children();
363   return ch;
364 }
365
366 /*!
367   \brief Get all the children of the specified tree item.
368   \internal
369   \param item tree item
370   \return list of the children
371 */
372 QList<SUIT_TreeModel::ItemPtr> SUIT_TreeModel::TreeSync::children( const ItemPtr& item ) const
373 {
374   QList<ItemPtr> ch;
375   if ( item ) 
376     ch = item->children();
377   return ch;
378 }
379
380 /*!
381   \brief Get item which is the parent for the specified item.
382   \internal
383   \param item tree item
384   \return parent item
385 */
386 SUIT_TreeModel::ItemPtr SUIT_TreeModel::TreeSync::parent( const ItemPtr& item ) const
387 {
388   return item ? item->parent() : 0;
389 }
390
391 /*!
392   \brief Check if the tree item needs updating.
393   \internal
394   \param item tree item to be checked
395   \return \c true if item needs updating
396
397   \todo finalize this method
398 */
399 bool SUIT_TreeModel::TreeSync::needUpdate( const ItemPtr& item ) const
400 {
401   bool update = false;
402   if ( item ) {
403     SUIT_DataObject* obj = item->dataObject();
404     if ( obj ) {
405       // TODO: find simplified way to check if an item is not up-to-date:
406       // - use check-sum of various item data
407       // - use "LastModified" time stamp in data objects and tree items - hardly possible, for sometimes data objects do not know that data changes...
408       // ...
409       update = true; // TEMPORARY!!!
410       // 1. check text
411 /*      update = ( item->text( 0 ) != obj->name() ) || myBrowser->needToUpdateTexts( item );
412
413       if ( !update ) { 
414         // 2. check pixmap (compare serialNumber()-s)
415         QPixmap objPix = obj->icon();
416         const QPixmap* itemPix = item->pixmap( 0 );
417         update = (  objPix.isNull() && (  itemPix && !itemPix->isNull() ) ) || 
418                  ( !objPix.isNull() && ( !itemPix ||  itemPix->isNull() ) ); 
419         if ( !update && !objPix.isNull() && itemPix && !itemPix->isNull() ) {
420           int aIconW = objPix.width();
421           if( aIconW > 20 ) {
422             QWMatrix aM;
423             double aScale = 20.0 / aIconW;
424             aM.scale( aScale, aScale );
425             objPix = objPix.xForm( aM );
426           }
427           update = ( objPix.serialNumber() != itemPix->serialNumber() );
428         }
429       }*/
430     }
431   }
432   return update;
433 }
434
435 /*!
436   \class SUIT_TreeModel
437   \brief Implementation of the model/view API based on the tree of SUIT_DataObject class
438   instances.
439
440   The SUIT_TreeModel class does not support insertion/removal of rows. It is synchronized 
441   automatically with the tree of data objects used by SUIT-based applications to 
442   expose their data in a hierarchical form to the user.
443 */
444
445 /*!
446   \brief Constructor.
447   \param parent parent object
448 */
449 SUIT_TreeModel::SUIT_TreeModel( QObject* parent )
450 : QAbstractItemModel( parent ),
451   myRoot( 0 ),
452   myRootItem( 0 ),
453   myAutoDeleteTree( false ),
454   myAutoUpdate( true ),
455   myUpdateModified( false )
456 {
457   initialize();
458 }
459
460 /*!
461   \brief Constructor.
462   \param root root data object
463   \param parent parent object
464 */
465 SUIT_TreeModel::SUIT_TreeModel( SUIT_DataObject* root, QObject* parent )
466 : QAbstractItemModel( parent ),
467   myRoot( root ),
468   myRootItem( 0 ),
469   myAutoDeleteTree( false ),
470   myAutoUpdate( true ),
471   myUpdateModified( false )
472 {
473   initialize();
474 }
475
476 /*!
477   \brief Destructor
478 */
479 SUIT_TreeModel::~SUIT_TreeModel()
480 {
481   if ( autoDeleteTree() ) {
482     SUIT_DataObject::disconnect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
483                                  this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
484     SUIT_DataObject::disconnect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
485                                  this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
486     SUIT_DataObject::disconnect( SIGNAL( modifed( SUIT_DataObject* ) ),
487                                  this, SLOT( onModified( SUIT_DataObject* ) ) );
488     delete myRoot;
489   }
490
491   delete myRootItem;
492 }
493
494 /*!
495   \brief Register new column in the model
496   \param group_id - unique data object group identificator
497   \param name - translated column name
498   \param custom_id - custom column id that should be passed into method SUIT_DataObject::data()
499  */
500 void SUIT_TreeModel::registerColumn( const int group_id, const QString& name, const int custom_id )
501 {
502   bool found = false;
503   for ( int i=0, n=myColumns.size(); i<n && !found; i++ ) {
504     if ( name == myColumns[i].myName ) {
505       myColumns[i].myIds.insert( group_id, custom_id );
506       found = true;
507     }
508   }
509   if ( !found ) {
510     ColumnInfo inf;
511     inf.myName = name;
512     inf.myIds.insert( group_id, custom_id );
513     inf.myAppropriate = Qtx::Shown;
514     inf.myHeaderFlags = Qtx::ShowAll;
515     int n = myColumns.size();
516     myColumns.resize( n+1 );
517     myColumns[n] = inf;
518     reset();
519   }
520 }
521
522 /*!
523   \brief Remove column from the model
524
525   Please take into account that column is removed only for given group_id, it means
526   that information of data objects with such group_id won't be shown.
527   If there is not any registered group_id for this column after removing, the column will be hidden
528   otherwise it continue to be shown
529
530   \param group_id - unique data object identificator allowing the classification of objects 
531   \param name - translated column name
532  */
533 void SUIT_TreeModel::unregisterColumn( const int group_id, const QString& name )
534 {
535   for ( int i = 0, n = myColumns.size(); i < n; i++ ) {
536     if ( myColumns[i].myName == name ) {
537       myColumns[i].myIds.remove( group_id );
538       if ( myColumns[i].myIds.isEmpty() ) {
539         myColumns.remove( i );
540         reset();
541       }
542       break;
543     }
544   }
545 }
546
547 /*!
548   \brief Change column icon.
549
550   \param name - column name
551   \param icon - new icon of the specified column
552 */
553 void SUIT_TreeModel::setColumnIcon( const QString& name, const QPixmap& icon )
554 {
555   for ( int i = 0, n = myColumns.size(); i < n; i++ ) {
556     if ( myColumns[i].myName == name ) {
557       myColumns[i].myIcon = icon;
558       break;
559     }
560   }
561 }
562
563 /*!
564   \brief Get column icon.
565
566   \param name - column name
567   \return icon of the specified column
568 */
569 QPixmap SUIT_TreeModel::columnIcon( const QString& name ) const
570 {
571   QPixmap res;
572   for ( int i = 0, n = myColumns.size(); i < n; i++ ) {
573     if ( myColumns[i].myName == name ) {
574       res = myColumns[i].myIcon;
575       break;
576     }
577   }
578   return res;
579 }
580
581 /*!
582   \brief Change appropriate status
583   
584   Appropriate status determines if the column should appear in the tree view header popup menu
585   (to show/hide the column).
586
587   If appropriate status is not specified yet, the \c Shown value is taken,
588   it means that column should be always visible.
589
590   \param name - column name
591   \param appr - new appropriate status
592 */
593 void SUIT_TreeModel::setAppropriate( const QString& name, const Qtx::Appropriate appr )
594 {
595   for ( int i = 0, n = myColumns.size(); i < n; i++ ) {
596     if ( myColumns[i].myName == name && myColumns[i].myAppropriate != appr ) {
597       myColumns[i].myAppropriate = appr;
598       emit headerDataChanged( Qt::Horizontal, i, i );
599       break;
600     }
601   }
602 }
603
604 /*!
605   \brief Check if the column should appear in the tree view header popup menu
606   (to show/hide the column).
607
608   Default implementation (if appropriate status is not specified yet)
609   returns \c Shown, it means that column should be always visible.
610
611   \param name - column name
612   \return appropriate status
613 */
614 Qtx::Appropriate SUIT_TreeModel::appropriate( const QString& name ) const
615 {
616   Qtx::Appropriate appr = Qtx::Shown;
617   for ( int i = 0, n = myColumns.size(); i < n; i++ ) {
618     if ( myColumns[i].myName == name ) {
619       appr = myColumns[i].myAppropriate;
620       break;
621     }
622   }
623   return appr;
624 }
625
626
627 /*!
628   \brief Set header flags.
629   
630   These flags allow show in the header of the column text (name of the column),
631   icon or both text and icon.
632   
633   \param name - column name
634   \param flags - header flags
635
636 */
637 void SUIT_TreeModel::setHeaderFlags( const QString& name, const Qtx::HeaderViewFlags flags )
638 {
639   for ( int i = 0, n = myColumns.size(); i < n; i++ ) {
640     if ( myColumns[i].myName == name && myColumns[i].myHeaderFlags != flags ) {
641       myColumns[i].myHeaderFlags = flags;
642       emit headerDataChanged( Qt::Horizontal, i, i );
643       break;
644     }
645   }
646 }
647
648 /*!
649   \brief Get the  header flags.
650   
651   These flags allow show in the header of the column text (name of the column),
652   icon or both text and icon.
653   
654   \param name - column name
655   \return header flags
656 */
657 Qtx::HeaderViewFlags SUIT_TreeModel::headerFlags( const QString& name ) const
658 {
659   Qtx::HeaderViewFlags flags;
660   for ( int i = 0, n = myColumns.size(); i < n; i++ ) {
661     if ( myColumns[i].myName == name ) {
662       flags = myColumns[i].myHeaderFlags;
663       break;
664     }
665   }
666   return flags;
667 }
668
669 /*!
670   \brief Set visibility state of the object.
671   
672   \param id - column name
673   \param state - visible state
674   \param emitChanged - if set to false, blocks dataChanged() signal, this can be used to
675   prevent emitting dataChanged() several times for the same data object
676 */
677 void SUIT_TreeModel::setVisibilityState( const QString& id, Qtx::VisibilityState state, bool emitChanged )
678 {
679   VisibilityMap::const_iterator it = myVisibilityMap.find( id );
680   if ( it != myVisibilityMap.end() && it.value() == state )
681     return;
682   
683   bool needSignal = false;
684   if ( state != Qtx::UnpresentableState ) {
685     myVisibilityMap.insert( id, state );
686     needSignal = true;
687   }
688   else {
689     needSignal = myVisibilityMap.remove( id ) > 0;
690   }
691   if ( emitChanged && needSignal ) {
692     QModelIndexList lst;
693     if ( searcher() ) {
694       SUIT_DataObject* o = searcher()->findObject( id );
695       if ( o ) lst << index( o );
696     }
697     else {
698       lst = match( index( 0, root()->customData( Qtx::IdType ).toInt() ), DisplayRole, id, 1, Qt::MatchExactly | Qt::MatchRecursive );
699     }
700     if ( !lst.isEmpty() ) {
701       QModelIndex idx = index( lst.first().row(), SUIT_DataObject::VisibilityId, lst.first().parent() );
702       emit dataChanged( idx, idx );
703     }
704   }
705 }
706
707 /*!
708   \brief Set visibility state for all objects.
709   
710   \param state - visible state
711 */
712 void SUIT_TreeModel::setVisibilityStateForAll( Qtx::VisibilityState state )
713 {
714   if ( state != Qtx::UnpresentableState ) {
715     VisibilityMap::ConstIterator it = myVisibilityMap.begin();
716     while ( it != myVisibilityMap.end() ) {
717       if ( it.value() != state )
718         setVisibilityState( it.key(), state );
719       it++;
720     }
721   }
722   else {
723     QList<QString> anIds = myVisibilityMap.keys();
724     myVisibilityMap.clear();
725     QList<QString>::ConstIterator it = anIds.begin();
726     while ( it != anIds.end() ) {
727       QModelIndexList lst;
728       if ( searcher() ) {
729         SUIT_DataObject* o = searcher()->findObject( *it );
730         if ( o ) lst << index( o );
731       }
732       else {
733         lst = match( index( 0, root()->customData( Qtx::IdType ).toInt() ), DisplayRole, (*it), 1, Qt::MatchExactly | Qt::MatchRecursive );
734       }
735       if ( !lst.isEmpty() ) {
736         QModelIndex idx = index( lst.first().row(), SUIT_DataObject::VisibilityId ,lst.first().parent() );
737         emit dataChanged( idx, idx );
738       }
739       it++;
740     }
741   }
742 }
743
744 /*!
745   \brief Get visibility state of the object.
746   
747   \param id - column name
748   \return visible state
749 */
750 Qtx::VisibilityState SUIT_TreeModel::visibilityState( const QString& id ) const
751 {
752   VisibilityMap::const_iterator it = myVisibilityMap.find( id );
753   return it != myVisibilityMap.end() ? it.value() : Qtx::UnpresentableState;
754 }
755
756 /*!
757   \brief Get data tree root object.
758   \return data tree root
759   \sa setRoot()
760 */
761 SUIT_DataObject* SUIT_TreeModel::root() const
762 {
763   return myRoot;
764 }
765
766 /*!
767   \brief Set data tree root object.
768   \param r new data tree root
769   \sa root()
770 */
771 void SUIT_TreeModel::setRoot( SUIT_DataObject* r )
772 {
773   if ( root() == r )
774     return;
775
776   if ( autoDeleteTree() ) {
777     SUIT_DataObject::disconnect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
778                                  this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
779     SUIT_DataObject::disconnect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
780                                  this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
781     SUIT_DataObject::disconnect( SIGNAL( modified( SUIT_DataObject* ) ),
782                                  this, SLOT( onModified( SUIT_DataObject* ) ) );
783     delete myRoot;
784     
785     if ( myRootItem ) {
786       QList<TreeItem*> items = myRootItem->children();
787       for ( QList<TreeItem*>::iterator anIt = items.begin(); anIt != items.end(); anIt++ )
788         delete *anIt;
789     }
790   }
791
792   myRoot = r;
793
794   //initialize();
795   reset();
796   emit modelUpdated();
797 }
798
799 /*!
800   \brief Get data for the specified model index and data role.
801   \param index model index
802   \param role data role
803   \return requested data
804   \sa setData()
805 */
806 QVariant SUIT_TreeModel::data( const QModelIndex& index, int role ) const
807 {
808   if ( !index.isValid() )
809     return QVariant();
810
811   SUIT_DataObject* obj = object( index );
812   if ( !obj )
813     return QVariant();
814
815   QColor c;
816   QVariant val;
817
818   int obj_group_id = obj->groupId();
819   const ColumnInfo& inf = myColumns[index.column()];
820
821   int id = -1;
822   if( inf.myIds.contains( 0 ) )
823     id = inf.myIds[0];
824   if( inf.myIds.contains( obj_group_id ) )
825     id = inf.myIds[obj_group_id];
826
827   if( id<0 )
828     return QVariant();
829
830   if ( obj )
831   {
832     switch ( role )
833         {
834     case DisplayRole:
835       // data object text for the specified column
836       val = obj->text( id );
837       break;
838     case EditRole:
839       // data object text for the specified column (for editor)
840       val = obj->text( id );
841       break;
842     case DecorationRole: {
843       // icon
844       if ( id == SUIT_DataObject::VisibilityId ) {
845         // for visibility column, icon is defined specifically (using data object id)
846         QString objId = objectId( index );
847         if ( myVisibilityMap.contains( objId ) ) {
848           // visibility status is defined -> return proper icon
849           SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();      
850           val  = ( myVisibilityMap.value( objId ) == Qtx::ShownState ) ? 
851             resMgr->loadPixmap( "SUIT", tr( "ICON_DATAOBJ_VISIBLE" ) ) : 
852             resMgr->loadPixmap( "SUIT", tr( "ICON_DATAOBJ_INVISIBLE" ) );
853         } 
854         else {
855           // visibility status is undefined -> no icon
856           val = QIcon();
857         }
858       }
859       else {
860         // for other columns get icon from the object
861         val = obj->icon( id );
862       }
863       break;
864     }
865     case ToolTipRole:
866       // data object tooltip for the specified column
867       val = obj->toolTip( id ); 
868       break;
869     case StatusTipRole:
870       // data object status tip for the specified column
871       val = obj->statusTip( id ); 
872       break;
873     case WhatsThisRole:
874       // data object what's this info for the specified column
875       val = obj->whatsThis( id ); 
876       break;
877     case FontRole:
878       // data object font for the specified column
879       val = obj->font( id ); 
880       break;
881     case TextAlignmentRole:
882       // data object text alignment for the specified column
883       val = obj->alignment( id ); 
884       break;
885     case BackgroundRole:
886       // data background color for the specified column
887       c = obj->color( SUIT_DataObject::Background, id );
888       if( !c.isValid() ) // default value
889             c = QApplication::palette().color( QPalette::Base );
890       c.setAlpha( 0 );
891       val = c; 
892       break;
893     case ForegroundRole:
894       // data foreground (text) color for the specified column
895       c = obj->color( SUIT_DataObject::Foreground, id );
896       if( !c.isValid() ) // default value
897             c = QApplication::palette().color( QPalette::Foreground );
898       val = c; 
899       break;
900     case BaseColorRole:
901       // editor background color for the specified column
902       c = obj->color( SUIT_DataObject::Base, id );
903       if( !c.isValid() ) // default value
904             c = QApplication::palette().color( QPalette::Base );
905       val = c; 
906       break;
907     case TextColorRole:
908       // editor foreground (text) color for the specified column
909       c = obj->color( SUIT_DataObject::Text, id );
910       if( !c.isValid() ) // default value
911             c = QApplication::palette().color( QPalette::Text );
912       val = c; 
913       break;
914     case HighlightRole:
915       // adta object highlighted background color for the specified column
916       c = obj->color( SUIT_DataObject::Highlight, id );
917       if( !c.isValid() ) // default value
918             c = QApplication::palette().color( QPalette::Highlight );
919       val = c; 
920       break;
921     case HighlightedTextRole:
922       // data object highlighted foreground (text) color for the specified column
923       c = obj->color( SUIT_DataObject::HighlightedText, id );
924       if( !c.isValid() ) // default value
925             c = QApplication::palette().color( QPalette::HighlightedText );
926       val = c; 
927       break;
928     case CheckStateRole:
929       // data object checked state for the specified column
930       // NOTE! three-state check is not supported currently
931       if( obj->isCheckable( id ) )
932             val = obj->isOn( id ) ? Qt::Checked : Qt::Unchecked; 
933       break;
934     case SizeHintRole:
935       // data size hint
936       // NOTE! not supported currently
937       break;
938     default:
939       break;
940     } // ... switch ( role ) ...
941   } // ... if ( obj ) ...
942   return val;
943 }
944
945 /*!
946   \brief Set data for the specified model index and data role.
947   \param index model index
948   \param value new data value
949   \param role data role
950   \return \c true if data is set
951   \sa data()
952 */
953 bool SUIT_TreeModel::setData( const QModelIndex& index, 
954                               const QVariant& value, int role )
955 {
956   if ( index.isValid() && value.isValid() ) {
957     SUIT_DataObject* obj = object( index );
958     if ( obj ) {
959       // NOTE! only 'check state' data is supported by default
960       switch ( role ) {
961       case CheckStateRole:
962         // checked state
963         if ( obj->isCheckable( index.column() ) ) {
964           obj->setOn( value.toBool(), index.column() );
965           emit( dataChanged( index, index ) );
966           return true;
967         }
968         break;
969       case EditRole: {
970         QString val = value.toString();
971         if ( !val.isEmpty() && obj->setName(val) ) {
972           emit( dataChanged( index, index ) );
973           return true;
974         }
975         return false;
976         break;
977       }
978       default:
979         break;
980       }
981     }
982   }
983   return QAbstractItemModel::setData( index, value, role );
984 }
985
986 /*!
987   \brief Get data flags for specified model index.
988   \param index model index
989   \return data flags
990 */
991 Qt::ItemFlags SUIT_TreeModel::flags( const QModelIndex& index ) const
992 {
993   Qt::ItemFlags f = 0;
994
995   if (!index.isValid())
996     //return Qt::ItemIsDropEnabled; // items can be dropped into the top level of the model
997     return f;
998
999   SUIT_DataObject* obj = object(index);
1000
1001   if (obj) {
1002     // data object is enabled
1003     if (obj->isEnabled())
1004       f = f | Qt::ItemIsEnabled;
1005
1006     // data object is selectable
1007     if (obj->isSelectable())
1008       f = f | Qt::ItemIsSelectable;
1009
1010     // data object is checkable
1011     if (obj->isCheckable(index.column()))
1012       f = f | Qt::ItemIsUserCheckable;
1013     
1014     // data object can be renamed
1015     if (obj->renameAllowed(index.column()))
1016       f = f | Qt::ItemIsEditable;
1017     
1018     // data object can be dragged
1019     if (obj->isDraggable())
1020       f = f | Qt::ItemIsDragEnabled;
1021     
1022     // another data object(s) can be dropped on this one
1023     if (obj->isDropAccepted())
1024       f = f | Qt::ItemIsDropEnabled;
1025   }
1026
1027   return f;
1028 }
1029
1030 Qt::DropActions SUIT_TreeModel::supportedDropActions() const
1031 {
1032   return Qt::CopyAction | Qt::MoveAction;
1033 }
1034
1035 /*!
1036   \brief Get header data (can be used in any data view).
1037   \param column column number
1038   \param orientation header orientation
1039   \param role data role
1040   \return header data
1041 */
1042 QVariant SUIT_TreeModel::headerData( int column, Qt::Orientation orientation, int role ) const
1043 {
1044   QVariant d;
1045   // NOTE! only horizontal header is supported
1046   if ( root() && orientation == Qt::Horizontal )
1047   {
1048     switch ( role )
1049         {
1050     case DisplayRole:
1051       // column title
1052       if((myColumns[column].myHeaderFlags & Qtx::ShowText) || 
1053          (myColumns[column].myHeaderFlags == Qtx::ShowAll)) 
1054         d = myColumns[column].myName;
1055       else
1056         d = QString();
1057       break;
1058     case DecorationRole:
1059       // column icon
1060       if((myColumns[column].myHeaderFlags & Qtx::ShowIcon) || 
1061          (myColumns[column].myHeaderFlags == Qtx::ShowAll)) 
1062         d = myColumns[column].myIcon;
1063       else
1064         d = QIcon();      
1065       break;
1066     case AppropriateRole:
1067       // appropriate flag (can column be hidden via context popup menu)
1068       d = myColumns[column].myAppropriate;
1069       break;
1070     default:
1071       break;
1072     }
1073   }
1074   return d;
1075 }
1076
1077 /*!
1078   \brief Create model index.
1079   \param row data row
1080   \param column data column
1081   \param parent parent model index
1082   \return model index
1083 */
1084 QModelIndex SUIT_TreeModel::index( int row, int column, 
1085                                    const QModelIndex& parent ) const
1086 {
1087   if( hasIndex( row, column, parent ) )
1088   {
1089     TreeItem* parentItem = treeItem( parent );
1090     if( parentItem )
1091     {
1092       TreeItem* childItem = parentItem->child( row );
1093       if( childItem )
1094         return createIndex( row, column, childItem );
1095     }
1096   }
1097   return QModelIndex();
1098 }
1099
1100 /*!
1101   \brief Get parent model index.
1102   \param index model index
1103   \return parent model index
1104 */
1105 QModelIndex SUIT_TreeModel::parent( const QModelIndex& index ) const
1106 {
1107   if ( !index.isValid() )
1108     return QModelIndex();
1109
1110   TreeItem* childItem = treeItem( index );
1111   TreeItem* parentItem = childItem ? childItem->parent() : 0;
1112
1113   if ( !parentItem || parentItem == rootItem() )
1114     return QModelIndex();
1115
1116   return createIndex( parentItem->position(), 0, parentItem );
1117 }
1118
1119 /*!
1120   \brief Get number of data columns.
1121   \param parent parent model index (not used)
1122   \return data columns number
1123   \sa rowCount()
1124 */
1125 int SUIT_TreeModel::columnCount( const QModelIndex& /*parent*/ ) const
1126 {
1127   return myColumns.size();
1128 }
1129
1130 /*!
1131   \brief Get number of data rows (children of the specified model index).
1132   \param parent parent model index
1133   \return data rows (children) number
1134   \sa columnCount()
1135 */
1136 int SUIT_TreeModel::rowCount( const QModelIndex& parent ) const
1137 {
1138   // Commented by rnv in the frame of the 
1139   // "20830: EDF 1357 GUI : Hide/Show Icon" imp
1140   // if ( parent.column() > 0 )
1141   // return 0;
1142
1143   TreeItem* parentItem = treeItem( parent );
1144
1145   return parentItem ? parentItem->childCount() : 0;
1146 }
1147
1148 /*!
1149   \brief Get data object by the specified model index.
1150   \param index model index
1151   \return data object corresponding to the model index
1152 */
1153 SUIT_DataObject* SUIT_TreeModel::object( const QModelIndex& index ) const
1154 {
1155   return object( treeItem( index ) );
1156 }
1157
1158 /*!
1159   \brief Get model index by the specified data object.
1160   \param obj data object
1161   \param column data object column
1162   \return model index
1163 */
1164 QModelIndex SUIT_TreeModel::index( const SUIT_DataObject* obj, int column ) const
1165 {
1166   if ( obj == root() )
1167     return QModelIndex();
1168
1169   TreeItem* item = treeItem( obj );
1170
1171   return item ? createIndex( item->position(), column, item ) : QModelIndex();
1172 }
1173
1174 /*!
1175   \brief Get 'auto-delete data tree' flag value.
1176   \return 'auto-delete data tree' flag value
1177   \sa setAutoDeleteTree()
1178 */
1179 bool SUIT_TreeModel::autoDeleteTree() const
1180 {
1181   return myAutoDeleteTree;
1182 }
1183
1184 /*!
1185   \brief Set 'auto-delete data tree' flag value.
1186
1187   If this flag is set to \c true, the data tree is deleted when
1188   the tree model is destroyed. Default value for this flag is \c false.
1189
1190   \param on 'auto-delete data tree' flag value
1191   \sa autoDeleteTree()
1192 */
1193 void SUIT_TreeModel::setAutoDeleteTree( const bool on )
1194 {
1195   myAutoDeleteTree = on;
1196 }
1197
1198 /*!
1199   \brief Get 'auto-update tree' flag value.
1200   \return 'auto-update tree' flag value
1201   \sa setAutoUpdate(), updateTree()
1202 */
1203 bool SUIT_TreeModel::autoUpdate() const
1204 {
1205   return myAutoUpdate;
1206 }
1207
1208 /*!
1209   \brief Set 'auto-update tree' flag value.
1210
1211   If this flag is set to \c true (by default), the model is updated
1212   automatically when data tree is changed.
1213
1214   \param on 'auto-update tree' flag value
1215   \sa autoUpdate(), updateTree()
1216 */
1217 void SUIT_TreeModel::setAutoUpdate( const bool on )
1218 {
1219   if ( myAutoUpdate == on )
1220     return;
1221
1222   SUIT_DataObject::disconnect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
1223                                this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
1224   SUIT_DataObject::disconnect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
1225                                this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
1226   SUIT_DataObject::disconnect( SIGNAL( modified( SUIT_DataObject* ) ),
1227                                this, SLOT( onModified( SUIT_DataObject* ) ) );
1228   myAutoUpdate = on;
1229
1230   if ( myAutoUpdate ) {
1231     SUIT_DataObject::connect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
1232                               this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
1233     SUIT_DataObject::connect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
1234                               this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
1235     SUIT_DataObject::connect( SIGNAL( modified( SUIT_DataObject* ) ),
1236                               this, SLOT( onModified( SUIT_DataObject* ) ) );
1237
1238     updateTree();
1239   }
1240 }
1241
1242 /*!
1243   \brief Get 'updateModified' flag value.
1244   \return 'updateModified' flag value
1245 */
1246 bool SUIT_TreeModel::updateModified() const
1247 {
1248   return myUpdateModified;
1249 }
1250 /*!
1251   \brief Set 'updateModified' flag value.
1252   \param on 'updateModified' flag value
1253 */
1254 void SUIT_TreeModel::setUpdateModified(const bool on)
1255 {
1256   myUpdateModified=on;
1257 }
1258
1259 /*!
1260   \brief Check if the specified column supports custom sorting.
1261   \param column column index on which data is being sorted
1262   \return \c true if column requires custom sorting
1263   \sa lessThan()
1264 */
1265 bool SUIT_TreeModel::customSorting( const int column ) const
1266 {
1267   return root() ? root()->customSorting( column ) : false;
1268 }
1269
1270 void SUIT_TreeModel::forgetObject( const SUIT_DataObject* obj )
1271 {
1272   removeItem( treeItem( obj ) );
1273 }
1274
1275 /*!
1276   \brief Compares two model indexes for the sorting purposes.
1277
1278   This method is called only for those columns for which customSorting()
1279   method returns \c true.
1280
1281   \param left first index to compare
1282   \param right second index to compare
1283   \return result of the comparison
1284   \sa customSorting()
1285 */
1286 bool SUIT_TreeModel::lessThan( const QModelIndex& left, const QModelIndex& right ) const
1287 {
1288   QVariant ldata = data( left );
1289   QVariant rdata = data( right );
1290   return root() ? root()->compare( ldata, rdata, left.column() ) : false;
1291 }
1292
1293 /*!
1294   \brief Get item delegate for the model.
1295   \return new item delegate
1296 */
1297 QAbstractItemDelegate* SUIT_TreeModel::delegate() const
1298 {
1299   return new SUIT_ItemDelegate( const_cast<SUIT_TreeModel*>( this ) );
1300 }
1301
1302
1303 void SUIT_TreeModel::emitClicked( SUIT_DataObject* obj, const QModelIndex& index) {
1304   int obj_group_id = obj->groupId();
1305   const ColumnInfo& inf = myColumns[index.column()];
1306
1307   int id = -1;
1308   if( inf.myIds.contains( 0 ) )
1309     id = inf.myIds[0];
1310   if( inf.myIds.contains( obj_group_id ) )
1311     id = inf.myIds[obj_group_id];
1312   emit clicked(obj, id);
1313 }
1314
1315 /*!
1316   \brief Update tree model.
1317
1318   Call this method when data tree is changed outside the model.
1319   If the 'auto-update' flag is set to \c true, the model
1320   is updated automatically when the data tree is changed.
1321
1322   \param index starting index for the updating
1323   \sa setAutoUpdate()
1324 */
1325 void SUIT_TreeModel::updateTree( const QModelIndex& index )
1326 {
1327   updateTree( object( index ) );
1328 }
1329
1330
1331 void SUIT_TreeModel::updateTreeModel(SUIT_DataObject* obj,TreeItem* item)
1332 {
1333   int kobj=0;
1334   int kitem=0;
1335   int nobjchild=obj->childCount();
1336   SUIT_DataObject* sobj=obj->childObject(kobj);
1337   TreeItem* sitem = item->child(kitem);
1338
1339   while(kobj < nobjchild)
1340     {
1341       if(sitem==0)
1342         {
1343           //end of item list
1344           sitem=createItemAtPos(sobj,item,kitem);
1345           updateTreeModel(sobj,sitem);
1346           kobj++;
1347           kitem++;
1348           sobj=obj->childObject(kobj);
1349           sitem = item->child(kitem);
1350         }
1351       else if(sitem->dataObject() != sobj)
1352         {
1353           if(treeItem(sobj))
1354             {
1355               // item : to remove
1356               removeItem(sitem);
1357               sitem = item->child(kitem);
1358             }
1359           else
1360             {
1361               // obj : new object
1362               sitem=createItemAtPos(sobj,item,kitem);
1363               updateTreeModel(sobj,sitem);
1364               kobj++;
1365               kitem++;
1366               sobj=obj->childObject(kobj);
1367               sitem = item->child(kitem);
1368             }
1369         }
1370       else
1371         {
1372           //obj and item are synchronised : go to next ones
1373           updateTreeModel(sobj,sitem);
1374           if(sobj->modified()) updateItem(sitem, true);
1375           sobj->update();
1376           kobj++;
1377           kitem++;
1378           sobj=obj->childObject(kobj);
1379           sitem = item->child(kitem);
1380         }
1381     }
1382   //remove remaining items
1383   for(int i = item->childCount(); i > kitem;i--)
1384     {
1385       sitem = item->child(i-1);
1386       removeItem(sitem);
1387     }
1388 }
1389
1390 /*!
1391   \brief Update tree model.
1392
1393   Call this method when data tree is changed outside the model.
1394   If the 'auto-update' flag is set to \c true, the model
1395   is updated automatically when the data tree is changed.
1396
1397   \param obj starting data object for the updating
1398   \sa setAutoUpdate()
1399 */
1400 void SUIT_TreeModel::updateTree( SUIT_DataObject* obj )
1401 {
1402   if ( !obj )
1403     obj = root();
1404
1405   else if ( obj->root() != root() )
1406     return;
1407
1408   if(updateModified())
1409     {
1410       updateTreeModel(obj,treeItem( obj ));
1411     }
1412   else
1413     {
1414       synchronize<ObjPtr,ItemPtr,SUIT_TreeModel::TreeSync>( obj,
1415                                                             treeItem( obj ),
1416                                                             SUIT_TreeModel::TreeSync( this ) );
1417     }
1418   emit modelUpdated();
1419 }
1420
1421 /*!
1422   \brief Initialize tree model.
1423 */
1424 void SUIT_TreeModel::initialize()
1425 {
1426   SUIT_DataObject::disconnect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
1427                                this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
1428   SUIT_DataObject::disconnect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
1429                                this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
1430   SUIT_DataObject::disconnect( SIGNAL( modified( SUIT_DataObject* ) ),
1431                                this, SLOT( onModified( SUIT_DataObject* ) ) );
1432   if ( autoUpdate() ) {
1433     SUIT_DataObject::connect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
1434                               this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
1435     SUIT_DataObject::connect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
1436                               this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
1437     SUIT_DataObject::connect( SIGNAL( modified( SUIT_DataObject* ) ),
1438                               this, SLOT( onModified( SUIT_DataObject* ) ) );
1439   }
1440
1441   myItems.clear(); // ????? is it really necessary
1442
1443   if ( !myRootItem )
1444     myRootItem = new TreeItem( 0 );
1445
1446   registerColumn( 0, QObject::tr( "NAME_COLUMN" ), SUIT_DataObject::NameId );
1447
1448   QString visCol = QObject::tr( "VISIBILITY_COLUMN" );
1449   registerColumn( 0, visCol, SUIT_DataObject::VisibilityId );
1450
1451   SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
1452   setColumnIcon( visCol, resMgr->loadPixmap( "SUIT", tr( "ICON_DATAOBJ_VISIBLE" ) ));
1453   setHeaderFlags( visCol, Qtx::ShowIcon);
1454
1455   updateTree();
1456 }
1457
1458 /*!
1459   \brief Get root tree item.
1460   \return root tree item
1461 */
1462 SUIT_TreeModel::TreeItem* SUIT_TreeModel::rootItem() const
1463 {
1464   return myRootItem;
1465 }
1466
1467 /*!
1468   \brief Get tree item corresponding to the specified model index.
1469   \param index model index
1470   \return tree item or root item if index is invalid
1471 */
1472 SUIT_TreeModel::TreeItem* SUIT_TreeModel::treeItem( const QModelIndex& index ) const
1473 {
1474   return index.isValid() ? static_cast<TreeItem*>( index.internalPointer() ) : rootItem();
1475 }
1476
1477 /*!
1478   \brief Get tree item corresponding to the specified data object.
1479   \param obj data object
1480   \return tree item or 0 if there is no tree item corresponding to \a obj
1481 */
1482 SUIT_TreeModel::TreeItem* SUIT_TreeModel::treeItem( const SUIT_DataObject* obj ) const
1483 {
1484   TreeItem* item = 0;
1485
1486   if ( obj == root() )
1487     item = rootItem();
1488   else if ( myItems.contains( const_cast<SUIT_DataObject*>( obj ) ) )
1489     item = myItems[ const_cast<SUIT_DataObject*>( obj ) ];
1490
1491   return item;
1492 }
1493
1494 /*!
1495   \brief Get data object corresponding to the specified tree item.
1496   \param item tree item
1497   \return data object or 0 if there is no data object corresponding to \a item
1498 */
1499 SUIT_DataObject* SUIT_TreeModel::object( const SUIT_TreeModel::TreeItem* item ) const
1500 {
1501   if ( item == rootItem() )
1502     return root();
1503  
1504   SUIT_DataObject* obj = item ? item->dataObject() : 0;
1505   return myItems.contains( obj ) ? obj : 0;
1506 }
1507
1508 /*!
1509   \brief Get unique object identifier
1510   
1511   Object identifier is customized via the Qtx::IdType custom data
1512
1513   \param index model index
1514   \return object identifier or null string if it isn't specified
1515   \sa SUIT_DataObject::customData()
1516 */
1517 QString SUIT_TreeModel::objectId( const QModelIndex& index ) const
1518 {
1519   QString objId;
1520   if ( index.isValid() ) {
1521     SUIT_DataObject* obj = object( index );
1522     if ( obj ) {
1523       int anId = obj->customData( Qtx::IdType ).toInt(); 
1524       objId = data( createIndex( index.row(), anId, index.internalPointer() ) ).toString();
1525     }
1526   }
1527   return objId;
1528 }
1529
1530 /*!
1531   \brief Create an item corresponding to the data object.
1532   \param obj source data object
1533   \param parent parent tree item
1534   \param after tree item after which new item should be inserted
1535   \return created tree item or 0 if item could not be created
1536 */
1537 SUIT_TreeModel::TreeItem* SUIT_TreeModel::createItem( SUIT_DataObject* obj,
1538                                                       SUIT_TreeModel::TreeItem* parent, 
1539                                                       SUIT_TreeModel::TreeItem* after )
1540 {
1541   if ( !obj )
1542     return 0;
1543
1544   SUIT_DataObject* parentObj = object( parent );
1545   QModelIndex parentIdx = index( parentObj );
1546
1547   SUIT_DataObject* afterObj = after ? object( after ) : 0;
1548   int row = afterObj ? afterObj->position() + 1 : 0;
1549
1550   beginInsertRows( parentIdx, row, row );
1551
1552   myItems[ obj ] = new TreeItem( obj, parent, after );
1553
1554   for(int pos=row;pos < parent->childCount();pos++)
1555     parent->child(pos)->setPosition(pos);
1556
1557   endInsertRows();
1558
1559   obj->setModified(false);
1560
1561   return myItems[ obj ];
1562 }
1563
1564 /*!
1565   \brief Create an item corresponding to the data object.
1566   \param obj source data object
1567   \param parent parent tree item
1568   \param pos tree item position into which new item should be inserted
1569   \return created tree item or 0 if item could not be created
1570 */
1571 SUIT_TreeModel::TreeItem* SUIT_TreeModel::createItemAtPos( SUIT_DataObject* obj,
1572                                                            SUIT_TreeModel::TreeItem* parent,
1573                                                            int pos )
1574 {
1575   if ( !obj )
1576     return 0;
1577
1578   SUIT_DataObject* parentObj = object( parent );
1579   QModelIndex parentIdx = index( parentObj );
1580
1581   int row = pos ;
1582   SUIT_TreeModel::TreeItem* after = pos>0 ? parent->child(pos-1) : 0 ;
1583
1584   beginInsertRows( parentIdx, row, row );
1585
1586   SUIT_TreeModel::TreeItem* item = new TreeItem( obj, parent, after );
1587   myItems[ obj ] = item;
1588
1589   for(int ppos=row;ppos < parent->childCount();ppos++)
1590     parent->child(ppos)->setPosition(ppos);
1591
1592   endInsertRows();
1593
1594   obj->setModified(false);
1595
1596   return item;
1597 }
1598
1599 /*!
1600   \brief Update tree item.
1601   \param item tree item to be updated
1602   \param emitLayoutChanged if signal about changed layout should be emitted
1603 */
1604 void SUIT_TreeModel::updateItem( SUIT_TreeModel::TreeItem* item, bool emitLayoutChanged )
1605 {
1606   if ( !item )
1607     return;
1608   
1609   SUIT_DataObject* obj = object( item );
1610   if ( !obj )
1611     return;
1612   
1613   // update all columns corresponding to the given data object
1614   /*To avoid crashes we should update any persistent model indexes before emitting layoutChanged(). In other words, when the structure changes:
1615       -  emit layoutAboutToBeChanged
1616       - Remember the QModelIndex that will change
1617       - call changePersistentIndex()
1618       - emit layoutChanged
1619   */
1620
1621     emit layoutAboutToBeChanged();
1622
1623     // Remember the QModelIndex that will change
1624     QModelIndexList fromIndexes;
1625     QModelIndexList toIndexes;
1626     for (int i = 0; i < columnCount() - 1; ++i) {
1627         fromIndexes.append( index( obj, i ));
1628         toIndexes.append(QModelIndex());
1629     }
1630     //changePersistentIndexList(fromIndexes, toIndexes); // Limitation: can lead to loss of selection
1631
1632     emit dataChanged( toIndexes.first(), toIndexes.last() );
1633     obj->setModified(false);
1634     if ( emitLayoutChanged )
1635       emit layoutChanged();
1636 }
1637
1638 /*!
1639   \brief Remove tree item (recursively).
1640   \param item tree item to be removed
1641 */
1642 void SUIT_TreeModel::removeItem( SUIT_TreeModel::TreeItem* item )
1643 {
1644   if ( !item )
1645     return;
1646
1647   // Remove list view items from <myItems> recursively for all children.
1648   // Otherwise, "delete item" line below will destroy all item's children,
1649   // and <myItems> will contain invalid pointers
1650   while( item->childCount() )
1651     removeItem( item->child( 0 ) );
1652
1653   SUIT_DataObject* obj = object( item );
1654   
1655   // Warning! obj can be deleted at this point!
1656
1657   TreeItem* parent=item->parent();
1658   SUIT_DataObject* parentObj = object( parent );
1659   QModelIndex parentIdx = index( parentObj, 0 );
1660   int row = item->position();
1661   
1662   beginRemoveRows( parentIdx, row, row );
1663   myItems.remove( obj );
1664
1665   if ( obj == root() )
1666     setRoot( 0 );
1667   else if ( parent )
1668     {
1669       parent->removeChild( item );
1670       for(int pos=row;pos < parent->childCount();pos++)
1671         parent->child(pos)->setPosition(pos);
1672     }
1673
1674   delete item;
1675
1676   endRemoveRows();
1677 }
1678
1679 /*!
1680   \brief Called when the data object is inserted to the tree.
1681   \param object data object being inserted
1682   \param parent parent data object
1683 */
1684 void SUIT_TreeModel::onInserted( SUIT_DataObject* /*object*/, SUIT_DataObject* parent )
1685 {
1686   if ( autoUpdate() )
1687     updateTree( parent );
1688 }
1689
1690 /*!
1691   \brief Called when the data object is removed from the tree.
1692   \param object data object being removed
1693   \param parent parent data object
1694 */
1695 void SUIT_TreeModel::onRemoved( SUIT_DataObject* /*object*/, SUIT_DataObject* parent )
1696 {
1697   if ( autoUpdate() )
1698     updateTree( parent );
1699 }
1700
1701 /*!
1702   \brief Called when the data object is modified. TreeSync is not used here for maximum efficiency.
1703   It is assumed that it is up to the application to decide when its data objects are modified.
1704   \param obj data object that has been modified
1705 */
1706 void SUIT_TreeModel::onModified( SUIT_DataObject* obj )
1707 {
1708   if ( autoUpdate() )
1709   {
1710     QModelIndex firstIdx = index( obj, 0 );
1711     QModelIndex lastIdx  = index( obj, columnCount() - 1 );
1712     emit dataChanged( firstIdx, lastIdx );
1713     obj->setModified(false);
1714   }
1715 }
1716
1717 /*!
1718   \brief Drag and Drop support.
1719 */
1720 QStringList SUIT_TreeModel::mimeTypes() const
1721 {
1722   QStringList types;
1723   types << "application/vnd.text.list";
1724   return types;
1725 }
1726
1727 /*!
1728   \brief Called when the data objects are exported(dragged) from the tree.
1729   \param indexes the list of exported objects
1730 */
1731 QMimeData* SUIT_TreeModel::mimeData( const QModelIndexList& indexes ) const
1732 {
1733   QMimeData* mimeData = new QMimeData();
1734   QByteArray encodedData;
1735
1736   QDataStream stream( &encodedData, QIODevice::WriteOnly );
1737
1738   foreach ( QModelIndex index, indexes ) {
1739     QString id = objectId( index );
1740     // we have to check only 0 column in order to avoid repeating items in the drag object
1741     // - QTreeView tries to drag indices for all visible columns
1742     if ( index.isValid() && index.column() == 0 && !id.isEmpty() )
1743       stream << id;
1744   }
1745
1746   mimeData->setData( "application/vnd.text.list", encodedData );
1747   return mimeData;
1748 }
1749
1750 bool SUIT_TreeModel::dropMimeData( const QMimeData* data, Qt::DropAction action,
1751                                    int row, int column, const QModelIndex& parent )
1752 {
1753   if ( action == Qt::IgnoreAction )
1754     // do nothing with data
1755     return false;
1756
1757   if ( !data->hasFormat( "application/vnd.text.list" ) )
1758     // not supported data dropped
1759     return false;
1760
1761   if ( !parent.isValid() )
1762     // dropping into the top level of the model is not allowed
1763     return false;
1764
1765   // get parent object
1766   SUIT_DataObject* pobj = object( parent );
1767   if ( !pobj )
1768     // invalid parent
1769     return false;
1770
1771   // decode mime data and collect data objects being dropped
1772   QByteArray encodedData = data->data( "application/vnd.text.list" );
1773   QDataStream stream( &encodedData, QIODevice::ReadOnly );
1774   
1775   DataObjectList objects;
1776
1777   while ( !stream.atEnd() ) {
1778     QString id;
1779     stream >> id;
1780     if ( !id.isEmpty() && searcher() ) {
1781       SUIT_DataObject* obj = searcher()->findObject( id );
1782       if ( obj ) objects << obj;
1783     }
1784   }
1785
1786   // emit signal
1787   emit dropped( objects, pobj, row, action );
1788
1789   // return true if there's any to drop
1790   return !objects.isEmpty();
1791 }
1792
1793 /*!
1794   \class SUIT_ProxyModel
1795   \brief Proxy model which can be used above the SUIT_TreeModel class
1796   to enable custom sorting/filtering of the data.
1797
1798   The SUIT_TreeModel class does not support custom sorting/filtering of the data.
1799   To use these features, the SUIT_ProxyModel class can be used as top-level
1800   wrapper for the SUIT_DataObject-based data tree model.
1801 */
1802
1803 /*!
1804   \brief Constructor.
1805   \param parent parent object
1806 */
1807 SUIT_ProxyModel::SUIT_ProxyModel( QObject* parent )
1808 : QSortFilterProxyModel( parent ),
1809   mySortingEnabled( true )
1810 {
1811   SUIT_TreeModel* model = new SUIT_TreeModel( this );
1812   connect( model, SIGNAL( modelUpdated() ), this, SIGNAL( modelUpdated() ) );
1813   connect( model, SIGNAL( clicked( SUIT_DataObject*, int ) ), this, SIGNAL(clicked( SUIT_DataObject*, int ) ) );
1814   connect( model, SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ),
1815            this,  SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ) );
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   setSourceModel( model );
1835   setDynamicSortFilter( true );
1836 }
1837
1838 /*!
1839   \brief Constructor.
1840   \param model tree model
1841   \param parent parent object
1842 */
1843 SUIT_ProxyModel::SUIT_ProxyModel( SUIT_AbstractModel* model, QObject* parent )
1844 : QSortFilterProxyModel( parent ),
1845   mySortingEnabled( true )
1846 {
1847   connect( *model, SIGNAL( modelUpdated() ), this, SIGNAL( modelUpdated() ) );
1848   connect( *model, SIGNAL( clicked( SUIT_DataObject*, int ) ), this, SIGNAL( clicked( SUIT_DataObject*, int ) ) );
1849   connect( *model, SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ),
1850            this,   SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ) );
1851   setSourceModel( *model );
1852   setDynamicSortFilter( true );
1853 }
1854
1855 /*!
1856   \brief Destructor.
1857 */
1858 SUIT_ProxyModel::~SUIT_ProxyModel()
1859 {
1860 }
1861
1862 /*!
1863   \brief Get data tree root object.
1864   \return data tree root
1865   \sa setRoot()
1866 */
1867 SUIT_DataObject* SUIT_ProxyModel::root() const
1868 {
1869   return treeModel() ? treeModel()->root() : 0;
1870 }
1871
1872 /*!
1873   \brief Set data tree root object.
1874   \param r new data tree root
1875   \sa root()
1876 */
1877 void SUIT_ProxyModel::setRoot( SUIT_DataObject* r )
1878 {
1879   if ( treeModel() )
1880     treeModel()->setRoot( r );
1881 }
1882
1883 /*!
1884   \brief Get data object by the specified model index.
1885   \param index model index
1886   \return data object corresponding to the model index
1887 */
1888 SUIT_DataObject* SUIT_ProxyModel::object( const QModelIndex& index ) const
1889 {
1890   return treeModel() ? treeModel()->object( mapToSource( index ) ) : 0;
1891 }
1892
1893 /*!
1894   \brief Get model index by the specified data object.
1895   \param obj data object
1896   \param column data object column
1897   \return model index
1898 */
1899 QModelIndex SUIT_ProxyModel::index( const SUIT_DataObject* obj, int column ) const
1900 {
1901   return treeModel() ? mapFromSource( treeModel()->index( obj, column ) ) : QModelIndex();
1902 }
1903
1904 /*!
1905   \brief Get 'auto-delete data tree' flag value.
1906   \return 'auto-delete data tree' flag value
1907   \sa setAutoDeleteTree()
1908 */
1909 bool SUIT_ProxyModel::autoDeleteTree() const
1910 {
1911   return treeModel() ? treeModel()->autoDeleteTree() : false;
1912 }
1913
1914 /*!
1915   \brief Set 'auto-delete data tree' flag value.
1916
1917   If this flag is set to \c true, the data tree is deleted when
1918   the tree model is destroyed. Default value for this flag is \c false.
1919
1920   \param on 'auto-delete data tree' flag value
1921   \sa autoDeleteTree()
1922 */
1923 void SUIT_ProxyModel::setAutoDeleteTree( const bool on )
1924 {
1925   if ( treeModel() )
1926     treeModel()->setAutoDeleteTree( on );
1927 }
1928
1929 /*!
1930   \brief Get 'auto-update tree' flag value.
1931   \return 'auto-update tree' flag value
1932   \sa setAutoUpdate(), updateTree()
1933 */
1934 bool SUIT_ProxyModel::autoUpdate() const
1935 {
1936   return treeModel() ? treeModel()->autoUpdate() : false;
1937 }
1938
1939 /*!
1940   \brief Get 'updateModified' flag value.
1941   \return 'updateModified' flag value
1942 */
1943 bool SUIT_ProxyModel::updateModified() const
1944 {
1945   return treeModel() ? treeModel()->updateModified() : false;
1946 }
1947 /*!
1948   \brief Set 'updateModified' flag value.
1949
1950   If this flag is set to \c true (default=false), the model is updated by updateTreeModel that 
1951   uses the isModified flag to update only modified objects
1952
1953   \param on 'updateModified' flag value
1954 */
1955 void SUIT_ProxyModel::setUpdateModified( const bool on )
1956 {
1957   if ( treeModel() )
1958     treeModel()->setUpdateModified( on );
1959 }
1960
1961 /*!
1962   \brief Set 'auto-update tree' flag value.
1963
1964   If this flag is set to \c true (by default), the model is updated
1965   automatically when data tree is changed.
1966
1967   \param on 'auto-update tree' flag value
1968   \sa autoUpdate(), updateTree()
1969 */
1970 void SUIT_ProxyModel::setAutoUpdate( const bool on )
1971 {
1972   if ( treeModel() )
1973     treeModel()->setAutoUpdate( on );
1974 }
1975
1976 /*!
1977   \brief Check if sorting is enabled.
1978   \return \c true if sorting is enabled
1979   \sa setSortingEnabled()
1980 */
1981 bool SUIT_ProxyModel::isSortingEnabled() const
1982 {
1983   return mySortingEnabled;
1984 }
1985
1986 SUIT_DataSearcher* SUIT_ProxyModel::searcher() const
1987 {
1988   return treeModel() ? treeModel()->searcher() : 0;
1989 }
1990
1991 void SUIT_ProxyModel::setSearcher( SUIT_DataSearcher* s )
1992 {
1993   if ( treeModel() ) treeModel()->setSearcher( s );
1994 }
1995
1996 /*!
1997   \brief Get item delegate for the model.
1998   \return new item delegate
1999 */
2000 QAbstractItemDelegate* SUIT_ProxyModel::delegate() const
2001 {
2002   return treeModel() ? treeModel()->delegate() : 0;
2003 }
2004
2005 /*!
2006   \brief Update tree model.
2007
2008   Call this method when data tree is changed outside the model.
2009   If the 'auto-update' flag is set to \c true, the model
2010   is updated automatically when the data tree is changed.
2011
2012   \param index starting index for the updating
2013   \sa setAutoUpdate()
2014 */
2015 void SUIT_ProxyModel::updateTree( const QModelIndex& index )
2016 {
2017   if ( treeModel() )
2018     treeModel()->updateTree( mapToSource( index ) );
2019 }
2020
2021 /*!
2022   \brief Update tree model.
2023
2024   Call this method when data tree is changed outside the model.
2025   If the 'auto-update' flag is set to \c true, the model
2026   is updated automatically when the data tree is changed.
2027
2028   \param obj starting data object for the updating
2029   \sa setAutoUpdate()
2030 */
2031 void SUIT_ProxyModel::updateTree( SUIT_DataObject* obj )
2032 {
2033   if ( treeModel() )
2034     treeModel()->updateTree( obj );
2035 }
2036
2037 void SUIT_ProxyModel::forgetObject( const SUIT_DataObject* obj )
2038 {
2039   if ( treeModel() )
2040     treeModel()->forgetObject( obj );
2041 }
2042
2043 /*!
2044   \brief Compares two model indexes for the sorting purposes.
2045   \param left first index to compare
2046   \param right second index to compare
2047   \return result of the comparison
2048 */
2049 bool SUIT_ProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right ) const
2050 {
2051   if ( !isSortingEnabled() && left.isValid() && right.isValid() ) {
2052     return left.row() < right.row();
2053   }
2054   if ( treeModel() && treeModel()->customSorting( left.column() ) ) {
2055     return treeModel()->lessThan( left, right );
2056   }
2057   return QSortFilterProxyModel::lessThan( left, right );
2058 }
2059
2060 /*!
2061   \brief Check if the specified column supports custom sorting.
2062   \param column column index on which data is being sorted
2063   \return \c true if column requires custom sorting
2064   \sa lessThan()
2065 */
2066 bool SUIT_ProxyModel::customSorting( const int column ) const
2067 {
2068   return treeModel() ? treeModel()->customSorting( column ) : false;
2069 }
2070
2071 /*!
2072   \brief Enable/disable sorting.
2073   \param enabled new flag state
2074   \sa isSortingEnabled()
2075 */
2076 void SUIT_ProxyModel::setSortingEnabled( bool enabled )
2077 {
2078   mySortingEnabled = enabled;
2079   clear();
2080 }
2081
2082 /*
2083   \brief Get tree model.
2084   \return tree model
2085 */
2086 SUIT_AbstractModel* SUIT_ProxyModel::treeModel() const
2087 {
2088   return dynamic_cast<SUIT_AbstractModel*>( sourceModel() );
2089 }
2090
2091 /*!
2092   \brief Filter rows
2093   \param sourceRow row index of the source data model
2094   \param sourceParent parent model index of the source data model
2095   \return \c true if the specified row should be filtered out (i.e. not displayed) or \c false otherwise
2096 */
2097 bool SUIT_ProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent ) const
2098 {
2099   SUIT_DataObject* o = treeModel()->object( sourceModel()->index( sourceRow, 0, sourceParent ) );
2100   SUIT_DataObject* p = o ? o->parent() : 0;
2101   return ( !p || p->expandable() ) && o && o->isVisible();
2102 }
2103
2104 /*!
2105   \brief Register new column in the model
2106   \param group_id - unique data object identificator allowing the classification of objects 
2107   \param name - translated column name
2108   \param custom_id - custom column id that should be passed into method SUIT_DataObject::data()
2109  */
2110 void SUIT_ProxyModel::registerColumn( const int group_id, const QString& name, const int custom_id )
2111 {
2112   if( treeModel() )
2113     treeModel()->registerColumn( group_id, name, custom_id );
2114 }
2115
2116 /*!
2117   \brief Remove column from the model
2118
2119   Please take into account that column is removed only for given group_id, it means
2120   that information of data objects with such group_id won't be shown.
2121   If there is not any registered group_id for this column after removing, the column will be hidden
2122   otherwise it continue to be shown
2123
2124   \param group_id - unique data object identificator allowing the classification of objects 
2125   \param name - translated column name
2126  */
2127 void SUIT_ProxyModel::unregisterColumn( const int group_id, const QString& name )
2128 {
2129   if( treeModel() )
2130     treeModel()->unregisterColumn( group_id, name );
2131 }
2132
2133 /*!
2134   \brief Change column icon.
2135
2136   \param name - column name
2137   \param icon - new icon of the specified column
2138 */
2139 void SUIT_ProxyModel::setColumnIcon( const QString& name, const QPixmap& icon )
2140 {
2141   if( treeModel() )
2142     treeModel()->setColumnIcon( name, icon );
2143 }
2144
2145 /*!
2146   \brief Get column icon.
2147
2148   \param name - column name
2149   \return icon of the specified column
2150 */
2151 QPixmap SUIT_ProxyModel::columnIcon( const QString& name ) const
2152 {
2153   return treeModel() ? treeModel()->columnIcon( name ) : QPixmap();
2154 }
2155
2156 /*!
2157   \brief Change appropriate status
2158   
2159   Appropriate status determines if the column should appear in the tree view header popup menu
2160   (to show/hide the column).
2161
2162   If appropriate status is not specified yet, the \c Shown value is taken,
2163   it means that column should be always visible.
2164
2165   \param name - column name
2166   \param appr - new appropriate status
2167 */
2168 void SUIT_ProxyModel::setAppropriate( const QString& name, const Qtx::Appropriate appr )
2169 {
2170   if( treeModel() )
2171     treeModel()->setAppropriate( name, appr );
2172 }
2173
2174 /*!
2175   \brief Check if the column should appear in the tree view header popup menu
2176   (to show/hide the column).
2177
2178   Default implementation (if appropriate status is not specified yet)
2179   returns \c Shown, it means that column should be always visible.
2180
2181   \param name - column name
2182   \return appropriate status
2183 */
2184 Qtx::Appropriate SUIT_ProxyModel::appropriate( const QString& name ) const
2185 {
2186   return treeModel() ? treeModel()->appropriate( name ) : Qtx::Shown;
2187 }
2188
2189 /*!
2190   \brief Set header flags.
2191   
2192   These flags allow show in the header of the column text (name of the column),
2193   icon or both text and icon.
2194   
2195   \param name - column name
2196   \param flags - header flags
2197
2198 */
2199 void SUIT_ProxyModel::setHeaderFlags( const QString& name, const Qtx::HeaderViewFlags flags )
2200 {
2201   if(treeModel())
2202     treeModel()->setHeaderFlags(name, flags);
2203 }
2204
2205 /*!
2206   \brief Get the  header flags.
2207   
2208   These flags allow show in the header of the column text (name of the column),
2209   icon or both text and icon.
2210   
2211   \param name - column name
2212   \return header flags
2213 */
2214 Qtx::HeaderViewFlags SUIT_ProxyModel::headerFlags( const QString& name ) const
2215 {
2216   return treeModel() ? treeModel()->headerFlags( name ) : Qtx::ShowAll;
2217 }
2218
2219 /*!
2220   \brief Set visibility state of the object.
2221   
2222   \param id - column name
2223   \param state - visible state
2224   \param emitChanged - if set to false, blocks dataChanged() signal, this can be used to
2225   prevent emitting dataChanged() several times for the same data object
2226 */
2227 void SUIT_ProxyModel::setVisibilityState(const QString& id, Qtx::VisibilityState state, bool emitChanged ) {
2228   if(treeModel())
2229     treeModel()->setVisibilityState(id,state,emitChanged);
2230 }
2231
2232 /*!
2233   \brief Set visibility state for all objects.
2234   
2235   \param id - column name
2236   \param state - visible state
2237 */
2238 void SUIT_ProxyModel::setVisibilityStateForAll(Qtx::VisibilityState state)
2239 {
2240   if(treeModel())
2241     treeModel()->setVisibilityStateForAll(state);
2242 }
2243
2244 /*!
2245   \brief Get visibility state of the object.
2246   
2247   \param id - column name
2248   \return visible state
2249 */
2250 Qtx::VisibilityState SUIT_ProxyModel::visibilityState(const QString& id) const
2251 {
2252   return treeModel() ? treeModel()->visibilityState(id) : Qtx::UnpresentableState;
2253 }
2254
2255 void SUIT_ProxyModel::emitClicked( SUIT_DataObject* obj, const QModelIndex& index)
2256 {
2257   if(treeModel())
2258     treeModel()->emitClicked(obj,index);
2259 }
2260
2261 /*!
2262   \class SUIT_ItemDelegate
2263   \brief An SUIT_DataObject-based item delegate class.
2264
2265   This class can be used to render the SUIT_DataObject-based item
2266   in the widgets like QTreeView and others.
2267   Refer to the Qt 4 documentation, model/view architecture 
2268   section for more details).
2269 */
2270
2271 /*!
2272   \brief Constructor.
2273   \param parent parent object
2274 */
2275 SUIT_ItemDelegate::SUIT_ItemDelegate( QObject* parent )
2276 : QItemDelegate( parent )
2277 {
2278 }
2279
2280 /*!
2281   \brief Render the item in the widget.
2282
2283   Customizes the item colors for the specific roles.
2284
2285   \param painter painter
2286   \param option painting option
2287   \param index model index being rendered
2288 */
2289 void SUIT_ItemDelegate::paint( QPainter* painter, 
2290                                const QStyleOptionViewItem& option,
2291                                const QModelIndex& index ) const
2292 {
2293   QStyleOptionViewItem opt = option;
2294   if ( index.isValid() ) {
2295     // Note: we check into account only custom roles; other roles are process
2296     //       correctly by the QItemDelegate class
2297     QVariant val = index.data( SUIT_TreeModel::BaseColorRole );
2298     if ( val.isValid() && val.value<QColor>().isValid() ) {
2299       QColor aBase = val.value<QColor>();
2300       aBase.setAlpha( 0 );
2301       opt.palette.setBrush( QPalette::Base, val.value<QColor>() );
2302     }
2303     val = index.data( SUIT_TreeModel::TextColorRole );
2304     if ( val.isValid() && val.value<QColor>().isValid() )
2305       opt.palette.setBrush( QPalette::Text, val.value<QColor>() );
2306     val = index.data( SUIT_TreeModel::HighlightRole );
2307     if ( val.isValid() && val.value<QColor>().isValid() )
2308       opt.palette.setBrush( QPalette::Highlight, val.value<QColor>() );
2309     val = index.data( SUIT_TreeModel::HighlightedTextRole );
2310     if ( val.isValid() && val.value<QColor>().isValid() )
2311       opt.palette.setBrush( QPalette::HighlightedText, val.value<QColor>() );      
2312   }
2313   QItemDelegate::paint( painter, opt, index );
2314 }
2315
2316 QSize SUIT_ItemDelegate::sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const
2317 {
2318     QSize size = QItemDelegate::sizeHint ( option, index );
2319 #if QT_VERSION >= 0x040500
2320     size.setHeight( size.height() + 1 );
2321 #endif
2322     return size;
2323 }