Salome HOME
Merge from V7_3_BR branch 18/12/2013
[modules/gui.git] / src / SUIT / SUIT_TreeModel.cxx
index 9e45581385b0201a3e381128fa200c99d7fc96c2..3a8eacc1a5012a891b6f823d851730af1cc4bb6c 100755 (executable)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2013  CEA/DEN, EDF R&D, OPEN CASCADE
 //
 // This library is free software; you can redistribute it and/or
 // modify it under the terms of the GNU Lesser General Public
@@ -483,6 +483,8 @@ SUIT_TreeModel::~SUIT_TreeModel()
                                  this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
     SUIT_DataObject::disconnect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
                                  this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
+    SUIT_DataObject::disconnect( SIGNAL( modifed( SUIT_DataObject* ) ),
+                                 this, SLOT( onModified( SUIT_DataObject* ) ) );
     delete myRoot;
   }
 
@@ -669,8 +671,10 @@ Qtx::HeaderViewFlags SUIT_TreeModel::headerFlags( const QString& name ) const
   
   \param id - column name
   \param state - visible state
+  \param emitChanged - if set to false, blocks dataChanged() signal, this can be used to
+  prevent emitting dataChanged() several times for the same data object
 */
-void SUIT_TreeModel::setVisibilityState( const QString& id, Qtx::VisibilityState state )
+void SUIT_TreeModel::setVisibilityState( const QString& id, Qtx::VisibilityState state, bool emitChanged )
 {
   VisibilityMap::const_iterator it = myVisibilityMap.find( id );
   if ( it != myVisibilityMap.end() && it.value() == state )
@@ -684,7 +688,7 @@ void SUIT_TreeModel::setVisibilityState( const QString& id, Qtx::VisibilityState
   else {
     needSignal = myVisibilityMap.remove( id ) > 0;
   }
-  if ( needSignal ) {
+  if ( emitChanged && needSignal ) {
     QModelIndexList lst;
     if ( searcher() ) {
       SUIT_DataObject* o = searcher()->findObject( id );
@@ -703,7 +707,6 @@ void SUIT_TreeModel::setVisibilityState( const QString& id, Qtx::VisibilityState
 /*!
   \brief Set visibility state for all objects.
   
-  \param id - column name
   \param state - visible state
 */
 void SUIT_TreeModel::setVisibilityStateForAll( Qtx::VisibilityState state )
@@ -775,7 +778,15 @@ void SUIT_TreeModel::setRoot( SUIT_DataObject* r )
                                  this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
     SUIT_DataObject::disconnect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
                                  this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
+    SUIT_DataObject::disconnect( SIGNAL( modified( SUIT_DataObject* ) ),
+                                 this, SLOT( onModified( SUIT_DataObject* ) ) );
     delete myRoot;
+    
+    if ( myRootItem ) {
+      QList<TreeItem*> items = myRootItem->children();
+      for ( QList<TreeItem*>::iterator anIt = items.begin(); anIt != items.end(); anIt++ )
+        delete *anIt;
+    }
   }
 
   myRoot = r;
@@ -1212,6 +1223,8 @@ void SUIT_TreeModel::setAutoUpdate( const bool on )
                                this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
   SUIT_DataObject::disconnect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
                                this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
+  SUIT_DataObject::disconnect( SIGNAL( modified( SUIT_DataObject* ) ),
+                               this, SLOT( onModified( SUIT_DataObject* ) ) );
   myAutoUpdate = on;
 
   if ( myAutoUpdate ) {
@@ -1219,6 +1232,8 @@ void SUIT_TreeModel::setAutoUpdate( const bool on )
                               this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
     SUIT_DataObject::connect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
                               this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
+    SUIT_DataObject::connect( SIGNAL( modified( SUIT_DataObject* ) ),
+                              this, SLOT( onModified( SUIT_DataObject* ) ) );
 
     updateTree();
   }
@@ -1326,10 +1341,7 @@ void SUIT_TreeModel::updateTreeModel(SUIT_DataObject* obj,TreeItem* item)
       if(sitem==0)
         {
           //end of item list
-          if(kitem==0)
-            sitem=createItemAtPos(sobj,item,0);
-          else
-            sitem=createItemAtPos(sobj,item,kitem);
+         sitem=createItemAtPos(sobj,item,kitem);
           updateTreeModel(sobj,sitem);
           kobj++;
           kitem++;
@@ -1347,7 +1359,8 @@ void SUIT_TreeModel::updateTreeModel(SUIT_DataObject* obj,TreeItem* item)
           else
             {
               // obj : new object
-              createItemAtPos(sobj,item,kitem);
+              sitem=createItemAtPos(sobj,item,kitem);
+             updateTreeModel(sobj,sitem);
               kobj++;
               kitem++;
               sobj=obj->childObject(kobj);
@@ -1359,7 +1372,7 @@ void SUIT_TreeModel::updateTreeModel(SUIT_DataObject* obj,TreeItem* item)
           //obj and item are synchronised : go to next ones
           updateTreeModel(sobj,sitem);
           if(sobj->modified()) updateItem(sitem, true);
-          if( sobj ) sobj->update();
+          sobj->update();
           kobj++;
           kitem++;
           sobj=obj->childObject(kobj);
@@ -1414,11 +1427,15 @@ void SUIT_TreeModel::initialize()
                                this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
   SUIT_DataObject::disconnect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
                                this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
+  SUIT_DataObject::disconnect( SIGNAL( modified( SUIT_DataObject* ) ),
+                               this, SLOT( onModified( SUIT_DataObject* ) ) );
   if ( autoUpdate() ) {
     SUIT_DataObject::connect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
                               this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
     SUIT_DataObject::connect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
                               this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
+    SUIT_DataObject::connect( SIGNAL( modified( SUIT_DataObject* ) ),
+                              this, SLOT( onModified( SUIT_DataObject* ) ) );
   }
 
   myItems.clear(); // ????? is it really necessary
@@ -1569,8 +1586,8 @@ SUIT_TreeModel::TreeItem* SUIT_TreeModel::createItemAtPos( SUIT_DataObject* obj,
   SUIT_TreeModel::TreeItem* item = new TreeItem( obj, parent, after );
   myItems[ obj ] = item;
 
-  for(int pos=row;pos < parent->childCount();pos++)
-    parent->child(pos)->setPosition(pos);
+  for(int ppos=row;ppos < parent->childCount();ppos++)
+    parent->child(ppos)->setPosition(ppos);
 
   endInsertRows();
 
@@ -1594,13 +1611,28 @@ void SUIT_TreeModel::updateItem( SUIT_TreeModel::TreeItem* item, bool emitLayout
     return;
   
   // update all columns corresponding to the given data object
-  //emit layoutAboutToBeChanged(); // VSR 25/04/2011: fix crash on delete objects
-  QModelIndex firstIdx = index( obj, 0 );
-  QModelIndex lastIdx  = index( obj, columnCount() - 1 );
-  emit dataChanged( firstIdx, lastIdx );
-  obj->setModified(false);
-  if( emitLayoutChanged )
-    emit layoutChanged();
+  /*To avoid crashes we should update any persistent model indexes before emitting layoutChanged(). In other words, when the structure changes:
+      -  emit layoutAboutToBeChanged
+      - Remember the QModelIndex that will change
+      - call changePersistentIndex()
+      - emit layoutChanged
+  */
+
+    emit layoutAboutToBeChanged();
+
+    // Remember the QModelIndex that will change
+    QModelIndexList fromIndexes;
+    QModelIndexList toIndexes;
+    for (int i = 0; i < columnCount() - 1; ++i) {
+        fromIndexes.append( index( obj, i ));
+        toIndexes.append(QModelIndex());
+    }
+    //changePersistentIndexList(fromIndexes, toIndexes); // Limitation: can lead to loss of selection
+
+    emit dataChanged( toIndexes.first(), toIndexes.last() );
+    obj->setModified(false);
+    if ( emitLayoutChanged )
+      emit layoutChanged();
 }
 
 /*!
@@ -1666,6 +1698,22 @@ void SUIT_TreeModel::onRemoved( SUIT_DataObject* /*object*/, SUIT_DataObject* pa
     updateTree( parent );
 }
 
+/*!
+  \brief Called when the data object is modified. TreeSync is not used here for maximum efficiency.
+  It is assumed that it is up to the application to decide when its data objects are modified.
+  \param obj data object that has been modified
+*/
+void SUIT_TreeModel::onModified( SUIT_DataObject* obj )
+{
+  if ( autoUpdate() )
+  {
+    QModelIndex firstIdx = index( obj, 0 );
+    QModelIndex lastIdx  = index( obj, columnCount() - 1 );
+    emit dataChanged( firstIdx, lastIdx );
+    obj->setModified(false);
+  }
+}
+
 /*!
   \brief Drag and Drop support.
 */
@@ -2173,11 +2221,12 @@ Qtx::HeaderViewFlags SUIT_ProxyModel::headerFlags( const QString& name ) const
   
   \param id - column name
   \param state - visible state
+  \param emitChanged - if set to false, blocks dataChanged() signal, this can be used to
+  prevent emitting dataChanged() several times for the same data object
 */
-void SUIT_ProxyModel::setVisibilityState(const QString& id, Qtx::VisibilityState state)
-{
+void SUIT_ProxyModel::setVisibilityState(const QString& id, Qtx::VisibilityState state, bool emitChanged ) {
   if(treeModel())
-    treeModel()->setVisibilityState(id,state);
+    treeModel()->setVisibilityState(id,state,emitChanged);
 }
 
 /*!