]> SALOME platform Git repositories - modules/gui.git/blob - src/SUIT/SUIT_TreeModel.cxx
Salome HOME
Merge from V6_main 11/02/2013
[modules/gui.git] / src / SUIT / SUIT_TreeModel.cxx
1 // Copyright (C) 2007-2012  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.
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   emit layoutAboutToBeChanged(); // Comment by VSR 25/04/2011: fix crash on delete objects. Uncomment by PRascle 18/12/2012 : required by Qt4.8 (original issue 22424 not accessible)
1615   QModelIndex firstIdx = index( obj, 0 );
1616   QModelIndex lastIdx  = index( obj, columnCount() - 1 );
1617   emit dataChanged( firstIdx, lastIdx );
1618   obj->setModified(false);
1619   if ( emitLayoutChanged )
1620     emit layoutChanged();
1621 }
1622
1623 /*!
1624   \brief Remove tree item (recursively).
1625   \param item tree item to be removed
1626 */
1627 void SUIT_TreeModel::removeItem( SUIT_TreeModel::TreeItem* item )
1628 {
1629   if ( !item )
1630     return;
1631
1632   // Remove list view items from <myItems> recursively for all children.
1633   // Otherwise, "delete item" line below will destroy all item's children,
1634   // and <myItems> will contain invalid pointers
1635   while( item->childCount() )
1636     removeItem( item->child( 0 ) );
1637
1638   SUIT_DataObject* obj = object( item );
1639   
1640   // Warning! obj can be deleted at this point!
1641
1642   TreeItem* parent=item->parent();
1643   SUIT_DataObject* parentObj = object( parent );
1644   QModelIndex parentIdx = index( parentObj, 0 );
1645   int row = item->position();
1646   
1647   beginRemoveRows( parentIdx, row, row );
1648   myItems.remove( obj );
1649
1650   if ( obj == root() )
1651     setRoot( 0 );
1652   else if ( parent )
1653     {
1654       parent->removeChild( item );
1655       for(int pos=row;pos < parent->childCount();pos++)
1656         parent->child(pos)->setPosition(pos);
1657     }
1658
1659   delete item;
1660
1661   endRemoveRows();
1662 }
1663
1664 /*!
1665   \brief Called when the data object is inserted to the tree.
1666   \param object data object being inserted
1667   \param parent parent data object
1668 */
1669 void SUIT_TreeModel::onInserted( SUIT_DataObject* /*object*/, SUIT_DataObject* parent )
1670 {
1671   if ( autoUpdate() )
1672     updateTree( parent );
1673 }
1674
1675 /*!
1676   \brief Called when the data object is removed from the tree.
1677   \param object data object being removed
1678   \param parent parent data object
1679 */
1680 void SUIT_TreeModel::onRemoved( SUIT_DataObject* /*object*/, SUIT_DataObject* parent )
1681 {
1682   if ( autoUpdate() )
1683     updateTree( parent );
1684 }
1685
1686 /*!
1687   \brief Called when the data object is modified. TreeSync is not used here for maximum efficiency.
1688   It is assumed that it is up to the application to decide when its data objects are modified.
1689   \param obj data object that has been modified
1690 */
1691 void SUIT_TreeModel::onModified( SUIT_DataObject* obj )
1692 {
1693   if ( autoUpdate() )
1694   {
1695     QModelIndex firstIdx = index( obj, 0 );
1696     QModelIndex lastIdx  = index( obj, columnCount() - 1 );
1697     emit dataChanged( firstIdx, lastIdx );
1698     obj->setModified(false);
1699   }
1700 }
1701
1702 /*!
1703   \brief Drag and Drop support.
1704 */
1705 QStringList SUIT_TreeModel::mimeTypes() const
1706 {
1707   QStringList types;
1708   types << "application/vnd.text.list";
1709   return types;
1710 }
1711
1712 /*!
1713   \brief Called when the data objects are exported(dragged) from the tree.
1714   \param indexes the list of exported objects
1715 */
1716 QMimeData* SUIT_TreeModel::mimeData( const QModelIndexList& indexes ) const
1717 {
1718   QMimeData* mimeData = new QMimeData();
1719   QByteArray encodedData;
1720
1721   QDataStream stream( &encodedData, QIODevice::WriteOnly );
1722
1723   foreach ( QModelIndex index, indexes ) {
1724     QString id = objectId( index );
1725     // we have to check only 0 column in order to avoid repeating items in the drag object
1726     // - QTreeView tries to drag indices for all visible columns
1727     if ( index.isValid() && index.column() == 0 && !id.isEmpty() )
1728       stream << id;
1729   }
1730
1731   mimeData->setData( "application/vnd.text.list", encodedData );
1732   return mimeData;
1733 }
1734
1735 bool SUIT_TreeModel::dropMimeData( const QMimeData* data, Qt::DropAction action,
1736                                    int row, int column, const QModelIndex& parent )
1737 {
1738   if ( action == Qt::IgnoreAction )
1739     // do nothing with data
1740     return false;
1741
1742   if ( !data->hasFormat( "application/vnd.text.list" ) )
1743     // not supported data dropped
1744     return false;
1745
1746   if ( !parent.isValid() )
1747     // dropping into the top level of the model is not allowed
1748     return false;
1749
1750   // get parent object
1751   SUIT_DataObject* pobj = object( parent );
1752   if ( !pobj )
1753     // invalid parent
1754     return false;
1755
1756   // decode mime data and collect data objects being dropped
1757   QByteArray encodedData = data->data( "application/vnd.text.list" );
1758   QDataStream stream( &encodedData, QIODevice::ReadOnly );
1759   
1760   DataObjectList objects;
1761
1762   while ( !stream.atEnd() ) {
1763     QString id;
1764     stream >> id;
1765     if ( !id.isEmpty() && searcher() ) {
1766       SUIT_DataObject* obj = searcher()->findObject( id );
1767       if ( obj ) objects << obj;
1768     }
1769   }
1770
1771   // emit signal
1772   emit dropped( objects, pobj, row, action );
1773
1774   // return true if there's any to drop
1775   return !objects.isEmpty();
1776 }
1777
1778 /*!
1779   \class SUIT_ProxyModel
1780   \brief Proxy model which can be used above the SUIT_TreeModel class
1781   to enable custom sorting/filtering of the data.
1782
1783   The SUIT_TreeModel class does not support custom sorting/filtering of the data.
1784   To use these features, the SUIT_ProxyModel class can be used as top-level
1785   wrapper for the SUIT_DataObject-based data tree model.
1786 */
1787
1788 /*!
1789   \brief Constructor.
1790   \param parent parent object
1791 */
1792 SUIT_ProxyModel::SUIT_ProxyModel( QObject* parent )
1793 : QSortFilterProxyModel( parent ),
1794   mySortingEnabled( true )
1795 {
1796   SUIT_TreeModel* model = new SUIT_TreeModel( this );
1797   connect( model, SIGNAL( modelUpdated() ), this, SIGNAL( modelUpdated() ) );
1798   connect( model, SIGNAL( clicked( SUIT_DataObject*, int ) ), this, SIGNAL(clicked( SUIT_DataObject*, int ) ) );
1799   connect( model, SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ),
1800            this,  SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ) );
1801   setSourceModel( model );
1802   setDynamicSortFilter( true );
1803 }
1804
1805 /*!
1806   \brief Constructor.
1807   \param root root data object
1808   \param parent parent object
1809 */
1810 SUIT_ProxyModel::SUIT_ProxyModel( SUIT_DataObject* root, QObject* parent )
1811 : QSortFilterProxyModel( parent ),
1812   mySortingEnabled( true )
1813 {
1814   SUIT_TreeModel* model = new SUIT_TreeModel( root, this );
1815   connect( model, SIGNAL( modelUpdated() ), this, SIGNAL( modelUpdated() ) );
1816   connect( model, SIGNAL( clicked( SUIT_DataObject*, int ) ), this, SIGNAL( clicked( SUIT_DataObject*, int ) ) );
1817   connect( model, SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ),
1818            this,  SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ) );
1819   setSourceModel( model );
1820   setDynamicSortFilter( true );
1821 }
1822
1823 /*!
1824   \brief Constructor.
1825   \param model tree model
1826   \param parent parent object
1827 */
1828 SUIT_ProxyModel::SUIT_ProxyModel( SUIT_AbstractModel* model, QObject* parent )
1829 : QSortFilterProxyModel( parent ),
1830   mySortingEnabled( true )
1831 {
1832   connect( *model, SIGNAL( modelUpdated() ), this, SIGNAL( modelUpdated() ) );
1833   connect( *model, SIGNAL( clicked( SUIT_DataObject*, int ) ), this, SIGNAL( clicked( SUIT_DataObject*, int ) ) );
1834   connect( *model, SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ),
1835            this,   SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ) );
1836   setSourceModel( *model );
1837   setDynamicSortFilter( true );
1838 }
1839
1840 /*!
1841   \brief Destructor.
1842 */
1843 SUIT_ProxyModel::~SUIT_ProxyModel()
1844 {
1845 }
1846
1847 /*!
1848   \brief Get data tree root object.
1849   \return data tree root
1850   \sa setRoot()
1851 */
1852 SUIT_DataObject* SUIT_ProxyModel::root() const
1853 {
1854   return treeModel() ? treeModel()->root() : 0;
1855 }
1856
1857 /*!
1858   \brief Set data tree root object.
1859   \param r new data tree root
1860   \sa root()
1861 */
1862 void SUIT_ProxyModel::setRoot( SUIT_DataObject* r )
1863 {
1864   if ( treeModel() )
1865     treeModel()->setRoot( r );
1866 }
1867
1868 /*!
1869   \brief Get data object by the specified model index.
1870   \param index model index
1871   \return data object corresponding to the model index
1872 */
1873 SUIT_DataObject* SUIT_ProxyModel::object( const QModelIndex& index ) const
1874 {
1875   return treeModel() ? treeModel()->object( mapToSource( index ) ) : 0;
1876 }
1877
1878 /*!
1879   \brief Get model index by the specified data object.
1880   \param obj data object
1881   \param column data object column
1882   \return model index
1883 */
1884 QModelIndex SUIT_ProxyModel::index( const SUIT_DataObject* obj, int column ) const
1885 {
1886   return treeModel() ? mapFromSource( treeModel()->index( obj, column ) ) : QModelIndex();
1887 }
1888
1889 /*!
1890   \brief Get 'auto-delete data tree' flag value.
1891   \return 'auto-delete data tree' flag value
1892   \sa setAutoDeleteTree()
1893 */
1894 bool SUIT_ProxyModel::autoDeleteTree() const
1895 {
1896   return treeModel() ? treeModel()->autoDeleteTree() : false;
1897 }
1898
1899 /*!
1900   \brief Set 'auto-delete data tree' flag value.
1901
1902   If this flag is set to \c true, the data tree is deleted when
1903   the tree model is destroyed. Default value for this flag is \c false.
1904
1905   \param on 'auto-delete data tree' flag value
1906   \sa autoDeleteTree()
1907 */
1908 void SUIT_ProxyModel::setAutoDeleteTree( const bool on )
1909 {
1910   if ( treeModel() )
1911     treeModel()->setAutoDeleteTree( on );
1912 }
1913
1914 /*!
1915   \brief Get 'auto-update tree' flag value.
1916   \return 'auto-update tree' flag value
1917   \sa setAutoUpdate(), updateTree()
1918 */
1919 bool SUIT_ProxyModel::autoUpdate() const
1920 {
1921   return treeModel() ? treeModel()->autoUpdate() : false;
1922 }
1923
1924 /*!
1925   \brief Get 'updateModified' flag value.
1926   \return 'updateModified' flag value
1927 */
1928 bool SUIT_ProxyModel::updateModified() const
1929 {
1930   return treeModel() ? treeModel()->updateModified() : false;
1931 }
1932 /*!
1933   \brief Set 'updateModified' flag value.
1934
1935   If this flag is set to \c true (default=false), the model is updated by updateTreeModel that 
1936   uses the isModified flag to update only modified objects
1937
1938   \param on 'updateModified' flag value
1939 */
1940 void SUIT_ProxyModel::setUpdateModified( const bool on )
1941 {
1942   if ( treeModel() )
1943     treeModel()->setUpdateModified( on );
1944 }
1945
1946 /*!
1947   \brief Set 'auto-update tree' flag value.
1948
1949   If this flag is set to \c true (by default), the model is updated
1950   automatically when data tree is changed.
1951
1952   \param on 'auto-update tree' flag value
1953   \sa autoUpdate(), updateTree()
1954 */
1955 void SUIT_ProxyModel::setAutoUpdate( const bool on )
1956 {
1957   if ( treeModel() )
1958     treeModel()->setAutoUpdate( on );
1959 }
1960
1961 /*!
1962   \brief Check if sorting is enabled.
1963   \return \c true if sorting is enabled
1964   \sa setSortingEnabled()
1965 */
1966 bool SUIT_ProxyModel::isSortingEnabled() const
1967 {
1968   return mySortingEnabled;
1969 }
1970
1971 SUIT_DataSearcher* SUIT_ProxyModel::searcher() const
1972 {
1973   return treeModel() ? treeModel()->searcher() : 0;
1974 }
1975
1976 void SUIT_ProxyModel::setSearcher( SUIT_DataSearcher* s )
1977 {
1978   if ( treeModel() ) treeModel()->setSearcher( s );
1979 }
1980
1981 /*!
1982   \brief Get item delegate for the model.
1983   \return new item delegate
1984 */
1985 QAbstractItemDelegate* SUIT_ProxyModel::delegate() const
1986 {
1987   return treeModel() ? treeModel()->delegate() : 0;
1988 }
1989
1990 /*!
1991   \brief Update tree model.
1992
1993   Call this method when data tree is changed outside the model.
1994   If the 'auto-update' flag is set to \c true, the model
1995   is updated automatically when the data tree is changed.
1996
1997   \param index starting index for the updating
1998   \sa setAutoUpdate()
1999 */
2000 void SUIT_ProxyModel::updateTree( const QModelIndex& index )
2001 {
2002   if ( treeModel() )
2003     treeModel()->updateTree( mapToSource( index ) );
2004 }
2005
2006 /*!
2007   \brief Update tree model.
2008
2009   Call this method when data tree is changed outside the model.
2010   If the 'auto-update' flag is set to \c true, the model
2011   is updated automatically when the data tree is changed.
2012
2013   \param obj starting data object for the updating
2014   \sa setAutoUpdate()
2015 */
2016 void SUIT_ProxyModel::updateTree( SUIT_DataObject* obj )
2017 {
2018   if ( treeModel() )
2019     treeModel()->updateTree( obj );
2020 }
2021
2022 void SUIT_ProxyModel::forgetObject( const SUIT_DataObject* obj )
2023 {
2024   if ( treeModel() )
2025     treeModel()->forgetObject( obj );
2026 }
2027
2028 /*!
2029   \brief Compares two model indexes for the sorting purposes.
2030   \param left first index to compare
2031   \param right second index to compare
2032   \return result of the comparison
2033 */
2034 bool SUIT_ProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right ) const
2035 {
2036   if ( !isSortingEnabled() && left.isValid() && right.isValid() ) {
2037     return left.row() < right.row();
2038   }
2039   if ( treeModel() && treeModel()->customSorting( left.column() ) ) {
2040     return treeModel()->lessThan( left, right );
2041   }
2042   return QSortFilterProxyModel::lessThan( left, right );
2043 }
2044
2045 /*!
2046   \brief Check if the specified column supports custom sorting.
2047   \param column column index on which data is being sorted
2048   \return \c true if column requires custom sorting
2049   \sa lessThan()
2050 */
2051 bool SUIT_ProxyModel::customSorting( const int column ) const
2052 {
2053   return treeModel() ? treeModel()->customSorting( column ) : false;
2054 }
2055
2056 /*!
2057   \brief Enable/disable sorting.
2058   \param enabled new flag state
2059   \sa isSortingEnabled()
2060 */
2061 void SUIT_ProxyModel::setSortingEnabled( bool enabled )
2062 {
2063   mySortingEnabled = enabled;
2064   clear();
2065 }
2066
2067 /*
2068   \brief Get tree model.
2069   \return tree model
2070 */
2071 SUIT_AbstractModel* SUIT_ProxyModel::treeModel() const
2072 {
2073   return dynamic_cast<SUIT_AbstractModel*>( sourceModel() );
2074 }
2075
2076 /*!
2077   \brief Filter rows
2078   \param sourceRow row index of the source data model
2079   \param sourceParent parent model index of the source data model
2080   \return \c true if the specified row should be filtered out (i.e. not displayed) or \c false otherwise
2081 */
2082 bool SUIT_ProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent ) const
2083 {
2084   SUIT_DataObject* o = treeModel()->object( sourceModel()->index( sourceRow, 0, sourceParent ) );
2085   SUIT_DataObject* p = o ? o->parent() : 0;
2086   return ( !p || p->expandable() ) && o && o->isVisible();
2087 }
2088
2089 /*!
2090   \brief Register new column in the model
2091   \param group_id - unique data object identificator allowing the classification of objects 
2092   \param name - translated column name
2093   \param custom_id - custom column id that should be passed into method SUIT_DataObject::data()
2094  */
2095 void SUIT_ProxyModel::registerColumn( const int group_id, const QString& name, const int custom_id )
2096 {
2097   if( treeModel() )
2098     treeModel()->registerColumn( group_id, name, custom_id );
2099 }
2100
2101 /*!
2102   \brief Remove column from the model
2103
2104   Please take into account that column is removed only for given group_id, it means
2105   that information of data objects with such group_id won't be shown.
2106   If there is not any registered group_id for this column after removing, the column will be hidden
2107   otherwise it continue to be shown
2108
2109   \param group_id - unique data object identificator allowing the classification of objects 
2110   \param name - translated column name
2111  */
2112 void SUIT_ProxyModel::unregisterColumn( const int group_id, const QString& name )
2113 {
2114   if( treeModel() )
2115     treeModel()->unregisterColumn( group_id, name );
2116 }
2117
2118 /*!
2119   \brief Change column icon.
2120
2121   \param name - column name
2122   \param icon - new icon of the specified column
2123 */
2124 void SUIT_ProxyModel::setColumnIcon( const QString& name, const QPixmap& icon )
2125 {
2126   if( treeModel() )
2127     treeModel()->setColumnIcon( name, icon );
2128 }
2129
2130 /*!
2131   \brief Get column icon.
2132
2133   \param name - column name
2134   \return icon of the specified column
2135 */
2136 QPixmap SUIT_ProxyModel::columnIcon( const QString& name ) const
2137 {
2138   return treeModel() ? treeModel()->columnIcon( name ) : QPixmap();
2139 }
2140
2141 /*!
2142   \brief Change appropriate status
2143   
2144   Appropriate status determines if the column should appear in the tree view header popup menu
2145   (to show/hide the column).
2146
2147   If appropriate status is not specified yet, the \c Shown value is taken,
2148   it means that column should be always visible.
2149
2150   \param name - column name
2151   \param appr - new appropriate status
2152 */
2153 void SUIT_ProxyModel::setAppropriate( const QString& name, const Qtx::Appropriate appr )
2154 {
2155   if( treeModel() )
2156     treeModel()->setAppropriate( name, appr );
2157 }
2158
2159 /*!
2160   \brief Check if the column should appear in the tree view header popup menu
2161   (to show/hide the column).
2162
2163   Default implementation (if appropriate status is not specified yet)
2164   returns \c Shown, it means that column should be always visible.
2165
2166   \param name - column name
2167   \return appropriate status
2168 */
2169 Qtx::Appropriate SUIT_ProxyModel::appropriate( const QString& name ) const
2170 {
2171   return treeModel() ? treeModel()->appropriate( name ) : Qtx::Shown;
2172 }
2173
2174 /*!
2175   \brief Set header flags.
2176   
2177   These flags allow show in the header of the column text (name of the column),
2178   icon or both text and icon.
2179   
2180   \param name - column name
2181   \param flags - header flags
2182
2183 */
2184 void SUIT_ProxyModel::setHeaderFlags( const QString& name, const Qtx::HeaderViewFlags flags )
2185 {
2186   if(treeModel())
2187     treeModel()->setHeaderFlags(name, flags);
2188 }
2189
2190 /*!
2191   \brief Get the  header flags.
2192   
2193   These flags allow show in the header of the column text (name of the column),
2194   icon or both text and icon.
2195   
2196   \param name - column name
2197   \return header flags
2198 */
2199 Qtx::HeaderViewFlags SUIT_ProxyModel::headerFlags( const QString& name ) const
2200 {
2201   return treeModel() ? treeModel()->headerFlags( name ) : Qtx::ShowAll;
2202 }
2203
2204 /*!
2205   \brief Set visibility state of the object.
2206   
2207   \param id - column name
2208   \param state - visible state
2209   \param emitChanged - if set to false, blocks dataChanged() signal, this can be used to
2210   prevent emitting dataChanged() several times for the same data object
2211 */
2212 void SUIT_ProxyModel::setVisibilityState(const QString& id, Qtx::VisibilityState state, bool emitChanged ) {
2213   if(treeModel())
2214     treeModel()->setVisibilityState(id,state,emitChanged);
2215 }
2216
2217 /*!
2218   \brief Set visibility state for all objects.
2219   
2220   \param id - column name
2221   \param state - visible state
2222 */
2223 void SUIT_ProxyModel::setVisibilityStateForAll(Qtx::VisibilityState state)
2224 {
2225   if(treeModel())
2226     treeModel()->setVisibilityStateForAll(state);
2227 }
2228
2229 /*!
2230   \brief Get visibility state of the object.
2231   
2232   \param id - column name
2233   \return visible state
2234 */
2235 Qtx::VisibilityState SUIT_ProxyModel::visibilityState(const QString& id) const
2236 {
2237   return treeModel() ? treeModel()->visibilityState(id) : Qtx::UnpresentableState;
2238 }
2239
2240 void SUIT_ProxyModel::emitClicked( SUIT_DataObject* obj, const QModelIndex& index)
2241 {
2242   if(treeModel())
2243     treeModel()->emitClicked(obj,index);
2244 }
2245
2246 /*!
2247   \class SUIT_ItemDelegate
2248   \brief An SUIT_DataObject-based item delegate class.
2249
2250   This class can be used to render the SUIT_DataObject-based item
2251   in the widgets like QTreeView and others.
2252   Refer to the Qt 4 documentation, model/view architecture 
2253   section for more details).
2254 */
2255
2256 /*!
2257   \brief Constructor.
2258   \param parent parent object
2259 */
2260 SUIT_ItemDelegate::SUIT_ItemDelegate( QObject* parent )
2261 : QItemDelegate( parent )
2262 {
2263 }
2264
2265 /*!
2266   \brief Render the item in the widget.
2267
2268   Customizes the item colors for the specific roles.
2269
2270   \param painter painter
2271   \param option painting option
2272   \param index model index being rendered
2273 */
2274 void SUIT_ItemDelegate::paint( QPainter* painter, 
2275                                const QStyleOptionViewItem& option,
2276                                const QModelIndex& index ) const
2277 {
2278   QStyleOptionViewItem opt = option;
2279   if ( index.isValid() ) {
2280     // Note: we check into account only custom roles; other roles are process
2281     //       correctly by the QItemDelegate class
2282     QVariant val = index.data( SUIT_TreeModel::BaseColorRole );
2283     if ( val.isValid() && val.value<QColor>().isValid() ) {
2284       QColor aBase = val.value<QColor>();
2285       aBase.setAlpha( 0 );
2286       opt.palette.setBrush( QPalette::Base, val.value<QColor>() );
2287     }
2288     val = index.data( SUIT_TreeModel::TextColorRole );
2289     if ( val.isValid() && val.value<QColor>().isValid() )
2290       opt.palette.setBrush( QPalette::Text, val.value<QColor>() );
2291     val = index.data( SUIT_TreeModel::HighlightRole );
2292     if ( val.isValid() && val.value<QColor>().isValid() )
2293       opt.palette.setBrush( QPalette::Highlight, val.value<QColor>() );
2294     val = index.data( SUIT_TreeModel::HighlightedTextRole );
2295     if ( val.isValid() && val.value<QColor>().isValid() )
2296       opt.palette.setBrush( QPalette::HighlightedText, val.value<QColor>() );      
2297   }
2298   QItemDelegate::paint( painter, opt, index );
2299 }
2300
2301 QSize SUIT_ItemDelegate::sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const
2302 {
2303     QSize size = QItemDelegate::sizeHint ( option, index );
2304 #if QT_VERSION >= 0x040500
2305     size.setHeight( size.height() + 1 );
2306 #endif
2307     return size;
2308 }