-// 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
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;
}
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 );
int n = myColumns.size();
myColumns.resize( n+1 );
myColumns[n] = inf;
- reset();
+ endResetModel();
}
}
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;
}
\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 )
else {
needSignal = myVisibilityMap.remove( id ) > 0;
}
- if ( needSignal ) {
+ if ( emitChanged && needSignal ) {
QModelIndexList lst;
if ( searcher() ) {
SUIT_DataObject* o = searcher()->findObject( id );
/*!
\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 );
}
/*!
{
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();
}
}
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:
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 ) {
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();
}
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
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();
}
/*!
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.
*/
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 );
}
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 );
}
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 );
}
\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);
}
/*!
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;
}