Salome HOME
Update from BR_V5_DEV 13Feb2009
[modules/gui.git] / src / SUIT / SUIT_TreeModel.cxx
1 //  Copyright (C) 2007-2008  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 //  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 //  This library is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU Lesser General Public
8 //  License as published by the Free Software Foundation; either
9 //  version 2.1 of the License.
10 //
11 //  This library is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 //  Lesser General Public License for more details.
15 //
16 //  You should have received a copy of the GNU Lesser General Public
17 //  License along with this library; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 // File:   SUIT_TreeModel.cxx
23 // Author: Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
24 //
25 #include "SUIT_TreeModel.h"
26 #include "SUIT_TreeSync.h"
27 #include "SUIT_DataObject.h"
28
29 #include <QApplication>
30 #include <QHash>
31
32 SUIT_AbstractModel::SUIT_AbstractModel()
33 {
34 }
35
36 SUIT_AbstractModel::operator const QAbstractItemModel*() const
37 {
38   return dynamic_cast<const QAbstractItemModel*>( this );
39 }
40
41 SUIT_AbstractModel::operator QAbstractItemModel*()
42 {
43   return dynamic_cast<QAbstractItemModel*>( this );
44 }
45
46 SUIT_AbstractModel::operator const QObject*() const
47 {
48   return dynamic_cast<const QObject*>( this );
49 }
50
51
52
53
54
55
56 /*!
57   \class SUIT_TreeModel::TreeItem
58   \brief Internal class used for tree view synchronizaton with data object tree.
59   \internal
60 */
61
62 class SUIT_TreeModel::TreeItem
63 {
64 public:
65   TreeItem( SUIT_DataObject* obj, TreeItem* parent = 0, TreeItem* after = 0 );
66   ~TreeItem();
67
68   void                  insertChild( TreeItem* child, TreeItem* after = 0 );
69   void                  removeChild( TreeItem* child );
70   SUIT_DataObject*      dataObject() const;
71   TreeItem*             parent() const;
72   int                   position() const;
73   int                   childCount() const;
74   TreeItem*             child( const int i );
75   QList<TreeItem*>      children() const;
76   TreeItem*             nextSibling() const;
77   TreeItem*             prevSibling() const;
78   
79 private:
80   TreeItem*             myParent;
81   QList<TreeItem*>      myChildren;
82   SUIT_DataObject*      myObj;
83 };
84
85 /*!
86   \brief Constructor.
87   \internal
88   \param obj data object
89   \param parent parent item
90   \param after tree item after each this one should be inserted
91 */
92 SUIT_TreeModel::TreeItem::TreeItem( SUIT_DataObject*          obj, 
93                                     SUIT_TreeModel::TreeItem* parent,
94                                     SUIT_TreeModel::TreeItem* after )
95 : myParent( parent ),
96   myObj( obj )
97 {
98   // Add <this> to the parent's children list
99   if ( myParent )
100     myParent->insertChild( this, after );
101 }
102
103 /*!
104   \brief Destructor. Deletes all child items recursively.
105   \internal
106 */
107 SUIT_TreeModel::TreeItem::~TreeItem()
108 {
109   // Ensure that all children are deleted;
110   // each child removes itself from the children list
111   while( myChildren.count() )
112     delete myChildren.at( 0 );
113
114   // Remove this item from the parent's children list
115   if ( myParent )
116     myParent->removeChild( this );
117 }
118
119 /*!
120   \brief Insert child item.
121   \internal
122   \param child child item being inserted
123   \param after tree item after each \a child should be inserted
124 */
125 void SUIT_TreeModel::TreeItem::insertChild( SUIT_TreeModel::TreeItem* child, 
126                                             SUIT_TreeModel::TreeItem* after )
127 {
128   if ( !child )
129     return;
130
131   int index = after ? myChildren.indexOf( after ) + 1 : 0;
132   myChildren.insert( index, child );
133 }
134
135 /*!
136   \brief Remove child item.
137   \internal
138   \param child child item being removed
139 */
140 void SUIT_TreeModel::TreeItem::removeChild( SUIT_TreeModel::TreeItem* child )
141 {
142   if ( !child )
143     return;
144   myChildren.removeAll( child );
145 }
146
147 /*!
148   \brief Get data object.
149   \internal
150   \return data object this item is associated to
151 */
152 SUIT_DataObject* SUIT_TreeModel::TreeItem::dataObject() const
153 {
154   return myObj;
155 }
156
157 /*!
158   \brief Get parent item.
159   \internal
160   \return parent item
161 */
162 SUIT_TreeModel::TreeItem* SUIT_TreeModel::TreeItem::parent() const
163 {
164   return myParent;
165 }
166
167 /*!
168   \brief Get position of this item in its parent's children list.
169   \internal
170   \return item position
171 */
172 int SUIT_TreeModel::TreeItem::position() const
173 {
174   return myParent ? myParent->myChildren.indexOf( (TreeItem*)this ) : -1;
175 }
176
177 /*!
178   \brief Get number of child items.
179   \internal
180   \return number of children
181 */
182 int SUIT_TreeModel::TreeItem::childCount() const
183 {
184   return myChildren.count();
185 }
186
187 /*!
188   \brief Get child item by specified index.
189   \internal
190   \param i child item index
191   \return child item or 0 if \a i is out of range
192 */
193 SUIT_TreeModel::TreeItem* SUIT_TreeModel::TreeItem::child( const int i )
194 {
195   return i >= 0 && i < myChildren.count() ? myChildren.at( i ) : 0;
196 }
197
198 /*!
199   \brief Get all child items.
200   \internal
201   \return list of child items
202 */
203 QList<SUIT_TreeModel::TreeItem*> SUIT_TreeModel::TreeItem::children() const
204 {
205   return myChildren;
206 }
207
208 /*!
209   \brief Get next sibling item.
210   \internal
211   \return next sibling item or 0 if there are no any
212 */
213 SUIT_TreeModel::TreeItem* SUIT_TreeModel::TreeItem::nextSibling() const
214 {
215   return parent() ? parent()->child( position()+1 ) : 0;
216 }
217
218 /*!
219   \brief Get previous sibling item.
220   \internal
221   \return previous sibling item or 0 if there are no any
222 */
223 SUIT_TreeModel::TreeItem* SUIT_TreeModel::TreeItem::prevSibling() const
224 {
225   return parent() ? parent()->child( position()-1 ) : 0;
226 }
227
228 /*!
229   \class SUIT_TreeModel::TreeSync
230   \brief Functor class for synchronizing data tree and tree model 
231          when the data tree is changed outside the model.
232   \internal
233 */
234
235 class SUIT_TreeModel::TreeSync
236 {
237 public:
238   TreeSync( SUIT_TreeModel* );
239   bool              isEqual( const ObjPtr&, const ItemPtr& ) const;
240   ObjPtr            nullSrc() const;
241   ItemPtr           nullTrg() const;
242   ItemPtr           createItem( const ObjPtr&, const ItemPtr&, const ItemPtr& ) const;
243   void              updateItem( const ObjPtr&, const ItemPtr& ) const;
244   void              deleteItemWithChildren( const ItemPtr& ) const;
245   QList<ObjPtr>     children( const ObjPtr& ) const;
246   QList<ItemPtr>    children( const ItemPtr& ) const;
247   ItemPtr           parent( const ItemPtr& ) const;
248 private:
249   bool              needUpdate( const ItemPtr& ) const;
250   SUIT_TreeModel*   myModel;
251 };
252
253 /*!
254   \brief Constructor.
255   \internal
256   \param model tree model
257 */
258 SUIT_TreeModel::TreeSync::TreeSync( SUIT_TreeModel* model )
259 : myModel( model )
260 {
261 }
262
263 /*!
264   \brief Check if item corresponds to the specified data object.
265   \internal
266   \param obj data object
267   \param item tree item 
268   \return \c true if item corresponds to the data object
269 */
270 bool SUIT_TreeModel::TreeSync::isEqual( const ObjPtr& obj, const ItemPtr& item ) const
271 {
272   bool isRoot = obj == myModel->root() && item == myModel->rootItem(),
273        isEq   = obj && item && item->dataObject() == obj;
274   return isRoot || ( !obj && !item ) || isEq;
275 }
276
277 /*!
278   \brief Get null data object.
279   \internal
280   \return null data object
281 */
282 SUIT_TreeModel::ObjPtr SUIT_TreeModel::TreeSync::nullSrc() const
283 {
284   return 0;
285 }
286
287 /*!
288   \brief Get null tree item.
289   \internal
290   \return null tree item
291 */
292 SUIT_TreeModel::ItemPtr SUIT_TreeModel::TreeSync::nullTrg() const
293 {
294   return 0;
295 }
296
297 /*!
298   \brief Create an item corresponding to the specified data object.
299   \internal
300   \param obj data object
301   \param parent parent tree item
302   \param after tree item after each new one should be inserted
303   \return created item
304 */
305 SUIT_TreeModel::ItemPtr SUIT_TreeModel::TreeSync::createItem( const ObjPtr&  obj,
306                                                               const ItemPtr& parent, 
307                                                               const ItemPtr& after ) const
308 {
309   ItemPtr item = myModel ? myModel->createItem( obj, parent, after ) : 0;
310
311   // Additional actions that can't be performed by the model, e.g. expanded state
312   if( item )
313     obj->update();
314   return item;
315 }
316
317 /*!
318   \brief Update tree item.
319   \internal
320   \param obj reference data object
321   \param item tree item to be updated
322 */
323 void SUIT_TreeModel::TreeSync::updateItem( const ObjPtr& obj, const ItemPtr& item ) const
324 {
325   if( obj )
326     obj->update();
327   if ( item && needUpdate( item ) ) 
328     myModel->updateItem( item );
329 }
330
331 /*!
332   \brief Delete item with all children recursively.
333   \internal
334   \param item tree item
335 */
336 void SUIT_TreeModel::TreeSync::deleteItemWithChildren( const ItemPtr& item ) const
337 {
338   // NOTE: item is deleted inside removeItem()!
339   myModel->removeItem( item );
340 }
341
342 /*!
343   \brief Get all the children of the specified data object.
344   \internal
345   \param obj data object
346   \return list of the children
347 */
348 QList<SUIT_TreeModel::ObjPtr> SUIT_TreeModel::TreeSync::children( const ObjPtr& obj ) const
349 {
350   QList<ObjPtr> ch;
351   if ( obj )
352     ch = obj->children();
353   return ch;
354 }
355
356 /*!
357   \brief Get all the children of the specified tree item.
358   \internal
359   \param item tree item
360   \return list of the children
361 */
362 QList<SUIT_TreeModel::ItemPtr> SUIT_TreeModel::TreeSync::children( const ItemPtr& item ) const
363 {
364   QList<ItemPtr> ch;
365   if ( item ) 
366     ch = item->children();
367   return ch;
368 }
369
370 /*!
371   \brief Get item which is the parent for the specified item.
372   \internal
373   \param item tree item
374   \return parent item
375 */
376 SUIT_TreeModel::ItemPtr SUIT_TreeModel::TreeSync::parent( const ItemPtr& item ) const
377 {
378   return item ? item->parent() : 0;
379 }
380
381 /*!
382   \brief Check if the tree item needs updating.
383   \internal
384   \param item tree item to be checked
385   \return \c true if item needs updating
386
387   \todo finalize this method
388 */
389 bool SUIT_TreeModel::TreeSync::needUpdate( const ItemPtr& item ) const
390 {
391   bool update = false;
392   if ( item ) {
393     SUIT_DataObject* obj = item->dataObject();
394     if ( obj ) {
395       // TODO: find simplified way to check if an item is not up-to-date:
396       // - use check-sum of various item data
397       // - use "LastModified" time stamp in data objects and tree items - hardly possible, for sometimes data objects do not know that data changes...
398       // ...
399       update = true; // TEMPORARY!!!
400       // 1. check text
401 /*      update = ( item->text( 0 ) != obj->name() ) || myBrowser->needToUpdateTexts( item );
402
403       if ( !update ) { 
404         // 2. check pixmap (compare serialNumber()-s)
405         QPixmap objPix = obj->icon();
406         const QPixmap* itemPix = item->pixmap( 0 );
407         update = (  objPix.isNull() && (  itemPix && !itemPix->isNull() ) ) || 
408                  ( !objPix.isNull() && ( !itemPix ||  itemPix->isNull() ) ); 
409         if ( !update && !objPix.isNull() && itemPix && !itemPix->isNull() ) {
410           int aIconW = objPix.width();
411           if( aIconW > 20 ) {
412             QWMatrix aM;
413             double aScale = 20.0 / aIconW;
414             aM.scale( aScale, aScale );
415             objPix = objPix.xForm( aM );
416           }
417           update = ( objPix.serialNumber() != itemPix->serialNumber() );
418         }
419       }*/
420     }
421   }
422   return update;
423 }
424
425 /*!
426   \class SUIT_TreeModel
427   \brief Implementation of the model/view API based on the tree of SUIT_DataObject class
428   instances.
429
430   The SUIT_TreeModel class does not support insertion/removal of rows. It is synchronized 
431   automatically with the tree of data objects used by SUIT-based applications to 
432   expose their data in a hierarchical form to the user.
433 */
434
435 /*!
436   \brief Constructor.
437   \param parent parent object
438 */
439 SUIT_TreeModel::SUIT_TreeModel( QObject* parent )
440 : QAbstractItemModel( parent ),
441   myRoot( 0 ),
442   myRootItem( 0 ),
443   myAutoDeleteTree( false ),
444   myAutoUpdate( true )
445 {
446   initialize();
447 }
448
449 /*!
450   \brief Constructor.
451   \param root root data object
452   \param parent parent object
453 */
454 SUIT_TreeModel::SUIT_TreeModel( SUIT_DataObject* root, QObject* parent )
455 : QAbstractItemModel( parent ),
456   myRoot( root ),
457   myRootItem( 0 ),
458   myAutoDeleteTree( false ),
459   myAutoUpdate( true )
460 {
461   initialize();
462 }
463
464 /*!
465   \brief Destructor
466 */
467 SUIT_TreeModel::~SUIT_TreeModel()
468 {
469   if ( autoDeleteTree() ) {
470     SUIT_DataObject::disconnect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
471                                  this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
472     SUIT_DataObject::disconnect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
473                                  this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
474     delete myRoot;
475   }
476
477   delete myRootItem;
478 }
479
480 /*!
481   \brief Register new column in the model
482   \param group_id - unique data object group identificator
483   \param name - translated column name
484   \param custom_id - custom column id that should be passed into method SUIT_DataObject::data()
485  */
486 void SUIT_TreeModel::registerColumn( const int group_id, const QString& name, const int custom_id )
487 {
488   bool found = false;
489   for( int i=0, n=myColumns.size(); i<n && !found; i++ )
490     if( name==myColumns[i].myName )
491         {
492           myColumns[i].myIds.insert( group_id, custom_id );
493           found = true;
494         }
495   if( !found )
496   {
497         ColumnInfo inf;
498         inf.myName = name;
499         inf.myIds.insert( group_id, custom_id );
500         inf.myAppropriate = Qtx::Shown;
501         int n = myColumns.size();
502         myColumns.resize( n+1 );
503         myColumns[n] = inf;
504         reset();
505   }
506 }
507
508 /*!
509   \brief Remove column from the model
510
511   Please take into account that column is removed only for given group_id, it means
512   that information of data objects with such group_id won't be shown.
513   If there is not any registered group_id for this column after removing, the column will be hidden
514   otherwise it continue to be shown
515
516   \param group_id - unique data object identificator allowing the classification of objects 
517   \param name - translated column name
518  */
519 void SUIT_TreeModel::unregisterColumn( const int group_id, const QString& name )
520 {
521   for( int i=0, n=myColumns.size(); i<n; i++ )
522     if( myColumns[i].myName==name )
523         {
524           myColumns[i].myIds.remove( group_id );
525           if( myColumns[i].myIds.isEmpty() )
526           {
527             myColumns.remove( i );
528                 reset();
529           }
530           break;
531     }
532 }
533
534 /*!
535   \brief Change column icon.
536
537   \param name - column name
538   \param icon - new icon of the specified column
539 */
540 void SUIT_TreeModel::setColumnIcon( const QString& name, const QPixmap& icon )
541 {
542   for( int i=0, n=myColumns.size(); i<n; i++ )
543     if( myColumns[i].myName==name )
544         {
545           myColumns[i].myIcon = icon;
546           break;
547         }
548 }
549
550 /*!
551   \brief Get column icon.
552
553   \param name - column name
554   \return icon of the specified column
555 */
556 QPixmap SUIT_TreeModel::columnIcon( const QString& name ) const
557 {
558   QPixmap res;
559   for( int i=0, n=myColumns.size(); i<n; i++ )
560     if( myColumns[i].myName==name )
561         {
562           res = myColumns[i].myIcon;
563           break;
564         }
565   return res;
566 }
567
568 /*!
569   \brief Change appropriate status
570   
571   Appropriate status determines if the column should appear in the tree view header popup menu
572   (to show/hide the column).
573
574   If appropriate status is not specified yet, the \c Shown value is taken,
575   it means that column should be always visible.
576
577   \param name - column name
578   \param appr - new appropriate status
579 */
580 void SUIT_TreeModel::setAppropriate( const QString& name, const Qtx::Appropriate appr )
581 {
582   for( int i=0, n=myColumns.size(); i<n; i++ )
583     if( myColumns[i].myName==name )
584         {
585           myColumns[i].myAppropriate = appr;
586           emit headerDataChanged( Qt::Horizontal, i, i );
587           break;
588         }
589 }
590
591 /*!
592   \brief Check if the column should appear in the tree view header popup menu
593   (to show/hide the column).
594
595   Default implementation (if appropriate status is not specified yet)
596   returns \c Shown, it means that column should be always visible.
597
598   \param name - column name
599   \return appropriate status
600 */
601 Qtx::Appropriate SUIT_TreeModel::appropriate( const QString& name ) const
602 {
603   Qtx::Appropriate appr = Qtx::Shown;
604   for( int i=0, n=myColumns.size(); i<n; i++ )
605     if( myColumns[i].myName==name )
606         {
607           appr = myColumns[i].myAppropriate;
608           break;
609         }
610   return appr;
611 }
612
613
614 /*!
615   \brief Get data tree root object.
616   \return data tree root
617   \sa setRoot()
618 */
619 SUIT_DataObject* SUIT_TreeModel::root() const
620 {
621   return myRoot;
622 }
623
624 /*!
625   \brief Set data tree root object.
626   \param r new data tree root
627   \sa root()
628 */
629 void SUIT_TreeModel::setRoot( SUIT_DataObject* r )
630 {
631   if ( root() == r )
632     return;
633
634   if ( autoDeleteTree() ) {
635     SUIT_DataObject::disconnect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
636                                  this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
637     SUIT_DataObject::disconnect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
638                                  this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
639     delete myRoot;
640   }
641
642   myRoot = r;
643
644   //initialize();
645   reset();
646   emit modelUpdated();
647 }
648
649 /*!
650   \brief Get data for the specified model index and data role.
651   \param index model index
652   \param role data role
653   \return requested data
654   \sa setData()
655 */
656 QVariant SUIT_TreeModel::data( const QModelIndex& index, int role ) const
657 {
658   if ( !index.isValid() )
659     return QVariant();
660
661   SUIT_DataObject* obj = object( index );
662
663   QColor c;
664   QVariant val;
665
666   int obj_group_id = obj->groupId();
667   const ColumnInfo& inf = myColumns[index.column()];
668
669   int id = -1;
670   if( inf.myIds.contains( 0 ) )
671     id = inf.myIds[0];
672   if( inf.myIds.contains( obj_group_id ) )
673     id = inf.myIds[obj_group_id];
674
675   if( id<0 )
676     return QVariant();
677
678   if ( obj )
679   {
680     switch ( role )
681         {
682     case DisplayRole:
683       // data object text for the specified column
684       val = obj->text( id ); 
685       break;
686     case DecorationRole:
687       // data object icon for the specified column
688       val = obj->icon( id ); 
689       break;
690     case ToolTipRole:
691       // data object tooltip for the specified column
692       val = obj->toolTip( id ); 
693       break;
694     case StatusTipRole:
695       // data object status tip for the specified column
696       val = obj->statusTip( id ); 
697       break;
698     case WhatsThisRole:
699       // data object what's this info for the specified column
700       val = obj->whatsThis( id ); 
701       break;
702     case FontRole:
703       // data object font for the specified column
704       val = obj->font( id ); 
705       break;
706     case TextAlignmentRole:
707       // data object text alignment for the specified column
708       val = obj->alignment( id ); 
709       break;
710     case BackgroundRole:
711       // data background color for the specified column
712       c = obj->color( SUIT_DataObject::Background, id );
713       if( !c.isValid() ) // default value
714             c = QApplication::palette().color( QPalette::Base );
715       c.setAlpha( 0 );
716       val = c; 
717       break;
718     case ForegroundRole:
719       // data foreground (text) color for the specified column
720       c = obj->color( SUIT_DataObject::Foreground, id );
721       if( !c.isValid() ) // default value
722             c = QApplication::palette().color( QPalette::Foreground );
723       val = c; 
724       break;
725     case BaseColorRole:
726       // editor background color for the specified column
727       c = obj->color( SUIT_DataObject::Base, id );
728       if( !c.isValid() ) // default value
729             c = QApplication::palette().color( QPalette::Base );
730       val = c; 
731       break;
732     case TextColorRole:
733       // editor foreground (text) color for the specified column
734       c = obj->color( SUIT_DataObject::Text, id );
735       if( !c.isValid() ) // default value
736             c = QApplication::palette().color( QPalette::Text );
737       val = c; 
738       break;
739     case HighlightRole:
740       // adta object highlighted background color for the specified column
741       c = obj->color( SUIT_DataObject::Highlight, id );
742       if( !c.isValid() ) // default value
743             c = QApplication::palette().color( QPalette::Highlight );
744       val = c; 
745       break;
746     case HighlightedTextRole:
747       // data object highlighted foreground (text) color for the specified column
748       c = obj->color( SUIT_DataObject::HighlightedText, id );
749       if( !c.isValid() ) // default value
750             c = QApplication::palette().color( QPalette::HighlightedText );
751       val = c; 
752       break;
753     case CheckStateRole:
754       // data object checked state for the specified column
755       // NOTE! three-state check is not supported currently
756       if( obj->isCheckable( id ) )
757             val = obj->isOn( id ) ? Qt::Checked : Qt::Unchecked; 
758       break;
759     case SizeHintRole:
760       // data size hint
761       // NOTE! not supported currently
762       break;
763     default:
764       break;
765     } // ... switch ( role ) ...
766   } // ... if ( obj ) ...
767   return val;
768 }
769
770 /*!
771   \brief Set data for the specified model index and data role.
772   \param index model index
773   \param value new data value
774   \param role data role
775   \return \c true if data is set
776   \sa data()
777 */
778 bool SUIT_TreeModel::setData( const QModelIndex& index, 
779                               const QVariant& value, int role )
780 {
781   if ( index.isValid() && value.isValid() ) {
782     SUIT_DataObject* obj = object( index );
783     if ( obj ) {
784       // NOTE! only 'check state' data is supported by default
785       switch ( role ) {
786       case CheckStateRole:
787         // checked state
788         if ( obj->isCheckable( index.column() ) ) {
789           obj->setOn( value.toBool(), index.column() );
790           emit( dataChanged( index, index ) );
791           return true;
792         }
793         break;
794       default:
795         break;
796       }
797     }
798   }
799   return QAbstractItemModel::setData( index, value, role );
800 }
801
802 /*!
803   \brief Get data flags for specified model index.
804   \param index model index
805   \return data flags
806 */
807 Qt::ItemFlags SUIT_TreeModel::flags( const QModelIndex& index ) const
808 {
809   if ( !index.isValid() )
810     return 0;
811
812   SUIT_DataObject* obj = object( index );
813   Qt::ItemFlags f = 0;
814
815   if ( obj ) {
816     // data object is enabled
817     if ( obj->isEnabled() )
818       f = f | Qt::ItemIsEnabled;
819
820     // data object is selectable
821     if ( obj->isSelectable() )
822       f = f | Qt::ItemIsSelectable;
823
824     // data object is checkable
825     if ( obj->isCheckable( index.column() ) )
826       f = f | Qt::ItemIsUserCheckable;
827   }
828   return f;
829 }
830
831 /*!
832   \brief Get header data (can be used in any data view).
833   \param column column number
834   \param orientation header orientation
835   \param role data role
836   \return header data
837 */
838 QVariant SUIT_TreeModel::headerData( int column, Qt::Orientation orientation, int role ) const
839 {
840   QVariant d;
841   // NOTE! only horizontal header is supported
842   if ( root() && orientation == Qt::Horizontal )
843   {
844     switch ( role )
845         {
846     case DisplayRole:
847       // column title
848       d = myColumns[column].myName;
849       break;
850     case DecorationRole:
851       // column icon
852       d = myColumns[column].myIcon;
853       break;
854     case AppropriateRole:
855       // appropriate flag (can column be hidden via context popup menu)
856       d = myColumns[column].myAppropriate;
857       break;
858     default:
859       break;
860     }
861   }
862   return d;
863 }
864
865 /*!
866   \brief Create model index.
867   \param row data row
868   \param column data column
869   \param parent parent model index
870   \return model index
871 */
872 QModelIndex SUIT_TreeModel::index( int row, int column, 
873                                    const QModelIndex& parent ) const
874 {
875   if( hasIndex( row, column, parent ) )
876   {
877     TreeItem* parentItem = treeItem( parent );
878     if( parentItem )
879     {
880       TreeItem* childItem = parentItem->child( row );
881       if( childItem )
882         return createIndex( row, column, childItem );
883     }
884   }
885   return QModelIndex();
886 }
887
888 /*!
889   \brief Get parent model index.
890   \param index model index
891   \return parent model index
892 */
893 QModelIndex SUIT_TreeModel::parent( const QModelIndex& index ) const
894 {
895   if ( !index.isValid() )
896     return QModelIndex();
897
898   TreeItem* childItem = treeItem( index );
899   TreeItem* parentItem = childItem ? childItem->parent() : 0;
900
901   if ( !parentItem || parentItem == rootItem() )
902     return QModelIndex();
903
904   return createIndex( parentItem->position(), 0, parentItem );
905 }
906
907 /*!
908   \brief Get number of data columns.
909   \param parent parent model index (not used)
910   \return data columns number
911   \sa rowCount()
912 */
913 int SUIT_TreeModel::columnCount( const QModelIndex& /*parent*/ ) const
914 {
915   return myColumns.size();
916 }
917
918 /*!
919   \brief Get number of data rows (children of the specified model index).
920   \param parent parent model index
921   \return data rows (children) number
922   \sa columnCount()
923 */
924 int SUIT_TreeModel::rowCount( const QModelIndex& parent ) const
925 {
926   if ( parent.column() > 0 )
927     return 0;
928
929   TreeItem* parentItem = treeItem( parent );
930
931   return parentItem ? parentItem->childCount() : 0;
932 }
933
934 /*!
935   \brief Get data object by the specified model index.
936   \param index model index
937   \return data object corresponding to the model index
938 */
939 SUIT_DataObject* SUIT_TreeModel::object( const QModelIndex& index ) const
940 {
941   return object( treeItem( index ) );
942 }
943
944 /*!
945   \brief Get model index by the specified data object.
946   \param obj data object
947   \param column data object column
948   \return model index
949 */
950 QModelIndex SUIT_TreeModel::index( const SUIT_DataObject* obj, int column ) const
951 {
952   if ( obj == root() )
953     return QModelIndex();
954
955   TreeItem* item = treeItem( obj );
956
957   return item ? createIndex( item->position(), column, item ) : QModelIndex();
958 }
959
960 /*!
961   \brief Get 'auto-delete data tree' flag value.
962   \return 'auto-delete data tree' flag value
963   \sa setAutoDeleteTree()
964 */
965 bool SUIT_TreeModel::autoDeleteTree() const
966 {
967   return myAutoDeleteTree;
968 }
969
970 /*!
971   \brief Set 'auto-delete data tree' flag value.
972
973   If this flag is set to \c true, the data tree is deleted when
974   the tree model is destroyed. Default value for this flag is \c false.
975
976   \param on 'auto-delete data tree' flag value
977   \sa autoDeleteTree()
978 */
979 void SUIT_TreeModel::setAutoDeleteTree( const bool on )
980 {
981   myAutoDeleteTree = on;
982 }
983
984 /*!
985   \brief Get 'auto-update tree' flag value.
986   \return 'auto-update tree' flag value
987   \sa setAutoUpdate(), updateTree()
988 */
989 bool SUIT_TreeModel::autoUpdate() const
990 {
991   return myAutoUpdate;
992 }
993
994 /*!
995   \brief Set 'auto-update tree' flag value.
996
997   If this flag is set to \c true (by default), the model is updated
998   automatically when data tree is changed.
999
1000   \param on 'auto-update tree' flag value
1001   \sa autoUpdate(), updateTree()
1002 */
1003 void SUIT_TreeModel::setAutoUpdate( const bool on )
1004 {
1005   if ( myAutoUpdate == on )
1006     return;
1007
1008   SUIT_DataObject::disconnect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
1009                                this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
1010   SUIT_DataObject::disconnect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
1011                                this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
1012   myAutoUpdate = on;
1013
1014   if ( myAutoUpdate ) {
1015     SUIT_DataObject::connect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
1016                               this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
1017     SUIT_DataObject::connect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
1018                               this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
1019
1020     updateTree();
1021   }
1022 }
1023
1024
1025 /*!
1026   \brief Check if the specified column supports custom sorting.
1027   \param column column index on which data is being sorted
1028   \return \c true if column requires custom sorting
1029   \sa lessThan()
1030 */
1031 bool SUIT_TreeModel::customSorting( const int column ) const
1032 {
1033   return root() ? root()->customSorting( column ) : false;
1034 }
1035
1036 /*!
1037   \brief Compares two model indexes for the sorting purposes.
1038
1039   This method is called only for those columns for which customSorting()
1040   method returns \c true.
1041
1042   \param left first index to compare
1043   \param right second index to compare
1044   \return result of the comparison
1045   \sa customSorting()
1046 */
1047 bool SUIT_TreeModel::lessThan( const QModelIndex& left, const QModelIndex& right ) const
1048 {
1049   QVariant ldata = data( left );
1050   QVariant rdata = data( right );
1051   return root() ? root()->compare( ldata, rdata, left.column() ) : false;
1052 }
1053
1054 /*!
1055   \brief Get item delegate for the model.
1056   \return new item delegate
1057 */
1058 QAbstractItemDelegate* SUIT_TreeModel::delegate() const
1059 {
1060   return new SUIT_ItemDelegate( const_cast<SUIT_TreeModel*>( this ) );
1061 }
1062
1063 /*!
1064   \brief Update tree model.
1065
1066   Call this method when data tree is changed outside the model.
1067   If the 'auto-update' flag is set to \c true, the model
1068   is updated automatically when the data tree is changed.
1069
1070   \param index starting index for the updating
1071   \sa setAutoUpdate()
1072 */
1073 void SUIT_TreeModel::updateTree( const QModelIndex& index )
1074 {
1075   updateTree( object( index ) );
1076 }
1077
1078 /*!
1079   \brief Update tree model.
1080
1081   Call this method when data tree is changed outside the model.
1082   If the 'auto-update' flag is set to \c true, the model
1083   is updated automatically when the data tree is changed.
1084
1085   \param obj starting data object for the updating
1086   \sa setAutoUpdate()
1087 */
1088 void SUIT_TreeModel::updateTree( SUIT_DataObject* obj )
1089 {
1090   if ( !obj )
1091     obj = root();
1092
1093   else if ( obj->root() != root() )
1094     return;
1095
1096   synchronize<ObjPtr,ItemPtr,SUIT_TreeModel::TreeSync>( obj, 
1097                                                         treeItem( obj ), 
1098                                                         SUIT_TreeModel::TreeSync( this ) );
1099   emit modelUpdated();
1100 }
1101
1102 /*!
1103   \brief Initialize tree model.
1104 */
1105 void SUIT_TreeModel::initialize()
1106 {
1107   SUIT_DataObject::disconnect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
1108                                this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
1109   SUIT_DataObject::disconnect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
1110                                this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
1111   if ( autoUpdate() ) {
1112     SUIT_DataObject::connect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
1113                               this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
1114     SUIT_DataObject::connect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
1115                               this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
1116   }
1117
1118   myItems.clear(); // ????? is it really necessary
1119
1120   if ( !myRootItem )
1121     myRootItem = new TreeItem( 0 );
1122
1123   registerColumn( 0, QObject::tr( "NAME_COLUMN" ), SUIT_DataObject::NameId );
1124   updateTree();
1125 }
1126
1127 /*!
1128   \brief Get root tree item.
1129   \return root tree item
1130 */
1131 SUIT_TreeModel::TreeItem* SUIT_TreeModel::rootItem() const
1132 {
1133   return myRootItem;
1134 }
1135
1136 /*!
1137   \brief Get tree item corresponding to the specified model index.
1138   \param index model index
1139   \return tree item or root item if index is invalid
1140 */
1141 SUIT_TreeModel::TreeItem* SUIT_TreeModel::treeItem( const QModelIndex& index ) const
1142 {
1143   return index.isValid() ? static_cast<TreeItem*>( index.internalPointer() ) : rootItem();
1144 }
1145
1146 /*!
1147   \brief Get tree item corresponding to the specified data object.
1148   \param obj data object
1149   \return tree item or 0 if there is no tree item corresponding to \a obj
1150 */
1151 SUIT_TreeModel::TreeItem* SUIT_TreeModel::treeItem( const SUIT_DataObject* obj ) const
1152 {
1153   TreeItem* item = 0;
1154
1155   if ( obj == root() )
1156     item = rootItem();
1157   else if ( myItems.contains( const_cast<SUIT_DataObject*>( obj ) ) )
1158     item = myItems[ const_cast<SUIT_DataObject*>( obj ) ];
1159
1160   return item;
1161 }
1162
1163 /*!
1164   \brief Get data object corresponding to the specified tree item.
1165   \param item tree item
1166   \return data object or 0 if there is no data object corresponding to \a item
1167 */
1168 SUIT_DataObject* SUIT_TreeModel::object( const SUIT_TreeModel::TreeItem* item ) const
1169 {
1170   if ( item == rootItem() )
1171     return root();
1172  
1173   SUIT_DataObject* obj = item ? item->dataObject() : 0;
1174   return myItems.contains( obj ) ? obj : 0;
1175 }
1176
1177 /*!
1178   \brief Create an item corresponding to the data object.
1179   \param obj source data object
1180   \param parent parent tree item
1181   \param after tree item after which new item should be inserted
1182   \return created tree item or 0 if item could not be created
1183 */
1184 SUIT_TreeModel::TreeItem* SUIT_TreeModel::createItem( SUIT_DataObject* obj,
1185                                                       SUIT_TreeModel::TreeItem* parent, 
1186                                                       SUIT_TreeModel::TreeItem* after )
1187 {
1188   if ( !obj )
1189     return 0;
1190
1191   SUIT_DataObject* parentObj = object( parent );
1192   QModelIndex parentIdx = index( parentObj );
1193
1194   SUIT_DataObject* afterObj = after ? object( after ) : 0;
1195   int row = afterObj ? afterObj->position() + 1 : 0;
1196
1197   beginInsertRows( parentIdx, row, row );
1198
1199   myItems[ obj ] = new TreeItem( obj, parent, after );
1200
1201   endInsertRows();
1202
1203   return myItems[ obj ];
1204 }
1205
1206 /*!
1207   \brief Update tree item.
1208   \param item tree item to be updated
1209 */
1210 void SUIT_TreeModel::updateItem( SUIT_TreeModel::TreeItem* item )
1211 {
1212   if ( !item )
1213     return;
1214   
1215   SUIT_DataObject* obj = object( item );
1216   if ( !obj )
1217     return;
1218   
1219   // update all columns corresponding to the given data object
1220   QModelIndex firstIdx = index( obj, 0 );
1221   QModelIndex lastIdx  = index( obj, columnCount() - 1 );
1222   emit dataChanged( firstIdx, lastIdx );
1223 }
1224
1225 /*!
1226   \brief Remove tree item (recursively).
1227   \param item tree item to be removed
1228 */
1229 void SUIT_TreeModel::removeItem( SUIT_TreeModel::TreeItem* item )
1230 {
1231   if ( !item )
1232     return;
1233
1234   // Remove list view items from <myItems> recursively for all children.
1235   // Otherwise, "delete item" line below will destroy all item's children,
1236   // and <myItems> will contain invalid pointers
1237   while( item->childCount() )
1238     removeItem( item->child( 0 ) );
1239
1240   SUIT_DataObject* obj = object( item );
1241   
1242   // Warning! obj can be deleted at this point!
1243
1244   SUIT_DataObject* parentObj = object( item->parent() );
1245   QModelIndex parentIdx = index( parentObj, 0 );
1246   int row = item->position();
1247   
1248   beginRemoveRows( parentIdx, row, row );
1249   myItems.remove( obj );
1250
1251   if ( obj == root() )
1252     setRoot( 0 );
1253   else if ( item->parent() )
1254     item->parent()->removeChild( item );
1255
1256   delete item;
1257
1258   endRemoveRows();
1259 }
1260
1261 /*!
1262   \brief Called when the data object is inserted to the tree.
1263   \param object data object being inserted
1264   \param parent parent data object
1265 */
1266 void SUIT_TreeModel::onInserted( SUIT_DataObject* /*object*/, SUIT_DataObject* parent )
1267 {
1268   if ( autoUpdate() )
1269     updateTree( parent );
1270 }
1271
1272 /*!
1273   \brief Called when the data object is removed from the tree.
1274   \param object data object being removed
1275   \param parent parent data object
1276 */
1277 void SUIT_TreeModel::onRemoved( SUIT_DataObject* /*object*/, SUIT_DataObject* parent )
1278 {
1279   if ( autoUpdate() )
1280     updateTree( parent );
1281 }
1282
1283 /*!
1284   \class SUIT_ProxyModel
1285   \brief Proxy model which can be used above the SUIT_TreeMovel class
1286   to enable custom sorting/filtering of the data.
1287
1288   The SUIT_TreeModel class does not support custom sorting/filtering of the data.
1289   To use these features, the SUIT_ProxyModel class can be used as top-level
1290   wrapper for the SUIT_DataObject-based data tree model.
1291 */
1292
1293 /*!
1294   \brief Constructor.
1295   \param parent parent object
1296 */
1297 SUIT_ProxyModel::SUIT_ProxyModel( QObject* parent )
1298 : QSortFilterProxyModel( parent ),
1299   mySortingEnabled( true )
1300 {
1301   SUIT_TreeModel* model = new SUIT_TreeModel( this );
1302   connect( model, SIGNAL( modelUpdated() ), this, SIGNAL( modelUpdated() ) );
1303   setSourceModel( model );
1304 }
1305
1306 /*!
1307   \brief Constructor.
1308   \param root root data object
1309   \param parent parent object
1310 */
1311 SUIT_ProxyModel::SUIT_ProxyModel( SUIT_DataObject* root, QObject* parent )
1312 : QSortFilterProxyModel( parent ),
1313   mySortingEnabled( true )
1314 {
1315   SUIT_TreeModel* model = new SUIT_TreeModel( root, this );
1316   connect( model, SIGNAL( modelUpdated() ), this, SIGNAL( modelUpdated() ) );
1317   setSourceModel( model );
1318 }
1319
1320 /*!
1321   \brief Constructor.
1322   \param model tree model
1323   \param parent parent object
1324 */
1325 SUIT_ProxyModel::SUIT_ProxyModel( SUIT_AbstractModel* model, QObject* parent )
1326 : QSortFilterProxyModel( parent ),
1327   mySortingEnabled( true )
1328 {
1329   connect( *model, SIGNAL( modelUpdated() ), this, SIGNAL( modelUpdated() ) );
1330   setSourceModel( *model );
1331 }
1332
1333 /*!
1334   \brief Destructor.
1335 */
1336 SUIT_ProxyModel::~SUIT_ProxyModel()
1337 {
1338 }
1339
1340 /*!
1341   \brief Get data tree root object.
1342   \return data tree root
1343   \sa setRoot()
1344 */
1345 SUIT_DataObject* SUIT_ProxyModel::root() const
1346 {
1347   return treeModel() ? treeModel()->root() : 0;
1348 }
1349
1350 /*!
1351   \brief Set data tree root object.
1352   \param r new data tree root
1353   \sa root()
1354 */
1355 void SUIT_ProxyModel::setRoot( SUIT_DataObject* r )
1356 {
1357   if ( treeModel() )
1358     treeModel()->setRoot( r );
1359 }
1360
1361 /*!
1362   \brief Get data object by the specified model index.
1363   \param index model index
1364   \return data object corresponding to the model index
1365 */
1366 SUIT_DataObject* SUIT_ProxyModel::object( const QModelIndex& index ) const
1367 {
1368   return treeModel() ? treeModel()->object( mapToSource( index ) ) : 0;
1369 }
1370
1371 /*!
1372   \brief Get model index by the specified data object.
1373   \param obj data object
1374   \param column data object column
1375   \return model index
1376 */
1377 QModelIndex SUIT_ProxyModel::index( const SUIT_DataObject* obj, int column ) const
1378 {
1379   return treeModel() ? mapFromSource( treeModel()->index( obj, column ) ) : QModelIndex();
1380 }
1381
1382 /*!
1383   \brief Get 'auto-delete data tree' flag value.
1384   \return 'auto-delete data tree' flag value
1385   \sa setAutoDeleteTree()
1386 */
1387 bool SUIT_ProxyModel::autoDeleteTree() const
1388 {
1389   return treeModel() ? treeModel()->autoDeleteTree() : false;
1390 }
1391
1392 /*!
1393   \brief Set 'auto-delete data tree' flag value.
1394
1395   If this flag is set to \c true, the data tree is deleted when
1396   the tree model is destroyed. Default value for this flag is \c false.
1397
1398   \param on 'auto-delete data tree' flag value
1399   \sa autoDeleteTree()
1400 */
1401 void SUIT_ProxyModel::setAutoDeleteTree( const bool on )
1402 {
1403   if ( treeModel() )
1404     treeModel()->setAutoDeleteTree( on );
1405 }
1406
1407 /*!
1408   \brief Get 'auto-update tree' flag value.
1409   \return 'auto-update tree' flag value
1410   \sa setAutoUpdate(), updateTree()
1411 */
1412 bool SUIT_ProxyModel::autoUpdate() const
1413 {
1414   return treeModel() ? treeModel()->autoUpdate() : false;
1415 }
1416
1417 /*!
1418   \brief Set 'auto-update tree' flag value.
1419
1420   If this flag is set to \c true (by default), the model is updated
1421   automatically when data tree is changed.
1422
1423   \param on 'auto-update tree' flag value
1424   \sa autoUpdate(), updateTree()
1425 */
1426 void SUIT_ProxyModel::setAutoUpdate( const bool on )
1427 {
1428   if ( treeModel() )
1429     treeModel()->setAutoUpdate( on );
1430 }
1431
1432 /*!
1433   \brief Check if sorting is enabled.
1434   \return \c true if sorting is enabled
1435   \sa setSortingEnabled()
1436 */
1437 bool SUIT_ProxyModel::isSortingEnabled() const
1438 {
1439   return mySortingEnabled;
1440 }
1441
1442 /*!
1443   \brief Get item delegate for the model.
1444   \return new item delegate
1445 */
1446 QAbstractItemDelegate* SUIT_ProxyModel::delegate() const
1447 {
1448   return treeModel() ? treeModel()->delegate() : 0;
1449 }
1450
1451 /*!
1452   \brief Update tree model.
1453
1454   Call this method when data tree is changed outside the model.
1455   If the 'auto-update' flag is set to \c true, the model
1456   is updated automatically when the data tree is changed.
1457
1458   \param index starting index for the updating
1459   \sa setAutoUpdate()
1460 */
1461 void SUIT_ProxyModel::updateTree( const QModelIndex& index )
1462 {
1463   if ( treeModel() )
1464     treeModel()->updateTree( mapToSource( index ) );
1465 }
1466
1467 /*!
1468   \brief Update tree model.
1469
1470   Call this method when data tree is changed outside the model.
1471   If the 'auto-update' flag is set to \c true, the model
1472   is updated automatically when the data tree is changed.
1473
1474   \param obj starting data object for the updating
1475   \sa setAutoUpdate()
1476 */
1477 void SUIT_ProxyModel::updateTree( SUIT_DataObject* obj )
1478 {
1479   if ( treeModel() )
1480     treeModel()->updateTree( obj );
1481 }
1482
1483 /*!
1484   \brief Compares two model indexes for the sorting purposes.
1485   \param left first index to compare
1486   \param right second index to compare
1487   \return result of the comparison
1488 */
1489 bool SUIT_ProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right ) const
1490 {
1491   if ( !isSortingEnabled() && left.isValid() && right.isValid() ) {
1492     return left.row() < right.row();
1493   }
1494   if ( treeModel() && treeModel()->customSorting( left.column() ) ) {
1495     return treeModel()->lessThan( left, right );
1496   }
1497   return QSortFilterProxyModel::lessThan( left, right );
1498 }
1499
1500 /*!
1501   \brief Check if the specified column supports custom sorting.
1502   \param column column index on which data is being sorted
1503   \return \c true if column requires custom sorting
1504   \sa lessThan()
1505 */
1506 bool SUIT_ProxyModel::customSorting( const int column ) const
1507 {
1508   return treeModel() ? treeModel()->customSorting( column ) : false;
1509 }
1510
1511 /*!
1512   \brief Enable/disable sorting.
1513   \param enabled new flag state
1514   \sa isSortingEnabled()
1515 */
1516 void SUIT_ProxyModel::setSortingEnabled( bool enabled )
1517 {
1518   mySortingEnabled = enabled;
1519   clear();
1520 }
1521
1522 /*
1523   \brief Get tree model.
1524   \return tree model
1525 */
1526 SUIT_AbstractModel* SUIT_ProxyModel::treeModel() const
1527 {
1528   return dynamic_cast<SUIT_AbstractModel*>( sourceModel() );
1529 }
1530
1531 /*!
1532   \brief Register new column in the model
1533   \param group_id - unique data object identificator allowing the classification of objects 
1534   \param name - translated column name
1535   \param custom_id - custom column id that should be passed into method SUIT_DataObject::data()
1536  */
1537 void SUIT_ProxyModel::registerColumn( const int group_id, const QString& name, const int custom_id )
1538 {
1539   if( treeModel() )
1540     treeModel()->registerColumn( group_id, name, custom_id );
1541 }
1542
1543 /*!
1544   \brief Remove column from the model
1545
1546   Please take into account that column is removed only for given group_id, it means
1547   that information of data objects with such group_id won't be shown.
1548   If there is not any registered group_id for this column after removing, the column will be hidden
1549   otherwise it continue to be shown
1550
1551   \param group_id - unique data object identificator allowing the classification of objects 
1552   \param name - translated column name
1553  */
1554 void SUIT_ProxyModel::unregisterColumn( const int group_id, const QString& name )
1555 {
1556   if( treeModel() )
1557     treeModel()->unregisterColumn( group_id, name );
1558 }
1559
1560 /*!
1561   \brief Change column icon.
1562
1563   \param name - column name
1564   \param icon - new icon of the specified column
1565 */
1566 void SUIT_ProxyModel::setColumnIcon( const QString& name, const QPixmap& icon )
1567 {
1568   if( treeModel() )
1569     treeModel()->setColumnIcon( name, icon );
1570 }
1571
1572 /*!
1573   \brief Get column icon.
1574
1575   \param name - column name
1576   \return icon of the specified column
1577 */
1578 QPixmap SUIT_ProxyModel::columnIcon( const QString& name ) const
1579 {
1580   return treeModel() ? treeModel()->columnIcon( name ) : QPixmap();
1581 }
1582
1583 /*!
1584   \brief Change appropriate status
1585   
1586   Appropriate status determines if the column should appear in the tree view header popup menu
1587   (to show/hide the column).
1588
1589   If appropriate status is not specified yet, the \c Shown value is taken,
1590   it means that column should be always visible.
1591
1592   \param name - column name
1593   \param appr - new appropriate status
1594 */
1595 void SUIT_ProxyModel::setAppropriate( const QString& name, const Qtx::Appropriate appr )
1596 {
1597   if( treeModel() )
1598     treeModel()->setAppropriate( name, appr );
1599 }
1600
1601 /*!
1602   \brief Check if the column should appear in the tree view header popup menu
1603   (to show/hide the column).
1604
1605   Default implementation (if appropriate status is not specified yet)
1606   returns \c Shown, it means that column should be always visible.
1607
1608   \param name - column name
1609   \return appropriate status
1610 */
1611 Qtx::Appropriate SUIT_ProxyModel::appropriate( const QString& name ) const
1612 {
1613   return treeModel() ? treeModel()->appropriate( name ) : Qtx::Shown;
1614 }
1615
1616
1617
1618
1619
1620
1621 /*!
1622   \class SUIT_ItemDelegate
1623   \brief An SUIT_DataObject-based item delegate class.
1624
1625   This class can be used to render the SUIT_DataObject-based item
1626   in the widgets like QTreeView and others.
1627   Refer to the Qt 4 documentation, model/view architecture 
1628   section for more details).
1629 */
1630
1631 /*!
1632   \brief Constructor.
1633   \param parent parent object
1634 */
1635 SUIT_ItemDelegate::SUIT_ItemDelegate( QObject* parent )
1636 : QItemDelegate( parent )
1637 {
1638 }
1639
1640 /*!
1641   \brief Render the item in the widget.
1642
1643   Customizes the item colors for the specific roles.
1644
1645   \param painter painter
1646   \param option painting option
1647   \param index model index being rendered
1648 */
1649 void SUIT_ItemDelegate::paint( QPainter* painter, 
1650                                const QStyleOptionViewItem& option,
1651                                const QModelIndex& index ) const
1652 {
1653   QStyleOptionViewItem opt = option;
1654   if ( index.isValid() ) {
1655     // Note: we check into account only custom roles; other roles are process
1656     //       correctly by the QItemDelegate class
1657     QVariant val = index.data( SUIT_TreeModel::BaseColorRole );
1658     if ( val.isValid() && val.value<QColor>().isValid() ) {
1659       QColor aBase = val.value<QColor>();
1660       aBase.setAlpha( 0 );
1661       opt.palette.setBrush( QPalette::Base, val.value<QColor>() );
1662     }
1663     val = index.data( SUIT_TreeModel::TextColorRole );
1664     if ( val.isValid() && val.value<QColor>().isValid() )
1665       opt.palette.setBrush( QPalette::Text, val.value<QColor>() );
1666     val = index.data( SUIT_TreeModel::HighlightRole );
1667     if ( val.isValid() && val.value<QColor>().isValid() )
1668       opt.palette.setBrush( QPalette::Highlight, val.value<QColor>() );
1669     val = index.data( SUIT_TreeModel::HighlightedTextRole );
1670     if ( val.isValid() && val.value<QColor>().isValid() )
1671       opt.palette.setBrush( QPalette::HighlightedText, val.value<QColor>() );
1672   }
1673   QItemDelegate::paint( painter, opt, index );
1674 }