diff --git a/Modules/QtWidgets/include/QmitkDataStorageTreeModel.h b/Modules/QtWidgets/include/QmitkDataStorageTreeModel.h index 7a4d99ae76..4e6386f0a4 100644 --- a/Modules/QtWidgets/include/QmitkDataStorageTreeModel.h +++ b/Modules/QtWidgets/include/QmitkDataStorageTreeModel.h @@ -1,261 +1,274 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QMITKDATASTORAGETREEMODEL_H_ #define QMITKDATASTORAGETREEMODEL_H_ #include #include #include #include #include #include "QmitkEnums.h" #include "QmitkCustomVariants.h" #include #include #include /// \ingroup QmitkModule class MITKQTWIDGETS_EXPORT QmitkDataStorageTreeModel : public QAbstractItemModel { //# CONSTANTS,TYPEDEFS public: static const std::string COLUMN_NAME; static const std::string COLUMN_TYPE; static const std::string COLUMN_VISIBILITY; //# CTORS,DTOR public: QmitkDataStorageTreeModel(mitk::DataStorage* _DataStorage , bool _PlaceNewNodesOnTop=false , QObject* parent = 0); ~QmitkDataStorageTreeModel(); //# GETTER public: /// /// Get node at a specific model index. /// This function is used to get a node from a QModelIndex /// mitk::DataNode::Pointer GetNode(const QModelIndex &index) const; /// /// Returns a copy of the node-vector that is shown by this model /// virtual QList GetNodeSet() const; /// /// Get the DataStorage. /// const mitk::DataStorage::Pointer GetDataStorage() const; /// /// Get the top placement flag /// bool GetPlaceNewNodesOnTopFlag() { return m_PlaceNewNodesOnTop; } /// /// Set the top placement flag /// void SetPlaceNewNodesOnTop(bool _PlaceNewNodesOnTop); //# (Re-)implemented from QAbstractItemModel //# Read model Qt::ItemFlags flags(const QModelIndex& index) const override; QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const override; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; int rowCount ( const QModelIndex & parent = QModelIndex() ) const override; int columnCount ( const QModelIndex & parent = QModelIndex() ) const override; //# hierarchical model /// /// called whenever the model or the view needs to create a QModelIndex for a particular /// child item (or a top-level item if parent is an invalid QModelIndex) /// QModelIndex index ( int row, int column, const QModelIndex & parent = QModelIndex() ) const override; QModelIndex parent ( const QModelIndex & index ) const override; //# editable model bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role = Qt::EditRole) override; bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override; Qt::DropActions supportedDropActions() const override; Qt::DropActions supportedDragActions() const override; QStringList mimeTypes() const override; QMimeData * mimeData(const QModelIndexList & indexes) const override; static QMimeData* mimeDataFromModelIndexList(const QModelIndexList& indexes); //# End of QAbstractItemModel //# SETTER public: /// /// Sets the DataStorage. The whole model will be resetted. /// void SetDataStorage(mitk::DataStorage* _DataStorage); /// /// Notify that the DataStorage was deleted. The whole model will be resetted. /// void SetDataStorageDeleted(const itk::Object* _DataStorage); /// /// Adds a node to this model. /// If a predicate is set (not null) the node will be checked against it.The node has to have a data object (no one wants to see empty nodes). /// virtual void AddNode(const mitk::DataNode* node); /// /// Removes a node from this model. Also removes any event listener from the node. /// virtual void RemoveNode(const mitk::DataNode* node); /// /// Sets a node to modfified. Called by the DataStorage /// virtual void SetNodeModified(const mitk::DataNode* node); /// /// \return an index for the given datatreenode in the tree. If the node is not found /// QModelIndex GetIndex(const mitk::DataNode*) const; + /// Set whether to allow hierarchy changes by dragging and dropping + void SetAllowHierarchyChange(bool allowHierarchyChange); + //# MISC protected: /// /// Helper class to represent a tree structure of DataNodes /// class TreeItem { public: /// /// Constructs a new TreeItem with the given DataNode (must not be 0) /// TreeItem(mitk::DataNode* _DataNode, TreeItem* _Parent=0); /// /// Removes itself as child from its parent-> Does not delete its children /// \sa Delete() /// virtual ~TreeItem(); /// /// Find the index of an item /// int IndexOfChild(const TreeItem* item) const; /// /// \return The child at pos index or 0 if it not exists /// TreeItem* GetChild(int index) const; /// /// Find the TreeItem containing a special tree node (recursive tree function) /// TreeItem* Find( const mitk::DataNode* _DataNode) const; /// /// Get the amount of children /// int GetChildCount() const; /// /// \return the index of this node in its parent list /// int GetIndex() const; /// /// \return the parent of this tree item /// TreeItem* GetParent() const; /// /// Return the DataNode associated with this node /// mitk::DataNode::Pointer GetDataNode() const; /// /// Get all children as vector /// std::vector GetChildren() const; /// /// add another item as a child of this (only if not already in that list) /// void AddChild( TreeItem* item); /// /// remove another item as child from this /// void RemoveChild( TreeItem* item); /// /// inserts a child at the given position. if pos is not in range /// the element is added at the end /// void InsertChild( TreeItem* item, int index=-1 ); /// Sets the parent on the treeitem void SetParent(TreeItem* _Parent); /// /// Deletes the whole tree branch /// void Delete(); protected: TreeItem* m_Parent; std::vector m_Children; mitk::DataNode::Pointer m_DataNode; }; QList ToTreeItemPtrList(const QMimeData* mimeData); QList ToTreeItemPtrList(const QByteArray& ba); /// /// Adjusts the LayerProperty according to the nodes position /// void AdjustLayerProperty(); /// /// invoked after m_DataStorage or m_Predicate changed /// TreeItem* TreeItemFromIndex(const QModelIndex &index) const; /// /// Gives a ModelIndex for the Tree Item /// QModelIndex IndexFromTreeItem(TreeItem*) const; /// /// Returns the first element in the nodes sources list (if available) or 0 /// mitk::DataNode* GetParentNode(const mitk::DataNode* node) const; /// /// Adds all Childs in parent to vec. Before a child is added the function is called recursively /// void TreeToVector(TreeItem* parent, std::vector& vec) const; /// /// Adds all Childs in parent to vec. Before a child is added the function is called recursively /// void TreeToNodeSet(TreeItem* parent, QList &vec) const; /// /// Update Tree Model /// void Update(); //# ATTRIBUTES protected: mitk::WeakPointer m_DataStorage; mitk::NodePredicateBase::Pointer m_Predicate; bool m_PlaceNewNodesOnTop; TreeItem* m_Root; + /// Flag to block the data storage events if nodes are added/removed by this class. + bool m_BlockDataStorageEvents; + + /// This decides whether or not it is allowed to assign a different parent to a node + /// If it is false, it is not possible to change the hierarchy of nodes by dragging + /// and dropping. + /// If it is true, dragging nodes on another node will replace all of their parents + /// with that one. + bool m_AllowHierarchyChange; + private: void AddNodeInternal(const mitk::DataNode*); void RemoveNodeInternal(const mitk::DataNode*); /// /// Checks if dicom properties patient name, study names and series name exists /// bool DicomPropertiesExists(const mitk::DataNode&) const; }; #endif /* QMITKDATASTORAGETREEMODEL_H_ */ diff --git a/Modules/QtWidgets/src/QmitkDataStorageTreeModel.cpp b/Modules/QtWidgets/src/QmitkDataStorageTreeModel.cpp index ef66593afc..bbc4b3e2e0 100644 --- a/Modules/QtWidgets/src/QmitkDataStorageTreeModel.cpp +++ b/Modules/QtWidgets/src/QmitkDataStorageTreeModel.cpp @@ -1,876 +1,965 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include #include #include #include #include #include #include "QmitkDataStorageTreeModel.h" #include "QmitkNodeDescriptorManager.h" #include #include #include #include #include #include #include #include +#include + QmitkDataStorageTreeModel::QmitkDataStorageTreeModel( mitk::DataStorage* _DataStorage , bool _PlaceNewNodesOnTop , QObject* parent ) : QAbstractItemModel(parent) , m_DataStorage(0) , m_PlaceNewNodesOnTop(_PlaceNewNodesOnTop) , m_Root(0) +, m_BlockDataStorageEvents(false) +, m_AllowHierarchyChange(false) { this->SetDataStorage(_DataStorage); } QmitkDataStorageTreeModel::~QmitkDataStorageTreeModel() { // set data storage to 0 = remove all listeners this->SetDataStorage(0); m_Root->Delete(); m_Root = 0; } mitk::DataNode::Pointer QmitkDataStorageTreeModel::GetNode( const QModelIndex &index ) const { return this->TreeItemFromIndex(index)->GetDataNode(); } const mitk::DataStorage::Pointer QmitkDataStorageTreeModel::GetDataStorage() const { return m_DataStorage.GetPointer(); } QModelIndex QmitkDataStorageTreeModel::index( int row, int column, const QModelIndex & parent ) const { TreeItem* parentItem; if (!parent.isValid()) parentItem = m_Root; else parentItem = static_cast(parent.internalPointer()); TreeItem *childItem = parentItem->GetChild(row); if (childItem) return createIndex(row, column, childItem); else return QModelIndex(); } int QmitkDataStorageTreeModel::rowCount(const QModelIndex &parent) const { TreeItem *parentTreeItem = this->TreeItemFromIndex(parent); return parentTreeItem->GetChildCount(); } Qt::ItemFlags QmitkDataStorageTreeModel::flags( const QModelIndex& index ) const { mitk::DataNode* dataNode = this->TreeItemFromIndex(index)->GetDataNode(); if (index.isValid()) { if(DicomPropertiesExists(*dataNode)) { return Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; } return Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; }else{ return Qt::ItemIsDropEnabled; } } int QmitkDataStorageTreeModel::columnCount( const QModelIndex& /* parent = QModelIndex() */ ) const { return 1; } QModelIndex QmitkDataStorageTreeModel::parent(const QModelIndex &index) const { if (!index.isValid()) return QModelIndex(); TreeItem *childItem = this->TreeItemFromIndex(index); TreeItem *parentItem = childItem->GetParent(); if (parentItem == m_Root) return QModelIndex(); return this->createIndex(parentItem->GetIndex(), 0, parentItem); } QmitkDataStorageTreeModel::TreeItem* QmitkDataStorageTreeModel::TreeItemFromIndex( const QModelIndex &index ) const { if (index.isValid()) return static_cast(index.internalPointer()); else return m_Root; } Qt::DropActions QmitkDataStorageTreeModel::supportedDropActions() const { return Qt::CopyAction | Qt::MoveAction; } Qt::DropActions QmitkDataStorageTreeModel::supportedDragActions() const { return Qt::CopyAction | Qt::MoveAction; } bool QmitkDataStorageTreeModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int /*column*/, const QModelIndex &parent) { // Early exit, returning true, but not actually doing anything (ignoring data). if (action == Qt::IgnoreAction) { return true; } // Note, we are returning true if we handled it, and false otherwise bool returnValue = false; if(data->hasFormat("application/x-qabstractitemmodeldatalist")) { returnValue = true; // First we extract a Qlist of TreeItem* pointers. QList listOfItemsToDrop = ToTreeItemPtrList(data); // Retrieve the TreeItem* where we are dropping stuff, and its parent. TreeItem* dropItem = this->TreeItemFromIndex(parent); TreeItem* parentItem = dropItem->GetParent(); // If item was dropped onto empty space, we select the root node if(dropItem == m_Root) { parentItem = m_Root; } // Dragging and Dropping is only allowed within the same parent, so use the first item in list to validate. // (otherwise, you could have a derived image such as a segmentation, and assign it to another image). // NOTE: We are assuming the input list is valid... i.e. when it was dragged, all the items had the same parent. - if(listOfItemsToDrop[0] != dropItem && listOfItemsToDrop[0]->GetParent() == parentItem) + // Determine whether or not the drag and drop operation is a valid one. + // Examples of invalid operations include: + // - dragging nodes with different parents + // - dragging nodes from one parent to another parent, if m_AllowHierarchyChange is false + // - dragging a node on one of its child nodes (only relevant if m_AllowHierarchyChange is true) + + bool isValidDragAndDropOperation(true); + + // different parents + { + TreeItem* firstParent = listOfItemsToDrop[0]->GetParent(); + QList::iterator diIter; + for (diIter = listOfItemsToDrop.begin() +1; + diIter != listOfItemsToDrop.end(); + diIter++) + { + if (firstParent != (*diIter)->GetParent()) + { + isValidDragAndDropOperation = false; + break; + } + } + } + + // dragging from one parent to another + { + isValidDragAndDropOperation = (listOfItemsToDrop[0]->GetParent() == parentItem) || (m_AllowHierarchyChange); + } + + // dragging on a child node of one the dragged nodes + { + QList::iterator diIter; + for (diIter = listOfItemsToDrop.begin(); + diIter != listOfItemsToDrop.end(); + diIter++) + { + TreeItem* tempItem = dropItem; + + while (tempItem != m_Root) + { + tempItem = tempItem->GetParent(); + if (tempItem == *diIter) + { + isValidDragAndDropOperation = false; + } + } + } + } + + if (!isValidDragAndDropOperation) + return isValidDragAndDropOperation; + + if (listOfItemsToDrop[0] != dropItem && isValidDragAndDropOperation) { // Retrieve the index of where we are dropping stuff. - QModelIndex dropItemModelIndex = this->IndexFromTreeItem(dropItem); QModelIndex parentModelIndex = this->IndexFromTreeItem(parentItem); int dragIndex = 0; // Iterate through the list of TreeItem (which may be at non-consecutive indexes). QList::iterator diIter; for (diIter = listOfItemsToDrop.begin(); diIter != listOfItemsToDrop.end(); diIter++) { TreeItem* itemToDrop = *diIter; if (itemToDrop->GetIndex() < row) { dragIndex = 1; } + // Here we assume that as you remove items, one at a time, that GetIndex() will be valid. - this->beginRemoveRows(parentModelIndex, (*diIter)->GetIndex(), (*diIter)->GetIndex()); - parentItem->RemoveChild(*diIter); + this->beginRemoveRows(this->IndexFromTreeItem((*diIter)->GetParent()), (*diIter)->GetIndex(), (*diIter)->GetIndex()); + (*diIter)->GetParent()->RemoveChild(*diIter); this->endRemoveRows(); } // row = -1 dropped on an item, row != -1 dropped in between two items // Select the target index position, or put it at the end of the list. int dropIndex = 0; if (row != -1) { if (dragIndex == 0) dropIndex = std::min(row, parentItem->GetChildCount() - 1); else dropIndex = std::min(row - 1, parentItem->GetChildCount() - 1); } else + { dropIndex = dropItem->GetIndex(); + } + QModelIndex dropItemModelIndex = this->IndexFromTreeItem(dropItem); if ((row == -1 && dropItemModelIndex.row() == -1) || dropItemModelIndex.row() > parentItem->GetChildCount()) dropIndex = parentItem->GetChildCount() - 1; // Now insert items again at the drop item position - this->beginInsertRows(parentModelIndex, dropIndex, dropIndex + listOfItemsToDrop.size() - 1); + + if (m_AllowHierarchyChange) + { + this->beginInsertRows(dropItemModelIndex, dropIndex, dropIndex + listOfItemsToDrop.size() - 1); + } + else + { + this->beginInsertRows(parentModelIndex, dropIndex, dropIndex + listOfItemsToDrop.size() - 1); + } for (diIter = listOfItemsToDrop.begin(); diIter != listOfItemsToDrop.end(); diIter++) { - parentItem->InsertChild( (*diIter), dropIndex ); + // dropped on node, behaviour depends on preference setting + if (m_AllowHierarchyChange) + { + m_BlockDataStorageEvents = true; + mitk::DataNode* droppedNode = (*diIter)->GetDataNode(); + mitk::DataNode* dropOntoNode = dropItem->GetDataNode(); + m_DataStorage->Remove(droppedNode); + m_DataStorage->Add(droppedNode, dropOntoNode); + m_BlockDataStorageEvents = false; + + dropItem->InsertChild((*diIter), dropIndex); + } + else + { + parentItem->InsertChild((*diIter), dropIndex); + } + dropIndex++; } this->endInsertRows(); // Change Layers to match. this->AdjustLayerProperty(); } } else if(data->hasFormat("application/x-mitk-datanodes")) { returnValue = true; int numberOfNodesDropped = 0; QList dataNodeList = QmitkMimeTypes::ToDataNodePtrList(data); mitk::DataNode* node = NULL; foreach(node, dataNodeList) { if(node && m_DataStorage.IsNotNull() && !m_DataStorage->Exists(node)) { m_DataStorage->Add( node ); mitk::BaseData::Pointer basedata = node->GetData(); if (basedata.IsNotNull()) { mitk::RenderingManager::GetInstance()->InitializeViews( basedata->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); numberOfNodesDropped++; } } } // Only do a rendering update, if we actually dropped anything. if (numberOfNodesDropped > 0) { mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } return returnValue; } QStringList QmitkDataStorageTreeModel::mimeTypes() const { QStringList types = QAbstractItemModel::mimeTypes(); types << "application/x-qabstractitemmodeldatalist"; types << "application/x-mitk-datanodes"; return types; } QMimeData * QmitkDataStorageTreeModel::mimeData(const QModelIndexList & indexes) const { return mimeDataFromModelIndexList(indexes); } QMimeData *QmitkDataStorageTreeModel::mimeDataFromModelIndexList(const QModelIndexList &indexes) { QMimeData * ret = new QMimeData; QString treeItemAddresses(""); QString dataNodeAddresses(""); QByteArray baTreeItemPtrs; QByteArray baDataNodePtrs; QDataStream dsTreeItemPtrs(&baTreeItemPtrs, QIODevice::WriteOnly); QDataStream dsDataNodePtrs(&baDataNodePtrs, QIODevice::WriteOnly); for (int i = 0; i < indexes.size(); i++) { TreeItem* treeItem = static_cast(indexes.at(i).internalPointer()); dsTreeItemPtrs << reinterpret_cast(treeItem); dsDataNodePtrs << reinterpret_cast(treeItem->GetDataNode().GetPointer()); // --------------- deprecated ----------------- unsigned long long treeItemAddress = reinterpret_cast(treeItem); unsigned long long dataNodeAddress = reinterpret_cast(treeItem->GetDataNode().GetPointer()); QTextStream(&treeItemAddresses) << treeItemAddress; QTextStream(&dataNodeAddresses) << dataNodeAddress; if (i != indexes.size() - 1) { QTextStream(&treeItemAddresses) << ","; QTextStream(&dataNodeAddresses) << ","; } // -------------- end deprecated ------------- } // ------------------ deprecated ----------------- ret->setData("application/x-qabstractitemmodeldatalist", QByteArray(treeItemAddresses.toLatin1())); ret->setData("application/x-mitk-datanodes", QByteArray(dataNodeAddresses.toLatin1())); // --------------- end deprecated ----------------- ret->setData(QmitkMimeTypes::DataStorageTreeItemPtrs, baTreeItemPtrs); ret->setData(QmitkMimeTypes::DataNodePtrs, baDataNodePtrs); return ret; } QVariant QmitkDataStorageTreeModel::data( const QModelIndex & index, int role ) const { mitk::DataNode* dataNode = this->TreeItemFromIndex(index)->GetDataNode(); // get name of treeItem (may also be edited) QString nodeName; if(DicomPropertiesExists(*dataNode)) { mitk::BaseProperty* seriesDescription = (dataNode->GetProperty("dicom.series.SeriesDescription")); mitk::BaseProperty* studyDescription = (dataNode->GetProperty("dicom.study.StudyDescription")); mitk::BaseProperty* patientsName = (dataNode->GetProperty("dicom.patient.PatientsName")); nodeName += QFile::encodeName(patientsName->GetValueAsString().c_str()) + "\n"; nodeName += QFile::encodeName(studyDescription->GetValueAsString().c_str()) + "\n"; nodeName += QFile::encodeName(seriesDescription->GetValueAsString().c_str()); } else { nodeName = QFile::encodeName(dataNode->GetName().c_str()); } if(nodeName.isEmpty()) { nodeName = "unnamed"; } if (role == Qt::DisplayRole) return nodeName; else if(role == Qt::ToolTipRole) return nodeName; else if(role == Qt::DecorationRole) { QmitkNodeDescriptor* nodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor(dataNode); return nodeDescriptor->GetIcon(); } else if(role == Qt::CheckStateRole) { return dataNode->IsVisible(0); } else if(role == QmitkDataNodeRole) { return QVariant::fromValue(mitk::DataNode::Pointer(dataNode)); } else if(role == QmitkDataNodeRawPointerRole) { return QVariant::fromValue(dataNode); } return QVariant(); } bool QmitkDataStorageTreeModel::DicomPropertiesExists(const mitk::DataNode& node) const { bool propertiesExists = false; mitk::BaseProperty* seriesDescription = (node.GetProperty("dicom.series.SeriesDescription")); mitk::BaseProperty* studyDescription = (node.GetProperty("dicom.study.StudyDescription")); mitk::BaseProperty* patientsName = (node.GetProperty("dicom.patient.PatientsName")); if(patientsName!=NULL && studyDescription!=NULL && seriesDescription!=NULL) { if((!patientsName->GetValueAsString().empty())&& (!studyDescription->GetValueAsString().empty())&& (!seriesDescription->GetValueAsString().empty())) { propertiesExists = true; } } return propertiesExists; } QVariant QmitkDataStorageTreeModel::headerData(int /*section*/, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole && m_Root) return QString::fromStdString(m_Root->GetDataNode()->GetName()); return QVariant(); } void QmitkDataStorageTreeModel::SetDataStorage( mitk::DataStorage* _DataStorage ) { if(m_DataStorage != _DataStorage) // dont take the same again { if(m_DataStorage.IsNotNull()) { // remove Listener for the data storage itself m_DataStorage.ObjectDelete.RemoveListener( mitk::MessageDelegate1( this, &QmitkDataStorageTreeModel::SetDataStorageDeleted ) ); // remove listeners for the nodes m_DataStorage->AddNodeEvent.RemoveListener( mitk::MessageDelegate1( this, &QmitkDataStorageTreeModel::AddNode ) ); m_DataStorage->ChangedNodeEvent.RemoveListener( mitk::MessageDelegate1( this, &QmitkDataStorageTreeModel::SetNodeModified ) ); m_DataStorage->RemoveNodeEvent.RemoveListener( mitk::MessageDelegate1( this, &QmitkDataStorageTreeModel::RemoveNode ) ); } // take over the new data storage m_DataStorage = _DataStorage; // delete the old root (if necessary, create new) if(m_Root) m_Root->Delete(); mitk::DataNode::Pointer rootDataNode = mitk::DataNode::New(); rootDataNode->SetName("Data Manager"); m_Root = new TreeItem(rootDataNode, 0); this->beginResetModel(); this->endResetModel(); if(m_DataStorage.IsNotNull()) { // add Listener for the data storage itself m_DataStorage.ObjectDelete.AddListener( mitk::MessageDelegate1( this, &QmitkDataStorageTreeModel::SetDataStorageDeleted ) ); // add listeners for the nodes m_DataStorage->AddNodeEvent.AddListener( mitk::MessageDelegate1( this, &QmitkDataStorageTreeModel::AddNode ) ); m_DataStorage->ChangedNodeEvent.AddListener( mitk::MessageDelegate1( this, &QmitkDataStorageTreeModel::SetNodeModified ) ); m_DataStorage->RemoveNodeEvent.AddListener( mitk::MessageDelegate1( this, &QmitkDataStorageTreeModel::RemoveNode ) ); mitk::DataStorage::SetOfObjects::ConstPointer _NodeSet = m_DataStorage->GetSubset(m_Predicate); // finally add all nodes to the model this->Update(); } } } void QmitkDataStorageTreeModel::SetDataStorageDeleted( const itk::Object* /*_DataStorage*/ ) { this->SetDataStorage(0); } void QmitkDataStorageTreeModel::AddNodeInternal(const mitk::DataNode *node) { if(node == 0 || m_DataStorage.IsNull() || !m_DataStorage->Exists(node) || m_Root->Find(node) != 0) return; // find out if we have a root node TreeItem* parentTreeItem = m_Root; QModelIndex index; mitk::DataNode* parentDataNode = this->GetParentNode(node); if(parentDataNode) // no top level data node { parentTreeItem = m_Root->Find(parentDataNode); // find the corresponding tree item if(!parentTreeItem) { this->AddNode(parentDataNode); parentTreeItem = m_Root->Find(parentDataNode); if(!parentTreeItem) return; } // get the index of this parent with the help of the grand parent index = this->createIndex(parentTreeItem->GetIndex(), 0, parentTreeItem); } // add node if(m_PlaceNewNodesOnTop) { // emit beginInsertRows event beginInsertRows(index, 0, 0); parentTreeItem->InsertChild(new TreeItem( const_cast(node)), 0); } else { beginInsertRows(index, parentTreeItem->GetChildCount() , parentTreeItem->GetChildCount()); new TreeItem(const_cast(node), parentTreeItem); } // emit endInsertRows event endInsertRows(); this->AdjustLayerProperty(); } void QmitkDataStorageTreeModel::AddNode( const mitk::DataNode* node ) { if(node == 0 + || m_BlockDataStorageEvents || m_DataStorage.IsNull() || !m_DataStorage->Exists(node) || m_Root->Find(node) != 0) return; this->AddNodeInternal(node); } void QmitkDataStorageTreeModel::SetPlaceNewNodesOnTop(bool _PlaceNewNodesOnTop) { m_PlaceNewNodesOnTop = _PlaceNewNodesOnTop; } void QmitkDataStorageTreeModel::RemoveNodeInternal( const mitk::DataNode* node ) { if(!m_Root) return; TreeItem* treeItem = m_Root->Find(node); if(!treeItem) return; // return because there is no treeitem containing this node TreeItem* parentTreeItem = treeItem->GetParent(); QModelIndex parentIndex = this->IndexFromTreeItem(parentTreeItem); // emit beginRemoveRows event (QModelIndex is empty because we dont have a tree model) this->beginRemoveRows(parentIndex, treeItem->GetIndex(), treeItem->GetIndex()); // remove node std::vector children = treeItem->GetChildren(); delete treeItem; // emit endRemoveRows event endRemoveRows(); // move all children of deleted node into its parent for ( std::vector::iterator it = children.begin() ; it != children.end(); it++) { // emit beginInsertRows event beginInsertRows(parentIndex, parentTreeItem->GetChildCount(), parentTreeItem->GetChildCount()); // add nodes again parentTreeItem->AddChild(*it); // emit endInsertRows event endInsertRows(); } this->AdjustLayerProperty(); } -void QmitkDataStorageTreeModel::RemoveNode( const mitk::DataNode* node ) +void QmitkDataStorageTreeModel::RemoveNode(const mitk::DataNode* node ) { - if (node == 0) + if (node == 0 || m_BlockDataStorageEvents) return; this->RemoveNodeInternal(node); } void QmitkDataStorageTreeModel::SetNodeModified( const mitk::DataNode* node ) { TreeItem* treeItem = m_Root->Find(node); if(treeItem) { TreeItem* parentTreeItem = treeItem->GetParent(); // as the root node should not be removed one should always have a parent item if(!parentTreeItem) return; QModelIndex index = this->createIndex(treeItem->GetIndex(), 0, treeItem); // now emit the dataChanged signal emit dataChanged(index, index); } } mitk::DataNode* QmitkDataStorageTreeModel::GetParentNode( const mitk::DataNode* node ) const { mitk::DataNode* dataNode = 0; mitk::DataStorage::SetOfObjects::ConstPointer _Sources = m_DataStorage->GetSources(node); if(_Sources->Size() > 0) dataNode = _Sources->front(); return dataNode; } bool QmitkDataStorageTreeModel::setData( const QModelIndex &index, const QVariant &value, int role ) { mitk::DataNode* dataNode = this->TreeItemFromIndex(index)->GetDataNode(); if(!dataNode) return false; if(role == Qt::EditRole && !value.toString().isEmpty()) { dataNode->SetStringProperty("name", value.toString().toStdString().c_str()); mitk::PlanarFigure* planarFigure = dynamic_cast(dataNode->GetData()); if (planarFigure != NULL) mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } else if(role == Qt::CheckStateRole) { // Please note: value.toInt() returns 2, independentely from the actual checkstate of the index element. // Therefore the checkstate is being estimated again here. QVariant qcheckstate = index.data(Qt::CheckStateRole); int checkstate = qcheckstate.toInt(); bool isVisible = bool(checkstate); dataNode->SetVisibility(!isVisible); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } // inform listeners about changes emit dataChanged(index, index); return true; } bool QmitkDataStorageTreeModel::setHeaderData( int /*section*/, Qt::Orientation /*orientation*/, const QVariant& /* value */, int /*role = Qt::EditRole*/ ) { return false; } void QmitkDataStorageTreeModel::AdjustLayerProperty() { /// transform the tree into an array and set the layer property descending std::vector vec; this->TreeToVector(m_Root, vec); int i = vec.size()-1; for(std::vector::const_iterator it = vec.begin(); it != vec.end(); ++it) { mitk::DataNode::Pointer dataNode = (*it)->GetDataNode(); bool fixedLayer = false; if (!(dataNode->GetBoolProperty("fixedLayer", fixedLayer) && fixedLayer)) dataNode->SetIntProperty("layer", i); --i; } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkDataStorageTreeModel::TreeToVector(TreeItem* parent, std::vector& vec) const { TreeItem* current; for(int i = 0; iGetChildCount(); ++i) { current = parent->GetChild(i); this->TreeToVector(current, vec); vec.push_back(current); } } QModelIndex QmitkDataStorageTreeModel::IndexFromTreeItem( TreeItem* item ) const { if(item == m_Root) return QModelIndex(); else return this->createIndex(item->GetIndex(), 0, item); } QList QmitkDataStorageTreeModel::GetNodeSet() const { QList res; if(m_Root) this->TreeToNodeSet(m_Root, res); return res; } void QmitkDataStorageTreeModel::TreeToNodeSet( TreeItem* parent, QList& vec ) const { TreeItem* current; for(int i = 0; iGetChildCount(); ++i) { current = parent->GetChild(i); vec.push_back(current->GetDataNode()); this->TreeToNodeSet(current, vec); } } QModelIndex QmitkDataStorageTreeModel::GetIndex( const mitk::DataNode* node ) const { if(m_Root) { TreeItem* item = m_Root->Find(node); if(item) return this->IndexFromTreeItem(item); } return QModelIndex(); } QList QmitkDataStorageTreeModel::ToTreeItemPtrList(const QMimeData* mimeData) { if (mimeData == NULL || !mimeData->hasFormat(QmitkMimeTypes::DataStorageTreeItemPtrs)) { return QList(); } return ToTreeItemPtrList(mimeData->data(QmitkMimeTypes::DataStorageTreeItemPtrs)); } QList QmitkDataStorageTreeModel::ToTreeItemPtrList(const QByteArray& ba) { QList result; QDataStream ds(ba); while(!ds.atEnd()) { quintptr treeItemPtr; ds >> treeItemPtr; result.push_back(reinterpret_cast(treeItemPtr)); } return result; } QmitkDataStorageTreeModel::TreeItem::TreeItem( mitk::DataNode* _DataNode, TreeItem* _Parent ) : m_Parent(_Parent) , m_DataNode(_DataNode) { if(m_Parent) m_Parent->AddChild(this); } QmitkDataStorageTreeModel::TreeItem::~TreeItem() { if(m_Parent) m_Parent->RemoveChild(this); } void QmitkDataStorageTreeModel::TreeItem::Delete() { while(m_Children.size() > 0) delete m_Children.back(); delete this; } QmitkDataStorageTreeModel::TreeItem* QmitkDataStorageTreeModel::TreeItem::Find( const mitk::DataNode* _DataNode ) const { QmitkDataStorageTreeModel::TreeItem* item = 0; if(_DataNode) { if(m_DataNode == _DataNode) item = const_cast(this); else { for(std::vector::const_iterator it = m_Children.begin(); it != m_Children.end(); ++it) { if(item) break; item = (*it)->Find(_DataNode); } } } return item; } int QmitkDataStorageTreeModel::TreeItem::IndexOfChild( const TreeItem* item ) const { std::vector::const_iterator it = std::find(m_Children.begin(), m_Children.end(), item); return it != m_Children.end() ? std::distance(m_Children.begin(), it): -1; } QmitkDataStorageTreeModel::TreeItem* QmitkDataStorageTreeModel::TreeItem::GetChild( int index ) const { return (m_Children.size() > 0 && index >= 0 && index < (int)m_Children.size())? m_Children.at(index): 0; } void QmitkDataStorageTreeModel::TreeItem::AddChild( TreeItem* item ) { this->InsertChild(item); } void QmitkDataStorageTreeModel::TreeItem::RemoveChild( TreeItem* item ) { std::vector::iterator it = std::find(m_Children.begin(), m_Children.end(), item); if(it != m_Children.end()) { m_Children.erase(it); item->SetParent(0); } } int QmitkDataStorageTreeModel::TreeItem::GetChildCount() const { return m_Children.size(); } int QmitkDataStorageTreeModel::TreeItem::GetIndex() const { if (m_Parent) return m_Parent->IndexOfChild(this); return 0; } QmitkDataStorageTreeModel::TreeItem* QmitkDataStorageTreeModel::TreeItem::GetParent() const { return m_Parent; } mitk::DataNode::Pointer QmitkDataStorageTreeModel::TreeItem::GetDataNode() const { return m_DataNode; } void QmitkDataStorageTreeModel::TreeItem::InsertChild( TreeItem* item, int index ) { std::vector::iterator it = std::find(m_Children.begin(), m_Children.end(), item); if(it == m_Children.end()) { if(m_Children.size() > 0 && index >= 0 && index < (int)m_Children.size()) { it = m_Children.begin(); std::advance(it, index); m_Children.insert(it, item); } else m_Children.push_back(item); // add parent if necessary if(item->GetParent() != this) item->SetParent(this); } } std::vector QmitkDataStorageTreeModel::TreeItem::GetChildren() const { return m_Children; } void QmitkDataStorageTreeModel::TreeItem::SetParent( TreeItem* _Parent ) { m_Parent = _Parent; if(m_Parent) m_Parent->AddChild(this); } void QmitkDataStorageTreeModel::Update() { if (m_DataStorage.IsNotNull()) { this->beginResetModel(); this->endResetModel(); mitk::DataStorage::SetOfObjects::ConstPointer _NodeSet = m_DataStorage->GetAll(); for (mitk::DataStorage::SetOfObjects::const_iterator it = _NodeSet->begin(); it != _NodeSet->end(); it++) { // save node this->AddNodeInternal(*it); } } } + +void QmitkDataStorageTreeModel::SetAllowHierarchyChange(bool allowHierarchyChange) +{ + m_AllowHierarchyChange = allowHierarchyChange; +} diff --git a/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerPreferencePage.cpp b/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerPreferencePage.cpp index 0f50735dfc..463d5dbfcd 100644 --- a/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerPreferencePage.cpp +++ b/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerPreferencePage.cpp @@ -1,105 +1,110 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkDataManagerPreferencePage.h" #include "QmitkDataManagerView.h" #include #include #include #include #include #include QmitkDataManagerPreferencePage::QmitkDataManagerPreferencePage() : m_MainControl(nullptr) { } void QmitkDataManagerPreferencePage::Init(berry::IWorkbench::Pointer ) { } void QmitkDataManagerPreferencePage::CreateQtControl(QWidget* parent) { berry::IPreferencesService* prefService = berry::Platform::GetPreferencesService(); m_DataManagerPreferencesNode = prefService->GetSystemPreferences()->Node(QmitkDataManagerView::VIEW_ID); m_MainControl = new QWidget(parent); m_EnableSingleEditing = new QCheckBox; m_PlaceNewNodesOnTop = new QCheckBox; m_ShowHelperObjects = new QCheckBox; m_ShowNodesContainingNoData = new QCheckBox; m_GlobalReinitOnNodeDelete = new QCheckBox; m_GlobalReinitOnNodeAdded = new QCheckBox; m_UseSurfaceDecimation = new QCheckBox; + m_AllowParentChange = new QCheckBox; auto formLayout = new QFormLayout; formLayout->addRow("&Single click property editing:", m_EnableSingleEditing); formLayout->addRow("&Place new nodes on top:", m_PlaceNewNodesOnTop); formLayout->addRow("&Show helper objects:", m_ShowHelperObjects); formLayout->addRow("&Show nodes containing no data", m_ShowNodesContainingNoData); formLayout->addRow("&Call global reinit if node is deleted", m_GlobalReinitOnNodeDelete); formLayout->addRow("&Call global reinit if node is added", m_GlobalReinitOnNodeAdded); formLayout->addRow("&Use surface decimation:", m_UseSurfaceDecimation); + formLayout->addRow("&Allow changing of parent node:", m_AllowParentChange); m_MainControl->setLayout(formLayout); this->Update(); } QWidget* QmitkDataManagerPreferencePage::GetQtControl() const { return m_MainControl; } bool QmitkDataManagerPreferencePage::PerformOk() { m_DataManagerPreferencesNode->PutBool("Single click property editing" , m_EnableSingleEditing->isChecked()); m_DataManagerPreferencesNode->PutBool("Place new nodes on top" , m_PlaceNewNodesOnTop->isChecked()); m_DataManagerPreferencesNode->PutBool("Show helper objects" , m_ShowHelperObjects->isChecked()); m_DataManagerPreferencesNode->PutBool("Show nodes containing no data" , m_ShowNodesContainingNoData->isChecked()); m_DataManagerPreferencesNode->PutBool("Call global reinit if node is deleted" , m_GlobalReinitOnNodeDelete->isChecked()); m_DataManagerPreferencesNode->PutBool("Call global reinit if node is added" , m_GlobalReinitOnNodeAdded->isChecked()); m_DataManagerPreferencesNode->PutBool("Use surface decimation" , m_UseSurfaceDecimation->isChecked()); + m_DataManagerPreferencesNode->PutBool("Allow changing of parent node" + , m_AllowParentChange->isChecked()); return true; } void QmitkDataManagerPreferencePage::PerformCancel() { } void QmitkDataManagerPreferencePage::Update() { m_EnableSingleEditing->setChecked(m_DataManagerPreferencesNode->GetBool("Single click property editing", true)); m_PlaceNewNodesOnTop->setChecked(m_DataManagerPreferencesNode->GetBool("Place new nodes on top", true)); m_ShowHelperObjects->setChecked(m_DataManagerPreferencesNode->GetBool("Show helper objects", false)); m_ShowNodesContainingNoData->setChecked(m_DataManagerPreferencesNode->GetBool("Show nodes containing no data", false)); m_UseSurfaceDecimation->setChecked(m_DataManagerPreferencesNode->GetBool("Use surface decimation", true)); m_GlobalReinitOnNodeDelete->setChecked(m_DataManagerPreferencesNode->GetBool("Call global reinit if node is deleted", true)); m_GlobalReinitOnNodeAdded->setChecked(m_DataManagerPreferencesNode->GetBool("Call global reinit if node is added", true)); + m_AllowParentChange->setChecked(m_DataManagerPreferencesNode->GetBool("Allow changing of parent node", false)); } diff --git a/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerPreferencePage.h b/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerPreferencePage.h index 48792ebb9e..b45b5b77ae 100644 --- a/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerPreferencePage.h +++ b/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerPreferencePage.h @@ -1,69 +1,70 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QMITKDATAMANAGERPREFERENCEPAGE_H_ #define QMITKDATAMANAGERPREFERENCEPAGE_H_ #include "berryIQtPreferencePage.h" #include #include class QWidget; class QCheckBox; struct MITK_QT_DATAMANAGER QmitkDataManagerPreferencePage : public QObject, public berry::IQtPreferencePage { Q_OBJECT Q_INTERFACES(berry::IPreferencePage) public: QmitkDataManagerPreferencePage(); void Init(berry::IWorkbench::Pointer workbench) override; void CreateQtControl(QWidget* widget) override; QWidget* GetQtControl() const override; /// /// \see IPreferencePage::PerformOk() /// virtual bool PerformOk() override; /// /// \see IPreferencePage::PerformCancel() /// virtual void PerformCancel() override; /// /// \see IPreferencePage::Update() /// virtual void Update() override; protected: QWidget* m_MainControl; QCheckBox* m_EnableSingleEditing; QCheckBox* m_PlaceNewNodesOnTop; QCheckBox* m_ShowHelperObjects; QCheckBox* m_ShowNodesContainingNoData; QCheckBox* m_GlobalReinitOnNodeDelete; QCheckBox* m_GlobalReinitOnNodeAdded; QCheckBox* m_UseSurfaceDecimation; + QCheckBox* m_AllowParentChange; berry::IPreferences::Pointer m_DataManagerPreferencesNode; }; #endif /* QMITKDATAMANAGERPREFERENCEPAGE_H_ */ diff --git a/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerView.cpp b/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerView.cpp index 218c02572b..a1122771b9 100644 --- a/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerView.cpp +++ b/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerView.cpp @@ -1,995 +1,1000 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkDataManagerView.h" //# Own Includes //## mitk #include "mitkDataStorageEditorInput.h" #include "mitkIDataStorageReference.h" #include "mitkNodePredicateDataType.h" #include "mitkCoreObjectFactory.h" #include "mitkColorProperty.h" #include "mitkCommon.h" #include "mitkNodePredicateData.h" #include "mitkNodePredicateNot.h" #include "mitkNodePredicateOr.h" #include "mitkNodePredicateProperty.h" #include "mitkEnumerationProperty.h" #include "mitkLookupTableProperty.h" #include "mitkProperties.h" #include #include #include #include #include //## Qmitk #include #include #include #include #include #include #include #include "src/internal/QmitkNodeTableViewKeyFilter.h" #include "src/internal/QmitkInfoDialog.h" #include "src/internal/QmitkDataManagerItemDelegate.h" //## Berry #include #include #include #include #include #include //# Toolkit Includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mitkDataNodeObject.h" #include "mitkIContextMenuAction.h" #include "berryIExtensionRegistry.h" #include "mitkRenderingModeProperty.h" const QString QmitkDataManagerView::VIEW_ID = "org.mitk.views.datamanager"; QmitkDataManagerView::QmitkDataManagerView() : m_GlobalReinitOnNodeDelete(true), m_ItemDelegate(NULL) { } QmitkDataManagerView::~QmitkDataManagerView() { //Remove all registered actions from each descriptor for (std::vector< std::pair< QmitkNodeDescriptor*, QAction* > >::iterator it = m_DescriptorActionList.begin();it != m_DescriptorActionList.end(); it++) { // first== the NodeDescriptor; second== the registered QAction (it->first)->RemoveAction(it->second); } } void QmitkDataManagerView::CreateQtPartControl(QWidget* parent) { m_CurrentRowCount = 0; m_Parent = parent; //# Preferences berry::IPreferencesService* prefService = berry::Platform::GetPreferencesService(); berry::IBerryPreferences::Pointer prefs = (prefService->GetSystemPreferences()->Node(VIEW_ID)) .Cast(); assert( prefs ); prefs->OnChanged.AddListener( berry::MessageDelegate1( this , &QmitkDataManagerView::OnPreferencesChanged ) ); //# GUI m_NodeTreeModel = new QmitkDataStorageTreeModel(this->GetDataStorage()); m_NodeTreeModel->setParent( parent ); m_NodeTreeModel->SetPlaceNewNodesOnTop( prefs->GetBool("Place new nodes on top", true) ); + m_NodeTreeModel->SetAllowHierarchyChange( + prefs->GetBool("Allow changing of parent node", false)); m_SurfaceDecimation = prefs->GetBool("Use surface decimation", false); // Prepare filters m_HelperObjectFilterPredicate = mitk::NodePredicateOr::New( mitk::NodePredicateProperty::New("helper object", mitk::BoolProperty::New(true)), mitk::NodePredicateProperty::New("hidden object", mitk::BoolProperty::New(true))); m_NodeWithNoDataFilterPredicate = mitk::NodePredicateData::New(0); m_FilterModel = new QmitkDataStorageFilterProxyModel(); m_FilterModel->setSourceModel(m_NodeTreeModel); m_FilterModel->AddFilterPredicate(m_HelperObjectFilterPredicate); m_FilterModel->AddFilterPredicate(m_NodeWithNoDataFilterPredicate); //# Tree View (experimental) m_NodeTreeView = new QTreeView; m_NodeTreeView->setHeaderHidden(true); m_NodeTreeView->setSelectionMode( QAbstractItemView::ExtendedSelection ); m_NodeTreeView->setSelectionBehavior( QAbstractItemView::SelectRows ); m_NodeTreeView->setAlternatingRowColors(true); m_NodeTreeView->setDragEnabled(true); m_NodeTreeView->setDropIndicatorShown(true); m_NodeTreeView->setAcceptDrops(true); m_NodeTreeView->setContextMenuPolicy(Qt::CustomContextMenu); m_NodeTreeView->setModel(m_FilterModel); m_NodeTreeView->setTextElideMode(Qt::ElideMiddle); m_NodeTreeView->installEventFilter(new QmitkNodeTableViewKeyFilter(this)); m_ItemDelegate = new QmitkDataManagerItemDelegate(m_NodeTreeView); m_NodeTreeView->setItemDelegate(m_ItemDelegate); QObject::connect( m_NodeTreeView, SIGNAL(customContextMenuRequested(const QPoint&)) , this, SLOT(NodeTableViewContextMenuRequested(const QPoint&)) ); QObject::connect( m_NodeTreeModel, SIGNAL(rowsInserted (const QModelIndex&, int, int)) , this, SLOT(NodeTreeViewRowsInserted ( const QModelIndex&, int, int )) ); QObject::connect( m_NodeTreeModel, SIGNAL(rowsRemoved (const QModelIndex&, int, int)) , this, SLOT(NodeTreeViewRowsRemoved( const QModelIndex&, int, int )) ); QObject::connect( m_NodeTreeView->selectionModel() , SIGNAL( selectionChanged ( const QItemSelection &, const QItemSelection & ) ) , this , SLOT( NodeSelectionChanged ( const QItemSelection &, const QItemSelection & ) ) ); //# m_NodeMenu m_NodeMenu = new QMenu(m_NodeTreeView); // # Actions berry::IEditorRegistry* editorRegistry = berry::PlatformUI::GetWorkbench()->GetEditorRegistry(); QList editors = editorRegistry->GetEditors("*.mitk"); if (editors.size() > 1) { m_ShowInMapper = new QSignalMapper(this); foreach(berry::IEditorDescriptor::Pointer descriptor, editors) { QAction* action = new QAction(descriptor->GetLabel(), this); m_ShowInActions << action; m_ShowInMapper->connect(action, SIGNAL(triggered()), m_ShowInMapper, SLOT(map())); m_ShowInMapper->setMapping(action, descriptor->GetId()); } connect(m_ShowInMapper, SIGNAL(mapped(QString)), this, SLOT(ShowIn(QString))); } QmitkNodeDescriptor* unknownDataNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetUnknownDataNodeDescriptor(); QmitkNodeDescriptor* imageDataNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("Image"); auto multiComponentImageDataNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("MultiComponentImage"); QmitkNodeDescriptor* diffusionImageDataNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("DiffusionImage"); QmitkNodeDescriptor* surfaceDataNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("Surface"); QAction* globalReinitAction = new QAction(QIcon(":/org.mitk.gui.qt.datamanager/Refresh_48.png"), "Global Reinit", this); QObject::connect( globalReinitAction, SIGNAL( triggered(bool) ) , this, SLOT( GlobalReinit(bool) ) ); unknownDataNodeDescriptor->AddAction(globalReinitAction); m_DescriptorActionList.push_back(std::pair(unknownDataNodeDescriptor, globalReinitAction)); QAction* saveAction = new QmitkFileSaveAction(QIcon(":/org.mitk.gui.qt.datamanager/Save_48.png"), this->GetSite()->GetWorkbenchWindow()); unknownDataNodeDescriptor->AddAction(saveAction); m_DescriptorActionList.push_back(std::pair(unknownDataNodeDescriptor,saveAction)); QAction* removeAction = new QAction(QIcon(":/org.mitk.gui.qt.datamanager/Remove_48.png"), "Remove", this); QObject::connect( removeAction, SIGNAL( triggered(bool) ) , this, SLOT( RemoveSelectedNodes(bool) ) ); unknownDataNodeDescriptor->AddAction(removeAction); m_DescriptorActionList.push_back(std::pair(unknownDataNodeDescriptor,removeAction)); QAction* reinitAction = new QAction(QIcon(":/org.mitk.gui.qt.datamanager/Refresh_48.png"), "Reinit", this); QObject::connect( reinitAction, SIGNAL( triggered(bool) ) , this, SLOT( ReinitSelectedNodes(bool) ) ); unknownDataNodeDescriptor->AddAction(reinitAction); m_DescriptorActionList.push_back(std::pair(unknownDataNodeDescriptor,reinitAction)); // find contextMenuAction extension points and add them to the node descriptor berry::IExtensionRegistry* extensionPointService = berry::Platform::GetExtensionRegistry(); QList cmActions( extensionPointService->GetConfigurationElementsFor("org.mitk.gui.qt.datamanager.contextMenuActions") ); QList::iterator cmActionsIt; QmitkNodeDescriptor* tmpDescriptor; QAction* contextMenuAction; QVariant cmActionDataIt; m_ConfElements.clear(); int i=1; for (cmActionsIt = cmActions.begin() ; cmActionsIt != cmActions.end() ; ++cmActionsIt) { QString cmNodeDescriptorName = (*cmActionsIt)->GetAttribute("nodeDescriptorName"); QString cmLabel = (*cmActionsIt)->GetAttribute("label"); QString cmClass = (*cmActionsIt)->GetAttribute("class"); if(!cmNodeDescriptorName.isEmpty() && !cmLabel.isEmpty() && !cmClass.isEmpty()) { QString cmIcon = (*cmActionsIt)->GetAttribute("icon"); // create context menu entry here tmpDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor(cmNodeDescriptorName); if(!tmpDescriptor) { MITK_WARN << "cannot add action \"" << cmLabel << "\" because descriptor " << cmNodeDescriptorName << " does not exist"; continue; } // check if the user specified an icon attribute if ( !cmIcon.isEmpty() ) { contextMenuAction = new QAction( QIcon(cmIcon), cmLabel, parent); } else { contextMenuAction = new QAction( cmLabel, parent); } tmpDescriptor->AddAction(contextMenuAction); m_DescriptorActionList.push_back(std::pair(tmpDescriptor,contextMenuAction)); m_ConfElements[contextMenuAction] = *cmActionsIt; cmActionDataIt.setValue(i); contextMenuAction->setData( cmActionDataIt ); connect( contextMenuAction, SIGNAL( triggered(bool) ) , this, SLOT( ContextMenuActionTriggered(bool) ) ); ++i; } } m_OpacitySlider = new QSlider; m_OpacitySlider->setMinimum(0); m_OpacitySlider->setMaximum(100); m_OpacitySlider->setOrientation(Qt::Horizontal); QObject::connect( m_OpacitySlider, SIGNAL( valueChanged(int) ) , this, SLOT( OpacityChanged(int) ) ); QLabel* _OpacityLabel = new QLabel("Opacity: "); QHBoxLayout* _OpacityWidgetLayout = new QHBoxLayout; _OpacityWidgetLayout->setContentsMargins(4,4,4,4); _OpacityWidgetLayout->addWidget(_OpacityLabel); _OpacityWidgetLayout->addWidget(m_OpacitySlider); QWidget* _OpacityWidget = new QWidget; _OpacityWidget->setLayout(_OpacityWidgetLayout); QWidgetAction* opacityAction = new QWidgetAction(this); opacityAction ->setDefaultWidget(_OpacityWidget); QObject::connect( opacityAction , SIGNAL( changed() ) , this, SLOT( OpacityActionChanged() ) ); unknownDataNodeDescriptor->AddAction(opacityAction , false); m_DescriptorActionList.push_back(std::pair(unknownDataNodeDescriptor,opacityAction)); m_ColorButton = new QPushButton; m_ColorButton->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Minimum); //m_ColorButton->setText("Change color"); QObject::connect( m_ColorButton, SIGNAL( clicked() ) , this, SLOT( ColorChanged() ) ); QLabel* _ColorLabel = new QLabel("Color: "); _ColorLabel->setSizePolicy(QSizePolicy::Minimum,QSizePolicy::Minimum); QHBoxLayout* _ColorWidgetLayout = new QHBoxLayout; _ColorWidgetLayout->setContentsMargins(4,4,4,4); _ColorWidgetLayout->addWidget(_ColorLabel); _ColorWidgetLayout->addWidget(m_ColorButton); QWidget* _ColorWidget = new QWidget; _ColorWidget->setLayout(_ColorWidgetLayout); QWidgetAction* colorAction = new QWidgetAction(this); colorAction->setDefaultWidget(_ColorWidget); QObject::connect( colorAction, SIGNAL( changed() ) , this, SLOT( ColorActionChanged() ) ); unknownDataNodeDescriptor->AddAction(colorAction, false); m_DescriptorActionList.push_back(std::pair(unknownDataNodeDescriptor,colorAction)); m_ComponentSlider = new QmitkNumberPropertySlider; m_ComponentSlider->setOrientation(Qt::Horizontal); //QObject::connect( m_OpacitySlider, SIGNAL( valueChanged(int) ) // , this, SLOT( OpacityChanged(int) ) ); QLabel* _ComponentLabel = new QLabel("Component: "); QHBoxLayout* _ComponentWidgetLayout = new QHBoxLayout; _ComponentWidgetLayout->setContentsMargins(4,4,4,4); _ComponentWidgetLayout->addWidget(_ComponentLabel); _ComponentWidgetLayout->addWidget(m_ComponentSlider); QLabel* _ComponentValueLabel = new QLabel(); _ComponentWidgetLayout->addWidget(_ComponentValueLabel); connect(m_ComponentSlider, SIGNAL(valueChanged(int)), _ComponentValueLabel, SLOT(setNum(int))); QWidget* _ComponentWidget = new QWidget; _ComponentWidget->setLayout(_ComponentWidgetLayout); QWidgetAction* componentAction = new QWidgetAction(this); componentAction->setDefaultWidget(_ComponentWidget); QObject::connect( componentAction , SIGNAL( changed() ) , this, SLOT( ComponentActionChanged() ) ); multiComponentImageDataNodeDescriptor->AddAction(componentAction, false); m_DescriptorActionList.push_back(std::pair(multiComponentImageDataNodeDescriptor,componentAction)); if (diffusionImageDataNodeDescriptor!=NULL) { diffusionImageDataNodeDescriptor->AddAction(componentAction, false); m_DescriptorActionList.push_back(std::pair(diffusionImageDataNodeDescriptor,componentAction)); } m_TextureInterpolation = new QAction("Texture Interpolation", this); m_TextureInterpolation->setCheckable ( true ); QObject::connect( m_TextureInterpolation, SIGNAL( changed() ) , this, SLOT( TextureInterpolationChanged() ) ); QObject::connect( m_TextureInterpolation, SIGNAL( toggled(bool) ) , this, SLOT( TextureInterpolationToggled(bool) ) ); imageDataNodeDescriptor->AddAction(m_TextureInterpolation, false); m_DescriptorActionList.push_back(std::pair(imageDataNodeDescriptor,m_TextureInterpolation)); if (diffusionImageDataNodeDescriptor!=NULL) { diffusionImageDataNodeDescriptor->AddAction(m_TextureInterpolation, false); m_DescriptorActionList.push_back(std::pair(diffusionImageDataNodeDescriptor,m_TextureInterpolation)); } m_ColormapAction = new QAction("Colormap", this); m_ColormapAction->setMenu(new QMenu); QObject::connect( m_ColormapAction->menu(), SIGNAL( aboutToShow() ) , this, SLOT( ColormapMenuAboutToShow() ) ); imageDataNodeDescriptor->AddAction(m_ColormapAction, false); m_DescriptorActionList.push_back(std::pair(imageDataNodeDescriptor, m_ColormapAction)); if (diffusionImageDataNodeDescriptor!=NULL) { diffusionImageDataNodeDescriptor->AddAction(m_ColormapAction, false); m_DescriptorActionList.push_back(std::pair(diffusionImageDataNodeDescriptor, m_ColormapAction)); } m_SurfaceRepresentation = new QAction("Surface Representation", this); m_SurfaceRepresentation->setMenu(new QMenu(m_NodeTreeView)); QObject::connect( m_SurfaceRepresentation->menu(), SIGNAL( aboutToShow() ) , this, SLOT( SurfaceRepresentationMenuAboutToShow() ) ); surfaceDataNodeDescriptor->AddAction(m_SurfaceRepresentation, false); m_DescriptorActionList.push_back(std::pair(surfaceDataNodeDescriptor, m_SurfaceRepresentation)); QAction* showOnlySelectedNodes = new QAction(QIcon(":/org.mitk.gui.qt.datamanager/ShowSelectedNode_48.png") , "Show only selected nodes", this); QObject::connect( showOnlySelectedNodes, SIGNAL( triggered(bool) ) , this, SLOT( ShowOnlySelectedNodes(bool) ) ); unknownDataNodeDescriptor->AddAction(showOnlySelectedNodes); m_DescriptorActionList.push_back(std::pair(unknownDataNodeDescriptor, showOnlySelectedNodes)); QAction* toggleSelectedVisibility = new QAction(QIcon(":/org.mitk.gui.qt.datamanager/InvertShowSelectedNode_48.png") , "Toggle visibility", this); QObject::connect( toggleSelectedVisibility, SIGNAL( triggered(bool) ) , this, SLOT( ToggleVisibilityOfSelectedNodes(bool) ) ); unknownDataNodeDescriptor->AddAction(toggleSelectedVisibility); m_DescriptorActionList.push_back(std::pair(unknownDataNodeDescriptor,toggleSelectedVisibility)); QAction* actionShowInfoDialog = new QAction(QIcon(":/org.mitk.gui.qt.datamanager/ShowDataInfo_48.png") , "Details...", this); QObject::connect( actionShowInfoDialog, SIGNAL( triggered(bool) ) , this, SLOT( ShowInfoDialogForSelectedNodes(bool) ) ); unknownDataNodeDescriptor->AddAction(actionShowInfoDialog); m_DescriptorActionList.push_back(std::pair(unknownDataNodeDescriptor,actionShowInfoDialog)); QGridLayout* _DndFrameWidgetLayout = new QGridLayout; _DndFrameWidgetLayout->addWidget(m_NodeTreeView, 0, 0); _DndFrameWidgetLayout->setContentsMargins(0,0,0,0); m_DndFrameWidget = new QmitkDnDFrameWidget(m_Parent); m_DndFrameWidget->setLayout(_DndFrameWidgetLayout); QVBoxLayout* layout = new QVBoxLayout(parent); layout->addWidget(m_DndFrameWidget); layout->setContentsMargins(0,0,0,0); m_Parent->setLayout(layout); } void QmitkDataManagerView::SetFocus() { } void QmitkDataManagerView::ContextMenuActionTriggered( bool ) { QAction* action = qobject_cast ( sender() ); std::map::iterator it = m_ConfElements.find( action ); if( it == m_ConfElements.end() ) { MITK_WARN << "associated conf element for action " << action->text().toStdString() << " not found"; return; } berry::IConfigurationElement::Pointer confElem = it->second; mitk::IContextMenuAction* contextMenuAction = confElem->CreateExecutableExtension("class"); QString className = confElem->GetAttribute("class"); QString smoothed = confElem->GetAttribute("smoothed"); if(className == "QmitkCreatePolygonModelAction") { contextMenuAction->SetDataStorage(this->GetDataStorage()); if(smoothed == "false") { contextMenuAction->SetSmoothed(false); } else { contextMenuAction->SetSmoothed(true); } contextMenuAction->SetDecimated(m_SurfaceDecimation); } else if(className == "QmitkStatisticsAction") { contextMenuAction->SetFunctionality(this); } else if(className == "QmitkCreateSimulationAction") { contextMenuAction->SetDataStorage(this->GetDataStorage()); } contextMenuAction->Run( this->GetCurrentSelection() ); // run the action } void QmitkDataManagerView::OnPreferencesChanged(const berry::IBerryPreferences* prefs) { if( m_NodeTreeModel->GetPlaceNewNodesOnTopFlag() != prefs->GetBool("Place new nodes on top", true) ) m_NodeTreeModel->SetPlaceNewNodesOnTop( !m_NodeTreeModel->GetPlaceNewNodesOnTopFlag() ); bool hideHelperObjects = !prefs->GetBool("Show helper objects", false); if (m_FilterModel->HasFilterPredicate(m_HelperObjectFilterPredicate) != hideHelperObjects) { if (hideHelperObjects) { m_FilterModel->AddFilterPredicate(m_HelperObjectFilterPredicate); } else { m_FilterModel->RemoveFilterPredicate(m_HelperObjectFilterPredicate); } } bool hideNodesWithNoData = !prefs->GetBool("Show nodes containing no data", false); if (m_FilterModel->HasFilterPredicate(m_NodeWithNoDataFilterPredicate) != hideNodesWithNoData) { if (hideNodesWithNoData) { m_FilterModel->AddFilterPredicate(m_NodeWithNoDataFilterPredicate); } else { m_FilterModel->RemoveFilterPredicate(m_NodeWithNoDataFilterPredicate); } } m_GlobalReinitOnNodeDelete = prefs->GetBool("Call global reinit if node is deleted", true); m_NodeTreeView->expandAll(); m_SurfaceDecimation = prefs->GetBool("Use surface decimation", false); + m_NodeTreeModel->SetAllowHierarchyChange( + prefs->GetBool("Allow changing of parent node", false)); + this->GlobalReinit(); } void QmitkDataManagerView::NodeTableViewContextMenuRequested( const QPoint & pos ) { QModelIndex selectedProxy = m_NodeTreeView->indexAt ( pos ); QModelIndex selected = m_FilterModel->mapToSource(selectedProxy); mitk::DataNode::Pointer node = m_NodeTreeModel->GetNode(selected); QList selectedNodes = this->GetCurrentSelection(); if(!selectedNodes.isEmpty()) { m_NodeMenu->clear(); QList actions; if(selectedNodes.size() == 1 ) { actions = QmitkNodeDescriptorManager::GetInstance()->GetActions(node); for(QList::iterator it = actions.begin(); it != actions.end(); ++it) { (*it)->setData(QVariant::fromValue(node.GetPointer())); } } else actions = QmitkNodeDescriptorManager::GetInstance()->GetActions(selectedNodes); if (!m_ShowInActions.isEmpty()) { QMenu* showInMenu = m_NodeMenu->addMenu("Show In"); showInMenu->addActions(m_ShowInActions); } m_NodeMenu->addActions(actions); m_NodeMenu->popup(QCursor::pos()); } } void QmitkDataManagerView::OpacityChanged(int value) { mitk::DataNode* node = m_NodeTreeModel->GetNode(m_FilterModel->mapToSource(m_NodeTreeView->selectionModel()->currentIndex())); if(node) { float opacity = static_cast(value)/100.0f; node->SetFloatProperty("opacity", opacity); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkDataManagerView::OpacityActionChanged() { mitk::DataNode* node = m_NodeTreeModel->GetNode(m_FilterModel->mapToSource(m_NodeTreeView->selectionModel()->currentIndex())); if(node) { float opacity = 0.0; if(node->GetFloatProperty("opacity", opacity)) { m_OpacitySlider->setValue(static_cast(opacity*100)); } } } void QmitkDataManagerView::ComponentActionChanged() { mitk::DataNode* node = m_NodeTreeModel->GetNode(m_FilterModel->mapToSource(m_NodeTreeView->selectionModel()->currentIndex())); mitk::IntProperty* componentProperty = NULL; int numComponents = 0; if(node) { componentProperty = dynamic_cast(node->GetProperty("Image.Displayed Component")); mitk::Image* img = dynamic_cast(node->GetData()); if (img != NULL) { numComponents = img->GetPixelType().GetNumberOfComponents(); } } if (componentProperty && numComponents > 1) { m_ComponentSlider->SetProperty(componentProperty); m_ComponentSlider->setMinValue(0); m_ComponentSlider->setMaxValue(numComponents-1); } else { m_ComponentSlider->SetProperty(static_cast(NULL)); } } void QmitkDataManagerView::ColorChanged() { mitk::DataNode* node = m_NodeTreeModel->GetNode(m_FilterModel->mapToSource(m_NodeTreeView->selectionModel()->currentIndex())); if(node) { mitk::Color color; mitk::ColorProperty::Pointer colorProp; node->GetProperty(colorProp,"color"); if(colorProp.IsNull()) return; color = colorProp->GetValue(); QColor initial(color.GetRed()*255,color.GetGreen()*255,color.GetBlue()*255); QColor qcolor = QColorDialog::getColor(initial,0,QString("Change color")); if (!qcolor.isValid()) return; m_ColorButton->setAutoFillBackground(true); node->SetProperty("color",mitk::ColorProperty::New(qcolor.red()/255.0,qcolor.green()/255.0,qcolor.blue()/255.0)); if (node->GetProperty("binaryimage.selectedcolor")) { node->SetProperty("binaryimage.selectedcolor",mitk::ColorProperty::New(qcolor.red()/255.0,qcolor.green()/255.0,qcolor.blue()/255.0)); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkDataManagerView::ColorActionChanged() { mitk::DataNode* node = m_NodeTreeModel->GetNode(m_FilterModel->mapToSource(m_NodeTreeView->selectionModel()->currentIndex())); if(node) { mitk::Color color; mitk::ColorProperty::Pointer colorProp; node->GetProperty(colorProp,"color"); if(colorProp.IsNull()) return; color = colorProp->GetValue(); QString styleSheet = "background-color:rgb("; styleSheet.append(QString::number(color[0]*255)); styleSheet.append(","); styleSheet.append(QString::number(color[1]*255)); styleSheet.append(","); styleSheet.append(QString::number(color[2]*255)); styleSheet.append(")"); m_ColorButton->setStyleSheet(styleSheet); } } void QmitkDataManagerView::TextureInterpolationChanged() { mitk::DataNode* node = m_NodeTreeModel->GetNode(m_FilterModel->mapToSource(m_NodeTreeView->selectionModel()->currentIndex())); if(node) { bool textureInterpolation = false; node->GetBoolProperty("texture interpolation", textureInterpolation); m_TextureInterpolation->setChecked(textureInterpolation); } } void QmitkDataManagerView::TextureInterpolationToggled( bool checked ) { mitk::DataNode* node = m_NodeTreeModel->GetNode(m_FilterModel->mapToSource(m_NodeTreeView->selectionModel()->currentIndex())); if(node) { node->SetBoolProperty("texture interpolation", checked); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkDataManagerView::ColormapActionToggled( bool /*checked*/ ) { mitk::DataNode* node = m_NodeTreeModel->GetNode(m_FilterModel->mapToSource(m_NodeTreeView->selectionModel()->currentIndex())); if(!node) return; mitk::LookupTableProperty::Pointer lookupTableProperty = dynamic_cast(node->GetProperty("LookupTable")); if (!lookupTableProperty) return; QAction* senderAction = qobject_cast(QObject::sender()); if(!senderAction) return; std::string activatedItem = senderAction->text().toStdString(); mitk::LookupTable::Pointer lookupTable = lookupTableProperty->GetValue(); if (!lookupTable) return; lookupTable->SetType(activatedItem); lookupTableProperty->SetValue(lookupTable); mitk::RenderingModeProperty::Pointer renderingMode = dynamic_cast(node->GetProperty("Image Rendering.Mode")); renderingMode->SetValue(mitk::RenderingModeProperty::LOOKUPTABLE_LEVELWINDOW_COLOR); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkDataManagerView::ColormapMenuAboutToShow() { mitk::DataNode* node = m_NodeTreeModel->GetNode(m_FilterModel->mapToSource(m_NodeTreeView->selectionModel()->currentIndex())); if(!node) return; mitk::LookupTableProperty::Pointer lookupTableProperty = dynamic_cast(node->GetProperty("LookupTable")); if (!lookupTableProperty) { mitk::LookupTable::Pointer mitkLut = mitk::LookupTable::New(); lookupTableProperty = mitk::LookupTableProperty::New(); lookupTableProperty->SetLookupTable(mitkLut); node->SetProperty("LookupTable", lookupTableProperty); } mitk::LookupTable::Pointer lookupTable = lookupTableProperty->GetValue(); if (!lookupTable) return; m_ColormapAction->menu()->clear(); QAction* tmp; int i = 0; std::string lutType = lookupTable->typenameList[i]; while (lutType != "END_OF_ARRAY") { tmp = m_ColormapAction->menu()->addAction(QString::fromStdString(lutType)); tmp->setCheckable(true); if (lutType == lookupTable->GetActiveTypeAsString()) { tmp->setChecked(true); } QObject::connect(tmp, SIGNAL(triggered(bool)), this, SLOT(ColormapActionToggled(bool))); lutType = lookupTable->typenameList[++i]; } } void QmitkDataManagerView::SurfaceRepresentationMenuAboutToShow() { mitk::DataNode* node = m_NodeTreeModel->GetNode(m_FilterModel->mapToSource(m_NodeTreeView->selectionModel()->currentIndex())); if(!node) return; mitk::EnumerationProperty* representationProp = dynamic_cast (node->GetProperty("material.representation")); if(!representationProp) return; // clear menu m_SurfaceRepresentation->menu()->clear(); QAction* tmp; // create menu entries for(mitk::EnumerationProperty::EnumConstIterator it=representationProp->Begin(); it!=representationProp->End() ; it++) { tmp = m_SurfaceRepresentation->menu()->addAction(QString::fromStdString(it->second)); tmp->setCheckable(true); if(it->second == representationProp->GetValueAsString()) { tmp->setChecked(true); } QObject::connect( tmp, SIGNAL( triggered(bool) ) , this, SLOT( SurfaceRepresentationActionToggled(bool) ) ); } } void QmitkDataManagerView::SurfaceRepresentationActionToggled( bool /*checked*/ ) { mitk::DataNode* node = m_NodeTreeModel->GetNode(m_FilterModel->mapToSource(m_NodeTreeView->selectionModel()->currentIndex())); if(!node) return; mitk::EnumerationProperty* representationProp = dynamic_cast (node->GetProperty("material.representation")); if(!representationProp) return; QAction* senderAction = qobject_cast ( QObject::sender() ); if(!senderAction) return; std::string activatedItem = senderAction->text().toStdString(); if ( activatedItem != representationProp->GetValueAsString() ) { if ( representationProp->IsValidEnumerationValue( activatedItem ) ) { representationProp->SetValue( activatedItem ); representationProp->InvokeEvent( itk::ModifiedEvent() ); representationProp->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } } void QmitkDataManagerView::ReinitSelectedNodes( bool ) { mitk::IRenderWindowPart* renderWindow = this->GetRenderWindowPart(); if (renderWindow == NULL) renderWindow = this->OpenRenderWindowPart(false); QList selectedNodes = this->GetCurrentSelection(); foreach(mitk::DataNode::Pointer node, selectedNodes) { mitk::BaseData::Pointer basedata = node->GetData(); if ( basedata.IsNotNull() && basedata->GetTimeGeometry()->IsValid() ) { renderWindow->GetRenderingManager()->InitializeViews( basedata->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); } } } void QmitkDataManagerView::RemoveSelectedNodes( bool ) { QModelIndexList indexesOfSelectedRowsFiltered = m_NodeTreeView->selectionModel()->selectedRows(); QModelIndexList indexesOfSelectedRows; for (int i = 0; i < indexesOfSelectedRowsFiltered.size(); ++i) { indexesOfSelectedRows.push_back(m_FilterModel->mapToSource(indexesOfSelectedRowsFiltered[i])); } if(indexesOfSelectedRows.size() < 1) { return; } std::vector selectedNodes; mitk::DataNode::Pointer node = 0; QString question = tr("Do you really want to remove "); for (QModelIndexList::iterator it = indexesOfSelectedRows.begin() ; it != indexesOfSelectedRows.end(); it++) { node = m_NodeTreeModel->GetNode(*it); // if node is not defined or if the node contains geometry data do not remove it if ( node.IsNotNull() /*& strcmp(node->GetData()->GetNameOfClass(), "PlaneGeometryData") != 0*/ ) { selectedNodes.push_back(node); question.append(QString::fromStdString(node->GetName())); question.append(", "); } } // remove the last two characters = ", " question = question.remove(question.size()-2, 2); question.append(" from data storage?"); QMessageBox::StandardButton answerButton = QMessageBox::question( m_Parent , tr("DataManager") , question , QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); if(answerButton == QMessageBox::Yes) { for (std::vector::iterator it = selectedNodes.begin() ; it != selectedNodes.end(); it++) { node = *it; this->GetDataStorage()->Remove(node); if (m_GlobalReinitOnNodeDelete) this->GlobalReinit(false); } } } void QmitkDataManagerView::MakeAllNodesInvisible( bool ) { QList nodes = m_NodeTreeModel->GetNodeSet(); foreach(mitk::DataNode::Pointer node, nodes) { node->SetVisibility(false); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkDataManagerView::ShowOnlySelectedNodes( bool ) { QList selectedNodes = this->GetCurrentSelection(); QList allNodes = m_NodeTreeModel->GetNodeSet(); foreach(mitk::DataNode::Pointer node, allNodes) { node->SetVisibility(selectedNodes.contains(node)); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkDataManagerView::ToggleVisibilityOfSelectedNodes( bool ) { QList selectedNodes = this->GetCurrentSelection(); bool isVisible = false; foreach(mitk::DataNode::Pointer node, selectedNodes) { isVisible = false; node->GetBoolProperty("visible", isVisible); node->SetVisibility(!isVisible); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkDataManagerView::ShowInfoDialogForSelectedNodes( bool ) { QList selectedNodes = this->GetCurrentSelection(); QmitkInfoDialog _QmitkInfoDialog(selectedNodes, this->m_Parent); _QmitkInfoDialog.exec(); } void QmitkDataManagerView::NodeChanged(const mitk::DataNode* /*node*/) { // m_FilterModel->invalidate(); // fix as proposed by R. Khlebnikov in the mitk-users mail from 02.09.2014 QMetaObject::invokeMethod( m_FilterModel, "invalidate", Qt::QueuedConnection ); } QItemSelectionModel *QmitkDataManagerView::GetDataNodeSelectionModel() const { return m_NodeTreeView->selectionModel(); } void QmitkDataManagerView::GlobalReinit( bool ) { mitk::IRenderWindowPart* renderWindow = this->GetRenderWindowPart(); if (renderWindow == NULL) renderWindow = this->OpenRenderWindowPart(false); // no render window available if (renderWindow == NULL) return; mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(this->GetDataStorage()); } void QmitkDataManagerView::NodeTreeViewRowsRemoved ( const QModelIndex & /*parent*/, int /*start*/, int /*end*/ ) { m_CurrentRowCount = m_NodeTreeModel->rowCount(); } void QmitkDataManagerView::NodeTreeViewRowsInserted( const QModelIndex & parent, int, int ) { QModelIndex viewIndex = m_FilterModel->mapFromSource(parent); m_NodeTreeView->setExpanded(viewIndex, true); // a new row was inserted if( m_CurrentRowCount == 0 && m_NodeTreeModel->rowCount() == 1 ) { this->OpenRenderWindowPart(); m_CurrentRowCount = m_NodeTreeModel->rowCount(); } } void QmitkDataManagerView::NodeSelectionChanged( const QItemSelection & /*selected*/, const QItemSelection & /*deselected*/ ) { QList nodes = m_NodeTreeModel->GetNodeSet(); foreach(mitk::DataNode::Pointer node, nodes) { if ( node.IsNotNull() ) node->SetBoolProperty("selected", false); } nodes.clear(); nodes = this->GetCurrentSelection(); foreach(mitk::DataNode::Pointer node, nodes) { if ( node.IsNotNull() ) node->SetBoolProperty("selected", true); } //changing the selection does NOT require any rendering processes! //mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkDataManagerView::ShowIn(const QString &editorId) { berry::IWorkbenchPage::Pointer page = this->GetSite()->GetPage(); berry::IEditorInput::Pointer input(new mitk::DataStorageEditorInput(this->GetDataStorageReference())); page->OpenEditor(input, editorId, false, berry::IWorkbenchPage::MATCH_ID); } mitk::IRenderWindowPart* QmitkDataManagerView::OpenRenderWindowPart(bool activatedEditor) { if (activatedEditor) { return this->GetRenderWindowPart(QmitkAbstractView::ACTIVATE | QmitkAbstractView::OPEN); } else { return this->GetRenderWindowPart(QmitkAbstractView::BRING_TO_FRONT | QmitkAbstractView::OPEN); } }