Commit c1ba6621 authored by sankhesh's avatar sankhesh
Browse files

BUG: Tree view expansion state save/restore while updating

The expansion states of hierarchy nodes are saved and restored when the tree
view is updated.
Save weak references to expanded nodes to avoid any dangling references at the
end.
Access children using model API and not MRML API
Moved recursive children expand state save method to P-implementation.
This fixes issue 2557.

git-svn-id: http://svn.slicer.org/Slicer4/trunk@21523 3bd1e089-480b-0410-8dfb-8563597acbee
parent 93ea4af1
......@@ -619,6 +619,7 @@ void qMRMLSceneModel::updateScene()
{
Q_D(qMRMLSceneModel);
emit sceneAboutToBeUpdated();
// Stop listening to all the nodes before we remove them (setRowCount) as some
// weird behavior could arise when removing the nodes (e.g onMRMLNodeModified
// could be called ...)
......@@ -688,6 +689,7 @@ void qMRMLSceneModel::updateScene()
// Populate scene with nodes
this->populateScene();
emit this->sceneUpdated();
}
//------------------------------------------------------------------------------
......
......@@ -225,6 +225,12 @@ signals :
/// qMRMLTreeView
void reparentedByDragAndDrop(vtkMRMLNode* node, vtkMRMLNode* newParent);
/// This signal is sent when the scene is about to be updated
void sceneAboutToBeUpdated();
/// This signal is sent after the scene is updated
void sceneUpdated();
protected:
qMRMLSceneModel(qMRMLSceneModelPrivate* pimpl, QObject *parent=0);
......
......@@ -66,7 +66,7 @@ qMRMLSortFilterProxyModel::qMRMLSortFilterProxyModel(QObject *vparent)
// in 2 steps, first a new row is created (which automatically calls
// filterAcceptsRow() that returns false) and then set the row with the
// correct values (which doesn't call filterAcceptsRow() on the up to date
// value unless DynamicSortFilter is true).
// value unless DynamicSortFilter is true).
this->setDynamicSortFilter(true);
}
......
......@@ -35,14 +35,19 @@
#include "qMRMLTreeView_p.h"
// MRML includes
#include <vtkMRMLDisplayNode.h>
#include <vtkMRMLDisplayableHierarchyNode.h>
#include <vtkMRMLDisplayableNode.h>
#include <vtkMRMLModelNode.h>
#include <vtkMRMLDisplayNode.h>
#include <vtkMRMLModelHierarchyLogic.h>
#include <vtkMRMLModelHierarchyNode.h>
#include <vtkMRMLModelNode.h>
#include <vtkMRMLScene.h>
// VTK includes
#include <vtkCollection.h>
#include <vtkCollectionIterator.h>
#include <vtkWeakPointer.h>
//------------------------------------------------------------------------------
qMRMLTreeViewPrivate::qMRMLTreeViewPrivate(qMRMLTreeView& object)
: q_ptr(&object)
......@@ -57,10 +62,12 @@ qMRMLTreeViewPrivate::qMRMLTreeViewPrivate(qMRMLTreeView& object)
this->DeleteAction = 0;
this->EditAction = 0;
this->SceneMenu = 0;
this->ExpandedNodes = vtkCollection::New();
}
//------------------------------------------------------------------------------
qMRMLTreeViewPrivate::~qMRMLTreeViewPrivate()
{
this->ExpandedNodes->Delete();
}
//------------------------------------------------------------------------------
......@@ -73,16 +80,16 @@ void qMRMLTreeViewPrivate::init()
q->setAutoScrollMargin(32); // scroll hot area sensitivity
this->setSortFilterProxyModel(new qMRMLSortFilterProxyModel(q));
q->setSceneModelType("Transform");
//ctkModelTester * tester = new ctkModelTester(p);
//tester->setModel(this->SortFilterModel);
//QObject::connect(q, SIGNAL(activated(QModelIndex)),
// q, SLOT(onActivated(QModelIndex)));
// q, SLOT(onActivated(QModelIndeK)));
//QObject::connect(q, SIGNAL(clicked(QModelIndex)),
// q, SLOT(onActivated(QModelIndex)));
q->setUniformRowHeights(true);
QObject::connect(q, SIGNAL(collapsed(QModelIndex)),
q, SLOT(onNumberOfVisibleIndexChanged()));
QObject::connect(q, SIGNAL(expanded(QModelIndex)),
......@@ -90,7 +97,7 @@ void qMRMLTreeViewPrivate::init()
//QObject::connect(q->header(), SIGNAL(sectionResized(int,int,int)),
// q, SLOT(onSectionResized()));
q->horizontalScrollBar()->installEventFilter(q);
this->NodeMenu = new QMenu(q);
this->NodeMenu->setObjectName("nodeMenuTreeView");
......@@ -114,6 +121,7 @@ void qMRMLTreeViewPrivate::init()
q, SLOT(editCurrentNode()));
this->SceneMenu = new QMenu(q);
this->SceneMenu->setObjectName("sceneMenuTreeView");
this->ExpandedNodes->RemoveAllItems();
}
//------------------------------------------------------------------------------
......@@ -129,6 +137,10 @@ void qMRMLTreeViewPrivate::setSceneModel(qMRMLSceneModel* newModel)
this->SceneModel = newModel;
this->SortFilterModel->setSourceModel(this->SceneModel);
QObject::connect(this->SceneModel, SIGNAL(sceneAboutToBeUpdated()),
q, SLOT(saveTreeExpandState()));
QObject::connect(this->SceneModel, SIGNAL(sceneUpdated()),
q, SLOT(loadTreeExpandState()));
q->expandToDepth(2);
}
......@@ -140,7 +152,7 @@ void qMRMLTreeViewPrivate::setSortFilterProxyModel(qMRMLSortFilterProxyModel* ne
{
return;
}
// delete the previous filter
delete this->SortFilterModel;
this->SortFilterModel = newSortModel;
......@@ -216,6 +228,33 @@ QSize qMRMLTreeViewPrivate::sizeHint()const
return this->TreeViewSizeHint;
}
//------------------------------------------------------------------------------
void qMRMLTreeViewPrivate::saveChildrenExpandState(QModelIndex &parentIndex)
{
Q_Q(qMRMLTreeView);
if (q->isExpanded(parentIndex))
{
// Store a weak reference to the parentNode in the vtkCollection.
// This helps avoid any dangling references if the node was deleted
// while updating scene.
vtkMRMLNode* parentNode = vtkMRMLNode::SafeDownCast(
q->sortFilterProxyModel()->mrmlNodeFromIndex(parentIndex));
if (parentNode)
{
vtkWeakPointer<vtkMRMLNode> weakNode =
vtkMRMLNode::SafeDownCast(parentNode);
this->ExpandedNodes->AddItem(weakNode);
}
}
// Iterate over children nodes recursively to save their expansion state
unsigned int numChildrenRows = q->sortFilterProxyModel()->rowCount(parentIndex);
for(unsigned int row = 0; row < numChildrenRows; ++row)
{
QModelIndex childIndex = q->sortFilterProxyModel()->index(row, 0, parentIndex);
this->saveChildrenExpandState(childIndex);
}
}
//------------------------------------------------------------------------------
// qMRMLTreeView
//------------------------------------------------------------------------------
......@@ -294,7 +333,7 @@ void qMRMLTreeView::setSceneModel(qMRMLSceneModel* newSceneModel, const QString&
{
Q_D(qMRMLTreeView);
if (!newSceneModel)
if (!newSceneModel)
{
return;
}
......@@ -576,16 +615,16 @@ void qMRMLTreeView::mousePressEvent(QMouseEvent* e)
{
Q_D(qMRMLTreeView);
this->QTreeView::mousePressEvent(e);
if (e->button() != Qt::RightButton)
{
return;
}
// get the index of the current column
QModelIndex index = this->indexAt(e->pos());
vtkMRMLNode* node = this->sortFilterProxyModel()->mrmlNodeFromIndex(index);
if (node)
{
d->NodeMenu->exec(e->globalPos());
......@@ -609,7 +648,7 @@ void qMRMLTreeView::mouseReleaseEvent(QMouseEvent* e)
QRect decorationElement =
this->style()->subElementRect(QStyle::SE_ItemViewItemDecoration, &opt, this);
//decorationElement.translate(this->visualRect(index).topLeft());
if (decorationElement.contains(e->pos()))
if (decorationElement.contains(e->pos()))
{
if (this->clickDecoration(index))
{
......@@ -675,6 +714,48 @@ void qMRMLTreeView::toggleVisibility(const QModelIndex& index)
}
}
//------------------------------------------------------------------------------
void qMRMLTreeView::saveTreeExpandState()
{
Q_D(qMRMLTreeView);
// Check if there is a scene loaded
QStandardItem* sceneItem = this->sceneModel()->mrmlSceneItem();
if (!sceneItem)
{
return;
}
// Erase previous tree expand state
d->ExpandedNodes->RemoveAllItems();
QModelIndex sceneIndex = this->sortFilterProxyModel()->mrmlSceneIndex();
d->saveChildrenExpandState(sceneIndex);
}
//------------------------------------------------------------------------------
void qMRMLTreeView::loadTreeExpandState()
{
Q_D(qMRMLTreeView);
// Check if there is a scene loaded
QStandardItem* sceneItem = this->sceneModel()->mrmlSceneItem();
if (!sceneItem)
{
return;
}
// Iterate over the vtkCollection of expanded nodes
vtkCollectionIterator* iter = d->ExpandedNodes->NewIterator();
for(iter->InitTraversal(); !iter->IsDoneWithTraversal(); iter->GoToNextItem())
{
vtkMRMLNode* node = vtkMRMLNode::SafeDownCast(iter->GetCurrentObject());
if (node)
{
// Expand the node
QModelIndex nodeIndex = this->sortFilterProxyModel()->indexFromMRMLNode(node);
this->expand(nodeIndex);
}
}
// Clear the vtkCollection now
d->ExpandedNodes->RemoveAllItems();
}
//------------------------------------------------------------------------------
void qMRMLTreeView::renameCurrentNode()
{
......
......@@ -43,7 +43,7 @@ class QMRML_WIDGETS_EXPORT qMRMLTreeView : public QTreeView
{
Q_OBJECT
QVTK_OBJECT
/// This property controls what type of scene representation
/// This property controls what type of scene representation
/// (which qMRMLSceneModel implementation/subclass)is used to populate
/// the nodes of the scene.
/// Some built-in model types are available :
......@@ -229,6 +229,17 @@ protected slots:
void onNumberOfVisibleIndexChanged();
void updateRootNode(vtkObject* modifiedRootNode);
/// Save the nodes currently expanded nodes so that their state can later
/// be restored by \a loadTreeExpandState(). Successive calls to
/// \a saveTreeExpandState() erase previous tree expand state.
/// \sa loadTreeExpandState()
void saveTreeExpandState();
/// Expand the nodes previously saved by \a saveTreeExpandState()
/// \sa saveTreeExpandState()
void loadTreeExpandState();
protected:
QScopedPointer<qMRMLTreeViewPrivate> d_ptr;
......
......@@ -30,6 +30,9 @@ class QMenu;
class qMRMLSceneModel;
class qMRMLSortFilterProxyModel;
// VTK includes
class vtkCollection;
//------------------------------------------------------------------------------
class qMRMLTreeViewPrivate
{
......@@ -44,6 +47,9 @@ public:
void setSortFilterProxyModel(qMRMLSortFilterProxyModel* newSortModel);
QSize sizeHint()const;
void recomputeSizeHint(bool forceUpdate = false);
/// Save the current expansion state of children nodes of a
/// vtkMRMLDisplayableHierarchyNode
void saveChildrenExpandState(QModelIndex& parentIndex);
qMRMLSceneModel* SceneModel;
qMRMLSortFilterProxyModel* SortFilterModel;
......@@ -58,6 +64,8 @@ public:
QAction* EditAction;
QMenu* SceneMenu;
vtkCollection* ExpandedNodes;
};
#endif
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment