Salome HOME
Remove QT4 compatibility.
[modules/gui.git] / src / SUIT / SUIT_TreeModel.cxx
old mode 100755 (executable)
new mode 100644 (file)
index 53c9a94..8feae8a
@@ -1,9 +1,9 @@
-// Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2019  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
 // License as published by the Free Software Foundation; either
-// version 2.1 of the License.
+// version 2.1 of the License, or (at your option) any later version.
 //
 // This library is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -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;
   }
 
@@ -498,6 +500,7 @@ SUIT_TreeModel::~SUIT_TreeModel()
 void SUIT_TreeModel::registerColumn( const int group_id, const QString& name, const int custom_id )
 {
   bool found = false;
+  beginResetModel();
   for ( int i=0, n=myColumns.size(); i<n && !found; i++ ) {
     if ( name == myColumns[i].myName ) {
       myColumns[i].myIds.insert( group_id, custom_id );
@@ -513,7 +516,7 @@ void SUIT_TreeModel::registerColumn( const int group_id, const QString& name, co
     int n = myColumns.size();
     myColumns.resize( n+1 );
     myColumns[n] = inf;
-    reset();
+    endResetModel();
   }
 }
 
@@ -531,11 +534,12 @@ void SUIT_TreeModel::registerColumn( const int group_id, const QString& name, co
 void SUIT_TreeModel::unregisterColumn( const int group_id, const QString& name )
 {
   for ( int i = 0, n = myColumns.size(); i < n; i++ ) {
+    beginResetModel();
     if ( myColumns[i].myName == name ) {
       myColumns[i].myIds.remove( group_id );
       if ( myColumns[i].myIds.isEmpty() ) {
-       myColumns.remove( i );
-       reset();
+        myColumns.remove( i );
+        endResetModel();
       }
       break;
     }
@@ -669,8 +673,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 +690,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,39 +709,12 @@ 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 )
 {
-  if ( state != Qtx::UnpresentableState ) {
-    VisibilityMap::ConstIterator it = myVisibilityMap.begin();
-    while ( it != myVisibilityMap.end() ) {
-      if ( it.value() != state )
-       setVisibilityState( it.key(), state );
-      it++;
-    }
-  }
-  else {
-    QList<QString> anIds = myVisibilityMap.keys();
-    myVisibilityMap.clear();
-    QList<QString>::ConstIterator it = anIds.begin();
-    while ( it != anIds.end() ) {
-      QModelIndexList lst;
-      if ( searcher() ) {
-       SUIT_DataObject* o = searcher()->findObject( *it );
-       if ( o ) lst << index( o );
-      }
-      else {
-       lst = match( index( 0, root()->customData( Qtx::IdType ).toInt() ), DisplayRole, (*it), 1, Qt::MatchExactly | Qt::MatchRecursive );
-      }
-      if ( !lst.isEmpty() ) {
-       QModelIndex idx = index( lst.first().row(), SUIT_DataObject::VisibilityId ,lst.first().parent() );
-       emit dataChanged( idx, idx );
-      }
-      it++;
-    }
-  }
+  foreach( QString id, myVisibilityMap.keys() )
+    setVisibilityState( id, state );
 }
 
 /*!
@@ -769,19 +748,28 @@ void SUIT_TreeModel::setRoot( SUIT_DataObject* r )
 {
   if ( root() == r )
     return;
+  beginResetModel();
 
   if ( autoDeleteTree() ) {
     SUIT_DataObject::disconnect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
                                  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;
 
   //initialize();
-  reset();
+  endResetModel();
   emit modelUpdated();
 }
 
@@ -956,12 +944,15 @@ bool SUIT_TreeModel::setData( const QModelIndex& index,
         }
         break;
       case EditRole: {
-       QString val = value.toString();
+           QString val = value.toString();
+           bool mod = obj->name() != val;
         if ( !val.isEmpty() && obj->setName(val) ) {
           emit( dataChanged( index, index ) );
-         return true;
-       }
-       return false;
+          if (mod)
+            emit ( renamed(obj) );
+          return true;
+        }
+        return false;
         break;
       }
       default:
@@ -1212,6 +1203,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 +1212,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();
   }
@@ -1412,11 +1407,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
@@ -1592,13 +1591,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();
 }
 
 /*!
@@ -1664,6 +1678,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.
 */
@@ -1763,6 +1793,7 @@ SUIT_ProxyModel::SUIT_ProxyModel( QObject* parent )
   connect( model, SIGNAL( clicked( SUIT_DataObject*, int ) ), this, SIGNAL(clicked( SUIT_DataObject*, int ) ) );
   connect( model, SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ),
            this,  SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ) );
+  connect( model, SIGNAL( renamed( SUIT_DataObject* ) ), this, SIGNAL( renamed( SUIT_DataObject* ) ) );
   setSourceModel( model );
   setDynamicSortFilter( true );
 }
@@ -1781,6 +1812,7 @@ SUIT_ProxyModel::SUIT_ProxyModel( SUIT_DataObject* root, QObject* parent )
   connect( model, SIGNAL( clicked( SUIT_DataObject*, int ) ), this, SIGNAL( clicked( SUIT_DataObject*, int ) ) );
   connect( model, SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ),
            this,  SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ) );
+  connect( model, SIGNAL( renamed( SUIT_DataObject* ) ), this, SIGNAL( renamed( SUIT_DataObject* ) ) );
   setSourceModel( model );
   setDynamicSortFilter( true );
 }
@@ -1798,6 +1830,7 @@ SUIT_ProxyModel::SUIT_ProxyModel( SUIT_AbstractModel* model, QObject* parent )
   connect( *model, SIGNAL( clicked( SUIT_DataObject*, int ) ), this, SIGNAL( clicked( SUIT_DataObject*, int ) ) );
   connect( *model, SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ),
            this,   SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ) );
+  connect( *model, SIGNAL( renamed( SUIT_DataObject* ) ), this, SIGNAL( renamed( SUIT_DataObject* ) ) );
   setSourceModel( *model );
   setDynamicSortFilter( true );
 }
@@ -2171,11 +2204,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);
 }
 
 /*!
@@ -2265,8 +2299,6 @@ void SUIT_ItemDelegate::paint( QPainter* painter,
 QSize SUIT_ItemDelegate::sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const
 {
     QSize size = QItemDelegate::sizeHint ( option, index );
-#if QT_VERSION >= 0x040500
     size.setHeight( size.height() + 1 );
-#endif
     return size;
 }