Back to index

salome-gui  6.5.0
SUIT_TreeModel.cxx
Go to the documentation of this file.
00001 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
00002 //
00003 // This library is free software; you can redistribute it and/or
00004 // modify it under the terms of the GNU Lesser General Public
00005 // License as published by the Free Software Foundation; either
00006 // version 2.1 of the License.
00007 //
00008 // This library is distributed in the hope that it will be useful,
00009 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00010 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011 // Lesser General Public License for more details.
00012 //
00013 // You should have received a copy of the GNU Lesser General Public
00014 // License along with this library; if not, write to the Free Software
00015 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
00016 //
00017 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
00018 //
00019 
00020 // File:   SUIT_TreeModel.cxx
00021 // Author: Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
00022 
00023 #include "SUIT_Session.h"
00024 #include "SUIT_TreeModel.h"
00025 #include "SUIT_TreeSync.h"
00026 #include "SUIT_DataObject.h"
00027 #include "SUIT_ResourceMgr.h"
00028 
00029 #include <QApplication>
00030 #include <QHash>
00031 #include <QMimeData>
00032 
00033 SUIT_AbstractModel::SUIT_AbstractModel() : mySearcher( 0 )
00034 {
00035 }
00036 
00037 SUIT_AbstractModel::operator const QAbstractItemModel*() const
00038 {
00039   return dynamic_cast<const QAbstractItemModel*>( this );
00040 }
00041 
00042 SUIT_AbstractModel::operator QAbstractItemModel*()
00043 {
00044   return dynamic_cast<QAbstractItemModel*>( this );
00045 }
00046 
00047 SUIT_AbstractModel::operator const QObject*() const
00048 {
00049   return dynamic_cast<const QObject*>( this );
00050 }
00051 
00052 SUIT_DataSearcher* SUIT_AbstractModel::searcher() const
00053 {
00054   return mySearcher;
00055 }
00056 
00057 void SUIT_AbstractModel::setSearcher( SUIT_DataSearcher* s )
00058 {
00059   mySearcher = s;
00060 }
00061 
00062 
00069 class SUIT_TreeModel::TreeItem
00070 {
00071 public:
00072   TreeItem( SUIT_DataObject* obj, TreeItem* parent = 0, TreeItem* after = 0 );
00073   ~TreeItem();
00074 
00075   void                  insertChild( TreeItem* child, TreeItem* after = 0 );
00076   void                  removeChild( TreeItem* child );
00077   SUIT_DataObject*      dataObject() const;
00078   TreeItem*             parent() const;
00079   int                   position() const;
00080   void                  setPosition(int position) {_position=position;};
00081   int                   childCount() const;
00082   TreeItem*             child( const int i );
00083   QList<TreeItem*>      children() const;
00084   TreeItem*             nextSibling() const;
00085   TreeItem*             prevSibling() const;
00086   
00087 private:
00088   TreeItem*             myParent;
00089   QList<TreeItem*>      myChildren;
00090   SUIT_DataObject*      myObj;
00091   int _position;
00092 };
00093 
00101 SUIT_TreeModel::TreeItem::TreeItem( SUIT_DataObject*          obj, 
00102                                     SUIT_TreeModel::TreeItem* parent,
00103                                     SUIT_TreeModel::TreeItem* after )
00104 : myParent( parent ),
00105   myObj( obj ),
00106   _position(-1)
00107 {
00108   // Add <this> to the parent's children list
00109   if ( myParent )
00110     myParent->insertChild( this, after );
00111 }
00112 
00117 SUIT_TreeModel::TreeItem::~TreeItem()
00118 {
00119   // Ensure that all children are deleted;
00120   // each child removes itself from the children list
00121   while( myChildren.count() )
00122     delete myChildren.at( 0 );
00123 
00124   // Remove this item from the parent's children list
00125   if ( myParent )
00126     myParent->removeChild( this );
00127 }
00128 
00135 void SUIT_TreeModel::TreeItem::insertChild( SUIT_TreeModel::TreeItem* child, 
00136                                             SUIT_TreeModel::TreeItem* after )
00137 {
00138   if ( !child )
00139     return;
00140 
00141   int index = after ? after->position() + 1 : 0;
00142   myChildren.insert( index, child );
00143 }
00144 
00150 void SUIT_TreeModel::TreeItem::removeChild( SUIT_TreeModel::TreeItem* child )
00151 {
00152   if ( !child )
00153     return;
00154   myChildren.removeAll( child );
00155 }
00156 
00162 SUIT_DataObject* SUIT_TreeModel::TreeItem::dataObject() const
00163 {
00164   return myObj;
00165 }
00166 
00172 SUIT_TreeModel::TreeItem* SUIT_TreeModel::TreeItem::parent() const
00173 {
00174   return myParent;
00175 }
00176 
00182 int SUIT_TreeModel::TreeItem::position() const
00183 {
00184   return _position;
00185 }
00186 
00192 int SUIT_TreeModel::TreeItem::childCount() const
00193 {
00194   return myChildren.count();
00195 }
00196 
00203 SUIT_TreeModel::TreeItem* SUIT_TreeModel::TreeItem::child( const int i )
00204 {
00205   return i >= 0 && i < myChildren.count() ? myChildren.at( i ) : 0;
00206 }
00207 
00213 QList<SUIT_TreeModel::TreeItem*> SUIT_TreeModel::TreeItem::children() const
00214 {
00215   return myChildren;
00216 }
00217 
00223 SUIT_TreeModel::TreeItem* SUIT_TreeModel::TreeItem::nextSibling() const
00224 {
00225   return parent() ? parent()->child( position()+1 ) : 0;
00226 }
00227 
00233 SUIT_TreeModel::TreeItem* SUIT_TreeModel::TreeItem::prevSibling() const
00234 {
00235   return parent() ? parent()->child( position()-1 ) : 0;
00236 }
00237 
00245 class SUIT_TreeModel::TreeSync
00246 {
00247 public:
00248   TreeSync( SUIT_TreeModel* );
00249   bool              isEqual( const ObjPtr&, const ItemPtr& ) const;
00250   ObjPtr            nullSrc() const;
00251   ItemPtr           nullTrg() const;
00252   ItemPtr           createItem( const ObjPtr&, const ItemPtr&, const ItemPtr& ) const;
00253   void              updateItem( const ObjPtr&, const ItemPtr& ) const;
00254   void              deleteItemWithChildren( const ItemPtr& ) const;
00255   QList<ObjPtr>     children( const ObjPtr& ) const;
00256   QList<ItemPtr>    children( const ItemPtr& ) const;
00257   ItemPtr           parent( const ItemPtr& ) const;
00258 private:
00259   bool              needUpdate( const ItemPtr& ) const;
00260   SUIT_TreeModel*   myModel;
00261 };
00262 
00268 SUIT_TreeModel::TreeSync::TreeSync( SUIT_TreeModel* model )
00269 : myModel( model )
00270 {
00271 }
00272 
00280 bool SUIT_TreeModel::TreeSync::isEqual( const ObjPtr& obj, const ItemPtr& item ) const
00281 {
00282   bool isRoot = obj == myModel->root() && item == myModel->rootItem(),
00283        isEq   = obj && item && item->dataObject() == obj;
00284   return isRoot || ( !obj && !item ) || isEq;
00285 }
00286 
00292 SUIT_TreeModel::ObjPtr SUIT_TreeModel::TreeSync::nullSrc() const
00293 {
00294   return 0;
00295 }
00296 
00302 SUIT_TreeModel::ItemPtr SUIT_TreeModel::TreeSync::nullTrg() const
00303 {
00304   return 0;
00305 }
00306 
00315 SUIT_TreeModel::ItemPtr SUIT_TreeModel::TreeSync::createItem( const ObjPtr&  obj,
00316                                                               const ItemPtr& parent, 
00317                                                               const ItemPtr& after ) const
00318 {
00319   ItemPtr item = myModel ? myModel->createItem( obj, parent, after ) : 0;
00320 
00321   // Additional actions that can't be performed by the model, e.g. expanded state
00322   if( item )
00323     obj->update();
00324   return item;
00325 }
00326 
00333 void SUIT_TreeModel::TreeSync::updateItem( const ObjPtr& obj, const ItemPtr& item ) const
00334 {
00335   if( obj )
00336     obj->update();
00337   if ( item && needUpdate( item ) ) 
00338     myModel->updateItem( item, false );
00339 }
00340 
00346 void SUIT_TreeModel::TreeSync::deleteItemWithChildren( const ItemPtr& item ) const
00347 {
00348   // NOTE: item is deleted inside removeItem()!
00349   myModel->removeItem( item );
00350 }
00351 
00358 QList<SUIT_TreeModel::ObjPtr> SUIT_TreeModel::TreeSync::children( const ObjPtr& obj ) const
00359 {
00360   QList<ObjPtr> ch;
00361   if ( obj )
00362     ch = obj->children();
00363   return ch;
00364 }
00365 
00372 QList<SUIT_TreeModel::ItemPtr> SUIT_TreeModel::TreeSync::children( const ItemPtr& item ) const
00373 {
00374   QList<ItemPtr> ch;
00375   if ( item ) 
00376     ch = item->children();
00377   return ch;
00378 }
00379 
00386 SUIT_TreeModel::ItemPtr SUIT_TreeModel::TreeSync::parent( const ItemPtr& item ) const
00387 {
00388   return item ? item->parent() : 0;
00389 }
00390 
00399 bool SUIT_TreeModel::TreeSync::needUpdate( const ItemPtr& item ) const
00400 {
00401   bool update = false;
00402   if ( item ) {
00403     SUIT_DataObject* obj = item->dataObject();
00404     if ( obj ) {
00405       // TODO: find simplified way to check if an item is not up-to-date:
00406       // - use check-sum of various item data
00407       // - use "LastModified" time stamp in data objects and tree items - hardly possible, for sometimes data objects do not know that data changes...
00408       // ...
00409       update = true; // TEMPORARY!!!
00410       // 1. check text
00411 /*      update = ( item->text( 0 ) != obj->name() ) || myBrowser->needToUpdateTexts( item );
00412 
00413       if ( !update ) { 
00414         // 2. check pixmap (compare serialNumber()-s)
00415         QPixmap objPix = obj->icon();
00416         const QPixmap* itemPix = item->pixmap( 0 );
00417         update = (  objPix.isNull() && (  itemPix && !itemPix->isNull() ) ) || 
00418                  ( !objPix.isNull() && ( !itemPix ||  itemPix->isNull() ) ); 
00419         if ( !update && !objPix.isNull() && itemPix && !itemPix->isNull() ) {
00420           int aIconW = objPix.width();
00421           if( aIconW > 20 ) {
00422             QWMatrix aM;
00423             double aScale = 20.0 / aIconW;
00424             aM.scale( aScale, aScale );
00425             objPix = objPix.xForm( aM );
00426           }
00427           update = ( objPix.serialNumber() != itemPix->serialNumber() );
00428         }
00429       }*/
00430     }
00431   }
00432   return update;
00433 }
00434 
00449 SUIT_TreeModel::SUIT_TreeModel( QObject* parent )
00450 : QAbstractItemModel( parent ),
00451   myRoot( 0 ),
00452   myRootItem( 0 ),
00453   myAutoDeleteTree( false ),
00454   myAutoUpdate( true ),
00455   myUpdateModified( false )
00456 {
00457   initialize();
00458 }
00459 
00465 SUIT_TreeModel::SUIT_TreeModel( SUIT_DataObject* root, QObject* parent )
00466 : QAbstractItemModel( parent ),
00467   myRoot( root ),
00468   myRootItem( 0 ),
00469   myAutoDeleteTree( false ),
00470   myAutoUpdate( true ),
00471   myUpdateModified( false )
00472 {
00473   initialize();
00474 }
00475 
00479 SUIT_TreeModel::~SUIT_TreeModel()
00480 {
00481   if ( autoDeleteTree() ) {
00482     SUIT_DataObject::disconnect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
00483                                  this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
00484     SUIT_DataObject::disconnect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
00485                                  this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
00486     delete myRoot;
00487   }
00488 
00489   delete myRootItem;
00490 }
00491 
00498 void SUIT_TreeModel::registerColumn( const int group_id, const QString& name, const int custom_id )
00499 {
00500   bool found = false;
00501   for ( int i=0, n=myColumns.size(); i<n && !found; i++ ) {
00502     if ( name == myColumns[i].myName ) {
00503       myColumns[i].myIds.insert( group_id, custom_id );
00504       found = true;
00505     }
00506   }
00507   if ( !found ) {
00508     ColumnInfo inf;
00509     inf.myName = name;
00510     inf.myIds.insert( group_id, custom_id );
00511     inf.myAppropriate = Qtx::Shown;
00512     inf.myHeaderFlags = Qtx::ShowAll;
00513     int n = myColumns.size();
00514     myColumns.resize( n+1 );
00515     myColumns[n] = inf;
00516     reset();
00517   }
00518 }
00519 
00531 void SUIT_TreeModel::unregisterColumn( const int group_id, const QString& name )
00532 {
00533   for ( int i = 0, n = myColumns.size(); i < n; i++ ) {
00534     if ( myColumns[i].myName == name ) {
00535       myColumns[i].myIds.remove( group_id );
00536       if ( myColumns[i].myIds.isEmpty() ) {
00537        myColumns.remove( i );
00538        reset();
00539       }
00540       break;
00541     }
00542   }
00543 }
00544 
00551 void SUIT_TreeModel::setColumnIcon( const QString& name, const QPixmap& icon )
00552 {
00553   for ( int i = 0, n = myColumns.size(); i < n; i++ ) {
00554     if ( myColumns[i].myName == name ) {
00555       myColumns[i].myIcon = icon;
00556       break;
00557     }
00558   }
00559 }
00560 
00567 QPixmap SUIT_TreeModel::columnIcon( const QString& name ) const
00568 {
00569   QPixmap res;
00570   for ( int i = 0, n = myColumns.size(); i < n; i++ ) {
00571     if ( myColumns[i].myName == name ) {
00572       res = myColumns[i].myIcon;
00573       break;
00574     }
00575   }
00576   return res;
00577 }
00578 
00591 void SUIT_TreeModel::setAppropriate( const QString& name, const Qtx::Appropriate appr )
00592 {
00593   for ( int i = 0, n = myColumns.size(); i < n; i++ ) {
00594     if ( myColumns[i].myName == name && myColumns[i].myAppropriate != appr ) {
00595       myColumns[i].myAppropriate = appr;
00596       emit headerDataChanged( Qt::Horizontal, i, i );
00597       break;
00598     }
00599   }
00600 }
00601 
00612 Qtx::Appropriate SUIT_TreeModel::appropriate( const QString& name ) const
00613 {
00614   Qtx::Appropriate appr = Qtx::Shown;
00615   for ( int i = 0, n = myColumns.size(); i < n; i++ ) {
00616     if ( myColumns[i].myName == name ) {
00617       appr = myColumns[i].myAppropriate;
00618       break;
00619     }
00620   }
00621   return appr;
00622 }
00623 
00624 
00635 void SUIT_TreeModel::setHeaderFlags( const QString& name, const Qtx::HeaderViewFlags flags )
00636 {
00637   for ( int i = 0, n = myColumns.size(); i < n; i++ ) {
00638     if ( myColumns[i].myName == name && myColumns[i].myHeaderFlags != flags ) {
00639       myColumns[i].myHeaderFlags = flags;
00640       emit headerDataChanged( Qt::Horizontal, i, i );
00641       break;
00642     }
00643   }
00644 }
00645 
00655 Qtx::HeaderViewFlags SUIT_TreeModel::headerFlags( const QString& name ) const
00656 {
00657   Qtx::HeaderViewFlags flags;
00658   for ( int i = 0, n = myColumns.size(); i < n; i++ ) {
00659     if ( myColumns[i].myName == name ) {
00660       flags = myColumns[i].myHeaderFlags;
00661       break;
00662     }
00663   }
00664   return flags;
00665 }
00666 
00673 void SUIT_TreeModel::setVisibilityState( const QString& id, Qtx::VisibilityState state )
00674 {
00675   VisibilityMap::const_iterator it = myVisibilityMap.find( id );
00676   if ( it != myVisibilityMap.end() && it.value() == state )
00677     return;
00678   
00679   bool needSignal = false;
00680   if ( state != Qtx::UnpresentableState ) {
00681     myVisibilityMap.insert( id, state );
00682     needSignal = true;
00683   }
00684   else {
00685     needSignal = myVisibilityMap.remove( id ) > 0;
00686   }
00687   if ( needSignal ) {
00688     QModelIndexList lst;
00689     if ( searcher() ) {
00690       SUIT_DataObject* o = searcher()->findObject( id );
00691       if ( o ) lst << index( o );
00692     }
00693     else {
00694       lst = match( index( 0, root()->customData( Qtx::IdType ).toInt() ), DisplayRole, id, 1, Qt::MatchExactly | Qt::MatchRecursive );
00695     }
00696     if ( !lst.isEmpty() ) {
00697       QModelIndex idx = index( lst.first().row(), SUIT_DataObject::VisibilityId, lst.first().parent() );
00698       emit dataChanged( idx, idx );
00699     }
00700   }
00701 }
00702 
00709 void SUIT_TreeModel::setVisibilityStateForAll( Qtx::VisibilityState state )
00710 {
00711   if ( state != Qtx::UnpresentableState ) {
00712     VisibilityMap::ConstIterator it = myVisibilityMap.begin();
00713     while ( it != myVisibilityMap.end() ) {
00714       if ( it.value() != state )
00715        setVisibilityState( it.key(), state );
00716       it++;
00717     }
00718   }
00719   else {
00720     QList<QString> anIds = myVisibilityMap.keys();
00721     myVisibilityMap.clear();
00722     QList<QString>::ConstIterator it = anIds.begin();
00723     while ( it != anIds.end() ) {
00724       QModelIndexList lst;
00725       if ( searcher() ) {
00726        SUIT_DataObject* o = searcher()->findObject( *it );
00727        if ( o ) lst << index( o );
00728       }
00729       else {
00730        lst = match( index( 0, root()->customData( Qtx::IdType ).toInt() ), DisplayRole, (*it), 1, Qt::MatchExactly | Qt::MatchRecursive );
00731       }
00732       if ( !lst.isEmpty() ) {
00733        QModelIndex idx = index( lst.first().row(), SUIT_DataObject::VisibilityId ,lst.first().parent() );
00734        emit dataChanged( idx, idx );
00735       }
00736       it++;
00737     }
00738   }
00739 }
00740 
00747 Qtx::VisibilityState SUIT_TreeModel::visibilityState( const QString& id ) const
00748 {
00749   VisibilityMap::const_iterator it = myVisibilityMap.find( id );
00750   return it != myVisibilityMap.end() ? it.value() : Qtx::UnpresentableState;
00751 }
00752 
00758 SUIT_DataObject* SUIT_TreeModel::root() const
00759 {
00760   return myRoot;
00761 }
00762 
00768 void SUIT_TreeModel::setRoot( SUIT_DataObject* r )
00769 {
00770   if ( root() == r )
00771     return;
00772 
00773   if ( autoDeleteTree() ) {
00774     SUIT_DataObject::disconnect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
00775                                  this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
00776     SUIT_DataObject::disconnect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
00777                                  this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
00778     delete myRoot;
00779   }
00780 
00781   myRoot = r;
00782 
00783   //initialize();
00784   reset();
00785   emit modelUpdated();
00786 }
00787 
00795 QVariant SUIT_TreeModel::data( const QModelIndex& index, int role ) const
00796 {
00797   if ( !index.isValid() )
00798     return QVariant();
00799 
00800   SUIT_DataObject* obj = object( index );
00801   if ( !obj )
00802     return QVariant();
00803 
00804   QColor c;
00805   QVariant val;
00806 
00807   int obj_group_id = obj->groupId();
00808   const ColumnInfo& inf = myColumns[index.column()];
00809 
00810   int id = -1;
00811   if( inf.myIds.contains( 0 ) )
00812     id = inf.myIds[0];
00813   if( inf.myIds.contains( obj_group_id ) )
00814     id = inf.myIds[obj_group_id];
00815 
00816   if( id<0 )
00817     return QVariant();
00818 
00819   if ( obj )
00820   {
00821     switch ( role )
00822         {
00823     case DisplayRole:
00824       // data object text for the specified column
00825       val = obj->text( id );
00826       break;
00827     case EditRole:
00828       // data object text for the specified column (for editor)
00829       val = obj->text( id );
00830       break;
00831     case DecorationRole: {
00832       // icon
00833       if ( id == SUIT_DataObject::VisibilityId ) {
00834        // for visibility column, icon is defined specifically (using data object id)
00835        QString objId = objectId( index );
00836        if ( myVisibilityMap.contains( objId ) ) {
00837          // visibility status is defined -> return proper icon
00838          SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();    
00839          val  = ( myVisibilityMap.value( objId ) == Qtx::ShownState ) ? 
00840            resMgr->loadPixmap( "SUIT", tr( "ICON_DATAOBJ_VISIBLE" ) ) : 
00841            resMgr->loadPixmap( "SUIT", tr( "ICON_DATAOBJ_INVISIBLE" ) );
00842        } 
00843        else {
00844          // visibility status is undefined -> no icon
00845          val = QIcon();
00846        }
00847       }
00848       else {
00849        // for other columns get icon from the object
00850        val = obj->icon( id );
00851       }
00852       break;
00853     }
00854     case ToolTipRole:
00855       // data object tooltip for the specified column
00856       val = obj->toolTip( id ); 
00857       break;
00858     case StatusTipRole:
00859       // data object status tip for the specified column
00860       val = obj->statusTip( id ); 
00861       break;
00862     case WhatsThisRole:
00863       // data object what's this info for the specified column
00864       val = obj->whatsThis( id ); 
00865       break;
00866     case FontRole:
00867       // data object font for the specified column
00868       val = obj->font( id ); 
00869       break;
00870     case TextAlignmentRole:
00871       // data object text alignment for the specified column
00872       val = obj->alignment( id ); 
00873       break;
00874     case BackgroundRole:
00875       // data background color for the specified column
00876       c = obj->color( SUIT_DataObject::Background, id );
00877       if( !c.isValid() ) // default value
00878             c = QApplication::palette().color( QPalette::Base );
00879       c.setAlpha( 0 );
00880       val = c; 
00881       break;
00882     case ForegroundRole:
00883       // data foreground (text) color for the specified column
00884       c = obj->color( SUIT_DataObject::Foreground, id );
00885       if( !c.isValid() ) // default value
00886             c = QApplication::palette().color( QPalette::Foreground );
00887       val = c; 
00888       break;
00889     case BaseColorRole:
00890       // editor background color for the specified column
00891       c = obj->color( SUIT_DataObject::Base, id );
00892       if( !c.isValid() ) // default value
00893             c = QApplication::palette().color( QPalette::Base );
00894       val = c; 
00895       break;
00896     case TextColorRole:
00897       // editor foreground (text) color for the specified column
00898       c = obj->color( SUIT_DataObject::Text, id );
00899       if( !c.isValid() ) // default value
00900             c = QApplication::palette().color( QPalette::Text );
00901       val = c; 
00902       break;
00903     case HighlightRole:
00904       // adta object highlighted background color for the specified column
00905       c = obj->color( SUIT_DataObject::Highlight, id );
00906       if( !c.isValid() ) // default value
00907             c = QApplication::palette().color( QPalette::Highlight );
00908       val = c; 
00909       break;
00910     case HighlightedTextRole:
00911       // data object highlighted foreground (text) color for the specified column
00912       c = obj->color( SUIT_DataObject::HighlightedText, id );
00913       if( !c.isValid() ) // default value
00914             c = QApplication::palette().color( QPalette::HighlightedText );
00915       val = c; 
00916       break;
00917     case CheckStateRole:
00918       // data object checked state for the specified column
00919       // NOTE! three-state check is not supported currently
00920       if( obj->isCheckable( id ) )
00921             val = obj->isOn( id ) ? Qt::Checked : Qt::Unchecked; 
00922       break;
00923     case SizeHintRole:
00924       // data size hint
00925       // NOTE! not supported currently
00926       break;
00927     default:
00928       break;
00929     } // ... switch ( role ) ...
00930   } // ... if ( obj ) ...
00931   return val;
00932 }
00933 
00942 bool SUIT_TreeModel::setData( const QModelIndex& index, 
00943                               const QVariant& value, int role )
00944 {
00945   if ( index.isValid() && value.isValid() ) {
00946     SUIT_DataObject* obj = object( index );
00947     if ( obj ) {
00948       // NOTE! only 'check state' data is supported by default
00949       switch ( role ) {
00950       case CheckStateRole:
00951         // checked state
00952         if ( obj->isCheckable( index.column() ) ) {
00953           obj->setOn( value.toBool(), index.column() );
00954           emit( dataChanged( index, index ) );
00955           return true;
00956         }
00957         break;
00958       case EditRole: {
00959        QString val = value.toString();
00960         if ( !val.isEmpty() && obj->setName(val) ) {
00961           emit( dataChanged( index, index ) );
00962          return true;
00963        }
00964        return false;
00965         break;
00966       }
00967       default:
00968         break;
00969       }
00970     }
00971   }
00972   return QAbstractItemModel::setData( index, value, role );
00973 }
00974 
00980 Qt::ItemFlags SUIT_TreeModel::flags( const QModelIndex& index ) const
00981 {
00982   Qt::ItemFlags f = 0;
00983 
00984   if (!index.isValid())
00985     //return Qt::ItemIsDropEnabled; // items can be dropped into the top level of the model
00986     return f;
00987 
00988   SUIT_DataObject* obj = object(index);
00989 
00990   if (obj) {
00991     // data object is enabled
00992     if (obj->isEnabled())
00993       f = f | Qt::ItemIsEnabled;
00994 
00995     // data object is selectable
00996     if (obj->isSelectable())
00997       f = f | Qt::ItemIsSelectable;
00998 
00999     // data object is checkable
01000     if (obj->isCheckable(index.column()))
01001       f = f | Qt::ItemIsUserCheckable;
01002     
01003     // data object can be renamed
01004     if (obj->renameAllowed(index.column()))
01005       f = f | Qt::ItemIsEditable;
01006     
01007     // data object can be dragged
01008     if (obj->isDraggable())
01009       f = f | Qt::ItemIsDragEnabled;
01010     
01011     // another data object(s) can be dropped on this one
01012     if (obj->isDropAccepted())
01013       f = f | Qt::ItemIsDropEnabled;
01014   }
01015 
01016   return f;
01017 }
01018 
01019 Qt::DropActions SUIT_TreeModel::supportedDropActions() const
01020 {
01021   return Qt::CopyAction | Qt::MoveAction;
01022 }
01023 
01031 QVariant SUIT_TreeModel::headerData( int column, Qt::Orientation orientation, int role ) const
01032 {
01033   QVariant d;
01034   // NOTE! only horizontal header is supported
01035   if ( root() && orientation == Qt::Horizontal )
01036   {
01037     switch ( role )
01038         {
01039     case DisplayRole:
01040       // column title
01041       if((myColumns[column].myHeaderFlags & Qtx::ShowText) || 
01042         (myColumns[column].myHeaderFlags == Qtx::ShowAll)) 
01043        d = myColumns[column].myName;
01044       else
01045        d = QString();
01046       break;
01047     case DecorationRole:
01048       // column icon
01049       if((myColumns[column].myHeaderFlags & Qtx::ShowIcon) || 
01050         (myColumns[column].myHeaderFlags == Qtx::ShowAll)) 
01051        d = myColumns[column].myIcon;
01052       else
01053        d = QIcon();      
01054       break;
01055     case AppropriateRole:
01056       // appropriate flag (can column be hidden via context popup menu)
01057       d = myColumns[column].myAppropriate;
01058       break;
01059     default:
01060       break;
01061     }
01062   }
01063   return d;
01064 }
01065 
01073 QModelIndex SUIT_TreeModel::index( int row, int column, 
01074                                    const QModelIndex& parent ) const
01075 {
01076   if( hasIndex( row, column, parent ) )
01077   {
01078     TreeItem* parentItem = treeItem( parent );
01079     if( parentItem )
01080     {
01081       TreeItem* childItem = parentItem->child( row );
01082       if( childItem )
01083         return createIndex( row, column, childItem );
01084     }
01085   }
01086   return QModelIndex();
01087 }
01088 
01094 QModelIndex SUIT_TreeModel::parent( const QModelIndex& index ) const
01095 {
01096   if ( !index.isValid() )
01097     return QModelIndex();
01098 
01099   TreeItem* childItem = treeItem( index );
01100   TreeItem* parentItem = childItem ? childItem->parent() : 0;
01101 
01102   if ( !parentItem || parentItem == rootItem() )
01103     return QModelIndex();
01104 
01105   return createIndex( parentItem->position(), 0, parentItem );
01106 }
01107 
01114 int SUIT_TreeModel::columnCount( const QModelIndex& /*parent*/ ) const
01115 {
01116   return myColumns.size();
01117 }
01118 
01125 int SUIT_TreeModel::rowCount( const QModelIndex& parent ) const
01126 {
01127   // Commented by rnv in the frame of the 
01128   // "20830: EDF 1357 GUI : Hide/Show Icon" imp
01129   // if ( parent.column() > 0 )
01130   // return 0;
01131 
01132   TreeItem* parentItem = treeItem( parent );
01133 
01134   return parentItem ? parentItem->childCount() : 0;
01135 }
01136 
01142 SUIT_DataObject* SUIT_TreeModel::object( const QModelIndex& index ) const
01143 {
01144   return object( treeItem( index ) );
01145 }
01146 
01153 QModelIndex SUIT_TreeModel::index( const SUIT_DataObject* obj, int column ) const
01154 {
01155   if ( obj == root() )
01156     return QModelIndex();
01157 
01158   TreeItem* item = treeItem( obj );
01159 
01160   return item ? createIndex( item->position(), column, item ) : QModelIndex();
01161 }
01162 
01168 bool SUIT_TreeModel::autoDeleteTree() const
01169 {
01170   return myAutoDeleteTree;
01171 }
01172 
01182 void SUIT_TreeModel::setAutoDeleteTree( const bool on )
01183 {
01184   myAutoDeleteTree = on;
01185 }
01186 
01192 bool SUIT_TreeModel::autoUpdate() const
01193 {
01194   return myAutoUpdate;
01195 }
01196 
01206 void SUIT_TreeModel::setAutoUpdate( const bool on )
01207 {
01208   if ( myAutoUpdate == on )
01209     return;
01210 
01211   SUIT_DataObject::disconnect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
01212                                this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
01213   SUIT_DataObject::disconnect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
01214                                this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
01215   myAutoUpdate = on;
01216 
01217   if ( myAutoUpdate ) {
01218     SUIT_DataObject::connect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
01219                               this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
01220     SUIT_DataObject::connect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
01221                               this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
01222 
01223     updateTree();
01224   }
01225 }
01226 
01231 bool SUIT_TreeModel::updateModified() const
01232 {
01233   return myUpdateModified;
01234 }
01239 void SUIT_TreeModel::setUpdateModified(const bool on)
01240 {
01241   myUpdateModified=on;
01242 }
01243 
01250 bool SUIT_TreeModel::customSorting( const int column ) const
01251 {
01252   return root() ? root()->customSorting( column ) : false;
01253 }
01254 
01255 void SUIT_TreeModel::forgetObject( const SUIT_DataObject* obj )
01256 {
01257   removeItem( treeItem( obj ) );
01258 }
01259 
01271 bool SUIT_TreeModel::lessThan( const QModelIndex& left, const QModelIndex& right ) const
01272 {
01273   QVariant ldata = data( left );
01274   QVariant rdata = data( right );
01275   return root() ? root()->compare( ldata, rdata, left.column() ) : false;
01276 }
01277 
01282 QAbstractItemDelegate* SUIT_TreeModel::delegate() const
01283 {
01284   return new SUIT_ItemDelegate( const_cast<SUIT_TreeModel*>( this ) );
01285 }
01286 
01287 
01288 void SUIT_TreeModel::emitClicked( SUIT_DataObject* obj, const QModelIndex& index) {
01289   int obj_group_id = obj->groupId();
01290   const ColumnInfo& inf = myColumns[index.column()];
01291 
01292   int id = -1;
01293   if( inf.myIds.contains( 0 ) )
01294     id = inf.myIds[0];
01295   if( inf.myIds.contains( obj_group_id ) )
01296     id = inf.myIds[obj_group_id];
01297   emit clicked(obj, id);
01298 }
01299 
01310 void SUIT_TreeModel::updateTree( const QModelIndex& index )
01311 {
01312   updateTree( object( index ) );
01313 }
01314 
01315 
01316 void SUIT_TreeModel::updateTreeModel(SUIT_DataObject* obj,TreeItem* item)
01317 {
01318   int kobj=0;
01319   int kitem=0;
01320   int nobjchild=obj->childCount();
01321   SUIT_DataObject* sobj=obj->childObject(kobj);
01322   TreeItem* sitem = item->child(kitem);
01323 
01324   while(kobj < nobjchild)
01325     {
01326       if(sitem==0)
01327         {
01328           //end of item list
01329           if(kitem==0)
01330             sitem=createItemAtPos(sobj,item,0);
01331           else
01332             sitem=createItemAtPos(sobj,item,kitem);
01333           updateTreeModel(sobj,sitem);
01334           kobj++;
01335           kitem++;
01336           sobj=obj->childObject(kobj);
01337           sitem = item->child(kitem);
01338         }
01339       else if(sitem->dataObject() != sobj)
01340         {
01341           if(treeItem(sobj))
01342             {
01343               // item : to remove
01344               removeItem(sitem);
01345               sitem = item->child(kitem);
01346             }
01347           else
01348             {
01349               // obj : new object
01350               createItemAtPos(sobj,item,kitem);
01351               kobj++;
01352               kitem++;
01353               sobj=obj->childObject(kobj);
01354               sitem = item->child(kitem);
01355             }
01356         }
01357       else
01358         {
01359           //obj and item are synchronised : go to next ones
01360           updateTreeModel(sobj,sitem);
01361           if(sobj->modified()) updateItem(sitem, true);
01362           if( sobj ) sobj->update();
01363           kobj++;
01364           kitem++;
01365           sobj=obj->childObject(kobj);
01366           sitem = item->child(kitem);
01367         }
01368     }
01369   //remove remaining items
01370   for(int i = item->childCount(); i > kitem;i--)
01371     {
01372       sitem = item->child(i-1);
01373       removeItem(sitem);
01374     }
01375 }
01376 
01387 void SUIT_TreeModel::updateTree( SUIT_DataObject* obj )
01388 {
01389   if ( !obj )
01390     obj = root();
01391 
01392   else if ( obj->root() != root() )
01393     return;
01394 
01395   if(updateModified())
01396     {
01397       updateTreeModel(obj,treeItem( obj ));
01398     }
01399   else
01400     {
01401       synchronize<ObjPtr,ItemPtr,SUIT_TreeModel::TreeSync>( obj,
01402                                                             treeItem( obj ),
01403                                                             SUIT_TreeModel::TreeSync( this ) );
01404     }
01405   emit modelUpdated();
01406 }
01407 
01411 void SUIT_TreeModel::initialize()
01412 {
01413   SUIT_DataObject::disconnect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
01414                                this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
01415   SUIT_DataObject::disconnect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
01416                                this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
01417   if ( autoUpdate() ) {
01418     SUIT_DataObject::connect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
01419                               this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
01420     SUIT_DataObject::connect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
01421                               this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
01422   }
01423 
01424   myItems.clear(); // ????? is it really necessary
01425 
01426   if ( !myRootItem )
01427     myRootItem = new TreeItem( 0 );
01428 
01429   registerColumn( 0, QObject::tr( "NAME_COLUMN" ), SUIT_DataObject::NameId );
01430 
01431   QString visCol = QObject::tr( "VISIBILITY_COLUMN" );
01432   registerColumn( 0, visCol, SUIT_DataObject::VisibilityId );
01433 
01434   SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
01435   setColumnIcon( visCol, resMgr->loadPixmap( "SUIT", tr( "ICON_DATAOBJ_VISIBLE" ) ));
01436   setHeaderFlags( visCol, Qtx::ShowIcon);
01437 
01438   updateTree();
01439 }
01440 
01445 SUIT_TreeModel::TreeItem* SUIT_TreeModel::rootItem() const
01446 {
01447   return myRootItem;
01448 }
01449 
01455 SUIT_TreeModel::TreeItem* SUIT_TreeModel::treeItem( const QModelIndex& index ) const
01456 {
01457   return index.isValid() ? static_cast<TreeItem*>( index.internalPointer() ) : rootItem();
01458 }
01459 
01465 SUIT_TreeModel::TreeItem* SUIT_TreeModel::treeItem( const SUIT_DataObject* obj ) const
01466 {
01467   TreeItem* item = 0;
01468 
01469   if ( obj == root() )
01470     item = rootItem();
01471   else if ( myItems.contains( const_cast<SUIT_DataObject*>( obj ) ) )
01472     item = myItems[ const_cast<SUIT_DataObject*>( obj ) ];
01473 
01474   return item;
01475 }
01476 
01482 SUIT_DataObject* SUIT_TreeModel::object( const SUIT_TreeModel::TreeItem* item ) const
01483 {
01484   if ( item == rootItem() )
01485     return root();
01486  
01487   SUIT_DataObject* obj = item ? item->dataObject() : 0;
01488   return myItems.contains( obj ) ? obj : 0;
01489 }
01490 
01500 QString SUIT_TreeModel::objectId( const QModelIndex& index ) const
01501 {
01502   QString objId;
01503   if ( index.isValid() ) {
01504     SUIT_DataObject* obj = object( index );
01505     if ( obj ) {
01506       int anId = obj->customData( Qtx::IdType ).toInt(); 
01507       objId = data( createIndex( index.row(), anId, index.internalPointer() ) ).toString();
01508     }
01509   }
01510   return objId;
01511 }
01512 
01520 SUIT_TreeModel::TreeItem* SUIT_TreeModel::createItem( SUIT_DataObject* obj,
01521                                                       SUIT_TreeModel::TreeItem* parent, 
01522                                                       SUIT_TreeModel::TreeItem* after )
01523 {
01524   if ( !obj )
01525     return 0;
01526 
01527   SUIT_DataObject* parentObj = object( parent );
01528   QModelIndex parentIdx = index( parentObj );
01529 
01530   SUIT_DataObject* afterObj = after ? object( after ) : 0;
01531   int row = afterObj ? afterObj->position() + 1 : 0;
01532 
01533   beginInsertRows( parentIdx, row, row );
01534 
01535   myItems[ obj ] = new TreeItem( obj, parent, after );
01536 
01537   for(int pos=row;pos < parent->childCount();pos++)
01538     parent->child(pos)->setPosition(pos);
01539 
01540   endInsertRows();
01541 
01542   obj->setModified(false);
01543 
01544   return myItems[ obj ];
01545 }
01546 
01554 SUIT_TreeModel::TreeItem* SUIT_TreeModel::createItemAtPos( SUIT_DataObject* obj,
01555                                                            SUIT_TreeModel::TreeItem* parent,
01556                                                            int pos )
01557 {
01558   if ( !obj )
01559     return 0;
01560 
01561   SUIT_DataObject* parentObj = object( parent );
01562   QModelIndex parentIdx = index( parentObj );
01563 
01564   int row = pos ;
01565   SUIT_TreeModel::TreeItem* after = pos>0 ? parent->child(pos-1) : 0 ;
01566 
01567   beginInsertRows( parentIdx, row, row );
01568 
01569   SUIT_TreeModel::TreeItem* item = new TreeItem( obj, parent, after );
01570   myItems[ obj ] = item;
01571 
01572   for(int pos=row;pos < parent->childCount();pos++)
01573     parent->child(pos)->setPosition(pos);
01574 
01575   endInsertRows();
01576 
01577   obj->setModified(false);
01578 
01579   return item;
01580 }
01581 
01587 void SUIT_TreeModel::updateItem( SUIT_TreeModel::TreeItem* item, bool emitLayoutChanged )
01588 {
01589   if ( !item )
01590     return;
01591   
01592   SUIT_DataObject* obj = object( item );
01593   if ( !obj )
01594     return;
01595   
01596   // update all columns corresponding to the given data object
01597   //emit layoutAboutToBeChanged(); // VSR 25/04/2011: fix crash on delete objects
01598   QModelIndex firstIdx = index( obj, 0 );
01599   QModelIndex lastIdx  = index( obj, columnCount() - 1 );
01600   emit dataChanged( firstIdx, lastIdx );
01601   obj->setModified(false);
01602   if( emitLayoutChanged )
01603     emit layoutChanged();
01604 }
01605 
01610 void SUIT_TreeModel::removeItem( SUIT_TreeModel::TreeItem* item )
01611 {
01612   if ( !item )
01613     return;
01614 
01615   // Remove list view items from <myItems> recursively for all children.
01616   // Otherwise, "delete item" line below will destroy all item's children,
01617   // and <myItems> will contain invalid pointers
01618   while( item->childCount() )
01619     removeItem( item->child( 0 ) );
01620 
01621   SUIT_DataObject* obj = object( item );
01622   
01623   // Warning! obj can be deleted at this point!
01624 
01625   TreeItem* parent=item->parent();
01626   SUIT_DataObject* parentObj = object( parent );
01627   QModelIndex parentIdx = index( parentObj, 0 );
01628   int row = item->position();
01629   
01630   beginRemoveRows( parentIdx, row, row );
01631   myItems.remove( obj );
01632 
01633   if ( obj == root() )
01634     setRoot( 0 );
01635   else if ( parent )
01636     {
01637       parent->removeChild( item );
01638       for(int pos=row;pos < parent->childCount();pos++)
01639         parent->child(pos)->setPosition(pos);
01640     }
01641 
01642   delete item;
01643 
01644   endRemoveRows();
01645 }
01646 
01652 void SUIT_TreeModel::onInserted( SUIT_DataObject* /*object*/, SUIT_DataObject* parent )
01653 {
01654   if ( autoUpdate() )
01655     updateTree( parent );
01656 }
01657 
01663 void SUIT_TreeModel::onRemoved( SUIT_DataObject* /*object*/, SUIT_DataObject* parent )
01664 {
01665   if ( autoUpdate() )
01666     updateTree( parent );
01667 }
01668 
01672 QStringList SUIT_TreeModel::mimeTypes() const
01673 {
01674   QStringList types;
01675   types << "application/vnd.text.list";
01676   return types;
01677 }
01678 
01683 QMimeData* SUIT_TreeModel::mimeData( const QModelIndexList& indexes ) const
01684 {
01685   QMimeData* mimeData = new QMimeData();
01686   QByteArray encodedData;
01687 
01688   QDataStream stream( &encodedData, QIODevice::WriteOnly );
01689 
01690   foreach ( QModelIndex index, indexes ) {
01691     QString id = objectId( index );
01692     // we have to check only 0 column in order to avoid repeating items in the drag object
01693     // - QTreeView tries to drag indices for all visible columns
01694     if ( index.isValid() && index.column() == 0 && !id.isEmpty() )
01695       stream << id;
01696   }
01697 
01698   mimeData->setData( "application/vnd.text.list", encodedData );
01699   return mimeData;
01700 }
01701 
01702 bool SUIT_TreeModel::dropMimeData( const QMimeData* data, Qt::DropAction action,
01703                                    int row, int column, const QModelIndex& parent )
01704 {
01705   if ( action == Qt::IgnoreAction )
01706     // do nothing with data
01707     return false;
01708 
01709   if ( !data->hasFormat( "application/vnd.text.list" ) )
01710     // not supported data dropped
01711     return false;
01712 
01713   if ( !parent.isValid() )
01714     // dropping into the top level of the model is not allowed
01715     return false;
01716 
01717   // get parent object
01718   SUIT_DataObject* pobj = object( parent );
01719   if ( !pobj )
01720     // invalid parent
01721     return false;
01722 
01723   // decode mime data and collect data objects being dropped
01724   QByteArray encodedData = data->data( "application/vnd.text.list" );
01725   QDataStream stream( &encodedData, QIODevice::ReadOnly );
01726   
01727   DataObjectList objects;
01728 
01729   while ( !stream.atEnd() ) {
01730     QString id;
01731     stream >> id;
01732     if ( !id.isEmpty() && searcher() ) {
01733       SUIT_DataObject* obj = searcher()->findObject( id );
01734       if ( obj ) objects << obj;
01735     }
01736   }
01737 
01738   // emit signal
01739   emit dropped( objects, pobj, row, action );
01740 
01741   // return true if there's any to drop
01742   return !objects.isEmpty();
01743 }
01744 
01759 SUIT_ProxyModel::SUIT_ProxyModel( QObject* parent )
01760 : QSortFilterProxyModel( parent ),
01761   mySortingEnabled( true )
01762 {
01763   SUIT_TreeModel* model = new SUIT_TreeModel( this );
01764   connect( model, SIGNAL( modelUpdated() ), this, SIGNAL( modelUpdated() ) );
01765   connect( model, SIGNAL( clicked( SUIT_DataObject*, int ) ), this, SIGNAL(clicked( SUIT_DataObject*, int ) ) );
01766   connect( model, SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ),
01767            this,  SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ) );
01768   setSourceModel( model );
01769   setDynamicSortFilter( true );
01770 }
01771 
01777 SUIT_ProxyModel::SUIT_ProxyModel( SUIT_DataObject* root, QObject* parent )
01778 : QSortFilterProxyModel( parent ),
01779   mySortingEnabled( true )
01780 {
01781   SUIT_TreeModel* model = new SUIT_TreeModel( root, this );
01782   connect( model, SIGNAL( modelUpdated() ), this, SIGNAL( modelUpdated() ) );
01783   connect( model, SIGNAL( clicked( SUIT_DataObject*, int ) ), this, SIGNAL( clicked( SUIT_DataObject*, int ) ) );
01784   connect( model, SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ),
01785            this,  SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ) );
01786   setSourceModel( model );
01787   setDynamicSortFilter( true );
01788 }
01789 
01795 SUIT_ProxyModel::SUIT_ProxyModel( SUIT_AbstractModel* model, QObject* parent )
01796 : QSortFilterProxyModel( parent ),
01797   mySortingEnabled( true )
01798 {
01799   connect( *model, SIGNAL( modelUpdated() ), this, SIGNAL( modelUpdated() ) );
01800   connect( *model, SIGNAL( clicked( SUIT_DataObject*, int ) ), this, SIGNAL( clicked( SUIT_DataObject*, int ) ) );
01801   connect( *model, SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ),
01802            this,   SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ) );
01803   setSourceModel( *model );
01804   setDynamicSortFilter( true );
01805 }
01806 
01810 SUIT_ProxyModel::~SUIT_ProxyModel()
01811 {
01812 }
01813 
01819 SUIT_DataObject* SUIT_ProxyModel::root() const
01820 {
01821   return treeModel() ? treeModel()->root() : 0;
01822 }
01823 
01829 void SUIT_ProxyModel::setRoot( SUIT_DataObject* r )
01830 {
01831   if ( treeModel() )
01832     treeModel()->setRoot( r );
01833 }
01834 
01840 SUIT_DataObject* SUIT_ProxyModel::object( const QModelIndex& index ) const
01841 {
01842   return treeModel() ? treeModel()->object( mapToSource( index ) ) : 0;
01843 }
01844 
01851 QModelIndex SUIT_ProxyModel::index( const SUIT_DataObject* obj, int column ) const
01852 {
01853   return treeModel() ? mapFromSource( treeModel()->index( obj, column ) ) : QModelIndex();
01854 }
01855 
01861 bool SUIT_ProxyModel::autoDeleteTree() const
01862 {
01863   return treeModel() ? treeModel()->autoDeleteTree() : false;
01864 }
01865 
01875 void SUIT_ProxyModel::setAutoDeleteTree( const bool on )
01876 {
01877   if ( treeModel() )
01878     treeModel()->setAutoDeleteTree( on );
01879 }
01880 
01886 bool SUIT_ProxyModel::autoUpdate() const
01887 {
01888   return treeModel() ? treeModel()->autoUpdate() : false;
01889 }
01890 
01895 bool SUIT_ProxyModel::updateModified() const
01896 {
01897   return treeModel() ? treeModel()->updateModified() : false;
01898 }
01907 void SUIT_ProxyModel::setUpdateModified( const bool on )
01908 {
01909   if ( treeModel() )
01910     treeModel()->setUpdateModified( on );
01911 }
01912 
01922 void SUIT_ProxyModel::setAutoUpdate( const bool on )
01923 {
01924   if ( treeModel() )
01925     treeModel()->setAutoUpdate( on );
01926 }
01927 
01933 bool SUIT_ProxyModel::isSortingEnabled() const
01934 {
01935   return mySortingEnabled;
01936 }
01937 
01938 SUIT_DataSearcher* SUIT_ProxyModel::searcher() const
01939 {
01940   return treeModel() ? treeModel()->searcher() : 0;
01941 }
01942 
01943 void SUIT_ProxyModel::setSearcher( SUIT_DataSearcher* s )
01944 {
01945   if ( treeModel() ) treeModel()->setSearcher( s );
01946 }
01947 
01952 QAbstractItemDelegate* SUIT_ProxyModel::delegate() const
01953 {
01954   return treeModel() ? treeModel()->delegate() : 0;
01955 }
01956 
01967 void SUIT_ProxyModel::updateTree( const QModelIndex& index )
01968 {
01969   if ( treeModel() )
01970     treeModel()->updateTree( mapToSource( index ) );
01971 }
01972 
01983 void SUIT_ProxyModel::updateTree( SUIT_DataObject* obj )
01984 {
01985   if ( treeModel() )
01986     treeModel()->updateTree( obj );
01987 }
01988 
01989 void SUIT_ProxyModel::forgetObject( const SUIT_DataObject* obj )
01990 {
01991   if ( treeModel() )
01992     treeModel()->forgetObject( obj );
01993 }
01994 
02001 bool SUIT_ProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right ) const
02002 {
02003   if ( !isSortingEnabled() && left.isValid() && right.isValid() ) {
02004     return left.row() < right.row();
02005   }
02006   if ( treeModel() && treeModel()->customSorting( left.column() ) ) {
02007     return treeModel()->lessThan( left, right );
02008   }
02009   return QSortFilterProxyModel::lessThan( left, right );
02010 }
02011 
02018 bool SUIT_ProxyModel::customSorting( const int column ) const
02019 {
02020   return treeModel() ? treeModel()->customSorting( column ) : false;
02021 }
02022 
02028 void SUIT_ProxyModel::setSortingEnabled( bool enabled )
02029 {
02030   mySortingEnabled = enabled;
02031   clear();
02032 }
02033 
02034 /*
02035   \brief Get tree model.
02036   \return tree model
02037 */
02038 SUIT_AbstractModel* SUIT_ProxyModel::treeModel() const
02039 {
02040   return dynamic_cast<SUIT_AbstractModel*>( sourceModel() );
02041 }
02042 
02049 bool SUIT_ProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent ) const
02050 {
02051   SUIT_DataObject* o = treeModel()->object( sourceModel()->index( sourceRow, 0, sourceParent ) );
02052   SUIT_DataObject* p = o ? o->parent() : 0;
02053   return ( !p || p->expandable() ) && o && o->isVisible();
02054 }
02055 
02062 void SUIT_ProxyModel::registerColumn( const int group_id, const QString& name, const int custom_id )
02063 {
02064   if( treeModel() )
02065     treeModel()->registerColumn( group_id, name, custom_id );
02066 }
02067 
02079 void SUIT_ProxyModel::unregisterColumn( const int group_id, const QString& name )
02080 {
02081   if( treeModel() )
02082     treeModel()->unregisterColumn( group_id, name );
02083 }
02084 
02091 void SUIT_ProxyModel::setColumnIcon( const QString& name, const QPixmap& icon )
02092 {
02093   if( treeModel() )
02094     treeModel()->setColumnIcon( name, icon );
02095 }
02096 
02103 QPixmap SUIT_ProxyModel::columnIcon( const QString& name ) const
02104 {
02105   return treeModel() ? treeModel()->columnIcon( name ) : QPixmap();
02106 }
02107 
02120 void SUIT_ProxyModel::setAppropriate( const QString& name, const Qtx::Appropriate appr )
02121 {
02122   if( treeModel() )
02123     treeModel()->setAppropriate( name, appr );
02124 }
02125 
02136 Qtx::Appropriate SUIT_ProxyModel::appropriate( const QString& name ) const
02137 {
02138   return treeModel() ? treeModel()->appropriate( name ) : Qtx::Shown;
02139 }
02140 
02151 void SUIT_ProxyModel::setHeaderFlags( const QString& name, const Qtx::HeaderViewFlags flags )
02152 {
02153   if(treeModel())
02154     treeModel()->setHeaderFlags(name, flags);
02155 }
02156 
02166 Qtx::HeaderViewFlags SUIT_ProxyModel::headerFlags( const QString& name ) const
02167 {
02168   return treeModel() ? treeModel()->headerFlags( name ) : Qtx::ShowAll;
02169 }
02170 
02177 void SUIT_ProxyModel::setVisibilityState(const QString& id, Qtx::VisibilityState state)
02178 {
02179   if(treeModel())
02180     treeModel()->setVisibilityState(id,state);
02181 }
02182 
02189 void SUIT_ProxyModel::setVisibilityStateForAll(Qtx::VisibilityState state)
02190 {
02191   if(treeModel())
02192     treeModel()->setVisibilityStateForAll(state);
02193 }
02194 
02201 Qtx::VisibilityState SUIT_ProxyModel::visibilityState(const QString& id) const
02202 {
02203   return treeModel() ? treeModel()->visibilityState(id) : Qtx::UnpresentableState;
02204 }
02205 
02206 void SUIT_ProxyModel::emitClicked( SUIT_DataObject* obj, const QModelIndex& index)
02207 {
02208   if(treeModel())
02209     treeModel()->emitClicked(obj,index);
02210 }
02211 
02226 SUIT_ItemDelegate::SUIT_ItemDelegate( QObject* parent )
02227 : QItemDelegate( parent )
02228 {
02229 }
02230 
02240 void SUIT_ItemDelegate::paint( QPainter* painter, 
02241                                const QStyleOptionViewItem& option,
02242                                const QModelIndex& index ) const
02243 {
02244   QStyleOptionViewItem opt = option;
02245   if ( index.isValid() ) {
02246     // Note: we check into account only custom roles; other roles are process
02247     //       correctly by the QItemDelegate class
02248     QVariant val = index.data( SUIT_TreeModel::BaseColorRole );
02249     if ( val.isValid() && val.value<QColor>().isValid() ) {
02250       QColor aBase = val.value<QColor>();
02251       aBase.setAlpha( 0 );
02252       opt.palette.setBrush( QPalette::Base, val.value<QColor>() );
02253     }
02254     val = index.data( SUIT_TreeModel::TextColorRole );
02255     if ( val.isValid() && val.value<QColor>().isValid() )
02256       opt.palette.setBrush( QPalette::Text, val.value<QColor>() );
02257     val = index.data( SUIT_TreeModel::HighlightRole );
02258     if ( val.isValid() && val.value<QColor>().isValid() )
02259       opt.palette.setBrush( QPalette::Highlight, val.value<QColor>() );
02260     val = index.data( SUIT_TreeModel::HighlightedTextRole );
02261     if ( val.isValid() && val.value<QColor>().isValid() )
02262       opt.palette.setBrush( QPalette::HighlightedText, val.value<QColor>() );      
02263   }
02264   QItemDelegate::paint( painter, opt, index );
02265 }
02266 
02267 QSize SUIT_ItemDelegate::sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const
02268 {
02269     QSize size = QItemDelegate::sizeHint ( option, index );
02270 #if QT_VERSION >= 0x040500
02271     size.setHeight( size.height() + 1 );
02272 #endif
02273     return size;
02274 }