diff --git a/Core/Code/DataManagement/mitkImageVtkReadAccessor.cpp b/Core/Code/DataManagement/mitkImageVtkReadAccessor.cpp index c3f8c3af71..61c439bb3c 100644 --- a/Core/Code/DataManagement/mitkImageVtkReadAccessor.cpp +++ b/Core/Code/DataManagement/mitkImageVtkReadAccessor.cpp @@ -1,61 +1,61 @@ /*=================================================================== 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 "mitkImageVtkReadAccessor.h" #include "mitkImage.h" #include const mitk::Image* mitk::ImageVtkReadAccessor::GetImage() const { return m_Image; } mitk::ImageVtkReadAccessor::ImageVtkReadAccessor( ImageConstPointer iP, const mitk::ImageDataItem* iDI, const vtkImageData* imageDataVtk) - : ImageAccessorBase(NULL, iDI) + : ImageAccessorBase(iP, iDI) , m_Image(iP.GetPointer()) , m_ImageDataVtk(imageDataVtk) { m_Image->m_VtkReadersLock.Lock(); m_Image->m_VtkReaders.push_back(this); //printf("m_VtkReaders.size(): %d\n", (int) m_Image->m_VtkReaders.size()); m_Image->m_VtkReadersLock.Unlock(); } mitk::ImageVtkReadAccessor::~ImageVtkReadAccessor() { m_Image->m_VtkReadersLock.Lock(); std::vector::iterator it = std::find(m_Image->m_VtkReaders.begin(), m_Image->m_VtkReaders.end(), this); if (it != m_Image->m_VtkReaders.end()) { m_Image->m_VtkReaders.erase(it); } //printf("m_VtkReaders.size(): %d\n", (int) m_Image->m_VtkReaders.size()); m_Image->m_VtkReadersLock.Unlock(); } const vtkImageData*mitk::ImageVtkReadAccessor::GetVtkImageData() const { return m_ImageDataVtk; } diff --git a/Core/Code/Internal/mitkImageVtkLegacyIO.cpp b/Core/Code/Internal/mitkImageVtkLegacyIO.cpp index 4ceb996638..a24fd7ed91 100644 --- a/Core/Code/Internal/mitkImageVtkLegacyIO.cpp +++ b/Core/Code/Internal/mitkImageVtkLegacyIO.cpp @@ -1,107 +1,107 @@ /*=================================================================== 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 "mitkImageVtkLegacyIO.h" #include "mitkImage.h" #include "mitkIOMimeTypes.h" #include "mitkImageVtkReadAccessor.h" #include #include #include #include #include namespace mitk { ImageVtkLegacyIO::ImageVtkLegacyIO() - : AbstractFileIO(Image::GetStaticNameOfClass(), IOMimeTypes::VTK_IMAGE_MIMETYPE(), "VTK XML Image") + : AbstractFileIO(Image::GetStaticNameOfClass(), IOMimeTypes::VTK_IMAGE_LEGACY_MIMETYPE(), "VTK Legacy Image") { this->RegisterService(); } std::vector ImageVtkLegacyIO::Read() { // The legay vtk reader cannot work with input streams const std::string fileName = this->GetLocalFileName(); vtkSmartPointer reader = vtkSmartPointer::New(); reader->SetFileName(fileName.c_str()); reader->Update(); if ( reader->GetOutput() != NULL ) { mitk::Image::Pointer output = mitk::Image::New(); output->Initialize(reader->GetOutput()); output->SetVolume(reader->GetOutput()->GetScalarPointer()); std::vector result; result.push_back(output.GetPointer()); return result; } else { mitkThrow() << "vtkStructuredPointsReader error: " << vtkErrorCode::GetStringFromErrorCode(reader->GetErrorCode()); } } IFileIO::ConfidenceLevel ImageVtkLegacyIO::GetReaderConfidenceLevel() const { if (AbstractFileIO::GetReaderConfidenceLevel() == Unsupported) return Unsupported; vtkSmartPointer reader = vtkSmartPointer::New(); reader->SetFileName(this->GetLocalFileName().c_str()); if (reader->IsFileStructuredPoints()) { return Supported; } return Unsupported; } void ImageVtkLegacyIO::Write() { ValidateOutputLocation(); const Image* input = dynamic_cast(this->GetInput()); vtkSmartPointer writer = vtkSmartPointer::New(); // The legacy vtk image writer cannot write to streams LocalFile localFile(this); writer->SetFileName(localFile.GetFileName().c_str()); - ImageVtkReadAccessor vtkReadAccessor(Image::ConstPointer(input), NULL, NULL); + ImageVtkReadAccessor vtkReadAccessor(Image::ConstPointer(input), NULL, input->GetVtkImageData()); writer->SetInputData(const_cast(vtkReadAccessor.GetVtkImageData())); if (writer->Write() == 0 || writer->GetErrorCode() != 0 ) { mitkThrow() << "vtkStructuredPointesWriter error: " << vtkErrorCode::GetStringFromErrorCode(writer->GetErrorCode()); } } IFileIO::ConfidenceLevel ImageVtkLegacyIO::GetWriterConfidenceLevel() const { if (AbstractFileIO::GetWriterConfidenceLevel() == Unsupported) return Unsupported; const Image* input = static_cast(this->GetInput()); if (input->GetDimension() == 3) return Supported; else if (input->GetDimension() < 3) return PartiallySupported; return Unsupported; } ImageVtkLegacyIO* ImageVtkLegacyIO::IOClone() const { return new ImageVtkLegacyIO(*this); } } diff --git a/Core/Code/Internal/mitkImageVtkXmlIO.cpp b/Core/Code/Internal/mitkImageVtkXmlIO.cpp index cb8c35da10..881f70b890 100644 --- a/Core/Code/Internal/mitkImageVtkXmlIO.cpp +++ b/Core/Code/Internal/mitkImageVtkXmlIO.cpp @@ -1,142 +1,142 @@ /*=================================================================== 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 "mitkImageVtkXmlIO.h" #include "mitkImage.h" #include "mitkIOMimeTypes.h" #include "mitkImageVtkReadAccessor.h" #include #include #include #include #include namespace mitk { class VtkXMLImageDataReader : public ::vtkXMLImageDataReader { public: static VtkXMLImageDataReader *New() { return new VtkXMLImageDataReader(); } vtkTypeMacro(VtkXMLImageDataReader,vtkXMLImageDataReader) void SetStream(std::istream* is) { this->Stream = is; } std::istream* GetStream() const { return this->Stream; } }; class VtkXMLImageDataWriter : public ::vtkXMLImageDataWriter { public: static VtkXMLImageDataWriter *New() { return new VtkXMLImageDataWriter(); } vtkTypeMacro(VtkXMLImageDataWriter,vtkXMLImageDataWriter) void SetStream(std::ostream* os) { this->Stream = os; } std::ostream* GetStream() const { return this->Stream; } }; ImageVtkXmlIO::ImageVtkXmlIO() : AbstractFileIO(Image::GetStaticNameOfClass(), IOMimeTypes::VTK_IMAGE_MIMETYPE(), "VTK XML Image") { this->RegisterService(); } std::vector ImageVtkXmlIO::Read() { vtkSmartPointer reader = vtkSmartPointer::New(); if (this->GetInputStream()) { reader->SetStream(this->GetInputStream()); } else { reader->SetFileName(this->GetInputLocation().c_str()); } reader->Update(); if (reader->GetOutput() != NULL) { mitk::Image::Pointer output = mitk::Image::New(); output->Initialize(reader->GetOutput()); output->SetVolume(reader->GetOutput()->GetScalarPointer()); std::vector result; result.push_back(output.GetPointer()); return result; } else { mitkThrow() << "vtkXMLImageDataReader error: " << vtkErrorCode::GetStringFromErrorCode(reader->GetErrorCode()); } } IFileIO::ConfidenceLevel ImageVtkXmlIO::GetReaderConfidenceLevel() const { if (AbstractFileIO::GetReaderConfidenceLevel() == Unsupported) return Unsupported; if (this->GetInputStream() == NULL) { // check if the xml vtk reader can handle the file vtkSmartPointer xmlReader = vtkSmartPointer::New(); if (xmlReader->CanReadFile(this->GetInputLocation().c_str()) != 0) { return Supported; } return Unsupported; } // in case of an input stream, VTK does not seem to have methods for // validating it return Supported; } void ImageVtkXmlIO::Write() { ValidateOutputLocation(); const Image* input = dynamic_cast(this->GetInput()); vtkSmartPointer writer = vtkSmartPointer::New(); if (this->GetOutputStream()) { writer->SetStream(this->GetOutputStream()); } else { writer->SetFileName(this->GetOutputLocation().c_str()); } - ImageVtkReadAccessor vtkReadAccessor(Image::ConstPointer(input), NULL, NULL); + ImageVtkReadAccessor vtkReadAccessor(Image::ConstPointer(input), NULL, input->GetVtkImageData()); writer->SetInputData(const_cast(vtkReadAccessor.GetVtkImageData())); if (writer->Write() == 0 || writer->GetErrorCode() != 0 ) { mitkThrow() << "vtkXMLImageDataWriter error: " << vtkErrorCode::GetStringFromErrorCode(writer->GetErrorCode()); } } IFileIO::ConfidenceLevel ImageVtkXmlIO::GetWriterConfidenceLevel() const { if (AbstractFileIO::GetWriterConfidenceLevel() == Unsupported) return Unsupported; const Image* input = static_cast(this->GetInput()); if (input->GetDimension() == 3) return Supported; else if (input->GetDimension() < 3) return PartiallySupported; return Unsupported; } ImageVtkXmlIO* ImageVtkXmlIO::IOClone() const { return new ImageVtkXmlIO(*this); } } diff --git a/Modules/QtWidgets/QmitkIOUtil.cpp b/Modules/QtWidgets/QmitkIOUtil.cpp index 8f2576dd14..8d170d27cb 100644 --- a/Modules/QtWidgets/QmitkIOUtil.cpp +++ b/Modules/QtWidgets/QmitkIOUtil.cpp @@ -1,528 +1,548 @@ /*=================================================================== 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 #include #include #include "mitkCoreServices.h" #include "mitkIMimeTypeProvider.h" #include "mitkMimeType.h" #include "mitkCustomMimeType.h" #include "mitkFileReaderRegistry.h" #include "mitkFileWriterRegistry.h" #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) { 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) { 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 (*.*)"); + 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())); } 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 (std::vector::const_iterator dataIter = iter->m_Output.begin(), dataIterEnd = iter->m_Output.end(); dataIter != dataIterEnd; ++dataIter) { qResult << *dataIter; } } 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())); } 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)); mitkThrow() << 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(); QFileInfo fileInfo(fileName); currentPath = fileInfo.absolutePath(); QString suffix = fileInfo.completeSuffix(); - mitk::MimeType mimeType = filters.GetMimeTypeForFilter(selectedFilter); + mitk::MimeType filterMimeType = filters.GetMimeTypeForFilter(selectedFilter); + mitk::MimeType selectedMimeType; - mitk::CoreServicePointer mimeTypeProvider(mitk::CoreServices::GetMimeTypeProvider()); - // If the filename contains a suffix, use it but check if it is valid - if (!suffix.isEmpty()) + if (fileInfo.exists() && !fileInfo.isFile()) { - std::vector availableTypes = mimeTypeProvider->GetMimeTypesForFile(stdFileName); - - // Check if the selected mime-type is related to the specified suffix (file extension). - // If not, get the best matching mime-type for the suffix. - if (std::find(availableTypes.begin(), availableTypes.end(), mimeType) == availableTypes.end()) - { - mimeType = mitk::MimeType(); - for (std::vector::const_iterator availIter = availableTypes.begin(), - availIterEnd = availableTypes.end(); availIter != availIterEnd; ++availIter) - { - if (filters.ContainsMimeType(availIter->GetName())) - { - mimeType = *availIter; - break; - } - } - } + QMessageBox::warning(parent, "Saving not possible", QString("The path \"%1\" is not a file").arg(fileName)); + continue; + } - if (!mimeType.IsValid()) + // 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->AppliesTo(stdFileName)) { - // The extension is not valid (no mime-type found), bail out - QMessageBox::warning(parent, - "Saving not possible", - QString("Extension \"%1\" unknown for type \"%2\"") - .arg(suffix) - .arg(QString::fromStdString((*dataIter)->GetNameOfClass()))); - continue; + selectedMimeType = *mimeTypeIter; + break; } } - else + + if (!selectedMimeType.IsValid()) { - // Create a default suffix, unless the file already exists and the user - // already confirmed to overwrite it (without using a suffix) - if (mimeType == SaveFilter::ALL_MIMETYPE()) - { - // Use the highest ranked mime-type from the list - mimeType = filters.GetDefaultMimeType(); - } + // 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 not able + // 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()) { - suffix = QString::fromStdString(mimeType.GetExtensions().front()); - fileName += "." + suffix; - // We changed the file name (added a suffix) so ask in case - // the file aready exists. - fileInfo = QFileInfo(fileName); - if (fileInfo.exists()) + if (filterMimeType == SaveFilter::ALL_MIMETYPE()) { - if (!fileInfo.isFile()) + if (suffix.isEmpty()) { - QMessageBox::warning(parent, "Saving not possible", QString("The path \"%1\" is not a file").arg(fileName)); - continue; + // Use the highest ranked mime-type from the list + selectedMimeType = filters.GetDefaultMimeType(); } - if (QMessageBox::question(parent, "Replace File", - QString("A file named \"%1\" already exists. Do you want to replace it?").arg(fileName)) == - QMessageBox::No) + } + else + { + selectedMimeType = filterMimeType; + } + + if (selectedMimeType.IsValid()) + { + suffix = QString::fromStdString(selectedMimeType.GetExtensions().front()); + fileName += "." + suffix; + stdFileName = QFile::encodeName(fileName).constData(); + // We changed the file name (added a suffix) so ask in case + // the file aready exists. + fileInfo = QFileInfo(fileName); + if (fileInfo.exists()) { - continue; + 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 = mimeType; + saveInfo.m_MimeType = selectedMimeType; // pre-select the best writer for the chosen mime-type - saveInfo.m_WriterSelector.Select(mimeType.GetName()); + 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 (std::vector::iterator extIter = extensions.begin(), extIterEnd = extensions.end(); extIter != extIterEnd; ++extIter) { filterExtensions << QString::fromStdString(*extIter); } 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(); } diff --git a/Modules/QtWidgets/QmitkIOUtil.h b/Modules/QtWidgets/QmitkIOUtil.h index 57fd830b33..8302d0c9fb 100644 --- a/Modules/QtWidgets/QmitkIOUtil.h +++ b/Modules/QtWidgets/QmitkIOUtil.h @@ -1,232 +1,227 @@ /*=================================================================== 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 _QmitkIOUtil__h_ #define _QmitkIOUtil__h_ #include "MitkQtWidgetsExports.h" // std #include // mitk includes #include #include #include #include #include #include #include #include //Qt #include #include class QWidget; class QString; class QStringList; namespace mitk { class DataStorage; class MimeType; struct IFileReader; } /** * @brief QmitkIOUtil Provides static helper methods to open and save files with Qt dialogs. */ class QMITK_EXPORT QmitkIOUtil : public mitk::IOUtil { public: class QMITK_EXPORT SaveFilter { public: static mitk::MimeType ALL_MIMETYPE(); SaveFilter(const SaveFilter& other); SaveFilter(const SaveInfo& saveInfo); SaveFilter& operator=(const SaveFilter& other); + std::vector GetMimeTypes() const; QString GetFilterForMimeType(const std::string& mimeType) const; mitk::MimeType GetMimeTypeForFilter(const QString& filter) const; QString GetDefaultFilter() const; QString GetDefaultExtension() const; mitk::MimeType GetDefaultMimeType() const; QString ToString() const; int Size() const; bool IsEmpty() const; bool ContainsMimeType(const std::string& mimeType); private: struct Impl; QScopedPointer d; }; /** * @brief GetFilterString * @return */ static QString GetFileOpenFilterString(); /** * @brief Loads the specified files * * This methods tries to load all specified files and pop-ups dialog boxes if further * user input is required (e.g. ambiguous mime-types or reader options). * * If the provided DataStorage is not NULL, some files will be added to it automatically, * dependeing on the IFileReader used. * * @param files A list of files to load. * @param ds An optional data storage passed to IFileReader instances * @return A list of BaseData instances which have not already been added to the data storage. */ static QList Load(const QStringList& paths, QWidget* parent = NULL); static mitk::DataStorage::SetOfObjects::Pointer Load(const QStringList& paths, mitk::DataStorage& storage, QWidget* parent = NULL); static QList Load(const QString& path, QWidget* parent = NULL); static mitk::DataStorage::SetOfObjects::Pointer Load(const QString& path, mitk::DataStorage& storage, QWidget* parent = NULL); using mitk::IOUtil::Load; static QString Save(const mitk::BaseData* data, const QString& defaultBaseName, const QString& defaultPath = QString(), QWidget* parent = NULL); /** * @brief Save a list of BaseData objects using a "File Save Dialog". * * For each element in the \c data vector, the following algorithm is * used to find a IFileWriter instance for writing the BaseData object. * * First, the user is prompted to select file names for each BaseData object. This * is equivalent to choosing a specific mime-type, either by selecting a filter * in the save dialog or by explicitly providing a file name extension: *
    *
  1. Get a list of registered IFileWriter objects for the current BaseData object. * If no writers are found, a message box displays a warning and * the process starts from the beginning for the next BaseData object.
  2. *
  3. A QFileDialog for prompting the user to select a file name is opened. * The mime-type associated with each IFileWriter object is used to create * a filter for file name extensions. * The best IFileWriter (see FileWriterSelector) for the current BaseData object * defines the default file name suffix via its associated mime-type. If the * file name is empty (the user cancelled the dialog), the remaining * BaseData objects are skipped. - *
  4. The file name suffix is extracted from the user-supplied file name and validated. - * If the suffix is not empty and it is either not contained in the - * extension list of the selected filter (from the QFileDialog) or the mime-type - * containing the suffix as an extension is not contained in the original - * list of compatible mime-types, a message box displays a warning and - * the process starts from the beginning with the next BaseData object. - * If the suffix is empty, a default suffix is created if the file name does - * not point to an already existing file (in that case, the user already - * confirmed to overwrite that file). The default suffix is the first entry - * in the extension list of the selected filter. If the special "all" - * filter is selected, the first entry from the extensions list of the - * highest-ranked compatible mime-type for the current base data object is used. - * The base data object is associated with the mime-type containing the suffix - * in its extension list. If the suffix is empty (the user is overwriting an - * existing file without an extension, the associated mime-type is the one - * of the selected filter or the mime-type of the best matching IFileWriter - * if the special "all" filter was selected.
  5. + *
  6. The file name is matched against valid mime-types. The first mime-type + * which accepts the file name is associated with the current BaseData object. + * If no mime-type accepts the supplied file name and the file already + * exists, the process starts from the beginning with the next BaseData object. + * Otherwise, if the selected filter is the special "all" filter and the + * file name does not contain periods (which may or may not mark the start of + * a file extension), the current BaseData object is associated with the + * default mime-type. If the selected filter is not the special "all" filter, + * the mime-type for this filter is associated with the current BaseData object. + * The default extension of the associated mime-type is then appended to the + * supplied file name. *
  7. The selected/derived file name and associated mime-type is stored in a list * and the process starts from the beginning for the next BaseData object.
  8. *
* * In the second phase, each BaseData object is saved to disk using the specified * file name and mime-type, according to the following procedure: *
    *
  1. If multiple IFileWriter objects are compatible with the current base data * object or if the single compatible IFileWriter provides configuration * options, a dialog window containing a list of IFileWriter objects and * configurable options is displayed. If the dialog is cancelled by the user, * neither the current nor the remaining base data objects are saved to disk. * If the user previously in this phase enabled the "remember options" checkbox * of the dialog, then the dialog is not shown for base data objects with the * same data type and associated mime-type if the file writer instance reports * a higher or equal confidence level for the current base data object.
  2. *
  3. The selected writer (either the only available one or the user selected one) * is used to write the base data object to disk. On failure, an error is * reported and the second phase continues with the next base data object.
  4. *
* * @param data * @param defaultBaseNames * @param defaultPath * @param parent * @return */ static QStringList Save(const std::vector& data, const QStringList& defaultBaseNames, const QString& defaultPath = QString(), QWidget* parent = NULL); using mitk::IOUtil::Save; /** * @brief SaveBaseDataWithDialog Convenience method to save any data with a Qt dialog. * @param data BaseData holding the data you wish to save. * @param fileName The file name where to save the data (including path and extension). * @param parent An optional QWidget as parent. If no parent is supplied, the QFileDialog can occur anywhere on the screen. * @deprecatedSince{2014_10} Use Save() instead. */ DEPRECATED(static void SaveBaseDataWithDialog(mitk::BaseData *data, std::string fileName, QWidget* parent = NULL)); /** * @brief SaveSurfaceWithDialog Convenience method to save a surface with a Qt dialog. * @param surface The surface to save. * @param fileName The file name where to save the data (including path and extension). * @param parent An optional QWidget as parent. If no parent is supplied, the QFileDialog can occur anywhere on the screen. * @deprecatedSince{2014_10} Use Save() instead. */ DEPRECATED(static void SaveSurfaceWithDialog(mitk::Surface::Pointer surface, std::string fileName = "", QWidget* parent = NULL)); /** * @brief SaveImageWithDialog Convenience method to save an image with a Qt dialog. * @param image The image to save. * @param fileName The file name where to save the data (including path and extension). * @param parent An optional QWidget as parent. If no parent is supplied, the QFileDialog can occur anywhere on the screen. * @deprecatedSince{2014_10} Use Save() instead. */ DEPRECATED(static void SaveImageWithDialog(mitk::Image::Pointer image, std::string fileName = "", QWidget* parent = NULL)); /** * @brief SavePointSetWithDialog Convenience method to save a pointset with a Qt dialog. * @param pointset The pointset to save. * @param fileName The file name where to save the data (including path and extension). * @param parent An optional QWidget as parent. If no parent is supplied, the QFileDialog can occur anywhere on the screen. * @deprecatedSince{2014_10} Use Save() instead. */ DEPRECATED(static void SavePointSetWithDialog(mitk::PointSet::Pointer pointset, std::string fileName = "", QWidget* parent = NULL)); private: struct Impl; }; #endif // _QmitkIOUtil__h_