diff --git a/Modules/QtWidgets/src/QmitkDataStorageTableModel.cpp b/Modules/QtWidgets/src/QmitkDataStorageTableModel.cpp index d74713c49f..c658d5a0c0 100644 --- a/Modules/QtWidgets/src/QmitkDataStorageTableModel.cpp +++ b/Modules/QtWidgets/src/QmitkDataStorageTableModel.cpp @@ -1,514 +1,514 @@ /*=================================================================== 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 "QmitkDataStorageTableModel.h" //# Own includes #include "QmitkCustomVariants.h" #include "QmitkEnums.h" #include "mitkNodePredicateBase.h" #include "mitkProperties.h" #include "mitkRenderingManager.h" #include //# Toolkit includes #include #include #include //#CTORS/DTOR QmitkDataStorageTableModel::QmitkDataStorageTableModel(mitk::DataStorage::Pointer _DataStorage, mitk::NodePredicateBase *_Predicate, QObject *parent) : QAbstractTableModel(parent), m_DataStorage(nullptr), m_Predicate(nullptr), m_BlockEvents(false), m_SortDescending(false) { this->SetPredicate(_Predicate); this->SetDataStorage(_DataStorage); } QmitkDataStorageTableModel::~QmitkDataStorageTableModel() { // set data storage 0 to remove event listeners this->SetDataStorage(nullptr); } //# Public GETTER const mitk::DataStorage::Pointer QmitkDataStorageTableModel::GetDataStorage() const { return m_DataStorage.GetPointer(); } mitk::NodePredicateBase::Pointer QmitkDataStorageTableModel::GetPredicate() const { return m_Predicate; } mitk::DataNode::Pointer QmitkDataStorageTableModel::GetNode(const QModelIndex &index) const { mitk::DataNode::Pointer node; if (index.isValid()) { node = m_NodeSet.at(index.row()); } return node; } QVariant QmitkDataStorageTableModel::headerData(int section, Qt::Orientation orientation, int role) const { QVariant headerData; // show only horizontal header if (role == Qt::DisplayRole) { if (orientation == Qt::Horizontal) { // first column: "Name" if (section == 0) headerData = "Name"; else if (section == 1) headerData = "Data Type"; else if (section == 2) headerData = "Visibility"; } else if (orientation == Qt::Vertical) { // show numbers for rows headerData = section + 1; } } return headerData; } Qt::ItemFlags QmitkDataStorageTableModel::flags(const QModelIndex &index) const { Qt::ItemFlags flags = QAbstractItemModel::flags(index); // name & visibility is editable if (index.column() == 0) { flags |= Qt::ItemIsEditable; } else if (index.column() == 2) { flags |= Qt::ItemIsUserCheckable; } return flags; } int QmitkDataStorageTableModel::rowCount(const QModelIndex &) const { return m_NodeSet.size(); } int QmitkDataStorageTableModel::columnCount(const QModelIndex &) const { // show name, type and visible columnn int columns = 3; return columns; } QVariant QmitkDataStorageTableModel::data(const QModelIndex &index, int role) const { QVariant data; if (index.isValid() && !m_NodeSet.empty()) { mitk::DataNode::Pointer node = m_NodeSet.at(index.row()); std::string nodeName = node->GetName(); if (nodeName.empty()) nodeName = "unnamed"; // get name if (index.column() == 0) { // get name of node (may also be edited) if (role == Qt::DisplayRole || role == Qt::EditRole) { - data = QFile::encodeName(nodeName.c_str()); + data = QString::fromStdString(nodeName); } else if (role == QmitkDataNodeRole) { data = QVariant::fromValue(node); } } else if (index.column() == 1) { QmitkNodeDescriptor *nodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor(node); // get type property of mitk::BaseData if (role == Qt::DisplayRole) { data = nodeDescriptor->GetNameOfClass(); } // show some nice icons for datatype else if (role == Qt::DecorationRole) { data = nodeDescriptor->GetIcon(); } } else if (index.column() == 2) { // get visible property of mitk::BaseData bool visibility = false; if (node->GetVisibility(visibility, nullptr) && role == Qt::CheckStateRole) { data = (visibility ? Qt::Checked : Qt::Unchecked); } // node->GetVisibility(visibility, 0) && role == Qt::CheckStateRole } // index.column() == 2 } // index.isValid() && !m_NodeSet.empty() return data; } //# Public SETTERS void QmitkDataStorageTableModel::SetPredicate(mitk::NodePredicateBase *_Predicate) { // ensure that a new predicate is set in order to avoid unnecessary changed events if (m_Predicate != _Predicate) { m_Predicate = _Predicate; this->Reset(); } } void QmitkDataStorageTableModel::SetDataStorage(mitk::DataStorage::Pointer _DataStorage) { // only proceed if we have a new datastorage if (m_DataStorage.GetPointer() != _DataStorage.GetPointer()) { // if a data storage was set before remove old event listeners if (m_DataStorage.IsNotNull()) { this->m_DataStorage->AddNodeEvent.RemoveListener( mitk::MessageDelegate1( this, &QmitkDataStorageTableModel::AddNode)); this->m_DataStorage->RemoveNodeEvent.RemoveListener( mitk::MessageDelegate1( this, &QmitkDataStorageTableModel::RemoveNode)); } // set new data storage m_DataStorage = _DataStorage.GetPointer(); // if new storage is not 0 subscribe for events if (m_DataStorage.IsNotNull()) { // subscribe for node added/removed events this->m_DataStorage->AddNodeEvent.AddListener( mitk::MessageDelegate1( this, &QmitkDataStorageTableModel::AddNode)); this->m_DataStorage->RemoveNodeEvent.AddListener( mitk::MessageDelegate1( this, &QmitkDataStorageTableModel::RemoveNode)); } // Reset model (even if datastorage is 0->will be checked in Reset()) this->Reset(); } } void QmitkDataStorageTableModel::AddNode(const mitk::DataNode *node) { // garantuee no recursions when a new node event is thrown if (!m_BlockEvents) { // if we have a predicate, check node against predicate first if (m_Predicate.IsNotNull() && !m_Predicate->CheckNode(node)) return; // dont add nodes without data (formerly known as helper objects) if (node->GetData() == nullptr) return; // create listener commands to listen to changes in the name or the visibility of the node itk::MemberCommand::Pointer propertyModifiedCommand = itk::MemberCommand::New(); propertyModifiedCommand->SetCallbackFunction(this, &QmitkDataStorageTableModel::PropertyModified); mitk::BaseProperty *tempProperty = nullptr; // add listener for properties tempProperty = node->GetProperty("visible"); if (tempProperty) m_VisiblePropertyModifiedObserverTags[tempProperty] = tempProperty->AddObserver(itk::ModifiedEvent(), propertyModifiedCommand); tempProperty = node->GetProperty("name"); if (tempProperty) m_NamePropertyModifiedObserverTags[tempProperty] = tempProperty->AddObserver(itk::ModifiedEvent(), propertyModifiedCommand); // emit beginInsertRows event beginInsertRows(QModelIndex(), m_NodeSet.size(), m_NodeSet.size()); // add node m_NodeSet.push_back(const_cast(node)); // emit endInsertRows event endInsertRows(); } } void QmitkDataStorageTableModel::RemoveNode(const mitk::DataNode *node) { // garantuee no recursions when a new node event is thrown if (!m_BlockEvents) { // find corresponding node auto nodeIt = std::find(m_NodeSet.begin(), m_NodeSet.end(), node); if (nodeIt != m_NodeSet.end()) { // now: remove listeners for name property ... mitk::BaseProperty *tempProperty = nullptr; tempProperty = (*nodeIt)->GetProperty("visible"); if (tempProperty) tempProperty->RemoveObserver(m_VisiblePropertyModifiedObserverTags[tempProperty]); m_VisiblePropertyModifiedObserverTags.erase(tempProperty); // ... and visibility property tempProperty = (*nodeIt)->GetProperty("name"); if (tempProperty) tempProperty->RemoveObserver(m_NamePropertyModifiedObserverTags[tempProperty]); m_NamePropertyModifiedObserverTags.erase(tempProperty); // get an index from iterator int row = std::distance(m_NodeSet.begin(), nodeIt); // emit beginRemoveRows event (QModelIndex is empty because we dont have a tree model) this->beginRemoveRows(QModelIndex(), row, row); // remove node m_NodeSet.erase(nodeIt); // emit endRemoveRows event endRemoveRows(); } } } void QmitkDataStorageTableModel::PropertyModified(const itk::Object *caller, const itk::EventObject &) { if (!m_BlockEvents) { // get modified property const mitk::BaseProperty *modifiedProperty = dynamic_cast(caller); if (modifiedProperty) { // find node that holds the modified property int row = -1; int column = -1; std::vector::iterator it; mitk::BaseProperty *visibilityProperty = nullptr; mitk::BaseProperty *nameProperty = nullptr; // search for property that changed and emit datachanged on the corresponding ModelIndex for (it = m_NodeSet.begin(); it != m_NodeSet.end(); it++) { // check for the visible property or the name property visibilityProperty = (*it)->GetProperty("visible"); if (modifiedProperty == visibilityProperty) { column = 2; break; } nameProperty = (*it)->GetProperty("name"); if (modifiedProperty == nameProperty) { column = 0; break; } } // if we have the property we have a valid iterator if (it != m_NodeSet.end()) row = std::distance(m_NodeSet.begin(), it); // now emit the dataChanged signal QModelIndex indexOfChangedProperty = index(row, column); emit dataChanged(indexOfChangedProperty, indexOfChangedProperty); } } } bool QmitkDataStorageTableModel::setData(const QModelIndex &index, const QVariant &value, int role) { bool noErr = false; if (index.isValid() && (role == Qt::EditRole || role == Qt::CheckStateRole)) { // any change events produced here should not be caught in this class // --> set m_BlockEvents to true m_BlockEvents = true; mitk::DataNode::Pointer node = m_NodeSet.at(index.row()); if (index.column() == 0) { node->SetStringProperty("name", value.toString().toStdString().c_str()); } else if (index.column() == 2) { node->SetBoolProperty("visible", (value.toInt() == Qt::Checked ? true : false)); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } // inform listeners about changes emit dataChanged(index, index); m_BlockEvents = false; noErr = true; } return noErr; } //#Protected SETTER void QmitkDataStorageTableModel::Reset() { mitk::DataStorage::SetOfObjects::ConstPointer _NodeSet; // remove all nodes now (dont use iterators because removing elements // would invalidate the iterator) // start at the last element: first in, last out unsigned int i = m_NodeSet.size(); while (!m_NodeSet.empty()) { --i; this->RemoveNode(m_NodeSet.at(i)); } // normally now everything should be empty->just to be sure // erase all arrays again m_NamePropertyModifiedObserverTags.clear(); m_VisiblePropertyModifiedObserverTags.clear(); m_NodeSet.clear(); // the whole reset depends on the fact if a data storage is set or not if (m_DataStorage.IsNotNull()) { if (m_Predicate.IsNotNull()) // get subset _NodeSet = m_DataStorage->GetSubset(m_Predicate); // if predicate is NULL, select all nodes else { _NodeSet = m_DataStorage->GetAll(); // remove ghost root node } // finally add all nodes to the model for (auto it = _NodeSet->begin(); it != _NodeSet->end(); it++) { // save node this->AddNode(*it); } } } void QmitkDataStorageTableModel::sort(int column, Qt::SortOrder order /*= Qt::AscendingOrder */) { bool sortDescending = (order == Qt::DescendingOrder) ? true : false; // do not sort twice !!! (dont know why, but qt calls this func twice. STUPID!) /* if(sortDescending != m_SortDescending) {*/ // m_SortDescending = sortDescending; DataNodeCompareFunction::CompareCriteria _CompareCriteria = DataNodeCompareFunction::CompareByName; DataNodeCompareFunction::CompareOperator _CompareOperator = sortDescending ? DataNodeCompareFunction::Greater : DataNodeCompareFunction::Less; if (column == 1) _CompareCriteria = DataNodeCompareFunction::CompareByClassName; else if (column == 2) _CompareCriteria = DataNodeCompareFunction::CompareByVisibility; DataNodeCompareFunction compareFunc(_CompareCriteria, _CompareOperator); std::sort(m_NodeSet.begin(), m_NodeSet.end(), compareFunc); QAbstractTableModel::beginResetModel(); QAbstractTableModel::endResetModel(); //} } std::vector QmitkDataStorageTableModel::GetNodeSet() const { return m_NodeSet; } QmitkDataStorageTableModel::DataNodeCompareFunction::DataNodeCompareFunction(CompareCriteria _CompareCriteria, CompareOperator _CompareOperator) : m_CompareCriteria(_CompareCriteria), m_CompareOperator(_CompareOperator) { } bool QmitkDataStorageTableModel::DataNodeCompareFunction::operator()(const mitk::DataNode::Pointer &_Left, const mitk::DataNode::Pointer &_Right) const { switch (m_CompareCriteria) { case CompareByClassName: if (m_CompareOperator == Less) return (_Left->GetData()->GetNameOfClass() < _Right->GetData()->GetNameOfClass()); else return (_Left->GetData()->GetNameOfClass() > _Right->GetData()->GetNameOfClass()); break; case CompareByVisibility: { bool _LeftVisibility = false; bool _RightVisibility = false; _Left->GetVisibility(_LeftVisibility, nullptr); _Right->GetVisibility(_RightVisibility, nullptr); if (m_CompareOperator == Less) return (_LeftVisibility < _RightVisibility); else return (_LeftVisibility > _RightVisibility); } break; // CompareByName: default: if (m_CompareOperator == Less) return (_Left->GetName() < _Right->GetName()); else return (_Left->GetName() > _Right->GetName()); break; } } diff --git a/Modules/QtWidgets/src/QmitkDataStorageTreeModel.cpp b/Modules/QtWidgets/src/QmitkDataStorageTreeModel.cpp index adbd312693..c26891224d 100644 --- a/Modules/QtWidgets/src/QmitkDataStorageTreeModel.cpp +++ b/Modules/QtWidgets/src/QmitkDataStorageTreeModel.cpp @@ -1,1010 +1,1010 @@ /*=================================================================== 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 #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); if (listOfItemsToDrop.empty()) { return false; } // 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. // 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 if ((!m_AllowHierarchyChange) && isValidDragAndDropOperation) { if (row == -1) // drag onto a node { isValidDragAndDropOperation = listOfItemsToDrop[0]->GetParent() == parentItem; } else // drag between nodes { isValidDragAndDropOperation = listOfItemsToDrop[0]->GetParent() == dropItem; } } // 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 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 the item is dragged down we have to compensate its final position for the // fact it is deleted lateron, this only applies if it is dragged within the same level if ((itemToDrop->GetIndex() < row) && (itemToDrop->GetParent() == dropItem)) { dragIndex = 1; } // Here we assume that as you remove items, one at a time, that GetIndex() will be valid. this->beginRemoveRows( this->IndexFromTreeItem(itemToDrop->GetParent()), itemToDrop->GetIndex(), itemToDrop->GetIndex()); itemToDrop->GetParent()->RemoveChild(itemToDrop); 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 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++) { // 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 { if (row == -1) // drag onto a node { parentItem->InsertChild((*diIter), dropIndex); } else // drag between nodes { dropItem->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(mitk::GeneratePropertyNameForDICOMTag(0x0008, 0x103e).c_str())); mitk::BaseProperty *studyDescription = (dataNode->GetProperty(mitk::GeneratePropertyNameForDICOMTag(0x0008, 0x1030).c_str())); mitk::BaseProperty *patientsName = (dataNode->GetProperty(mitk::GeneratePropertyNameForDICOMTag(0x0010, 0x0010).c_str())); mitk::BaseProperty *seriesDescription_deprecated = (dataNode->GetProperty("dicom.series.SeriesDescription")); mitk::BaseProperty *studyDescription_deprecated = (dataNode->GetProperty("dicom.study.StudyDescription")); mitk::BaseProperty *patientsName_deprecated = (dataNode->GetProperty("dicom.patient.PatientsName")); if (patientsName) { - nodeName += QFile::encodeName(patientsName->GetValueAsString().c_str()) + "\n"; - nodeName += QFile::encodeName(studyDescription->GetValueAsString().c_str()) + "\n"; - nodeName += QFile::encodeName(seriesDescription->GetValueAsString().c_str()); + nodeName += QString::fromStdString(patientsName->GetValueAsString()) + "\n"; + nodeName += QString::fromStdString(studyDescription->GetValueAsString()) + "\n"; + nodeName += QString::fromStdString(seriesDescription->GetValueAsString()); } else { /** Code coveres the deprecated property naming for backwards compatibility */ - nodeName += QFile::encodeName(patientsName_deprecated->GetValueAsString().c_str()) + "\n"; - nodeName += QFile::encodeName(studyDescription_deprecated->GetValueAsString().c_str()) + "\n"; - nodeName += QFile::encodeName(seriesDescription_deprecated->GetValueAsString().c_str()); + nodeName += QString::fromStdString(patientsName_deprecated->GetValueAsString()) + "\n"; + nodeName += QString::fromStdString(studyDescription_deprecated->GetValueAsString()) + "\n"; + nodeName += QString::fromStdString(seriesDescription_deprecated->GetValueAsString()); } } else { - nodeName = QFile::encodeName(dataNode->GetName().c_str()); + nodeName = QString::fromStdString(dataNode->GetName()); } 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_deprecated = (node.GetProperty("dicom.series.SeriesDescription")); mitk::BaseProperty *studyDescription_deprecated = (node.GetProperty("dicom.study.StudyDescription")); mitk::BaseProperty *patientsName_deprecated = (node.GetProperty("dicom.patient.PatientsName")); mitk::BaseProperty *seriesDescription = (node.GetProperty(mitk::GeneratePropertyNameForDICOMTag(0x0008, 0x103e).c_str())); mitk::BaseProperty *studyDescription = (node.GetProperty(mitk::GeneratePropertyNameForDICOMTag(0x0008, 0x1030).c_str())); mitk::BaseProperty *patientsName = (node.GetProperty(mitk::GeneratePropertyNameForDICOMTag(0x0010, 0x0010).c_str())); if (patientsName != NULL && studyDescription != NULL && seriesDescription != NULL) { if ((!patientsName->GetValueAsString().empty()) && (!studyDescription->GetValueAsString().empty()) && (!seriesDescription->GetValueAsString().empty())) { propertiesExists = true; } } /** Code coveres the deprecated property naming for backwards compatibility */ if (patientsName_deprecated != NULL && studyDescription_deprecated != NULL && seriesDescription_deprecated != NULL) { if ((!patientsName_deprecated->GetValueAsString().empty()) && (!studyDescription_deprecated->GetValueAsString().empty()) && (!seriesDescription_deprecated->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) { 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; i < parent->GetChildCount(); ++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; i < parent->GetChildCount(); ++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/Modules/QtWidgets/src/QmitkIOUtil.cpp b/Modules/QtWidgets/src/QmitkIOUtil.cpp index 74138d33d5..5f7d047d26 100644 --- a/Modules/QtWidgets/src/QmitkIOUtil.cpp +++ b/Modules/QtWidgets/src/QmitkIOUtil.cpp @@ -1,540 +1,540 @@ /*=================================================================== 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 "QmitkIOUtil.h" #include "mitkCoreServices.h" #include "mitkCustomMimeType.h" #include "mitkFileReaderRegistry.h" #include "mitkFileWriterRegistry.h" #include "mitkIMimeTypeProvider.h" #include "mitkMimeType.h" #include #include #include "QmitkFileReaderOptionsDialog.h" #include "QmitkFileWriterOptionsDialog.h" // QT #include #include #include #include // ITK #include #include struct QmitkIOUtil::Impl { struct ReaderOptionsDialogFunctor : public ReaderOptionsFunctorBase { virtual bool operator()(LoadInfo &loadInfo) override { QmitkFileReaderOptionsDialog dialog(loadInfo); if (dialog.exec() == QDialog::Accepted) { return !dialog.ReuseOptions(); } else { loadInfo.m_Cancel = true; return true; } } }; struct WriterOptionsDialogFunctor : public WriterOptionsFunctorBase { virtual bool operator()(SaveInfo &saveInfo) override { QmitkFileWriterOptionsDialog dialog(saveInfo); if (dialog.exec() == QDialog::Accepted) { return !dialog.ReuseOptions(); } else { saveInfo.m_Cancel = true; return true; } } }; }; struct MimeTypeComparison : public std::unary_function { MimeTypeComparison(const std::string &mimeTypeName) : m_Name(mimeTypeName) {} bool operator()(const mitk::MimeType &mimeType) const { return mimeType.GetName() == m_Name; } const std::string m_Name; }; QString QmitkIOUtil::GetFileOpenFilterString() { QString filters; mitk::CoreServicePointer mimeTypeProvider(mitk::CoreServices::GetMimeTypeProvider()); std::vector categories = mimeTypeProvider->GetCategories(); for (std::vector::iterator cat = categories.begin(); cat != categories.end(); ++cat) { QSet filterExtensions; std::vector mimeTypes = mimeTypeProvider->GetMimeTypesForCategory(*cat); for (std::vector::iterator mt = mimeTypes.begin(); mt != mimeTypes.end(); ++mt) { std::vector extensions = mt->GetExtensions(); for (std::vector::iterator ext = extensions.begin(); ext != extensions.end(); ++ext) { filterExtensions << QString::fromStdString(*ext); } } QString filter = QString::fromStdString(*cat) + " ("; foreach (const QString &extension, filterExtensions) { filter += "*." + extension + " "; } filter = filter.replace(filter.size() - 1, 1, ')'); filters += ";;" + filter; } filters.prepend("All (*)"); return filters; } QList QmitkIOUtil::Load(const QStringList &paths, QWidget *parent) { std::vector loadInfos; foreach (const QString &file, paths) { - loadInfos.push_back(LoadInfo(file.toStdString())); + loadInfos.push_back(LoadInfo(file.toLocal8Bit().constData())); } Impl::ReaderOptionsDialogFunctor optionsCallback; std::string errMsg = Load(loadInfos, NULL, NULL, &optionsCallback); if (!errMsg.empty()) { QMessageBox::warning(parent, "Error reading files", QString::fromStdString(errMsg)); mitkThrow() << errMsg; } QList qResult; for (std::vector::const_iterator iter = loadInfos.begin(), iterEnd = loadInfos.end(); iter != iterEnd; ++iter) { for (const auto &elem : iter->m_Output) { qResult << elem; } } return qResult; } mitk::DataStorage::SetOfObjects::Pointer QmitkIOUtil::Load(const QStringList &paths, mitk::DataStorage &storage, QWidget *parent) { std::vector loadInfos; foreach (const QString &file, paths) { - loadInfos.push_back(LoadInfo(QFile::encodeName(file).constData())); + loadInfos.push_back(LoadInfo(file.toLocal8Bit().constData())); } mitk::DataStorage::SetOfObjects::Pointer nodeResult = mitk::DataStorage::SetOfObjects::New(); Impl::ReaderOptionsDialogFunctor optionsCallback; std::string errMsg = Load(loadInfos, nodeResult, &storage, &optionsCallback); if (!errMsg.empty()) { QMessageBox::warning(parent, "Error reading files", QString::fromStdString(errMsg)); } return nodeResult; } QList QmitkIOUtil::Load(const QString &path, QWidget *parent) { QStringList paths; paths << path; return Load(paths, parent); } mitk::DataStorage::SetOfObjects::Pointer QmitkIOUtil::Load(const QString &path, mitk::DataStorage &storage, QWidget *parent) { QStringList paths; paths << path; return Load(paths, storage, parent); } QString QmitkIOUtil::Save(const mitk::BaseData *data, const QString &defaultBaseName, const QString &defaultPath, QWidget *parent) { std::vector dataVector; dataVector.push_back(data); QStringList defaultBaseNames; defaultBaseNames.push_back(defaultBaseName); return Save(dataVector, defaultBaseNames, defaultPath, parent).back(); } QStringList QmitkIOUtil::Save(const std::vector &data, const QStringList &defaultBaseNames, const QString &defaultPath, QWidget *parent) { QStringList fileNames; QString currentPath = defaultPath; std::vector saveInfos; int counter = 0; for (std::vector::const_iterator dataIter = data.begin(), dataIterEnd = data.end(); dataIter != dataIterEnd; ++dataIter, ++counter) { SaveInfo saveInfo(*dataIter, mitk::MimeType(), std::string()); SaveFilter filters(saveInfo); // If there is only the "__all__" filter string, it means there is no writer for this base data if (filters.Size() < 2) { QMessageBox::warning( parent, "Saving not possible", QString("No writer available for type \"%1\"").arg(QString::fromStdString((*dataIter)->GetNameOfClass()))); continue; } // Construct a default path and file name QString filterString = filters.ToString(); QString selectedFilter = filters.GetDefaultFilter(); QString fileName = currentPath; QString dialogTitle = "Save " + QString::fromStdString((*dataIter)->GetNameOfClass()); if (counter < defaultBaseNames.size()) { dialogTitle += " \"" + defaultBaseNames[counter] + "\""; fileName += QDir::separator() + defaultBaseNames[counter]; // We do not append an extension to the file name by default. The extension // is chosen by the user by either selecting a filter or writing the // extension in the file name himself (in the file save dialog). /* QString defaultExt = filters.GetDefaultExtension(); if (!defaultExt.isEmpty()) { fileName += "." + defaultExt; } */ } // Ask the user for a file name QString nextName = QFileDialog::getSaveFileName(parent, dialogTitle, fileName, filterString, &selectedFilter); if (nextName.isEmpty()) { // We stop asking for further file names, but we still save the // data where the user already confirmed the save dialog. break; } fileName = nextName; - std::string stdFileName = QFile::encodeName(fileName).constData(); + std::string stdFileName = fileName.toLocal8Bit().constData(); QFileInfo fileInfo(fileName); currentPath = fileInfo.absolutePath(); QString suffix = fileInfo.completeSuffix(); mitk::MimeType filterMimeType = filters.GetMimeTypeForFilter(selectedFilter); mitk::MimeType selectedMimeType; if (fileInfo.exists() && !fileInfo.isFile()) { QMessageBox::warning(parent, "Saving not possible", QString("The path \"%1\" is not a file").arg(fileName)); continue; } // Theoretically, the user could have entered an extension that does not match the selected filter // The extension then has prioritry over the filter // Check if one of the available mime-types match the filename std::vector filterMimeTypes = filters.GetMimeTypes(); for (std::vector::const_iterator mimeTypeIter = filterMimeTypes.begin(), mimeTypeIterEnd = filterMimeTypes.end(); mimeTypeIter != mimeTypeIterEnd; ++mimeTypeIter) { if (mimeTypeIter->MatchesExtension(stdFileName)) { selectedMimeType = *mimeTypeIter; break; } } if (!selectedMimeType.IsValid()) { // The file name either does not contain an extension or the // extension is unknown. // If the file already exists, we stop here because we are unable // to (over)write the file without adding a custom suffix. If the file // does not exist, we add the default extension from the currently // selected filter. If the "All" filter was selected, we only add the // default extensions if the file name itself does not already contain // an extension. if (!fileInfo.exists()) { if (filterMimeType == SaveFilter::ALL_MIMETYPE()) { if (suffix.isEmpty()) { // Use the highest ranked mime-type from the list selectedMimeType = filters.GetDefaultMimeType(); } } else { selectedMimeType = filterMimeType; } if (selectedMimeType.IsValid()) { suffix = QString::fromStdString(selectedMimeType.GetExtensions().front()); fileName += "." + suffix; - stdFileName = QFile::encodeName(fileName).constData(); + stdFileName = fileName.toLocal8Bit().constData(); // We changed the file name (added a suffix) so ask in case // the file aready exists. fileInfo = QFileInfo(fileName); if (fileInfo.exists()) { if (!fileInfo.isFile()) { QMessageBox::warning( parent, "Saving not possible", QString("The path \"%1\" is not a file").arg(fileName)); continue; } if (QMessageBox::question( parent, "Replace File", QString("A file named \"%1\" already exists. Do you want to replace it?").arg(fileName)) == QMessageBox::No) { continue; } } } } } if (!selectedMimeType.IsValid()) { // The extension/filename is not valid (no mime-type found), bail out QMessageBox::warning( parent, "Saving not possible", QString("No mime-type available which can handle \"%1\".").arg(fileName)); continue; } if (!QFileInfo(fileInfo.absolutePath()).isWritable()) { QMessageBox::warning(parent, "Saving not possible", QString("The path \"%1\" is not writable").arg(fileName)); continue; } fileNames.push_back(fileName); saveInfo.m_Path = stdFileName; saveInfo.m_MimeType = selectedMimeType; // pre-select the best writer for the chosen mime-type saveInfo.m_WriterSelector.Select(selectedMimeType.GetName()); saveInfos.push_back(saveInfo); } if (!saveInfos.empty()) { Impl::WriterOptionsDialogFunctor optionsCallback; std::string errMsg = Save(saveInfos, &optionsCallback); if (!errMsg.empty()) { QMessageBox::warning(parent, "Error writing files", QString::fromStdString(errMsg)); mitkThrow() << errMsg; } } return fileNames; } void QmitkIOUtil::SaveBaseDataWithDialog(mitk::BaseData *data, std::string fileName, QWidget * /*parent*/) { Save(data, fileName); } void QmitkIOUtil::SaveSurfaceWithDialog(mitk::Surface::Pointer surface, std::string fileName, QWidget * /*parent*/) { Save(surface, fileName); } void QmitkIOUtil::SaveImageWithDialog(mitk::Image::Pointer image, std::string fileName, QWidget * /*parent*/) { Save(image, fileName); } void QmitkIOUtil::SavePointSetWithDialog(mitk::PointSet::Pointer pointset, std::string fileName, QWidget * /*parent*/) { Save(pointset, fileName); } struct QmitkIOUtil::SaveFilter::Impl { Impl(const mitk::IOUtil::SaveInfo &saveInfo) : m_SaveInfo(saveInfo) { // Add an artifical filter for "All" m_MimeTypes.push_back(ALL_MIMETYPE()); m_FilterStrings.push_back("All (*.*)"); // Get all writers and their mime types for the given base data type // (this is sorted already) std::vector mimeTypes = saveInfo.m_WriterSelector.GetMimeTypes(); for (std::vector::const_reverse_iterator iter = mimeTypes.rbegin(), iterEnd = mimeTypes.rend(); iter != iterEnd; ++iter) { QList filterExtensions; mitk::MimeType mimeType = *iter; std::vector extensions = mimeType.GetExtensions(); for (auto &extension : extensions) { filterExtensions << QString::fromStdString(extension); } if (m_DefaultExtension.isEmpty()) { m_DefaultExtension = QString::fromStdString(extensions.front()); } QString filter = QString::fromStdString(mimeType.GetComment()) + " ("; foreach (const QString &extension, filterExtensions) { filter += "*." + extension + " "; } filter = filter.replace(filter.size() - 1, 1, ')'); m_MimeTypes.push_back(mimeType); m_FilterStrings.push_back(filter); } } const mitk::IOUtil::SaveInfo m_SaveInfo; std::vector m_MimeTypes; QStringList m_FilterStrings; QString m_DefaultExtension; }; mitk::MimeType QmitkIOUtil::SaveFilter::ALL_MIMETYPE() { static mitk::CustomMimeType allMimeType(std::string("__all__")); return mitk::MimeType(allMimeType, -1, -1); } QmitkIOUtil::SaveFilter::SaveFilter(const QmitkIOUtil::SaveFilter &other) : d(new Impl(*other.d)) { } QmitkIOUtil::SaveFilter::SaveFilter(const SaveInfo &saveInfo) : d(new Impl(saveInfo)) { } QmitkIOUtil::SaveFilter &QmitkIOUtil::SaveFilter::operator=(const QmitkIOUtil::SaveFilter &other) { d.reset(new Impl(*other.d)); return *this; } std::vector QmitkIOUtil::SaveFilter::GetMimeTypes() const { return d->m_MimeTypes; } QString QmitkIOUtil::SaveFilter::GetFilterForMimeType(const std::string &mimeType) const { std::vector::const_iterator iter = std::find_if(d->m_MimeTypes.begin(), d->m_MimeTypes.end(), MimeTypeComparison(mimeType)); if (iter == d->m_MimeTypes.end()) { return QString(); } int index = static_cast(iter - d->m_MimeTypes.begin()); if (index < 0 || index >= d->m_FilterStrings.size()) { return QString(); } return d->m_FilterStrings[index]; } mitk::MimeType QmitkIOUtil::SaveFilter::GetMimeTypeForFilter(const QString &filter) const { int index = d->m_FilterStrings.indexOf(filter); if (index < 0) { return mitk::MimeType(); } return d->m_MimeTypes[index]; } QString QmitkIOUtil::SaveFilter::GetDefaultFilter() const { if (d->m_FilterStrings.size() > 1) { return d->m_FilterStrings.at(1); } else if (d->m_FilterStrings.size() > 0) { return d->m_FilterStrings.front(); } return QString(); } QString QmitkIOUtil::SaveFilter::GetDefaultExtension() const { return d->m_DefaultExtension; } mitk::MimeType QmitkIOUtil::SaveFilter::GetDefaultMimeType() const { if (d->m_MimeTypes.size() > 1) { return d->m_MimeTypes.at(1); } else if (d->m_MimeTypes.size() > 0) { return d->m_MimeTypes.front(); } return mitk::MimeType(); } QString QmitkIOUtil::SaveFilter::ToString() const { return d->m_FilterStrings.join(";;"); } int QmitkIOUtil::SaveFilter::Size() const { return d->m_FilterStrings.size(); } bool QmitkIOUtil::SaveFilter::IsEmpty() const { return d->m_FilterStrings.isEmpty(); } bool QmitkIOUtil::SaveFilter::ContainsMimeType(const std::string &mimeType) { return std::find_if(d->m_MimeTypes.begin(), d->m_MimeTypes.end(), MimeTypeComparison(mimeType)) != d->m_MimeTypes.end(); }