diff --git a/Core/Code/IO/mitkAbstractFileIO.cpp b/Core/Code/IO/mitkAbstractFileIO.cpp index 61293e7d42..af6a7bf5db 100644 --- a/Core/Code/IO/mitkAbstractFileIO.cpp +++ b/Core/Code/IO/mitkAbstractFileIO.cpp @@ -1,188 +1,178 @@ /*=================================================================== 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 "mitkAbstractFileIO.h" +#include "mitkCustomMimeType.h" + namespace mitk { AbstractFileIO::ReaderOptions AbstractFileIO::GetReaderOptions() const { return AbstractFileReader::GetOptions(); } us::Any AbstractFileIO::GetReaderOption(const std::string& name) const { return AbstractFileReader::GetOption(name); } void AbstractFileIO::SetReaderOptions(const AbstractFileIO::ReaderOptions& options) { AbstractFileReader::SetOptions(options); } void AbstractFileIO::SetReaderOption(const std::string& name, const us::Any& value) { AbstractFileReader::SetOption(name, value); } std::pair, us::ServiceRegistration > AbstractFileIO::RegisterService(us::ModuleContext* context) { std::pair, us::ServiceRegistration > result; result.first = this->AbstractFileReader::RegisterService(context); result.second = this->AbstractFileWriter::RegisterService(context); return result; } -AbstractFileIO::AbstractFileIO() -{ -} - AbstractFileIO::AbstractFileIO(const AbstractFileIO& other) : AbstractFileReader(other) , AbstractFileWriter(other) { } +AbstractFileIO::AbstractFileIO(const std::string& baseDataType) + : AbstractFileReader() + , AbstractFileWriter(baseDataType) +{ +} + AbstractFileIO::AbstractFileIO(const std::string& baseDataType, - const AbstractFileIO::MimeType& mimeType, + const CustomMimeType& mimeType, const std::string& description) : AbstractFileReader(mimeType, description) - , AbstractFileWriter() + , AbstractFileWriter(baseDataType, mimeType, description) { - this->AbstractFileWriter::SetBaseDataType(baseDataType); - this->AbstractFileWriter::SetMimeType(mimeType); } AbstractFileIO::AbstractFileIO(const std::string& baseDataType, const std::string& extension, const std::string& description) : AbstractFileReader(extension, description) + , AbstractFileWriter(baseDataType, extension, description) { - this->AbstractFileWriter::SetBaseDataType(baseDataType); - this->AbstractFileWriter::AddExtension(extension); - this->AbstractFileWriter::SetDescription(description); } -void AbstractFileIO::SetMimeType(const std::string& mimeType) +AbstractFileIO::ReaderConfidenceLevel AbstractFileIO::GetReaderConfidenceLevel(const std::string& /*path*/) const { - this->AbstractFileReader::SetMimeType(mimeType); - this->AbstractFileWriter::SetMimeType(mimeType); + return IFileReader::Supported; } -std::string AbstractFileIO::GetMimeType() const +AbstractFileIO::WriterConfidenceLevel AbstractFileIO::GetWriterConfidenceLevel(const BaseData* /*data*/) const { - std::string mimeType = this->AbstractFileReader::GetMimeType(); - if (mimeType != this->AbstractFileWriter::GetMimeType()) - { - MITK_WARN << "Reader and writer mime-tpyes are different, using the mime-type from IFileReader"; - } - return mimeType; + return IFileWriter::Supported; } -void AbstractFileIO::SetCategory(const std::string& category) +void AbstractFileIO::SetMimeType(const CustomMimeType& mimeType) { - this->AbstractFileReader::SetCategory(category); - this->AbstractFileWriter::SetCategory(category); + this->AbstractFileReader::SetMimeType(mimeType); + this->AbstractFileWriter::SetMimeType(mimeType); } -std::string AbstractFileIO::GetCategory() const +CustomMimeType AbstractFileIO::GetMimeType() const { - std::string category = this->AbstractFileReader::GetCategory(); - if (category != this->AbstractFileWriter::GetCategory()) + CustomMimeType mimeType = this->AbstractFileReader::GetMimeType(); + if (mimeType.GetName() != this->AbstractFileWriter::GetMimeType().GetName()) { MITK_WARN << "Reader and writer mime-tpyes are different, using the mime-type from IFileReader"; } - return category; -} - -std::vector AbstractFileIO::GetExtensions() const -{ - std::vector extensions = this->AbstractFileReader::GetExtensions(); - if (extensions != this->AbstractFileWriter::GetExtensions()) - { - MITK_WARN << "Reader and writer extensions are different, using extensions from IFileReader"; - } - return extensions; -} - -void AbstractFileIO::AddExtension(const std::string& extension) -{ - this->AbstractFileReader::AddExtension(extension); - this->AbstractFileWriter::AddExtension(extension); + return mimeType; } void AbstractFileIO::SetReaderDescription(const std::string& description) { this->AbstractFileReader::SetDescription(description); } std::string AbstractFileIO::GetReaderDescription() const { return this->AbstractFileReader::GetDescription(); } void AbstractFileIO::SetWriterDescription(const std::string& description) { this->AbstractFileWriter::SetDescription(description); } std::string AbstractFileIO::GetWriterDescription() const { return this->AbstractFileWriter::GetDescription(); } void AbstractFileIO::SetDefaultReaderOptions(const AbstractFileIO::ReaderOptions& defaultOptions) { this->AbstractFileReader::SetDefaultOptions(defaultOptions); } AbstractFileIO::ReaderOptions AbstractFileIO::GetDefaultReaderOptions() const { return this->AbstractFileReader::GetDefaultOptions(); } void AbstractFileIO::SetDefaultWriterOptions(const AbstractFileIO::WriterOptions& defaultOptions) { this->AbstractFileWriter::SetDefaultOptions(defaultOptions); } AbstractFileIO::WriterOptions AbstractFileIO::GetDefaultWriterOptions() const { return this->AbstractFileWriter::GetDefaultOptions(); } void AbstractFileIO::SetReaderRanking(int ranking) { this->AbstractFileReader::SetRanking(ranking); } int AbstractFileIO::GetReaderRanking() const { return this->AbstractFileReader::GetRanking(); } void AbstractFileIO::SetWriterRanking(int ranking) { this->AbstractFileWriter::SetRanking(ranking); } int AbstractFileIO::GetWriterRanking() const { return this->AbstractFileWriter::GetRanking(); } +AbstractFileIO::ReaderConfidenceLevel AbstractFileIO::GetConfidenceLevel(const std::string& path) const +{ + ReaderConfidenceLevel level = AbstractFileReader::GetConfidenceLevel(path); + if (level == IFileReader::Unsupported) return level; + return this->GetReaderConfidenceLevel(path); +} +AbstractFileIO::WriterConfidenceLevel AbstractFileIO::GetConfidenceLevel(const BaseData* data) const +{ + WriterConfidenceLevel level = AbstractFileWriter::GetConfidenceLevel(data); + if (level == IFileWriter::Unsupported) return level; + return this->GetWriterConfidenceLevel(data); +} } diff --git a/Core/Code/IO/mitkAbstractFileIO.h b/Core/Code/IO/mitkAbstractFileIO.h index aca3673bd4..35434f1781 100644 --- a/Core/Code/IO/mitkAbstractFileIO.h +++ b/Core/Code/IO/mitkAbstractFileIO.h @@ -1,128 +1,130 @@ /*=================================================================== 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 MITKABSTRACTFILEIO_H #define MITKABSTRACTFILEIO_H #include "mitkAbstractFileReader.h" #include "mitkAbstractFileWriter.h" namespace mitk { class MITK_CORE_EXPORT AbstractFileIO : public AbstractFileReader, public AbstractFileWriter { public: typedef IFileReader::Options ReaderOptions; typedef IFileWriter::Options WriterOptions; + typedef IFileReader::ConfidenceLevel ReaderConfidenceLevel; + typedef IFileWriter::ConfidenceLevel WriterConfidenceLevel; + ReaderOptions GetReaderOptions() const; us::Any GetReaderOption(const std::string &name) const; void SetReaderOptions(const ReaderOptions& options); void SetReaderOption(const std::string& name, const us::Any& value); std::pair, us::ServiceRegistration > RegisterService(us::ModuleContext* context = us::GetModuleContext()); protected: - typedef AbstractFileReader::MimeType MimeType; - - AbstractFileIO(); - AbstractFileIO(const AbstractFileIO& other); + AbstractFileIO(const std::string& baseDataType); + /** * Associate this reader instance with the given MIME type. * * @param mimeType The mime type this reader can read. * @param description A human readable description of this reader. * * @throws std::invalid_argument if \c mimeType is empty. * * @see RegisterService */ - explicit AbstractFileIO(const std::string& baseDataType, const MimeType& mimeType, + explicit AbstractFileIO(const std::string& baseDataType, const CustomMimeType& mimeType, const std::string& description); /** * Associate this reader with the given file extension. * * Additonal file extensions can be added by sub-classes by calling AddExtension - * or SetExtensions. + * or SetExtensions on the CustomMimeType object returned by GetMimeType() and + * setting the modified object again via SetMimeType(). * * @param extension The file extension (without a leading period) for which a registered - * IMimeType object is looked up and associated with this reader instance. + * mime-type object is looked up and associated with this instance. * @param description A human readable description of this reader. * * @see RegisterService */ explicit AbstractFileIO(const std::string& baseDataType, const std::string& extension, const std::string& description); - void SetMimeType(const std::string& mimeType); + virtual ReaderConfidenceLevel GetReaderConfidenceLevel(const std::string& path) const; + virtual WriterConfidenceLevel GetWriterConfidenceLevel(const BaseData* data) const; + + void SetMimeType(const CustomMimeType& mimeType); /** * @return The mime-type this reader can handle. */ - std::string GetMimeType() const; - - void SetCategory(const std::string& category); - std::string GetCategory() const; - - std::vector GetExtensions() const; - void AddExtension(const std::string& extension); + CustomMimeType GetMimeType() const; void SetReaderDescription(const std::string& description); std::string GetReaderDescription() const; void SetWriterDescription(const std::string& description); std::string GetWriterDescription() const; void SetDefaultReaderOptions(const ReaderOptions& defaultOptions); ReaderOptions GetDefaultReaderOptions() const; void SetDefaultWriterOptions(const WriterOptions& defaultOptions); WriterOptions GetDefaultWriterOptions() const; /** * \brief Set the service ranking for this file reader. * * Default is zero and should only be chosen differently for a reason. * The ranking is used to determine which reader to use if several * equivalent readers have been found. * It may be used to replace a default reader from MITK in your own project. * E.g. if you want to use your own reader for nrrd files instead of the default, * implement it and give it a higher ranking than zero. */ void SetReaderRanking(int ranking); int GetReaderRanking() const; void SetWriterRanking(int ranking); int GetWriterRanking() const; private: AbstractFileIO& operator=(const AbstractFileIO& other); virtual AbstractFileIO* Clone() const = 0; + virtual ReaderConfidenceLevel GetConfidenceLevel(const std::string& path) const; + virtual WriterConfidenceLevel GetConfidenceLevel(const BaseData *data) const; + }; } #endif // MITKABSTRACTFILEIO_H diff --git a/Core/Code/IO/mitkAbstractFileReader.cpp b/Core/Code/IO/mitkAbstractFileReader.cpp index 28c3bf1b0b..53d5b92684 100644 --- a/Core/Code/IO/mitkAbstractFileReader.cpp +++ b/Core/Code/IO/mitkAbstractFileReader.cpp @@ -1,396 +1,346 @@ /*=================================================================== 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 namespace mitk { class AbstractFileReader::Impl : public FileReaderWriterBase { public: Impl() : FileReaderWriterBase() , m_PrototypeFactory(NULL) {} Impl(const Impl& other) : FileReaderWriterBase(other) , m_PrototypeFactory(NULL) {} us::PrototypeServiceFactory* m_PrototypeFactory; us::ServiceRegistration m_Reg; }; AbstractFileReader::AbstractFileReader() : d(new Impl) { } AbstractFileReader::~AbstractFileReader() { UnregisterService(); delete d->m_PrototypeFactory; - - d->UnregisterMimeType(); } AbstractFileReader::AbstractFileReader(const AbstractFileReader& other) : d(new Impl(*other.d.get())) { } -AbstractFileReader::AbstractFileReader(const MimeType& mimeType, const std::string& description) +AbstractFileReader::AbstractFileReader(const CustomMimeType& mimeType, const std::string& description) : d(new Impl) { d->SetMimeType(mimeType); d->SetDescription(description); } AbstractFileReader::AbstractFileReader(const std::string& extension, const std::string& description) : d(new Impl) { + CustomMimeType customMimeType; + customMimeType.AddExtension(extension); + d->SetMimeType(customMimeType); d->SetDescription(description); - d->AddExtension(extension); } ////////////////////// Reading ///////////////////////// std::vector > AbstractFileReader::Read(const std::string& path) { if (!itksys::SystemTools::FileExists(path.c_str())) { mitkThrow() << "File '" + path + "' not found."; } std::ifstream stream; stream.open(path.c_str(), std::ios_base::in | std::ios_base::binary); try { return this->Read(stream); } catch (mitk::Exception& e) { mitkReThrow(e) << "Error reading file '" << path << "'"; } catch (const std::exception& e) { mitkThrow() << "Error reading file '" << path << "': " << e.what(); } } std::vector > AbstractFileReader::Read(std::istream& stream) { // Create a temporary file and copy the data to it std::ofstream tmpOutputStream; std::string tmpFilePath = IOUtil::CreateTemporaryFile(tmpOutputStream); tmpOutputStream << stream.rdbuf(); tmpOutputStream.close(); // Now read from the temporary file std::vector > result = this->Read(tmpFilePath); std::remove(tmpFilePath.c_str()); return result; } DataStorage::SetOfObjects::Pointer AbstractFileReader::Read(const std::string& path, DataStorage& ds) { DataStorage::SetOfObjects::Pointer result = DataStorage::SetOfObjects::New(); std::vector data = this->Read(path); for (std::vector::iterator iter = data.begin(); iter != data.end(); ++iter) { mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(*iter); this->SetDefaultDataNodeProperties(node, path); ds.Add(node); result->InsertElement(result->Size(), node); } return result; } DataStorage::SetOfObjects::Pointer AbstractFileReader::Read(std::istream& stream, DataStorage& ds) { DataStorage::SetOfObjects::Pointer result = DataStorage::SetOfObjects::New(); std::vector data = this->Read(stream); for (std::vector::iterator iter = data.begin(); iter != data.end(); ++iter) { mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(*iter); this->SetDefaultDataNodeProperties(node, std::string()); ds.Add(node); result->InsertElement(result->Size(), node); } return result; } +IFileReader::ConfidenceLevel AbstractFileReader::GetConfidenceLevel(const std::string& path) const +{ + return itksys::SystemTools::FileExists(path.c_str(), true) ? Supported : Unsupported; +} + //////////// µS Registration & Properties ////////////// us::ServiceRegistration AbstractFileReader::RegisterService(us::ModuleContext* context) { if (d->m_PrototypeFactory) return us::ServiceRegistration(); if(context == NULL) { context = us::GetModuleContext(); } d->RegisterMimeType(context); - if (this->GetMimeType().empty()) + if (this->GetMimeType().GetName().empty()) { MITK_WARN << "Not registering reader due to empty MIME type."; return us::ServiceRegistration(); } struct PrototypeFactory : public us::PrototypeServiceFactory { AbstractFileReader* const m_Prototype; PrototypeFactory(AbstractFileReader* prototype) : m_Prototype(prototype) {} us::InterfaceMap GetService(us::Module* /*module*/, const us::ServiceRegistrationBase& /*registration*/) { return us::MakeInterfaceMap(m_Prototype->Clone()); } void UngetService(us::Module* /*module*/, const us::ServiceRegistrationBase& /*registration*/, const us::InterfaceMap& service) { delete us::ExtractInterface(service); } }; d->m_PrototypeFactory = new PrototypeFactory(this); us::ServiceProperties props = this->GetServiceProperties(); d->m_Reg = context->RegisterService(d->m_PrototypeFactory, props); return d->m_Reg; } void AbstractFileReader::UnregisterService() { try { d->m_Reg.Unregister(); } catch (const std::exception&) {} } us::ServiceProperties AbstractFileReader::GetServiceProperties() const { us::ServiceProperties result; result[IFileReader::PROP_DESCRIPTION()] = this->GetDescription(); - result[IFileReader::PROP_MIMETYPE()] = this->GetMimeType(); + result[IFileReader::PROP_MIMETYPE()] = this->GetMimeType().GetName(); result[us::ServiceConstants::SERVICE_RANKING()] = this->GetRanking(); return result; } -us::ServiceRegistration AbstractFileReader::RegisterMimeType(us::ModuleContext* context) +us::ServiceRegistration AbstractFileReader::RegisterMimeType(us::ModuleContext* context) { return d->RegisterMimeType(context); } -void AbstractFileReader::SetMimeType(const std::string& mimeType) +void AbstractFileReader::SetMimeType(const CustomMimeType& mimeType) { d->SetMimeType(mimeType); } -void AbstractFileReader::SetCategory(const std::string& category) -{ - d->SetCategory(category); -} - -void AbstractFileReader::AddExtension(const std::string& extension) -{ - d->AddExtension(extension); -} - void AbstractFileReader::SetDescription(const std::string& description) { d->SetDescription(description); } void AbstractFileReader::SetRanking(int ranking) { d->SetRanking(ranking); } int AbstractFileReader::GetRanking() const { return d->GetRanking(); } //////////////////////// Options /////////////////////// void AbstractFileReader::SetDefaultOptions(const IFileReader::Options& defaultOptions) { d->SetDefaultOptions(defaultOptions); } IFileReader::Options AbstractFileReader::GetDefaultOptions() const { return d->GetDefaultOptions(); } IFileReader::Options AbstractFileReader::GetOptions() const { return d->GetOptions(); } us::Any AbstractFileReader::GetOption(const std::string& name) const { return d->GetOption(name); } void AbstractFileReader::SetOptions(const Options& options) { d->SetOptions(options); } void AbstractFileReader::SetOption(const std::string& name, const us::Any& value) { d->SetOption(name, value); } ////////////////// MISC ////////////////// -bool AbstractFileReader::CanRead(const std::string& path) const -{ - if (!itksys::SystemTools::FileExists(path.c_str(), true)) - { - return false; - } - - // Default implementation only checks if extension is correct - std::string extension = itksys::SystemTools::GetFilenameExtension(path); - extension = extension.substr(1, extension.size()-1); - if (!d->HasExtension(extension)) - { - return false; - } - - std::ifstream stream(path.c_str()); - return this->CanRead(stream); -} - -bool AbstractFileReader::CanRead(std::istream& stream) const -{ - return stream.good(); -} - void AbstractFileReader::AddProgressCallback(const ProgressCallback& callback) { d->AddProgressCallback(callback); } void AbstractFileReader::RemoveProgressCallback(const ProgressCallback& callback) { d->RemoveProgressCallback(callback); } ////////////////// µS related Getters ////////////////// -std::string AbstractFileReader::GetCategory() const -{ - return d->GetCategory(); -} -std::string AbstractFileReader::GetMimeType() const +CustomMimeType AbstractFileReader::GetMimeType() const { return d->GetMimeType(); } -std::vector AbstractFileReader::GetExtensions() const -{ - return d->GetExtensions(); -} - std::string AbstractFileReader::GetDescription() const { return d->GetDescription(); } -AbstractFileReader::MimeType::MimeType(const std::string& mimeType) - : std::string(mimeType) -{ - if (this->empty()) - { - throw std::invalid_argument("MIME type must not be empty."); - } -} - -AbstractFileReader::MimeType::MimeType() -{ -} - void AbstractFileReader::SetDefaultDataNodeProperties(DataNode* node, const std::string& filePath) { // path if (!filePath.empty()) { mitk::StringProperty::Pointer pathProp = mitk::StringProperty::New( itksys::SystemTools::GetFilenamePath(filePath) ); node->SetProperty(StringProperty::PATH, pathProp); } // name already defined? mitk::StringProperty::Pointer nameProp = dynamic_cast(node->GetProperty("name")); if(nameProp.IsNull() || (strcmp(nameProp->GetValue(),"No Name!")==0)) { // name already defined in BaseData mitk::StringProperty::Pointer baseDataNameProp = dynamic_cast(node->GetData()->GetProperty("name").GetPointer() ); if(baseDataNameProp.IsNull() || (strcmp(baseDataNameProp->GetValue(),"No Name!")==0)) { // name neither defined in node, nor in BaseData -> name = filebasename; nameProp = mitk::StringProperty::New(itksys::SystemTools::GetFilenameWithoutExtension(itksys::SystemTools::GetFilenameName(filePath))); node->SetProperty("name", nameProp); } else { // name defined in BaseData! nameProp = mitk::StringProperty::New(baseDataNameProp->GetValue()); node->SetProperty("name", nameProp); } } // visibility if(!node->GetProperty("visible")) { node->SetVisibility(true); } } } diff --git a/Core/Code/IO/mitkAbstractFileReader.h b/Core/Code/IO/mitkAbstractFileReader.h index cbbead95b3..5c1b17dc4d 100644 --- a/Core/Code/IO/mitkAbstractFileReader.h +++ b/Core/Code/IO/mitkAbstractFileReader.h @@ -1,220 +1,185 @@ /*=================================================================== 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 AbstractFileReader_H_HEADER_INCLUDED_C1E7E521 #define AbstractFileReader_H_HEADER_INCLUDED_C1E7E521 // Macro #include // MITK #include #include -#include // Microservices #include #include #include namespace us { struct PrototypeServiceFactory; } namespace mitk { +class CustomMimeType; + /** * @brief Base class for creating mitk::BaseData objects from files or streams. * @ingroup Process */ class MITK_CORE_EXPORT AbstractFileReader : public mitk::IFileReader { public: /** * @brief Reads the given \c path and creates a list BaseData objects. * * The default implementation opens a std::ifstream in binary mode for reading * and passed the stream to Read(std::istream&). * * @param path The absolute path to a file include the file name extension. * @return */ virtual std::vector > Read(const std::string& path); virtual std::vector > Read(std::istream& stream) = 0; virtual DataStorage::SetOfObjects::Pointer Read(const std::string& path, mitk::DataStorage& ds); virtual DataStorage::SetOfObjects::Pointer Read(std::istream& stream, mitk::DataStorage& ds); + virtual ConfidenceLevel GetConfidenceLevel(const std::string &path) const; + virtual Options GetOptions() const; virtual us::Any GetOption(const std::string &name) const; virtual void SetOptions(const Options& options); virtual void SetOption(const std::string& name, const us::Any& value); - /** - * @brief Checks if the specified path can be read. - * - * The default implementation checks if the path exists and contains a - * file extension associated with the mime-type of this reader. - * It then creates a std::ifstream object for the given path and - * calls CanRead(const std::istream&). - * - * @param path The absolute path to a file. - * @return \c true if the file can be read, \c false otherwise. - */ - virtual bool CanRead(const std::string& path) const; - - /** - * @brief Checks if the specified input stream can be read. - * - * @param stream The stream to be read. - * @return \c true if the stream is good, \c false otherwise. - */ - virtual bool CanRead(std::istream& stream) const; - virtual void AddProgressCallback(const ProgressCallback& callback); virtual void RemoveProgressCallback(const ProgressCallback& callback); /** * Associate this reader with the MIME type returned by the current IMimeTypeProvider * service for the provided extension if the MIME type exists, otherwise registers * a new MIME type when RegisterService() is called. * * If no MIME type for \c extension is already registered, a call to RegisterService() * will register a new MIME type and associate this reader instance with it. The MIME * type id can be set via SetMimeType() or it will be auto-generated using \c extension, * having the form "application/vnd.mitk.". * * @param extension The file extension (without a leading period) for which a registered - * IMimeType object is looked up and associated with this reader instance. + * mime-type object is looked up and associated with this reader instance. * @param description A human readable description of this reader. */ us::ServiceRegistration RegisterService(us::ModuleContext* context = us::GetModuleContext()); void UnregisterService(); protected: - class MITK_CORE_EXPORT MimeType : public std::string - { - public: - MimeType(const std::string& mimeType); - - private: - MimeType(); - - friend class AbstractFileReader; - }; - AbstractFileReader(); ~AbstractFileReader(); AbstractFileReader(const AbstractFileReader& other); /** * Associate this reader instance with the given MIME type. * * @param mimeType The mime type this reader can read. * @param description A human readable description of this reader. * * @throws std::invalid_argument if \c mimeType is empty. * * @see RegisterService */ - explicit AbstractFileReader(const MimeType& mimeType, const std::string& description); + explicit AbstractFileReader(const CustomMimeType& mimeType, const std::string& description); /** * Associate this reader with the given file extension. * * Additonal file extensions can be added by sub-classes by calling AddExtension * or SetExtensions. * * @param extension The file extension (without a leading period) for which a registered - * IMimeType object is looked up and associated with this reader instance. + * mime-type object is looked up and associated with this reader instance. * @param description A human readable description of this reader. * * @see RegisterService */ explicit AbstractFileReader(const std::string& extension, const std::string& description); virtual us::ServiceProperties GetServiceProperties() const; /** - * Registers a new IMimeType service object. + * Registers a new CustomMimeType service object. * * This method is called from RegisterService and the default implementation - * registers a new IMimeType service object if all of the following conditions + * registers a new mime-type service object if all of the following conditions * are true: * - * - The reader + * - TODO * * @param context * @return * @throws std::invalid_argument if \c context is NULL. */ - virtual us::ServiceRegistration RegisterMimeType(us::ModuleContext* context); + virtual us::ServiceRegistration RegisterMimeType(us::ModuleContext* context); - void SetMimeType(const std::string& mimeType); + void SetMimeType(const CustomMimeType& mimeType); /** * @return The mime-type this reader can handle. */ - std::string GetMimeType() const; - - void SetCategory(const std::string& category); - std::string GetCategory() const; - - std::vector GetExtensions() const; - void AddExtension(const std::string& extension); + CustomMimeType GetMimeType() const; void SetDescription(const std::string& description); std::string GetDescription() const; void SetDefaultOptions(const Options& defaultOptions); Options GetDefaultOptions() const; /** * \brief Set the service ranking for this file reader. * * Default is zero and should only be chosen differently for a reason. * The ranking is used to determine which reader to use if several * equivalent readers have been found. * It may be used to replace a default reader from MITK in your own project. * E.g. if you want to use your own reader for nrrd files instead of the default, * implement it and give it a higher ranking than zero. */ void SetRanking(int ranking); int GetRanking() const; virtual void SetDefaultDataNodeProperties(DataNode* node, const std::string& filePath); private: AbstractFileReader& operator=(const AbstractFileReader& other); virtual mitk::IFileReader* Clone() const = 0; class Impl; std::auto_ptr d; }; } // namespace mitk #endif /* AbstractFileReader_H_HEADER_INCLUDED_C1E7E521 */ diff --git a/Core/Code/IO/mitkAbstractFileWriter.cpp b/Core/Code/IO/mitkAbstractFileWriter.cpp index c5fcccff65..b54a9d5e9c 100644 --- a/Core/Code/IO/mitkAbstractFileWriter.cpp +++ b/Core/Code/IO/mitkAbstractFileWriter.cpp @@ -1,324 +1,304 @@ /*=================================================================== 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 namespace mitk { class AbstractFileWriter::Impl : public FileReaderWriterBase { public: Impl() : FileReaderWriterBase() , m_PrototypeFactory(NULL) {} Impl(const Impl& other) : FileReaderWriterBase(other) , m_BaseDataType(other.m_BaseDataType) , m_PrototypeFactory(NULL) {} std::string m_BaseDataType; us::PrototypeServiceFactory* m_PrototypeFactory; us::ServiceRegistration m_Reg; }; -AbstractFileWriter::AbstractFileWriter() - : d(new Impl) -{ -} - AbstractFileWriter::~AbstractFileWriter() { UnregisterService(); delete d->m_PrototypeFactory; - - d->UnregisterMimeType(); } AbstractFileWriter::AbstractFileWriter(const AbstractFileWriter& other) : d(new Impl(*other.d.get())) { } -AbstractFileWriter::AbstractFileWriter(const std::string& baseDataType, const MimeType& mimeType, +AbstractFileWriter::AbstractFileWriter(const std::string& baseDataType) + : d(new Impl) +{ + d->m_BaseDataType = baseDataType; +} + +AbstractFileWriter::AbstractFileWriter(const std::string& baseDataType, const CustomMimeType& mimeType, const std::string& description) : d(new Impl) { d->m_BaseDataType = baseDataType; d->SetMimeType(mimeType); d->SetDescription(description); } AbstractFileWriter::AbstractFileWriter(const std::string& baseDataType, const std::string& extension, const std::string& description) : d(new Impl) { d->m_BaseDataType = baseDataType; d->SetDescription(description); - d->AddExtension(extension); + CustomMimeType customMimeType; + customMimeType.AddExtension(extension); + d->SetMimeType(customMimeType); } ////////////////////// Writing ///////////////////////// void AbstractFileWriter::Write(const BaseData* data, const std::string& path) { std::ofstream stream; stream.open(path.c_str()); try { this->Write(data, stream); } catch(mitk::Exception& e) { mitkReThrow(e) << "Error writing file '" << path << "'"; } catch(const std::exception& e) { mitkThrow() << "Error writing file '" << path << "': " << e.what(); } } +IFileWriter::ConfidenceLevel AbstractFileWriter::GetConfidenceLevel(const BaseData* data) const +{ + if (data == NULL) return Unsupported; + + if (data->GetNameOfClass() == d->m_BaseDataType) + { + return Supported; + } + return Unsupported; +} + void AbstractFileWriter::Write(const BaseData* data, std::ostream& stream) { // Create a temporary file and write the data to it std::ofstream tmpOutputStream; std::string tmpFilePath = IOUtil::CreateTemporaryFile(tmpOutputStream); this->Write(data, tmpFilePath); tmpOutputStream.close(); // Now copy the contents std::ifstream tmpInputStream(tmpFilePath.c_str(), std::ios_base::binary); stream << tmpInputStream.rdbuf(); tmpInputStream.close(); std::remove(tmpFilePath.c_str()); } //////////// µS Registration & Properties ////////////// us::ServiceRegistration AbstractFileWriter::RegisterService(us::ModuleContext* context) { if (d->m_PrototypeFactory) return us::ServiceRegistration(); if(context == NULL) { context = us::GetModuleContext(); } d->RegisterMimeType(context); - if (this->GetMimeType().empty()) + if (this->GetMimeType().GetName().empty()) { MITK_WARN << "Not registering writer due to empty MIME type."; return us::ServiceRegistration(); } struct PrototypeFactory : public us::PrototypeServiceFactory { AbstractFileWriter* const m_Prototype; PrototypeFactory(AbstractFileWriter* prototype) : m_Prototype(prototype) {} us::InterfaceMap GetService(us::Module* /*module*/, const us::ServiceRegistrationBase& /*registration*/) { return us::MakeInterfaceMap(m_Prototype->Clone()); } void UngetService(us::Module* /*module*/, const us::ServiceRegistrationBase& /*registration*/, const us::InterfaceMap& service) { delete us::ExtractInterface(service); } }; d->m_PrototypeFactory = new PrototypeFactory(this); us::ServiceProperties props = this->GetServiceProperties(); d->m_Reg = context->RegisterService(d->m_PrototypeFactory, props); return d->m_Reg; } void AbstractFileWriter::UnregisterService() { try { d->m_Reg.Unregister(); } catch (const std::exception&) {} } us::ServiceProperties AbstractFileWriter::GetServiceProperties() const { us::ServiceProperties result; result[IFileWriter::PROP_DESCRIPTION()] = this->GetDescription(); - result[IFileWriter::PROP_MIMETYPE()] = this->GetMimeType(); + result[IFileWriter::PROP_MIMETYPE()] = this->GetMimeType().GetName(); result[IFileWriter::PROP_BASEDATA_TYPE()] = d->m_BaseDataType; result[us::ServiceConstants::SERVICE_RANKING()] = this->GetRanking(); // for (IFileWriter::OptionList::const_iterator it = d->m_Options.begin(); it != d->m_Options.end(); ++it) // { // result[it->first] = std::string("true"); // } return result; } -std::string AbstractFileWriter::GetMimeType() const +CustomMimeType AbstractFileWriter::GetMimeType() const { return d->GetMimeType(); } -us::ServiceRegistration AbstractFileWriter::RegisterMimeType(us::ModuleContext* context) +us::ServiceRegistration AbstractFileWriter::RegisterMimeType(us::ModuleContext* context) { return d->RegisterMimeType(context); } -void AbstractFileWriter::SetMimeType(const std::string& mimeType) +void AbstractFileWriter::SetMimeType(const CustomMimeType& mimeType) { d->SetMimeType(mimeType); } void AbstractFileWriter::SetRanking(int ranking) { d->SetRanking(ranking); } //////////////////////// Options /////////////////////// void AbstractFileWriter::SetDefaultOptions(const IFileWriter::Options& defaultOptions) { d->SetDefaultOptions(defaultOptions); } IFileWriter::Options AbstractFileWriter::GetDefaultOptions() const { return d->GetDefaultOptions(); } IFileWriter::Options AbstractFileWriter::GetOptions() const { return d->GetOptions(); } us::Any AbstractFileWriter::GetOption(const std::string& name) const { return d->GetOption(name); } void AbstractFileWriter::SetOption(const std::string& name, const us::Any& value) { d->SetOption(name, value); } void AbstractFileWriter::SetOptions(const Options& options) { d->SetOptions(options); } ////////////////// MISC ////////////////// void AbstractFileWriter::AddProgressCallback(const ProgressCallback& callback) { d->AddProgressCallback(callback); } void AbstractFileWriter::RemoveProgressCallback(const ProgressCallback& callback) { d->RemoveProgressCallback(callback); } ////////////////// µS related Getters ////////////////// int AbstractFileWriter::GetRanking() const { return d->GetRanking(); } -std::vector AbstractFileWriter::GetExtensions() const -{ - return d->GetExtensions(); -} - -void AbstractFileWriter::AddExtension(const std::string& extension) -{ - d->AddExtension(extension); -} - -void AbstractFileWriter::SetCategory(const std::string& category) -{ - d->SetCategory(category); -} - -std::string AbstractFileWriter::GetCategory() const -{ - return d->GetCategory(); -} - void AbstractFileWriter::SetBaseDataType(const std::string& baseDataType) { d->m_BaseDataType = baseDataType; } std::string AbstractFileWriter::GetDescription() const { return d->GetDescription(); } std::string AbstractFileWriter::GetBaseDataType() const { return d->m_BaseDataType; } void AbstractFileWriter::SetDescription(const std::string& description) { d->SetDescription(description); } -AbstractFileWriter::MimeType::MimeType(const std::string& mimeType) - : std::string(mimeType) -{ - if (this->empty()) - { - throw std::invalid_argument("MIME type must not be empty."); - } -} - -AbstractFileWriter::MimeType::MimeType() -{ -} - } diff --git a/Core/Code/IO/mitkAbstractFileWriter.h b/Core/Code/IO/mitkAbstractFileWriter.h index e55483bed2..ff54e219db 100644 --- a/Core/Code/IO/mitkAbstractFileWriter.h +++ b/Core/Code/IO/mitkAbstractFileWriter.h @@ -1,178 +1,162 @@ /*=================================================================== 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 AbstractFileWriter_H_HEADER_INCLUDED_C1E7E521 #define AbstractFileWriter_H_HEADER_INCLUDED_C1E7E521 // Macro #include // MITK #include -#include // Microservices #include #include #include #include namespace us { struct PrototypeServiceFactory; } namespace mitk { +class CustomMimeType; + /** * @brief Base class for writing mitk::BaseData objects to files or streams. * * In general, all file writers should derive from this class, this way it is * made sure that the new implementation is * exposed to the Microservice-Framework and that is automatically available troughout MITK. * The default implementation only requires one Write() * method and the Clone() method to be implemented. * * @ingroup Process */ class MITK_CORE_EXPORT AbstractFileWriter : public mitk::IFileWriter { public: /** * \brief Write the data in data to the the location specified in path */ virtual void Write(const BaseData* data, const std::string& path); /** * \brief Write the data in data to the the stream specified in stream */ virtual void Write(const BaseData* data, std::ostream& stream ) = 0; + virtual ConfidenceLevel GetConfidenceLevel(const BaseData *data) const; + virtual Options GetOptions() const; virtual us::Any GetOption(const std::string &name) const; virtual void SetOptions(const Options& options); virtual void SetOption(const std::string& name, const us::Any& value); virtual void AddProgressCallback(const ProgressCallback& callback); virtual void RemoveProgressCallback(const ProgressCallback& callback); us::ServiceRegistration RegisterService(us::ModuleContext* context = us::GetModuleContext()); void UnregisterService(); protected: - class MITK_CORE_EXPORT MimeType : public std::string - { - public: - MimeType(const std::string& mimeType); - - private: - MimeType(); - - friend class AbstractFileReader; - }; - - AbstractFileWriter(); ~AbstractFileWriter(); AbstractFileWriter(const AbstractFileWriter& other); - AbstractFileWriter(const std::string& basedataType, const MimeType& mimeType, const std::string& description); + AbstractFileWriter(const std::string& baseDataType); - AbstractFileWriter(const std::string& basedataType, const std::string& extension, const std::string& description); + AbstractFileWriter(const std::string& baseDataType, const CustomMimeType& mimeType, const std::string& description); + + AbstractFileWriter(const std::string& baseDataType, const std::string& extension, const std::string& description); virtual us::ServiceProperties GetServiceProperties() const; /** - * Registers a new IMimeType service object. + * Registers a new CustomMimeType service object. * * This method is called from RegisterService and the default implementation - * registers a new IMimeType service object if all of the following conditions + * registers a new mime-type service object if all of the following conditions * are true: * - * - The writer + * - TODO * * @param context * @return * @throws std::invalid_argument if \c context is NULL. */ - virtual us::ServiceRegistration RegisterMimeType(us::ModuleContext* context); + virtual us::ServiceRegistration RegisterMimeType(us::ModuleContext* context); - void SetMimeType(const std::string& mimeType); + void SetMimeType(const CustomMimeType& mimeType); /** * @return Get the mime-type this writer can handle. */ - std::string GetMimeType() const; - - void SetCategory(const std::string& category); - std::string GetCategory() const; - - /** - * \brief Get file extension that this writer is able to handle. - */ - std::vector GetExtensions() const; - void AddExtension(const std::string& extension); + CustomMimeType GetMimeType() const; /** * \brief Sets a human readable description of this writer. * * This will be used in file dialogs for example. */ void SetDescription(const std::string& description); std::string GetDescription() const; void SetDefaultOptions(const Options& defaultOptions); Options GetDefaultOptions() const; /** * \brief Set the service ranking for this file writer. * * Default is zero and should only be chosen differently for a reason. * The ranking is used to determine which writer to use if several * equivalent writers have been found. * It may be used to replace a default writer from MITK in your own project. * E.g. if you want to use your own writer for nrrd files instead of the default, * implement it and give it a higher ranking than zero. */ void SetRanking(int ranking); int GetRanking() const; /** * \brief Sets the name of the mitk::Basedata that this writer is able to handle. * * The correct value is the one given as the first parameter in the mitkNewMacro of that BaseData derivate. * You can also retrieve it by calling GetNameOfClass() on an instance of said data. */ void SetBaseDataType(const std::string& baseDataType); virtual std::string GetBaseDataType() const; private: AbstractFileWriter& operator=(const AbstractFileWriter& other); virtual mitk::IFileWriter* Clone() const = 0; class Impl; std::auto_ptr d; }; } // namespace mitk #endif /* AbstractFileWriter_H_HEADER_INCLUDED_C1E7E521 */ diff --git a/Core/Code/IO/mitkCustomMimeType.cpp b/Core/Code/IO/mitkCustomMimeType.cpp new file mode 100644 index 0000000000..87b3d14517 --- /dev/null +++ b/Core/Code/IO/mitkCustomMimeType.cpp @@ -0,0 +1,140 @@ +/*=================================================================== + +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 "mitkCustomMimeType.h" + +#include "mitkMimeType.h" + +#include + +namespace mitk { + +struct CustomMimeType::Impl +{ + std::string m_Name; + std::string m_Category; + std::vector m_Extensions; + std::string m_Comment; +}; + +CustomMimeType::CustomMimeType() + : d(new Impl) +{ +} + +CustomMimeType::CustomMimeType(const std::string& name) + : d(new Impl) +{ + d->m_Name = name; +} + +CustomMimeType::CustomMimeType(const CustomMimeType& other) + : d(new Impl(*other.d.get())) +{ +} + +CustomMimeType::CustomMimeType(const MimeType& other) + : d(new Impl) +{ + d->m_Name = other.GetName(); + d->m_Category = other.GetCategory(); + d->m_Extensions = other.GetExtensions(); + d->m_Comment = other.GetComment(); +} + +CustomMimeType& CustomMimeType::operator=(const CustomMimeType& other) +{ + CustomMimeType tmp(other); + Swap(tmp); + return *this; +} + +CustomMimeType&CustomMimeType::operator=(const MimeType& other) +{ + CustomMimeType tmp(other); + Swap(tmp); + return *this; +} + +std::string CustomMimeType::GetName() const +{ + return d->m_Name; +} + +std::string CustomMimeType::GetCategory() const +{ + return d->m_Category; +} + +std::vector CustomMimeType::GetExtensions() const +{ + return d->m_Extensions; +} + +std::string CustomMimeType::GetComment() const +{ + if (!d->m_Comment.empty()) return d->m_Comment; + if (!d->m_Extensions.empty()) + { + return d->m_Extensions.front() + " File"; + } + return "Unknown"; +} + +void CustomMimeType::SetName(const std::string& name) +{ + d->m_Name = name; +} + +void CustomMimeType::SetCategory(const std::string& category) +{ + d->m_Category = category; +} + +void CustomMimeType::SetExtension(const std::string& extension) +{ + d->m_Extensions.clear(); + d->m_Extensions.push_back(extension); +} + +void CustomMimeType::AddExtension(const std::string& extension) +{ + if (std::find(d->m_Extensions.begin(), d->m_Extensions.end(), extension) == + d->m_Extensions.end()) + { + d->m_Extensions.push_back(extension); + } +} + +void CustomMimeType::SetComment(const std::string& comment) +{ + d->m_Comment = comment; +} + +void CustomMimeType::Swap(CustomMimeType& r) +{ + Impl* d1 = d.release(); + Impl* d2 = r.d.release(); + d.reset(d2); + r.d.reset(d1); +} + +void swap(CustomMimeType& l, CustomMimeType& r) +{ + l.Swap(r); +} + +} diff --git a/Core/Code/IO/mitkCustomMimeType.h b/Core/Code/IO/mitkCustomMimeType.h new file mode 100644 index 0000000000..e9eed60a5c --- /dev/null +++ b/Core/Code/IO/mitkCustomMimeType.h @@ -0,0 +1,69 @@ +/*=================================================================== + +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 MITKCUSTOMMIMETYPE_H +#define MITKCUSTOMMIMETYPE_H + +#include + +#include + +#include +#include +#include + +namespace mitk { + +class MimeType; + +class MITK_CORE_EXPORT CustomMimeType +{ +public: + + CustomMimeType(); + CustomMimeType(const std::string& name); + CustomMimeType(const CustomMimeType& other); + explicit CustomMimeType(const MimeType& other); + + CustomMimeType& operator=(const CustomMimeType& other); + CustomMimeType& operator=(const MimeType& other); + + std::string GetName() const; + std::string GetCategory() const; + std::vector GetExtensions() const; + std::string GetComment() const; + + void SetName(const std::string& name); + void SetCategory(const std::string& category); + void SetExtension(const std::string& extension); + void AddExtension(const std::string& extension); + void SetComment(const std::string& comment); + + void Swap(CustomMimeType& r); + +private: + + struct Impl; + std::auto_ptr d; +}; + +void swap(CustomMimeType& l, CustomMimeType& r); + +} + +US_DECLARE_SERVICE_INTERFACE(mitk::CustomMimeType, "org.mitk.CustomMimeType") + +#endif // MITKCUSTOMMIMETYPE_H diff --git a/Core/Code/IO/mitkFileReaderRegistry.cpp b/Core/Code/IO/mitkFileReaderRegistry.cpp index 098477197b..5cc681ba03 100644 --- a/Core/Code/IO/mitkFileReaderRegistry.cpp +++ b/Core/Code/IO/mitkFileReaderRegistry.cpp @@ -1,121 +1,129 @@ /*=================================================================== 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 "mitkFileReaderRegistry.h" #include "mitkIMimeTypeProvider.h" #include "mitkCoreServices.h" // Microservices #include #include #include #include #include "itksys/SystemTools.hxx" mitk::FileReaderRegistry::FileReaderRegistry() { } mitk::FileReaderRegistry::~FileReaderRegistry() { for (std::map >::iterator iter = m_ServiceObjects.begin(), end = m_ServiceObjects.end(); iter != end; ++iter) { iter->second.UngetService(iter->first); } } -mitk::FileReaderRegistry::ReaderReference mitk::FileReaderRegistry::GetReference(const std::string& mimeType, us::ModuleContext* context) +mitk::MimeType mitk::FileReaderRegistry::GetMimeTypeForExtension(const std::string& extension, us::ModuleContext* context) +{ + mitk::CoreServicePointer mimeTypeProvider(mitk::CoreServices::GetMimeTypeProvider(context)); + std::vector mimeTypes = mimeTypeProvider->GetMimeTypesForExtension(extension); + if (mimeTypes.empty()) + { + return MimeType(); + } + else + { + return mimeTypes.front(); + } +} + +mitk::FileReaderRegistry::ReaderReference mitk::FileReaderRegistry::GetReference(const MimeType& mimeType, us::ModuleContext* context) { std::vector refs = GetReferences(mimeType, context); if (refs.empty()) return ReaderReference(); std::sort(refs.begin(), refs.end()); return refs.back(); } -std::vector mitk::FileReaderRegistry::GetReferences(const std::string& mimeType, us::ModuleContext* context) +std::vector mitk::FileReaderRegistry::GetReferences(const MimeType& mimeType, us::ModuleContext* context) { std::string filter = us::LDAPProp(us::ServiceConstants::OBJECTCLASS()) == us_service_interface_iid() && - us::LDAPProp(IFileReader::PROP_MIMETYPE()) == mimeType; + us::LDAPProp(IFileReader::PROP_MIMETYPE()) == mimeType.GetName(); return context->GetServiceReferences(filter); } mitk::IFileReader* mitk::FileReaderRegistry::GetReader(const mitk::FileReaderRegistry::ReaderReference& ref, us::ModuleContext* context) { us::ServiceObjects serviceObjects = context->GetServiceObjects(ref); mitk::IFileReader* reader = serviceObjects.GetService(); m_ServiceObjects.insert(std::make_pair(reader, serviceObjects)); return reader; } -mitk::IFileReader* mitk::FileReaderRegistry::GetReader(const std::string& extension, us::ModuleContext* context ) +mitk::IFileReader* mitk::FileReaderRegistry::GetReader(const MimeType& mimeType, us::ModuleContext* context ) { - std::vector results = GetReaders(extension, context); + std::vector results = GetReaders(mimeType, context); if (results.empty()) return NULL; return results.front(); } -std::vector mitk::FileReaderRegistry::GetReaders(const std::string& extension, us::ModuleContext* context ) +std::vector mitk::FileReaderRegistry::GetReaders(const MimeType& mimeType, us::ModuleContext* context ) { std::vector result; - // filter for mime type - mitk::IMimeTypeProvider* mimeTypeProvider = mitk::CoreServices::GetMimeTypeProvider(context); - std::vector mimeTypes = mimeTypeProvider->GetMimeTypesForExtension(extension); - if (mimeTypes.empty()) - { - MITK_WARN << "No mime-type information for extension " << extension << " available."; - return result; - } - std::vector > refs = GetReferences(mimeTypes.front(), context); + if (!mimeType.IsValid()) return result; + + std::vector > refs = GetReferences(mimeType, context); std::sort(refs.begin(), refs.end()); result.reserve(refs.size()); // Translate List of ServiceRefs to List of Pointers for (std::vector >::const_reverse_iterator iter = refs.rbegin(), end = refs.rend(); iter != end; ++iter) { us::ServiceObjects serviceObjects = context->GetServiceObjects(*iter); mitk::IFileReader* reader = serviceObjects.GetService(); m_ServiceObjects.insert(std::make_pair(reader, serviceObjects)); result.push_back(reader); } return result; } void mitk::FileReaderRegistry::UngetReader(mitk::IFileReader* reader) { std::map >::iterator readerIter = m_ServiceObjects.find(reader); if (readerIter != m_ServiceObjects.end()) { readerIter->second.UngetService(reader); m_ServiceObjects.erase(readerIter); } } void mitk::FileReaderRegistry::UngetReaders(const std::vector& readers) { for (std::vector::const_iterator iter = readers.begin(), end = readers.end(); iter != end; ++iter) { this->UngetReader(*iter); } } diff --git a/Core/Code/IO/mitkFileReaderRegistry.h b/Core/Code/IO/mitkFileReaderRegistry.h index 4291e6684d..2699e4d6d6 100644 --- a/Core/Code/IO/mitkFileReaderRegistry.h +++ b/Core/Code/IO/mitkFileReaderRegistry.h @@ -1,81 +1,89 @@ /*=================================================================== 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 FileReaderRegistry_H_HEADER_INCLUDED_C1E7E521 #define FileReaderRegistry_H_HEADER_INCLUDED_C1E7E521 #include #include #include // Microservices #include #include #include namespace mitk { +class MimeType; + /** - * @ingroup Process + * @ingroup IO * * Provides convenient access to mitk::IFileReader instances and reading * files into mitk::BaseData types. * * \note The life-time of all mitk::IFileReader objects returned by an * instance of this class ends with the destruction of that instance. */ class MITK_CORE_EXPORT FileReaderRegistry { public: typedef us::ServiceReference ReaderReference; FileReaderRegistry(); ~FileReaderRegistry(); - static ReaderReference GetReference(const std::string& mimeType, us::ModuleContext* context = us::GetModuleContext()); + /** + * @brief Get the highest ranked mime-type for the given extension. + * @param extension A file name extension without a leading dot. + * @param context + * @return The highest ranked mime-type containing \c extension in + * its extension list. + */ + static MimeType GetMimeTypeForExtension(const std::string& extension, us::ModuleContext* context = us::GetModuleContext()); + + static ReaderReference GetReference(const MimeType& mimeType, us::ModuleContext* context = us::GetModuleContext()); - static std::vector GetReferences(const std::string& mimeType, us::ModuleContext* context = us::GetModuleContext()); + static std::vector GetReferences(const MimeType& mimeType, us::ModuleContext* context = us::GetModuleContext()); mitk::IFileReader* GetReader(const ReaderReference& ref, us::ModuleContext* context = us::GetModuleContext()); - /** - * Returns a compatible Reader to the given file extension - */ - mitk::IFileReader* GetReader(const std::string& extension, us::ModuleContext* context = us::GetModuleContext() ); + mitk::IFileReader* GetReader(const MimeType& mimeType, us::ModuleContext* context = us::GetModuleContext()); - std::vector GetReaders(const std::string& extension, us::ModuleContext* context = us::GetModuleContext() ); + std::vector GetReaders(const MimeType& mimeType, us::ModuleContext* context = us::GetModuleContext()); void UngetReader(mitk::IFileReader* reader); void UngetReaders(const std::vector& readers); private: // purposely not implemented FileReaderRegistry(const FileReaderRegistry&); FileReaderRegistry& operator=(const FileReaderRegistry&); std::map > m_ServiceObjects; }; } // namespace mitk #endif /* FileReaderRegistry_H_HEADER_INCLUDED_C1E7E521 */ diff --git a/Core/Code/IO/mitkFileReaderSelector.cpp b/Core/Code/IO/mitkFileReaderSelector.cpp new file mode 100644 index 0000000000..2f66010ea4 --- /dev/null +++ b/Core/Code/IO/mitkFileReaderSelector.cpp @@ -0,0 +1,265 @@ +/*=================================================================== + +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 "mitkFileReaderSelector.h" + +#include +#include +#include + +#include +#include +#include + +namespace mitk { + +struct FileReaderSelector::Impl : us::SharedData +{ + Impl() + : m_BestId(-1) + , m_SelectedId(m_BestId) + {} + + Impl(const Impl& other) + : us::SharedData(other) + , m_BestId(-1) + , m_SelectedId(m_BestId) + {} + + FileReaderRegistry m_ReaderRegistry; + std::map m_Items; + std::vector m_MimeTypes; + long m_BestId; + long m_SelectedId; +}; + +FileReaderSelector::FileReaderSelector(const FileReaderSelector& other) + : m_Data(other.m_Data) +{ +} + +FileReaderSelector::FileReaderSelector(const std::string& path) + : m_Data(new Impl) +{ + mitk::CoreServicePointer mimeTypeProvider(mitk::CoreServices::GetMimeTypeProvider()); + + // Get all mime types and associated readers for the given file path + + m_Data->m_MimeTypes = mimeTypeProvider->GetMimeTypesForFile(path); + if (m_Data->m_MimeTypes.empty()) return; + + for (std::vector::const_iterator mimeTypeIter = m_Data->m_MimeTypes.begin(), + mimeTypeIterEnd = m_Data->m_MimeTypes.end(); mimeTypeIter != mimeTypeIterEnd; ++mimeTypeIter) + { + std::vector refs = m_Data->m_ReaderRegistry.GetReferences(*mimeTypeIter); + for (std::vector::const_iterator readerIter = refs.begin(), + iterEnd = refs.end(); readerIter != iterEnd; ++readerIter) + { + IFileReader* reader = m_Data->m_ReaderRegistry.GetReader(*readerIter); + if (reader == NULL) continue; + try + { + std::cout << "*** Checking confidence level of " << typeid(*reader).name() << " ... "; + IFileReader::ConfidenceLevel confidenceLevel = reader->GetConfidenceLevel(path); + std::cout << confidenceLevel << std::endl; + if (confidenceLevel == IFileReader::Unsupported) + { + continue; + } + + Item item; + item.m_FileReaderRef = *readerIter; + item.m_FileReader = reader; + item.m_ConfidenceLevel = confidenceLevel; + item.m_MimeType = *mimeTypeIter; + item.m_Id = us::any_cast(readerIter->GetProperty(us::ServiceConstants::SERVICE_ID())); + m_Data->m_Items.insert(std::make_pair(item.m_Id, item)); + //m_Data->m_MimeTypes.insert(mimeType); + } + catch (const us::BadAnyCastException& e) + { + MITK_WARN << "Unexpected: " << e.what(); + } + catch (const std::exception& e) + { + // Log the error but continue + MITK_WARN << "IFileWriter::GetConfidenceLevel exception: " << e.what(); + } + } + } + + // get the "best" reader + + if (!m_Data->m_Items.empty()) + { + std::set sortedItems; + for (std::map::const_iterator iter = m_Data->m_Items.begin(), + iterEnd = m_Data->m_Items.end(); iter != iterEnd; ++iter) + { + sortedItems.insert(iter->second); + } + m_Data->m_BestId = sortedItems.rbegin()->GetServiceId(); + m_Data->m_SelectedId = m_Data->m_BestId; + } +} + +FileReaderSelector::~FileReaderSelector() +{ +} + +FileReaderSelector& FileReaderSelector::operator=(const FileReaderSelector& other) +{ + m_Data = other.m_Data; + return *this; +} + +std::vector FileReaderSelector::GetMimeTypes() const +{ + return m_Data->m_MimeTypes; +} + +std::vector FileReaderSelector::Get() const +{ + std::vector result; + for (std::map::const_iterator iter = m_Data->m_Items.begin(), + iterEnd = m_Data->m_Items.end(); iter != iterEnd; ++iter) + { + result.push_back(iter->second); + } + std::sort(result.begin(), result.end()); + return result; +} + +FileReaderSelector::Item FileReaderSelector::Get(long id) const +{ + std::map::const_iterator iter = m_Data->m_Items.find(id); + if (iter != m_Data->m_Items.end()) + { + return iter->second; + } + return Item(); +} + +FileReaderSelector::Item FileReaderSelector::GetDefault() const +{ + return Get(m_Data->m_BestId); +} + +long FileReaderSelector::GetDefaultId() const +{ + return m_Data->m_BestId; +} + +FileReaderSelector::Item FileReaderSelector::GetSelected() const +{ + return Get(m_Data->m_SelectedId); +} + +long FileReaderSelector::GetSelectedId() const +{ + return m_Data->m_SelectedId; +} + +bool FileReaderSelector::Select(const FileReaderSelector::Item& item) +{ + return Select(item.m_Id); +} + +bool FileReaderSelector::Select(long id) +{ + if (id > -1) + { + if (m_Data->m_Items.find(id) == m_Data->m_Items.end()) + { + return false; + } + m_Data->m_SelectedId = id; + return true; + } + return false; +} + +void FileReaderSelector::Swap(FileReaderSelector& fws) +{ + m_Data.Swap(fws.m_Data); +} + +IFileReader* FileReaderSelector::Item::GetReader() const +{ + return m_FileReader; +} + +std::string FileReaderSelector::Item::GetDescription() const +{ + us::Any descr = m_FileReaderRef.GetProperty(IFileReader::PROP_DESCRIPTION()); + if (descr.Empty()) return std::string(); + return descr.ToString(); +} + +IFileReader::ConfidenceLevel FileReaderSelector::Item::GetConfidenceLevel() const +{ + return m_ConfidenceLevel; +} + +MimeType FileReaderSelector::Item::GetMimeType() const +{ + return m_MimeType; +} + +us::ServiceReference FileReaderSelector::Item::GetReference() const +{ + return m_FileReaderRef; +} + +long FileReaderSelector::Item::GetServiceId() const +{ + return m_Id; +} + +bool FileReaderSelector::Item::operator<(const FileReaderSelector::Item& other) const +{ + // sort by confidence level first (ascending) + if (m_ConfidenceLevel == other.m_ConfidenceLevel) + { + // sort by mime-type ranking + if (m_MimeType < other.m_MimeType) + { + return true; + } + else if (other.m_MimeType < m_MimeType) + { + return false; + } + else + { + // sort by file writer service ranking + return m_FileReaderRef < other.m_FileReaderRef; + } + } + return m_ConfidenceLevel < other.m_ConfidenceLevel; +} + +FileReaderSelector::Item::Item() + : m_FileReader(NULL) + , m_Id(-1) +{} + +void swap(FileReaderSelector& frs1, FileReaderSelector& frs2) +{ + frs1.Swap(frs2); +} + +} diff --git a/Core/Code/IO/mitkFileReaderSelector.h b/Core/Code/IO/mitkFileReaderSelector.h new file mode 100644 index 0000000000..ea8d38c0bc --- /dev/null +++ b/Core/Code/IO/mitkFileReaderSelector.h @@ -0,0 +1,111 @@ +/*=================================================================== + +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 MITKFILEREADERSELECTOR_H +#define MITKFILEREADERSELECTOR_H + +#include + +#include + +#include + +#include +#include + +namespace mitk { + +class BaseData; + +class MITK_CORE_EXPORT FileReaderSelector +{ +public: + + class Item + { + public: + + IFileReader* GetReader() const; + std::string GetDescription() const; + IFileReader::ConfidenceLevel GetConfidenceLevel() const; + MimeType GetMimeType() const; + us::ServiceReference GetReference() const; + long GetServiceId() const; + + bool operator<(const Item& other) const; + + private: + + friend class FileReaderSelector; + + Item(); + + us::ServiceReference m_FileReaderRef; + IFileReader* m_FileReader; + IFileReader::ConfidenceLevel m_ConfidenceLevel; + MimeType m_MimeType; + long m_Id; + }; + + FileReaderSelector(const FileReaderSelector& other); + FileReaderSelector(const std::string& path); + + ~FileReaderSelector(); + + FileReaderSelector& operator=(const FileReaderSelector& other); + + std::vector GetMimeTypes() const; + + /** + * @brief Get a sorted list of file reader items. + * + *
    + *
  1. Confidence level (ascending)
  2. + *
  3. MimeType ordering (ascending)
  4. + *
  5. File Reader service ranking (ascending)
  6. + *
+ * + * This means the best matching item is at the back of the returned + * container. + * + * @return + */ + std::vector Get() const; + + Item Get(long id) const; + + Item GetDefault() const; + long GetDefaultId() const; + + Item GetSelected() const; + long GetSelectedId() const; + + bool Select(const Item& item); + bool Select(long id); + + void Swap(FileReaderSelector& fws); + +private: + + struct Impl; + us::ExplicitlySharedDataPointer m_Data; +}; + +void swap(FileReaderSelector& fws1, FileReaderSelector& fws2); + +} + +#endif // MITKFILEREADERSELECTOR_H diff --git a/Core/Code/IO/mitkFileWriterRegistry.cpp b/Core/Code/IO/mitkFileWriterRegistry.cpp index 306f853730..f52915ee60 100644 --- a/Core/Code/IO/mitkFileWriterRegistry.cpp +++ b/Core/Code/IO/mitkFileWriterRegistry.cpp @@ -1,211 +1,144 @@ /*=================================================================== 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 "mitkFileWriterRegistry.h" // MITK #include "mitkIMimeTypeProvider.h" #include "mitkCoreServices.h" #include "mitkBaseData.h" // Microservices #include #include #include #include mitk::FileWriterRegistry::FileWriterRegistry() { } mitk::FileWriterRegistry::~FileWriterRegistry() { for (std::map >::iterator iter = m_ServiceObjects.begin(), end = m_ServiceObjects.end(); iter != end; ++iter) { iter->second.UngetService(iter->first); } } -std::pair mitk::FileWriterRegistry::GetDefaultExtension(const mitk::FileWriterRegistry::WriterReference& ref, us::ModuleContext* context) -{ - if (!ref) return std::make_pair(std::string(), std::string()); - - std::string mimeType = ref.GetProperty(IFileWriter::PROP_MIMETYPE()).ToString(); - - CoreServicePointer mimeTypeProvider(CoreServices::GetMimeTypeProvider(context)); - std::vector extensions = mimeTypeProvider->GetExtensions(mimeType); - if (extensions.empty()) return std::make_pair(std::string(), std::string()); - return std::make_pair(extensions.front(), mimeType); -} - -std::pair mitk::FileWriterRegistry::GetDefaultExtension(const mitk::BaseData* data, us::ModuleContext* context) -{ - return GetDefaultExtension(GetReference(data, context)); -} - mitk::FileWriterRegistry::WriterReference mitk::FileWriterRegistry::GetReference(const mitk::BaseData* baseData, us::ModuleContext* context) { - return GetReference(baseData->GetNameOfClass(), context); + return GetReference(baseData, std::string(), context); } mitk::FileWriterRegistry::WriterReference mitk::FileWriterRegistry::GetReference(const mitk::BaseData* baseData, const std::string& mimeType, us::ModuleContext* context) { - return GetReference(baseData->GetNameOfClass(), mimeType, context); -} - -mitk::FileWriterRegistry::WriterReference mitk::FileWriterRegistry::GetReference(const std::string& baseDataType, us::ModuleContext* context) -{ - std::vector refs = GetReferences(baseDataType, context); + std::vector refs = GetReferences(baseData, mimeType, context); if (refs.empty()) return WriterReference(); - std::sort(refs.begin(), refs.end()); - return refs.back(); -} -mitk::FileWriterRegistry::WriterReference mitk::FileWriterRegistry::GetReference(const std::string& baseDataType, const std::string& mimeType, us::ModuleContext* context) -{ - std::vector refs = GetReferences(baseDataType, mimeType, context); - if (refs.empty()) return WriterReference(); std::sort(refs.begin(), refs.end()); - return refs.back(); + return refs.back(); } std::vector mitk::FileWriterRegistry::GetReferences(const mitk::BaseData* baseData, us::ModuleContext* context) { - return GetReferences(baseData->GetNameOfClass(), context); + return GetReferences(baseData, std::string(), context); } std::vector mitk::FileWriterRegistry::GetReferences(const mitk::BaseData* baseData, const std::string& mimeType, us::ModuleContext* context) -{ - return GetReferences(baseData->GetNameOfClass(), mimeType, context); -} - -std::vector mitk::FileWriterRegistry::GetReferences(const std::string& baseDataType, us::ModuleContext* context) -{ - return GetReferences(baseDataType, std::string(), context); -} - -std::vector mitk::FileWriterRegistry::GetReferences(const std::string& baseDataType, const std::string& mimeType, us::ModuleContext* context) { std::string filter = us::LDAPProp(us::ServiceConstants::OBJECTCLASS()) == us_service_interface_iid() && - us::LDAPProp(IFileWriter::PROP_BASEDATA_TYPE()) == baseDataType && + us::LDAPProp(IFileWriter::PROP_BASEDATA_TYPE()) == baseData->GetNameOfClass() && (mimeType.empty() ? us::LDAPPropExpr(std::string()) : us::LDAPProp(IFileWriter::PROP_MIMETYPE()) == mimeType); return context->GetServiceReferences(filter); } -mitk::IFileWriter*mitk::FileWriterRegistry::GetWriter(const mitk::FileWriterRegistry::WriterReference& ref, us::ModuleContext* context) +mitk::IFileWriter* mitk::FileWriterRegistry::GetWriter(const mitk::FileWriterRegistry::WriterReference& ref, us::ModuleContext* context) { + if (!ref) return NULL; + us::ServiceObjects serviceObjects = context->GetServiceObjects(ref); mitk::IFileWriter* writer = serviceObjects.GetService(); m_ServiceObjects.insert(std::make_pair(writer, serviceObjects)); return writer; } -mitk::IFileWriter*mitk::FileWriterRegistry::GetWriter(const std::string& baseDataType, us::ModuleContext* context) -{ - std::vector result = GetWriters(baseDataType, context); - if (result.empty()) - { - return NULL; - } - return result.front(); -} - -mitk::IFileWriter*mitk::FileWriterRegistry::GetWriter(const std::string& baseDataType, const std::string& mimeType, us::ModuleContext* context) -{ - std::vector result = GetWriters(baseDataType, mimeType, context); - if (result.empty()) - { - return NULL; - } - return result.front(); -} - -mitk::IFileWriter*mitk::FileWriterRegistry::GetWriter(const mitk::BaseData* baseData, us::ModuleContext* context) +mitk::IFileWriter* mitk::FileWriterRegistry::GetWriter(const mitk::BaseData* baseData, us::ModuleContext* context) { - return GetWriter(baseData->GetNameOfClass(), context); + return GetWriter(GetReference(baseData, context), context); } -mitk::IFileWriter*mitk::FileWriterRegistry::GetWriter(const mitk::BaseData* baseData, const std::string& mimeType, us::ModuleContext* context) +mitk::IFileWriter* mitk::FileWriterRegistry::GetWriter(const mitk::BaseData* baseData, const std::string& mimeType, us::ModuleContext* context) { - return GetWriter(baseData->GetNameOfClass(), mimeType, context); + return GetWriter(GetReference(baseData, mimeType, context), context); } -std::vector mitk::FileWriterRegistry::GetWriters(const std::string& baseDataType, us::ModuleContext* context) +std::vector mitk::FileWriterRegistry::GetWriters(const mitk::BaseData* baseData, us::ModuleContext* context) { - return GetWriters(baseDataType, std::string(), context); + return GetWriters(baseData, std::string(), context); } -std::vector mitk::FileWriterRegistry::GetWriters(const std::string& baseDataType, const std::string& mimeType, us::ModuleContext* context) +std::vector mitk::FileWriterRegistry::GetWriters(const mitk::BaseData* baseData, const std::string& mimeType, us::ModuleContext* context) { std::vector result; std::vector > refs; if (mimeType.empty()) { - refs = GetReferences(baseDataType, context); + refs = GetReferences(baseData, context); } else { - refs = GetReferences(baseDataType, mimeType, context); + refs = GetReferences(baseData, mimeType, context); } std::sort(refs.begin(), refs.end()); result.reserve(refs.size()); // Translate List of ServiceRefs to List of Pointers for (std::vector >::const_reverse_iterator iter = refs.rbegin(), end = refs.rend(); iter != end; ++iter) { us::ServiceObjects serviceObjects = context->GetServiceObjects(*iter); mitk::IFileWriter* writer = serviceObjects.GetService(); m_ServiceObjects.insert(std::make_pair(writer, serviceObjects)); result.push_back(writer); } return result; } -std::vector mitk::FileWriterRegistry::GetWriters(const mitk::BaseData* baseData, us::ModuleContext* context) -{ - return GetWriters(baseData->GetNameOfClass(), context); -} - -std::vector mitk::FileWriterRegistry::GetWriters(const mitk::BaseData* baseData, const std::string& mimeType, us::ModuleContext* context) -{ - return GetWriters(baseData->GetNameOfClass(), mimeType, context); -} - void mitk::FileWriterRegistry::UngetWriter(mitk::IFileWriter* writer) { std::map >::iterator writerIter = m_ServiceObjects.find(writer); if (writerIter != m_ServiceObjects.end()) { writerIter->second.UngetService(writer); m_ServiceObjects.erase(writerIter); } } void mitk::FileWriterRegistry::UngetWriters(const std::vector& writers) { for (std::vector::const_iterator iter = writers.begin(), end = writers.end(); iter != end; ++iter) { this->UngetWriter(*iter); } } diff --git a/Core/Code/IO/mitkFileWriterRegistry.h b/Core/Code/IO/mitkFileWriterRegistry.h index bf6fc6375d..caebfc08c2 100644 --- a/Core/Code/IO/mitkFileWriterRegistry.h +++ b/Core/Code/IO/mitkFileWriterRegistry.h @@ -1,107 +1,82 @@ /*=================================================================== 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 FileWriterRegistry_H_HEADER_INCLUDED_C1E7E521 #define FileWriterRegistry_H_HEADER_INCLUDED_C1E7E521 #include // Microservices #include #include #include #include "mitkIFileWriter.h" namespace mitk { class BaseData; } namespace mitk { /** - * @ingroup Process + * @ingroup IO * * Provides convenient access to mitk::IFileWriter instances and writing * files from mitk::BaseData types. * * \note The life-time of all mitk::IFileWriter objects returned by an * instance of this class ends with the destruction of that instance. */ class MITK_CORE_EXPORT FileWriterRegistry { public: typedef us::ServiceReference WriterReference; FileWriterRegistry(); ~FileWriterRegistry(); - /** - * @brief Get the default file name extension for writing. - * - * The default extension is computed by retrieving the highest ranked - * mitk::IMimeType instance for the given mitk::IFileWriter reference - * and using the first extension from the mime types extension list. - * - * @param ref The IFileWriter service reference - * @param context The us::ModuleContext to look up IMimeType services - * @return The default extension without a leading period for the given - * \c ref. Returns an empty string if there is no registered - * mime type with this file writer reference. - */ - static std::pair GetDefaultExtension(const WriterReference& ref, us::ModuleContext* context = us::GetModuleContext()); - - static std::pair GetDefaultExtension(const BaseData* data, us::ModuleContext* context = us::GetModuleContext()); - static WriterReference GetReference(const BaseData* baseData, us::ModuleContext* context = us::GetModuleContext()); static WriterReference GetReference(const BaseData* baseData, const std::string& mimeType, us::ModuleContext* context = us::GetModuleContext()); - static WriterReference GetReference(const std::string& baseDataType, us::ModuleContext* context = us::GetModuleContext()); - static WriterReference GetReference(const std::string& baseDataType, const std::string& mimeType, us::ModuleContext* context = us::GetModuleContext()); static std::vector GetReferences(const BaseData* baseData, us::ModuleContext* context = us::GetModuleContext()); static std::vector GetReferences(const BaseData* baseData, const std::string& mimeType, us::ModuleContext* context = us::GetModuleContext()); - static std::vector GetReferences(const std::string& baseDataType, us::ModuleContext* context = us::GetModuleContext()); - static std::vector GetReferences(const std::string& baseDataType, const std::string& mimeType, us::ModuleContext* context = us::GetModuleContext()); IFileWriter* GetWriter(const WriterReference& ref, us::ModuleContext* context = us::GetModuleContext()); - IFileWriter* GetWriter(const std::string& baseDataType, us::ModuleContext* context = us::GetModuleContext()); - IFileWriter* GetWriter(const std::string& baseDataType, const std::string& mimeType, us::ModuleContext* context = us::GetModuleContext()); IFileWriter* GetWriter(const BaseData* baseData, us::ModuleContext* context = us::GetModuleContext()); IFileWriter* GetWriter(const BaseData* baseData, const std::string& mimeType, us::ModuleContext* context = us::GetModuleContext()); - std::vector GetWriters(const std::string& baseDataType, us::ModuleContext* context = us::GetModuleContext()); - std::vector GetWriters(const std::string& baseDataType, const std::string& mimeType, us::ModuleContext* context = us::GetModuleContext()); std::vector GetWriters(const BaseData* baseData, us::ModuleContext* context = us::GetModuleContext()); std::vector GetWriters(const BaseData* baseData, const std::string& mimeType, us::ModuleContext* context = us::GetModuleContext()); void UngetWriter(IFileWriter* writer); void UngetWriters(const std::vector& writers); private: // purposely not implemented FileWriterRegistry(const FileWriterRegistry&); FileWriterRegistry& operator=(const FileWriterRegistry&); std::map > m_ServiceObjects; }; } // namespace mitk #endif /* FileWriterRegistry_H_HEADER_INCLUDED_C1E7E521 */ diff --git a/Core/Code/IO/mitkFileWriterSelector.cpp b/Core/Code/IO/mitkFileWriterSelector.cpp new file mode 100644 index 0000000000..daf039eac1 --- /dev/null +++ b/Core/Code/IO/mitkFileWriterSelector.cpp @@ -0,0 +1,275 @@ +/*=================================================================== + +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 "mitkFileWriterSelector.h" + +#include +#include +#include + +#include +#include +#include + +namespace mitk { + +struct FileWriterSelector::Impl : us::SharedData +{ + Impl() + : m_BestId(-1) + , m_SelectedId(m_BestId) + {} + + Impl(const Impl& other) + : us::SharedData(other) + , m_BestId(-1) + , m_SelectedId(m_BestId) + {} + + FileWriterRegistry m_WriterRegistry; + std::map m_Items; + std::set m_MimeTypes; + long m_BestId; + long m_SelectedId; +}; + +FileWriterSelector::FileWriterSelector(const FileWriterSelector& other) + : m_Data(other.m_Data) +{ +} + +FileWriterSelector::FileWriterSelector(const BaseData* baseData, const std::string& destMimeType) + : m_Data(new Impl) +{ + mitk::CoreServicePointer mimeTypeProvider(mitk::CoreServices::GetMimeTypeProvider()); + + // Get all writers and their mime types for the given base data type + std::vector refs = m_Data->m_WriterRegistry.GetReferences(baseData, destMimeType); + us::ServiceReference bestRef; + for (std::vector::const_iterator iter = refs.begin(), + iterEnd = refs.end(); iter != iterEnd; ++iter) + { + std::string mimeTypeName = iter->GetProperty(IFileWriter::PROP_MIMETYPE()).ToString(); + if (!mimeTypeName.empty()) + { + MimeType mimeType = mimeTypeProvider->GetMimeTypeForName(mimeTypeName); + if (mimeType.IsValid()) + { + // There is a registered mime-type for this writer. Now get the confidence level + // of this writer for writing the given base data object. + + IFileWriter* writer = m_Data->m_WriterRegistry.GetWriter(*iter); + if (writer == NULL) continue; + try + { + std::cout << "*** Checking confidence level of " << typeid(*writer).name() << " ... "; + IFileWriter::ConfidenceLevel confidenceLevel = writer->GetConfidenceLevel(baseData); + std::cout << confidenceLevel << std::endl; + if (confidenceLevel == IFileWriter::Unsupported) + { + continue; + } + + Item item; + item.m_FileWriterRef = *iter; + item.m_FileWriter = writer; + item.m_ConfidenceLevel = confidenceLevel; + item.m_MimeType = mimeType; + item.m_Id = us::any_cast(iter->GetProperty(us::ServiceConstants::SERVICE_ID())); + m_Data->m_Items.insert(std::make_pair(item.m_Id, item)); + m_Data->m_MimeTypes.insert(mimeType); + if (!bestRef || bestRef < *iter) + { + bestRef = *iter; + } + } + catch (const us::BadAnyCastException& e) + { + MITK_WARN << "Unexpected: " << e.what(); + } + + catch (const std::exception& e) + { + // Log the error but continue + MITK_WARN << "IFileWriter::GetConfidenceLevel exception: " << e.what(); + } + } + } + } + + if (bestRef) + { + try + { + m_Data->m_BestId = us::any_cast(bestRef.GetProperty(us::ServiceConstants::SERVICE_ID())); + m_Data->m_SelectedId = m_Data->m_BestId; + } catch (const us::BadAnyCastException&) {} + } +} + +FileWriterSelector::~FileWriterSelector() +{ +} + +FileWriterSelector& FileWriterSelector::operator=(const FileWriterSelector& other) +{ + m_Data = other.m_Data; + return *this; +} + +std::vector FileWriterSelector::Get(const std::string& mimeType) const +{ + std::vector result; + for (std::map::const_iterator iter = m_Data->m_Items.begin(), + iterEnd = m_Data->m_Items.end(); iter != iterEnd; ++iter) + { + if (mimeType.empty() || iter->second.GetMimeType().GetName() == mimeType) + { + result.push_back(iter->second); + } + } + std::sort(result.begin(), result.end()); + return result; +} + +std::vector FileWriterSelector::Get() const +{ + return Get(this->GetSelected().m_MimeType.GetName()); +} + +FileWriterSelector::Item FileWriterSelector::Get(long id) const +{ + std::map::const_iterator iter = m_Data->m_Items.find(id); + if (iter != m_Data->m_Items.end()) + { + return iter->second; + } + return Item(); +} + +FileWriterSelector::Item FileWriterSelector::GetDefault() const +{ + return Get(m_Data->m_BestId); +} + +long FileWriterSelector::GetDefaultId() const +{ + return m_Data->m_BestId; +} + +FileWriterSelector::Item FileWriterSelector::GetSelected() const +{ + return Get(m_Data->m_SelectedId); +} + +long FileWriterSelector::GetSelectedId() const +{ + return m_Data->m_SelectedId; +} + +bool FileWriterSelector::Select(const std::string& mimeType) +{ + std::vector items = Get(mimeType); + if (items.empty()) return false; + return Select(items.back()); +} + +bool FileWriterSelector::Select(const FileWriterSelector::Item& item) +{ + return Select(item.m_Id); +} + +bool FileWriterSelector::Select(long id) +{ + if (id > -1) + { + if (m_Data->m_Items.find(id) == m_Data->m_Items.end()) + { + return false; + } + m_Data->m_SelectedId = id; + return true; + } + return false; +} + +std::vector FileWriterSelector::GetMimeTypes() const +{ + std::vector result; + result.reserve(m_Data->m_MimeTypes.size()); + result.assign(m_Data->m_MimeTypes.begin(), m_Data->m_MimeTypes.end()); + return result; +} + +void FileWriterSelector::Swap(FileWriterSelector& fws) +{ + m_Data.Swap(fws.m_Data); +} + +IFileWriter* FileWriterSelector::Item::GetWriter() const +{ + return m_FileWriter; +} + +std::string FileWriterSelector::Item::GetDescription() const +{ + us::Any descr = m_FileWriterRef.GetProperty(IFileWriter::PROP_DESCRIPTION()); + if (descr.Empty()) return std::string(); + return descr.ToString(); +} + +IFileWriter::ConfidenceLevel FileWriterSelector::Item::GetConfidenceLevel() const +{ + return m_ConfidenceLevel; +} + +MimeType FileWriterSelector::Item::GetMimeType() const +{ + return m_MimeType; +} + +us::ServiceReference FileWriterSelector::Item::GetReference() const +{ + return m_FileWriterRef; +} + +long FileWriterSelector::Item::GetServiceId() const +{ + return m_Id; +} + +bool FileWriterSelector::Item::operator<(const FileWriterSelector::Item& other) const +{ + // sort by confidence level first (ascending) + if (m_ConfidenceLevel == other.m_ConfidenceLevel) + { + // sort by file writer service ranking + return m_FileWriterRef < other.m_FileWriterRef; + } + return m_ConfidenceLevel < other.m_ConfidenceLevel; +} + +FileWriterSelector::Item::Item() + : m_FileWriter(NULL) + , m_Id(-1) +{} + +void swap(FileWriterSelector& fws1, FileWriterSelector& fws2) +{ + fws1.Swap(fws2); +} + +} diff --git a/Core/Code/IO/mitkFileWriterSelector.h b/Core/Code/IO/mitkFileWriterSelector.h new file mode 100644 index 0000000000..2295ee5849 --- /dev/null +++ b/Core/Code/IO/mitkFileWriterSelector.h @@ -0,0 +1,122 @@ +/*=================================================================== + +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 MITKFILEWRITERSELECTOR_H +#define MITKFILEWRITERSELECTOR_H + +#include + +#include + +#include + +#include +#include + +namespace mitk { + +class BaseData; + +class MITK_CORE_EXPORT FileWriterSelector +{ +public: + + class Item + { + public: + + IFileWriter* GetWriter() const; + std::string GetDescription() const; + IFileWriter::ConfidenceLevel GetConfidenceLevel() const; + MimeType GetMimeType() const; + us::ServiceReference GetReference() const; + long GetServiceId() const; + + bool operator<(const Item& other) const; + + private: + + friend class FileWriterSelector; + + Item(); + + us::ServiceReference m_FileWriterRef; + IFileWriter* m_FileWriter; + IFileWriter::ConfidenceLevel m_ConfidenceLevel; + MimeType m_MimeType; + long m_Id; + }; + + FileWriterSelector(const FileWriterSelector& other); + FileWriterSelector(const BaseData* baseData, const std::string& destMimeType = std::string()); + + ~FileWriterSelector(); + + FileWriterSelector& operator=(const FileWriterSelector& other); + + /** + * @brief Get a sorted list of file writer info objects. + * + *
    + *
  1. Confidence level (ascending)
  2. + *
  3. File Writer service ranking (ascending)
  4. + *
+ * + * This means the best matching item is at the back of the returned + * container. + * + * @param mimeType + * @return + */ + std::vector Get(const std::string& mimeType) const; + + /** + * @brief Get a sorted list of file writer info objects. + * + * The returned objects will have the same mime-type as the currently + * selected item. + * + * @return Ordered list of file writer items. + */ + std::vector Get() const; + + Item Get(long id) const; + + Item GetDefault() const; + long GetDefaultId() const; + + Item GetSelected() const; + long GetSelectedId() const; + + bool Select(const std::string& mimeType); + bool Select(const Item& item); + bool Select(long id); + + std::vector GetMimeTypes() const; + + void Swap(FileWriterSelector& fws); + +private: + + struct Impl; + us::ExplicitlySharedDataPointer m_Data; +}; + +void swap(FileWriterSelector& fws1, FileWriterSelector& fws2); + +} + +#endif // MITKFILEWRITERSELECTOR_H diff --git a/Core/Code/IO/mitkIOUtil.cpp b/Core/Code/IO/mitkIOUtil.cpp index 8ba3832c78..bb242a74d1 100644 --- a/Core/Code/IO/mitkIOUtil.cpp +++ b/Core/Code/IO/mitkIOUtil.cpp @@ -1,1160 +1,1095 @@ /*=================================================================== 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 "mitkIOUtil.h" #include #include +#include #include #include #include #include #include #include #include #include #include //ITK #include //VTK #include #include #include #include #include static std::string GetLastErrorStr() { #ifdef US_PLATFORM_POSIX return std::string(strerror(errno)); #else // Retrieve the system error message for the last-error code LPVOID lpMsgBuf; DWORD dw = GetLastError(); FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL ); std::string errMsg((LPCTSTR)lpMsgBuf); LocalFree(lpMsgBuf); return errMsg; #endif } #ifdef US_PLATFORM_WINDOWS #include #include // make the posix flags point to the obsolte bsd types on windows #define S_IRUSR S_IREAD #define S_IWUSR S_IWRITE #else #include #include #include #endif #include #include static const char validLetters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; // A cross-platform version of the mkstemps function static int mkstemps_compat(char* tmpl, int suffixlen) { static unsigned long long value = 0; int savedErrno = errno; // Lower bound on the number of temporary files to attempt to generate. #define ATTEMPTS_MIN (62 * 62 * 62) /* The number of times to attempt to generate a temporary file. To conform to POSIX, this must be no smaller than TMP_MAX. */ #if ATTEMPTS_MIN < TMP_MAX const unsigned int attempts = TMP_MAX; #else const unsigned int attempts = ATTEMPTS_MIN; #endif const int len = strlen(tmpl); if ((len - suffixlen) < 6 || strncmp(&tmpl[len - 6 - suffixlen], "XXXXXX", 6)) { errno = EINVAL; return -1; } /* This is where the Xs start. */ char* XXXXXX = &tmpl[len - 6 - suffixlen]; /* Get some more or less random data. */ #ifdef US_PLATFORM_WINDOWS { SYSTEMTIME stNow; FILETIME ftNow; // get system time GetSystemTime(&stNow); stNow.wMilliseconds = 500; if (!SystemTimeToFileTime(&stNow, &ftNow)) { errno = -1; return -1; } unsigned long long randomTimeBits = ((static_cast(ftNow.dwHighDateTime) << 32) | static_cast(ftNow.dwLowDateTime)); value = randomTimeBits ^ static_cast(GetCurrentThreadId()); } #else { struct timeval tv; gettimeofday(&tv, NULL); unsigned long long randomTimeBits = ((static_cast(tv.tv_usec) << 32) | static_cast(tv.tv_sec)); value = randomTimeBits ^ static_cast(getpid()); } #endif for (unsigned int count = 0; count < attempts; value += 7777, ++count) { unsigned long long v = value; /* Fill in the random bits. */ XXXXXX[0] = validLetters[v % 62]; v /= 62; XXXXXX[1] = validLetters[v % 62]; v /= 62; XXXXXX[2] = validLetters[v % 62]; v /= 62; XXXXXX[3] = validLetters[v % 62]; v /= 62; XXXXXX[4] = validLetters[v % 62]; v /= 62; XXXXXX[5] = validLetters[v % 62]; int fd = open (tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); if (fd >= 0) { errno = savedErrno; return fd; } else if (errno != EEXIST) { return -1; } } /* We got out of the loop because we ran out of combinations to try. */ errno = EEXIST; return -1; } // A cross-platform version of the POSIX mkdtemp function static char* mkdtemps_compat(char* tmpl, int suffixlen) { static unsigned long long value = 0; int savedErrno = errno; // Lower bound on the number of temporary dirs to attempt to generate. #define ATTEMPTS_MIN (62 * 62 * 62) /* The number of times to attempt to generate a temporary dir. To conform to POSIX, this must be no smaller than TMP_MAX. */ #if ATTEMPTS_MIN < TMP_MAX const unsigned int attempts = TMP_MAX; #else const unsigned int attempts = ATTEMPTS_MIN; #endif const int len = strlen(tmpl); if ((len - suffixlen) < 6 || strncmp(&tmpl[len - 6 - suffixlen], "XXXXXX", 6)) { errno = EINVAL; return NULL; } /* This is where the Xs start. */ char* XXXXXX = &tmpl[len - 6 - suffixlen]; /* Get some more or less random data. */ #ifdef US_PLATFORM_WINDOWS { SYSTEMTIME stNow; FILETIME ftNow; // get system time GetSystemTime(&stNow); stNow.wMilliseconds = 500; if (!SystemTimeToFileTime(&stNow, &ftNow)) { errno = -1; return NULL; } unsigned long long randomTimeBits = ((static_cast(ftNow.dwHighDateTime) << 32) | static_cast(ftNow.dwLowDateTime)); value = randomTimeBits ^ static_cast(GetCurrentThreadId()); } #else { struct timeval tv; gettimeofday(&tv, NULL); unsigned long long randomTimeBits = ((static_cast(tv.tv_usec) << 32) | static_cast(tv.tv_sec)); value = randomTimeBits ^ static_cast(getpid()); } #endif unsigned int count = 0; for (; count < attempts; value += 7777, ++count) { unsigned long long v = value; /* Fill in the random bits. */ XXXXXX[0] = validLetters[v % 62]; v /= 62; XXXXXX[1] = validLetters[v % 62]; v /= 62; XXXXXX[2] = validLetters[v % 62]; v /= 62; XXXXXX[3] = validLetters[v % 62]; v /= 62; XXXXXX[4] = validLetters[v % 62]; v /= 62; XXXXXX[5] = validLetters[v % 62]; #ifdef US_PLATFORM_WINDOWS int fd = _mkdir (tmpl); //, _S_IREAD | _S_IWRITE | _S_IEXEC); #else int fd = mkdir (tmpl, S_IRUSR | S_IWUSR | S_IXUSR); #endif if (fd >= 0) { errno = savedErrno; return tmpl; } else if (errno != EEXIST) { return NULL; } } /* We got out of the loop because we ran out of combinations to try. */ errno = EEXIST; return NULL; } //#endif // ***************************************************************** // Utility code US_HASH_FUNCTION_NAMESPACE_BEGIN US_HASH_FUNCTION_BEGIN(std::vector) std::string imploded; imploded.reserve(256); for(std::vector::const_iterator iter = arg.begin(), iterEnd = arg.end(); iter != iterEnd; ++iter) { imploded += *iter; } return US_HASH_FUNCTION(std::string, imploded); US_HASH_FUNCTION_END US_HASH_FUNCTION_NAMESPACE_END -namespace { - -class FileSorter -{ - -public: - - typedef std::vector MimeTypeVector; - typedef std::vector FileVector; - - FileSorter() - {} - -private: - - FileSorter(const FileSorter&); - FileSorter& operator=(const FileSorter&); - - typedef US_UNORDERED_MAP_TYPE HashMapType; - - HashMapType m_MimeTypesToFiles; - -public: - - typedef HashMapType::const_iterator Iterator; - - void AddFile(const std::string& file, const std::string& mimeType) - { - MimeTypeVector mimeTypes; - mimeTypes.push_back(mimeType); - m_MimeTypesToFiles[mimeTypes].push_back(file); - } - - void AddFile(const std::string& file, const MimeTypeVector& mimeTypes) - { - m_MimeTypesToFiles[mimeTypes].push_back(file); - } - - Iterator Begin() const - { - return m_MimeTypesToFiles.begin(); - } - - Iterator End() const - { - return m_MimeTypesToFiles.end(); - } - -}; - -class SaveInfoSorter -{ -public: - - typedef std::vector SaveInfoVector; - -private: - - typedef US_UNORDERED_MAP_TYPE HashMapType; - - HashMapType m_SaveInfoMap; - -public: - - typedef HashMapType::const_iterator Iterator; - - void AddSaveInfo(const mitk::IOUtil::SaveInfo& info) - { - std::string key = std::string(info.m_BaseData->GetNameOfClass()) + "+" + info.m_MimeType; - m_SaveInfoMap[key].push_back(info); - } - - Iterator Begin() const - { - return m_SaveInfoMap.begin(); - } - - Iterator End() const - { - return m_SaveInfoMap.end(); - } -}; - -} //************************************************************** // mitk::IOUtil method definitions namespace mitk { const std::string IOUtil::DEFAULTIMAGEEXTENSION = ".nrrd"; const std::string IOUtil::DEFAULTSURFACEEXTENSION = ".stl"; const std::string IOUtil::DEFAULTPOINTSETEXTENSION = ".mps"; struct IOUtil::Impl { struct FixedReaderOptionsFunctor : public ReaderOptionsFunctorBase { FixedReaderOptionsFunctor(const IFileReader::Options& options) : m_Options(options) {} - virtual bool operator()(const std::string& /*path*/, const std::vector& /*readerLabels*/, - const std::vector& readers, IFileReader*& selectedReader) + virtual bool operator()(LoadInfo& loadInfo) { - selectedReader = readers.front(); - selectedReader->SetOptions(m_Options); + IFileReader* reader = loadInfo.m_ReaderSelector.GetSelected().GetReader(); + if (reader) + { + reader->SetOptions(m_Options); + } return false; } private: const IFileReader::Options& m_Options; }; struct FixedWriterOptionsFunctor : public WriterOptionsFunctorBase { FixedWriterOptionsFunctor(const IFileReader::Options& options) : m_Options(options) {} - virtual bool operator()(const std::string& /*path*/, const std::vector& /*writerLabels*/, - const std::vector& writers, IFileWriter*& selectedWriter) + virtual bool operator()(SaveInfo& saveInfo) { - selectedWriter = writers.front(); - selectedWriter->SetOptions(m_Options); + IFileWriter* writer = saveInfo.m_WriterSelector.GetSelected().GetWriter(); + if (writer) + { + writer->SetOptions(m_Options); + } return false; } private: const IFileWriter::Options& m_Options; }; static BaseData::Pointer LoadBaseDataFromFile(const std::string& path); static void SetDefaultDataNodeProperties(mitk::DataNode* node, const std::string& filePath = std::string()); }; #ifdef US_PLATFORM_WINDOWS std::string IOUtil::GetProgramPath() { char path[512]; std::size_t index = std::string(path, GetModuleFileName(NULL, path, 512)).find_last_of('\\'); return std::string(path, index); } #elif defined(US_PLATFORM_APPLE) #include std::string IOUtil::GetProgramPath() { char path[512]; uint32_t size = sizeof(path); if (_NSGetExecutablePath(path, &size) == 0) { std::size_t index = std::string(path).find_last_of('/'); std::string strPath = std::string(path, index); //const char* execPath = strPath.c_str(); //mitk::StandardFileLocations::GetInstance()->AddDirectoryForSearch(execPath,false); return strPath; } return std::string(); } #else #include #include #include std::string IOUtil::GetProgramPath() { std::stringstream ss; ss << "/proc/" << getpid() << "/exe"; char proc[512] = {0}; ssize_t ch = readlink(ss.str().c_str(), proc, 512); if (ch == -1) return std::string(); std::size_t index = std::string(proc).find_last_of('/'); return std::string(proc, index); } #endif std::string IOUtil::GetTempPath() { static std::string result; if (result.empty()) { #ifdef US_PLATFORM_WINDOWS char tempPathTestBuffer[1]; DWORD bufferLength = ::GetTempPath(1, tempPathTestBuffer); if (bufferLength == 0) { mitkThrow() << GetLastErrorStr(); } std::vector tempPath(bufferLength); bufferLength = ::GetTempPath(bufferLength, &tempPath[0]); if (bufferLength == 0) { mitkThrow() << GetLastErrorStr(); } result.assign(tempPath.begin(), tempPath.begin() + static_cast(bufferLength)); #else result = "/tmp/"; #endif } return result; } std::string IOUtil::CreateTemporaryFile(const std::string& templateName, std::string path) { ofstream tmpOutputStream; std::string returnValue = CreateTemporaryFile(tmpOutputStream,templateName,path); tmpOutputStream.close(); return returnValue; } std::string IOUtil::CreateTemporaryFile(std::ofstream& f, const std::string& templateName, std::string path) { return CreateTemporaryFile(f, std::ios_base::out | std::ios_base::trunc, templateName, path); } std::string IOUtil::CreateTemporaryFile(std::ofstream& f, std::ios_base::openmode mode, const std::string& templateName, std::string path) { if (path.empty()) { path = GetTempPath(); } path += "/" + templateName; std::vector dst_path(path.begin(), path.end()); dst_path.push_back('\0'); std::size_t lastX = path.find_last_of('X'); std::size_t firstX = path.find_last_not_of('X', lastX); int firstNonX = firstX == std::string::npos ? - 1 : firstX - 1; while (lastX != std::string::npos && (lastX - firstNonX) < 6) { lastX = path.find_last_of('X', firstX); firstX = path.find_last_not_of('X', lastX); firstNonX = firstX == std::string::npos ? - 1 : firstX - 1; } std::size_t suffixlen = lastX == std::string::npos ? path.size() : path.size() - lastX - 1; int fd = mkstemps_compat(&dst_path[0], suffixlen); if(fd != -1) { path.assign(dst_path.begin(), dst_path.end() - 1); f.open(path.c_str(), mode | std::ios_base::out | std::ios_base::trunc); close(fd); } else { mitkThrow() << "Creating temporary file " << &dst_path[0] << " failed: " << GetLastErrorStr(); } return path; } std::string IOUtil::CreateTemporaryDirectory(const std::string& templateName, std::string path) { if (path.empty()) { path = GetTempPath(); } path += "/" + templateName; std::vector dst_path(path.begin(), path.end()); dst_path.push_back('\0'); std::size_t lastX = path.find_last_of('X'); std::size_t firstX = path.find_last_not_of('X', lastX); int firstNonX = firstX == std::string::npos ? - 1 : firstX - 1; while (lastX != std::string::npos && (lastX - firstNonX) < 6) { lastX = path.find_last_of('X', firstX); firstX = path.find_last_not_of('X', lastX); firstNonX = firstX == std::string::npos ? - 1 : firstX - 1; } std::size_t suffixlen = lastX == std::string::npos ? path.size() : path.size() - lastX - 1; if(mkdtemps_compat(&dst_path[0], suffixlen) == NULL) { mitkThrow() << "Creating temporary directory " << &dst_path[0] << " failed: " << GetLastErrorStr(); } path.assign(dst_path.begin(), dst_path.end() - 1); return path; } DataStorage::SetOfObjects::Pointer IOUtil::Load(const std::string& path, DataStorage& storage) { std::vector paths; paths.push_back(path); return Load(paths, storage); } DataStorage::SetOfObjects::Pointer IOUtil::Load(const std::string& path, const IFileReader::Options& options, DataStorage& storage) { - std::vector paths; - paths.push_back(path); + std::vector loadInfos; + loadInfos.push_back(LoadInfo(path)); DataStorage::SetOfObjects::Pointer nodeResult = DataStorage::SetOfObjects::New(); Impl::FixedReaderOptionsFunctor optionsCallback(options); - std::string errMsg = Load(paths, NULL, nodeResult, &storage, &optionsCallback); + std::string errMsg = Load(loadInfos, nodeResult, &storage, &optionsCallback); if (!errMsg.empty()) { mitkThrow() << errMsg; } return nodeResult; } std::vector IOUtil::Load(const std::string& path) { std::vector paths; paths.push_back(path); return Load(paths); } std::vector IOUtil::Load(const std::string& path, const IFileReader::Options& options) { - std::vector paths; - paths.push_back(path); - std::vector result; + std::vector loadInfos; + loadInfos.push_back(LoadInfo(path)); Impl::FixedReaderOptionsFunctor optionsCallback(options); - std::string errMsg = Load(paths, &result, NULL, NULL, &optionsCallback); + std::string errMsg = Load(loadInfos, NULL, NULL, &optionsCallback); if (!errMsg.empty()) { mitkThrow() << errMsg; } - return result; + return loadInfos.front().m_Output; } DataStorage::SetOfObjects::Pointer IOUtil::Load(const std::vector& paths, DataStorage& storage) { DataStorage::SetOfObjects::Pointer nodeResult = DataStorage::SetOfObjects::New(); - std::string errMsg = Load(paths, NULL, nodeResult, &storage, NULL); + std::vector loadInfos; + for (std::vector::const_iterator iter = paths.begin(), iterEnd = paths.end(); + iter != iterEnd; ++iter) + { + LoadInfo loadInfo(*iter); + loadInfos.push_back(loadInfo); + } + std::string errMsg = Load(loadInfos, nodeResult, &storage, NULL); if (!errMsg.empty()) { mitkThrow() << errMsg; } return nodeResult; } std::vector IOUtil::Load(const std::vector& paths) { std::vector result; - std::string errMsg = Load(paths, &result, NULL, NULL, NULL); + std::vector loadInfos; + for (std::vector::const_iterator iter = paths.begin(), iterEnd = paths.end(); + iter != iterEnd; ++iter) + { + LoadInfo loadInfo(*iter); + loadInfos.push_back(loadInfo); + } + std::string errMsg = Load(loadInfos, NULL, NULL, NULL); if (!errMsg.empty()) { mitkThrow() << errMsg; } + + for (std::vector::const_iterator iter = loadInfos.begin(), iterEnd = loadInfos.end(); + iter != iterEnd; ++iter) + { + result.insert(result.end(), iter->m_Output.begin(), iter->m_Output.end()); + } return result; } int IOUtil::LoadFiles(const std::vector &fileNames, DataStorage& ds) { return static_cast(Load(fileNames, ds)->Size()); } DataStorage::Pointer IOUtil::LoadFiles(const std::vector& fileNames) { mitk::StandaloneDataStorage::Pointer ds = mitk::StandaloneDataStorage::New(); Load(fileNames, *ds); return ds.GetPointer(); } BaseData::Pointer IOUtil::LoadBaseData(const std::string& path) { return Impl::LoadBaseDataFromFile(path); } BaseData::Pointer IOUtil::Impl::LoadBaseDataFromFile(const std::string& path) { std::vector baseDataList = Load(path); // The Load(path) call above should throw an exception if nothing could be loaded assert(!baseDataList.empty()); return baseDataList.front(); } DataNode::Pointer IOUtil::LoadDataNode(const std::string& path) { BaseData::Pointer baseData = Impl::LoadBaseDataFromFile(path); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(baseData); Impl::SetDefaultDataNodeProperties(node, path); return node; } Image::Pointer IOUtil::LoadImage(const std::string& path) { BaseData::Pointer baseData = Impl::LoadBaseDataFromFile(path); mitk::Image::Pointer image = dynamic_cast(baseData.GetPointer()); if(image.IsNull()) { mitkThrow() << path << " is not a mitk::Image but a " << baseData->GetNameOfClass(); } return image; } Surface::Pointer IOUtil::LoadSurface(const std::string& path) { BaseData::Pointer baseData = Impl::LoadBaseDataFromFile(path); mitk::Surface::Pointer surface = dynamic_cast(baseData.GetPointer()); if(surface.IsNull()) { mitkThrow() << path << " is not a mitk::Surface but a " << baseData->GetNameOfClass(); } return surface; } PointSet::Pointer IOUtil::LoadPointSet(const std::string& path) { BaseData::Pointer baseData = Impl::LoadBaseDataFromFile(path); mitk::PointSet::Pointer pointset = dynamic_cast(baseData.GetPointer()); if(pointset.IsNull()) { mitkThrow() << path << " is not a mitk::PointSet but a " << baseData->GetNameOfClass(); } return pointset; } -std::string IOUtil::Load(const std::vector& paths, std::vector* result, +std::string IOUtil::Load(std::vector& loadInfos, DataStorage::SetOfObjects* nodeResult, DataStorage* ds, ReaderOptionsFunctorBase* optionsCallback) { - if (paths.empty()) + if (loadInfos.empty()) { return "No input files given"; } - int filesToRead = paths.size(); + int filesToRead = loadInfos.size(); mitk::ProgressBar::GetInstance()->AddStepsToDo(2*filesToRead); - CoreServicePointer mimeTypeProvider(CoreServices::GetMimeTypeProvider()); - std::string errMsg; - // group the selected files by mime-type(s) - FileSorter fileSorter; - std::string noMimeTypeError; - for(std::vector::const_iterator selectedFileIter = paths.begin(), - iterEnd = paths.end(); selectedFileIter != iterEnd; ++selectedFileIter) + std::map usedReaderItems; + + for(std::vector::iterator infoIter = loadInfos.begin(), + infoIterEnd = loadInfos.end(); infoIter != infoIterEnd; ++infoIter) { - std::vector mimeTypes = mimeTypeProvider->GetMimeTypesForFile(*selectedFileIter); - if (!mimeTypes.empty()) - { - fileSorter.AddFile(*selectedFileIter, mimeTypes); - } - else + std::vector readers = infoIter->m_ReaderSelector.Get(); + + if (readers.empty()) { - noMimeTypeError += " * " + *selectedFileIter + "\n"; + errMsg += "No reader available for '" + infoIter->m_Path + "'\n"; + continue; } - } - if (!noMimeTypeError.empty()) - { - errMsg += "Unknown file format for\n\n" + noMimeTypeError + "\n\n"; - } - - FileReaderRegistry readerRegistry; + bool callOptionsCallback = readers.size() > 1 || !readers.front().GetReader()->GetOptions().empty(); - for(FileSorter::Iterator iter = fileSorter.Begin(), endIter = fileSorter.End(); - iter != endIter; ++iter) - { - std::vector finalReaders; - std::vector finalReaderLabels; - const FileSorter::FileVector& currentFiles = iter->second; - const FileSorter::MimeTypeVector& fileMimeTypes = iter->first; - for(FileSorter::MimeTypeVector::const_iterator mimeTypeIter = fileMimeTypes.begin(), - mimeTypeIterEnd = fileMimeTypes.end(); mimeTypeIter != mimeTypeIterEnd; ++mimeTypeIter) + // check if we already used a reader which should be re-used + std::vector currMimeTypes = infoIter->m_ReaderSelector.GetMimeTypes(); + std::string selectedMimeType; + for (std::vector::const_iterator mimeTypeIter = currMimeTypes.begin(), + mimeTypeIterEnd = currMimeTypes.end(); mimeTypeIter != mimeTypeIterEnd; ++mimeTypeIter) { - // Get all IFileReader references for the given mime-type - std::vector readerRefs = readerRegistry.GetReferences(*mimeTypeIter); - // Sort according to priority (ascending) - std::sort(readerRefs.begin(), readerRefs.end()); - - // Loop over all readers, starting at the highest priority, and check if it - // really can read the file (well, the first in the list). - for (std::vector::reverse_iterator readerRef = readerRefs.rbegin(); - readerRef != readerRefs.rend(); ++readerRef) + std::map::const_iterator oldSelectedItemIter = + usedReaderItems.find(mimeTypeIter->GetName()); + if (oldSelectedItemIter != usedReaderItems.end()) { - mitk::IFileReader* reader = readerRegistry.GetReader(*readerRef); - try + // we found an already used item for a mime-type which is contained + // in the current reader set, check all current readers if there service + // id equals the old reader + for (std::vector::const_iterator currReaderItem = readers.begin(), + currReaderItemEnd = readers.end(); currReaderItem != currReaderItemEnd; ++currReaderItem) { - if (reader->CanRead(currentFiles.front())) + if (currReaderItem->GetMimeType().GetName() == mimeTypeIter->GetName() && + currReaderItem->GetServiceId() == oldSelectedItemIter->second.GetServiceId() && + currReaderItem->GetConfidenceLevel() >= oldSelectedItemIter->second.GetConfidenceLevel()) { - finalReaders.push_back(reader); - finalReaderLabels.push_back(readerRef->GetProperty(mitk::IFileReader::PROP_DESCRIPTION()).ToString()); + // okay, we used the same reader already, re-use its options + selectedMimeType = mimeTypeIter->GetName(); + callOptionsCallback = false; + infoIter->m_ReaderSelector.Select(oldSelectedItemIter->second.GetServiceId()); + infoIter->m_ReaderSelector.GetSelected().GetReader()->SetOptions( + oldSelectedItemIter->second.GetReader()->GetOptions()); + break; } } - catch (const std::exception& e) - { - MITK_ERROR << "Calling CanRead('" << currentFiles.front() << "') on " << typeid(reader).name() << "failed: " << e.what(); - } + if (!selectedMimeType.empty()) break; } } - if (finalReaders.empty()) + if (callOptionsCallback && optionsCallback) { - errMsg += "No reader available for files\n\n"; - for(FileSorter::FileVector::const_iterator fileIter = currentFiles.begin(), - fileIterEnd = currentFiles.end(); fileIter != fileIterEnd; ++fileIter) + callOptionsCallback = (*optionsCallback)(*infoIter); + if (!callOptionsCallback && !infoIter->m_Cancel) { - errMsg += " * " + *fileIter + "\n"; + usedReaderItems.erase(selectedMimeType); + FileReaderSelector::Item selectedItem = infoIter->m_ReaderSelector.GetSelected(); + usedReaderItems.insert(std::make_pair(selectedItem.GetMimeType().GetName(), + selectedItem)); } } - else + + if (infoIter->m_Cancel) { - // TODO check if the reader can read a series of files and if yes, - // pass the complete file list to one "Read" call. + errMsg += "Reading operation(s) cancelled."; + break; + } - bool callOptionsCallback = finalReaders.size() > 1 || !finalReaders.front()->GetOptions().empty(); - mitk::IFileReader* selectedReader = finalReaders.front(); + IFileReader* reader = infoIter->m_ReaderSelector.GetSelected().GetReader(); + if (reader == NULL) + { + errMsg += "Unexpected NULL reader."; + break; + } - for(FileSorter::FileVector::const_iterator fileIter = currentFiles.begin(), - fileIterEnd = currentFiles.end(); fileIter != fileIterEnd; ++fileIter) + MITK_INFO << "******* USING READER " << typeid(*reader).name() << "*********"; + + // Do the actual reading + try + { + DataStorage::SetOfObjects::Pointer nodes; + if (ds != NULL) { - if (callOptionsCallback && optionsCallback) - { - callOptionsCallback = (*optionsCallback)(*fileIter, finalReaderLabels, finalReaders, selectedReader); - } - if (selectedReader == NULL) + nodes = reader->Read(infoIter->m_Path, *ds); + } + else + { + nodes = DataStorage::SetOfObjects::New(); + std::vector baseData = reader->Read(infoIter->m_Path); + for (std::vector::iterator iter = baseData.begin(); + iter != baseData.end(); ++iter) { - errMsg += "Reading operation(s) cancelled."; - break; + if (iter->IsNotNull()) + { + mitk::DataNode::Pointer node = mitk::DataNode::New(); + node->SetData(*iter); + nodes->InsertElement(nodes->Size(), node); + } } + } - MITK_INFO << "******* USING READER " << typeid(*selectedReader).name() << "*********"; - - // Do the actual reading - try + for (DataStorage::SetOfObjects::ConstIterator nodeIter = nodes->Begin(), + nodeIterEnd = nodes->End(); nodeIter != nodeIterEnd; ++nodeIter) + { + const mitk::DataNode::Pointer& node = nodeIter->Value(); + mitk::BaseData::Pointer data = node->GetData(); + if (data.IsNull()) { - // Correct conversion for File names.(BUG 12252) - const std::string& stdFile = *fileIter; - - DataStorage::SetOfObjects::Pointer nodes; - // Now do the actual reading - if (ds != NULL) - { - nodes = selectedReader->Read(stdFile, *ds); - } - else - { - nodes = DataStorage::SetOfObjects::New(); - std::vector baseData = selectedReader->Read(stdFile); - for (std::vector::iterator iter = baseData.begin(); - iter != baseData.end(); ++iter) - { - if (iter->IsNotNull()) - { - mitk::DataNode::Pointer node = mitk::DataNode::New(); - node->SetData(*iter); - nodes->InsertElement(nodes->Size(), node); - } - } - } + continue; + } - for (DataStorage::SetOfObjects::ConstIterator nodeIter = nodes->Begin(), - nodeIterEnd = nodes->End(); nodeIter != nodeIterEnd; ++nodeIter) - { - const mitk::DataNode::Pointer& node = nodeIter->Value(); - mitk::BaseData::Pointer data = node->GetData(); - if (data.IsNull()) - { - continue; - } - - mitk::StringProperty::Pointer pathProp = mitk::StringProperty::New(stdFile); - data->SetProperty("path", pathProp); - - if (result) - { - result->push_back(data); - } - if (nodeResult) - { - nodeResult->push_back(nodeIter->Value()); - } - } + mitk::StringProperty::Pointer pathProp = mitk::StringProperty::New(infoIter->m_Path); + data->SetProperty("path", pathProp); - if ((result && result->empty()) || (nodeResult && nodeResult->Size() == 0)) - { - errMsg += "Unknown read error occurred reading " + stdFile; - } - } - catch (const std::exception& e) + infoIter->m_Output.push_back(data); + if (nodeResult) { - errMsg += "Exception occured when reading file " + *fileIter + ":\n" + e.what() + "\n\n"; + nodeResult->push_back(nodeIter->Value()); } - mitk::ProgressBar::GetInstance()->Progress(2); - --filesToRead; } - if (selectedReader == NULL) + if (infoIter->m_Output.empty() || (nodeResult && nodeResult->Size() == 0)) { - // reading was cancelled within the optionsCallback, - // break outer loop as well - break; + errMsg += "Unknown read error occurred reading " + infoIter->m_Path; } } - - for(std::vector::const_iterator readerIter = finalReaders.begin(), - readerIterEnd = finalReaders.end(); readerIter != readerIterEnd; ++readerIter) + catch (const std::exception& e) { - readerRegistry.UngetReader(*readerIter); + errMsg += "Exception occured when reading file " + infoIter->m_Path + ":\n" + e.what() + "\n\n"; } + mitk::ProgressBar::GetInstance()->Progress(2); + --filesToRead; } if (!errMsg.empty()) { MITK_ERROR << errMsg; } mitk::ProgressBar::GetInstance()->Progress(2*filesToRead); return errMsg; } void IOUtil::Save(const BaseData* data, const std::string& path) { Save(data, path, IFileWriter::Options()); } void IOUtil::Save(const BaseData* data, const std::string& path, const IFileWriter::Options& options) { Save(data, std::string(), path, options); } -void IOUtil::Save(const BaseData* data, const std::string& mimeType, const std::string& path) +void IOUtil::Save(const BaseData* data, const std::string& mimeType, const std::string& path, + bool addExtension) { - Save(data, mimeType, path, IFileWriter::Options()); + Save(data, mimeType, path, IFileWriter::Options(), addExtension); } void IOUtil::Save(const BaseData* data, const std::string& mimeType, const std::string& path, - const IFileWriter::Options& options) + const IFileWriter::Options& options, bool addExtension) { std::string errMsg; if (options.empty()) { - errMsg = Save(data, mimeType, path, NULL); + errMsg = Save(data, mimeType, path, NULL, addExtension); } else { Impl::FixedWriterOptionsFunctor optionsCallback(options); - errMsg = Save(data, mimeType, path, &optionsCallback); + errMsg = Save(data, mimeType, path, &optionsCallback, addExtension); } if (!errMsg.empty()) { mitkThrow() << errMsg; } } -void IOUtil::Save(const std::vector& saveInfos) +void IOUtil::Save(std::vector& saveInfos) { std::string errMsg = Save(saveInfos, NULL); if (!errMsg.empty()) { mitkThrow() << errMsg; } } bool IOUtil::SaveImage(mitk::Image::Pointer image, const std::string& path) { Save(image, path); return true; } bool IOUtil::SaveSurface(Surface::Pointer surface, const std::string& path) { Save(surface, path); return true; } bool IOUtil::SavePointSet(PointSet::Pointer pointset, const std::string& path) { Save(pointset, path); return true; } bool IOUtil::SaveBaseData( mitk::BaseData* data, const std::string& path) { Save(data, path); return true; } -std::string IOUtil::Save(const BaseData* data, const std::string& mimeType, const std::string& path, - WriterOptionsFunctorBase* optionsCallback) +std::string IOUtil::Save(const BaseData* data, const std::string& mimeTypeN, const std::string& path, + WriterOptionsFunctorBase* optionsCallback, bool addExtension) { if (path.empty()) { return "No output filename given"; } - std::vector infos; - infos.push_back(SaveInfo(data, mimeType, path)); - return Save(infos, optionsCallback); -} + mitk::CoreServicePointer mimeTypeProvider(mitk::CoreServices::GetMimeTypeProvider()); -std::string IOUtil::Save(const std::vector& saveInfos, WriterOptionsFunctorBase* optionsCallback) -{ - if (saveInfos.empty()) - { - return "No data for saving available"; - } - - int filesToWrite = saveInfos.size(); - mitk::ProgressBar::GetInstance()->AddStepsToDo(2*filesToWrite); + std::string mimeTypeName = mimeTypeN; - std::string errMsg; - - // Group the SaveInfo objects by base data type and mime-type - SaveInfoSorter infoSorter; - std::string infoError; - for (std::vector::const_iterator iter = saveInfos.begin(), iterEnd = saveInfos.end(); - iter != iterEnd; ++iter) + // If no mime-type is provided, we try to get the mime-type from the + // highest ranked IFileWriter object for the given BaseData type + if (mimeTypeName.empty()) { - if (iter->m_BaseData == NULL) + std::vector refs = us::GetModuleContext()->GetServiceReferences( + us::LDAPProp(us::ServiceConstants::OBJECTCLASS()) == us_service_interface_iid() && + us::LDAPProp(IFileWriter::PROP_BASEDATA_TYPE()) == data->GetNameOfClass()); + std::sort(refs.begin(), refs.end()); + if (!refs.empty()) { - infoError += "Cannot save NULL data to path " + (iter->m_Path.empty() ? "(NULL)" : iter->m_Path) + "\n"; - continue; + us::Any mimeProp = refs.back().GetProperty(IFileWriter::PROP_MIMETYPE()); + if (mimeProp.Type() == typeid(std::string)) + { + mimeTypeName = us::any_cast(mimeProp); + } } - if (iter->m_Path.empty()) + } + + MimeType mimeType = mimeTypeProvider->GetMimeTypeForName(mimeTypeName); + if (mimeType.IsValid()) + { + std::string ext = itksys::SystemTools::GetFilenameExtension(path); + if (ext.empty() && addExtension) { - infoError += std::string("Cannot save ") + (iter->m_BaseData == NULL ? "(NULL)" : iter->m_BaseData->GetNameOfClass()) + - " data to unknown file path.\n"; - continue; + ext = mimeType.GetExtensions().empty() ? std::string() : "." + mimeType.GetExtensions().front(); } - infoSorter.AddSaveInfo(*iter); + std::vector infos; + infos.push_back(SaveInfo(data, mimeType, path + ext)); + return Save(infos, optionsCallback); } + return "The mime-type '" + mimeTypeName + "' is not registered"; +} - if(!infoError.empty()) +std::string IOUtil::Save(std::vector& saveInfos, WriterOptionsFunctorBase* optionsCallback) +{ + if (saveInfos.empty()) { - errMsg += "Invalid information:\n\n" + infoError + "\n\n"; + return "No data for saving available"; } - FileWriterRegistry writerRegistry; + int filesToWrite = saveInfos.size(); + mitk::ProgressBar::GetInstance()->AddStepsToDo(2*filesToWrite); - for (SaveInfoSorter::Iterator iter = infoSorter.Begin(), endIter = infoSorter.End(); - iter != endIter; ++iter) - { - const SaveInfoSorter::SaveInfoVector& currentInfos = iter->second; + std::string errMsg; - const std::string baseDataType = currentInfos.front().m_BaseData->GetNameOfClass(); - const std::string mimeType = currentInfos.front().m_MimeType; + std::set usedSaveInfos; - // Get all IFileWriter references for the base data and mime type - std::vector writerRefs = - writerRegistry.GetReferences(baseDataType, mimeType); - std::sort(writerRefs.begin(), writerRefs.end()); - std::reverse(writerRefs.begin(), writerRefs.end()); + for (std::vector::iterator infoIter = saveInfos.begin(), + infoIterEnd = saveInfos.end(); infoIter != infoIterEnd; ++infoIter) + { + const std::string baseDataType = infoIter->m_BaseData->GetNameOfClass(); - std::vector writers; - std::vector writerLabels; - for (std::vector::const_iterator iter = writerRefs.begin(), - iterEnd = writerRefs.end(); iter != iterEnd; ++iter) - { - IFileWriter* writer = writerRegistry.GetWriter(*iter); - if (writer) - { - writers.push_back(writer); - writerLabels.push_back(iter->GetProperty(IFileWriter::PROP_DESCRIPTION()).ToString()); - } - } + std::vector writers = infoIter->m_WriterSelector.Get(); // Error out if no compatible Writer was found if (writers.empty()) { errMsg += std::string("No writer available for ") + baseDataType + " data.\n"; + continue; } - else - { - bool callOptionsCallback = writers.size() > 1 || !writers.front()->GetOptions().empty(); - mitk::IFileWriter* selectedWriter = writers.front(); - for (SaveInfoSorter::SaveInfoVector::const_iterator infoIter = currentInfos.begin(), - infoIterEnd = currentInfos.end(); infoIter != infoIterEnd; ++infoIter) + bool callOptionsCallback = writers.size() > 1 || !writers[0].GetWriter()->GetOptions().empty(); + + // check if we already used a writer for this base data type + // which should be re-used + std::set::const_iterator oldSaveInfoIter = usedSaveInfos.find(*infoIter); + if (oldSaveInfoIter != usedSaveInfos.end()) + { + // we previously saved a base data object of the same data with the same mime-type, + // check if the same writer is contained in the current writer set and if the + // confidence level matches + FileWriterSelector::Item oldSelectedItem = + oldSaveInfoIter->m_WriterSelector.Get(oldSaveInfoIter->m_WriterSelector.GetSelectedId()); + for (std::vector::const_iterator currWriterItem = writers.begin(), + currWriterItemEnd = writers.end(); currWriterItem != currWriterItemEnd; ++currWriterItem) { - if (callOptionsCallback && optionsCallback) - { - callOptionsCallback = (*optionsCallback)(infoIter->m_Path, writerLabels, writers, selectedWriter); - } - if (selectedWriter == NULL) + if (currWriterItem->GetServiceId() == oldSelectedItem.GetServiceId() && + currWriterItem->GetConfidenceLevel() >= oldSelectedItem.GetConfidenceLevel()) { - errMsg += "Writing operation(s) cancelled."; + // okay, we used the same writer already, re-use its options + callOptionsCallback = false; + infoIter->m_WriterSelector.Select(oldSaveInfoIter->m_WriterSelector.GetSelectedId()); + infoIter->m_WriterSelector.GetSelected().GetWriter()->SetOptions( + oldSelectedItem.GetWriter()->GetOptions()); break; } - - MITK_INFO << "******* USING WRITER " << typeid(*selectedWriter).name() << "*********"; - - // Do the actual writing - try - { - selectedWriter->Write(infoIter->m_BaseData, infoIter->m_Path); - } - catch(const std::exception& e) - { - errMsg += std::string("Exception occurred when writing to ") + infoIter->m_Path + ":\n" + e.what() + "\n"; - } - mitk::ProgressBar::GetInstance()->Progress(2); - --filesToWrite; } + } - if (selectedWriter == NULL) + if (callOptionsCallback && optionsCallback) + { + callOptionsCallback = (*optionsCallback)(*infoIter); + if (!callOptionsCallback && !infoIter->m_Cancel) { - // writing was cancelled within the optionsCallback, - // break outer loop as well - break; + usedSaveInfos.erase(*infoIter); + usedSaveInfos.insert(*infoIter); } } - for(std::vector::const_iterator writerIter = writers.begin(), - writerIterEnd = writers.end(); writerIter != writerIterEnd; ++writerIter) + if (infoIter->m_Cancel) + { + errMsg += "Writing operation(s) cancelled."; + break; + } + + IFileWriter* writer = infoIter->m_WriterSelector.GetSelected().GetWriter(); + if (writer == NULL) { - writerRegistry.UngetWriter(*writerIter); + errMsg += "Unexpected NULL writer."; + break; } + + MITK_INFO << "******* USING WRITER " << typeid(*writer).name() << "*********"; + + // Do the actual writing + try + { + writer->Write(infoIter->m_BaseData, infoIter->m_Path); + } + catch(const std::exception& e) + { + errMsg += std::string("Exception occurred when writing to ") + infoIter->m_Path + ":\n" + e.what() + "\n"; + } + mitk::ProgressBar::GetInstance()->Progress(2); + --filesToWrite; } if (!errMsg.empty()) { MITK_ERROR << errMsg; } mitk::ProgressBar::GetInstance()->Progress(2*filesToWrite); return errMsg; } // This method can be removed after the deprecated LoadDataNode() method was removed void IOUtil::Impl::SetDefaultDataNodeProperties(DataNode* node, const std::string& filePath) { // path mitk::StringProperty::Pointer pathProp = mitk::StringProperty::New( itksys::SystemTools::GetFilenamePath(filePath) ); node->SetProperty(StringProperty::PATH, pathProp); // name already defined? mitk::StringProperty::Pointer nameProp = dynamic_cast(node->GetProperty("name")); if(nameProp.IsNull() || (strcmp(nameProp->GetValue(),"No Name!")==0)) { // name already defined in BaseData mitk::StringProperty::Pointer baseDataNameProp = dynamic_cast(node->GetData()->GetProperty("name").GetPointer() ); if(baseDataNameProp.IsNull() || (strcmp(baseDataNameProp->GetValue(),"No Name!")==0)) { // name neither defined in node, nor in BaseData -> name = filename nameProp = mitk::StringProperty::New( itksys::SystemTools::GetFilenameWithoutExtension(filePath)); node->SetProperty("name", nameProp); } else { // name defined in BaseData! nameProp = mitk::StringProperty::New(baseDataNameProp->GetValue()); node->SetProperty("name", nameProp); } } // visibility if(!node->GetProperty("visible")) { node->SetVisibility(true); } } -IOUtil::SaveInfo::SaveInfo(const BaseData* baseData, const std::string& mimeType, const std::string& path) +IOUtil::SaveInfo::SaveInfo(const BaseData* baseData) + : m_BaseData(baseData) + , m_WriterSelector(baseData, std::string()) + , m_Cancel(false) +{ +} + +IOUtil::SaveInfo::SaveInfo(const BaseData* baseData, const MimeType& mimeType, + const std::string& path) : m_BaseData(baseData) , m_MimeType(mimeType) + , m_WriterSelector(baseData, mimeType.IsValid() ? mimeType.GetName() : std::string()) , m_Path(path) + , m_Cancel(false) +{ +} + +bool IOUtil::SaveInfo::operator<(const IOUtil::SaveInfo& other) const +{ + int r = strcmp(m_BaseData->GetNameOfClass(), other.m_BaseData->GetNameOfClass()); + if (r == 0) + { + return m_WriterSelector.GetSelected().GetMimeType() < + other.m_WriterSelector.GetSelected().GetMimeType(); + } + return r < 0; +} + +IOUtil::LoadInfo::LoadInfo(const std::string& path) + : m_Path(path) + , m_ReaderSelector(path) + , m_Cancel(false) { } } diff --git a/Core/Code/IO/mitkIOUtil.h b/Core/Code/IO/mitkIOUtil.h index d768a3e056..140b6e23c5 100644 --- a/Core/Code/IO/mitkIOUtil.h +++ b/Core/Code/IO/mitkIOUtil.h @@ -1,393 +1,446 @@ /*=================================================================== 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 MITKIOUTIL_H #define MITKIOUTIL_H #include #include #include #include #include #include #include +#include +#include #include namespace mitk { +class FileWriterRegistry; + /** * \ingroup IO * * \brief A utility class to load and save data from/to the local file system. * - * This method LoadFiles queries the MITK Micro Services registry for registered mitk::IDataNodeReader service - * instances. The service instance with the highest ranking will be asked first to load the - * given file. On error (exception thrown) or if no mitk::DataNode was constructed, the next - * service instance is used. - * * The methods LoadImage, LoadSurface, and LoadPointSet are convenience methods for general loading of - * the three main data types in MITK. They all use the more generic method LoadDataNode. + * the three main data types in MITK. They all use the more generic method Load(). * - * The methods SaveImage, SaveSurface, and SurfacePointSet are also meant for convenience (e.g. during testing). - * Currently, there is no generic way to save a generic DataNode with an appropriate format. Thus, every method - * initializes the corresponding instance of the special writer for the data type. - * - * \see mitk::IDataNodeReader + * \see QmitkIOUtil */ class MITK_CORE_EXPORT IOUtil { public: + struct LoadInfo + { + LoadInfo(const std::string& path); + + std::string m_Path; + std::vector m_Output; + + FileReaderSelector m_ReaderSelector; + bool m_Cancel; + }; + struct SaveInfo { - SaveInfo(const BaseData* baseData, const std::string& mimeType, const std::string& path); + SaveInfo(const BaseData* baseData); + SaveInfo(const BaseData* baseData, const MimeType& mimeType, const std::string& path); + + bool operator<(const SaveInfo& other) const; + /// The BaseData object to save. const BaseData* m_BaseData; - std::string m_MimeType; + + /// The selected mime-type, used to restrict results from FileWriterSelector. + MimeType m_MimeType; + /// Contains a set of IFileWriter objects. + FileWriterSelector m_WriterSelector; + /// The path to write the BaseData object to. std::string m_Path; + /// Flag indicating if sub-sequent save operations are to be canceled. + bool m_Cancel; }; /** * Get the file system path where the running executable is located. * * @return The location of the currently running executable, without the filename. */ static std::string GetProgramPath(); /** * Get the default temporary path. * * @return The default path for temporary data. */ static std::string GetTempPath(); /** * Create and open a temporary file. * * This method generates a unique temporary filename from \c templateName, creates * and opens the file using the output stream \c tmpStream and returns the name of * the newly create file. * * The \c templateName argument must contain six consective 'X' characters ("XXXXXX") * and these are replaced with a string that makes the filename unique. * * The file is created with read and write permissions for owner only. * * @param tmpStream The output stream for writing to the temporary file. * @param templateName An optional template for the filename. * @param path An optional path where the temporary file should be created. Defaults * to the default temp path as returned by GetTempPath(). * @return The filename of the created temporary file. * * @throw mitk::Exception if the temporary file could not be created. */ static std::string CreateTemporaryFile(std::ofstream& tmpStream, const std::string& templateName = "XXXXXX", std::string path = std::string()); /** * Create and open a temporary file. * * This method generates a unique temporary filename from \c templateName, creates * and opens the file using the output stream \c tmpStream and the specified open * mode \c mode and returns the name of the newly create file. The open mode is always * OR'd with \begin{code}std::ios_base::out | std::ios_base::trunc\end{code}. * * The \c templateName argument must contain six consective 'X' characters ("XXXXXX") * and these are replaced with a string that makes the filename unique. * * The file is created with read and write permissions for owner only. * * @param tmpStream The output stream for writing to the temporary file. * @param mode The open mode for the temporary file stream. * @param templateName An optional template for the filename. * @param path An optional path where the temporary file should be created. Defaults * to the default temp path as returned by GetTempPath(). * @return The filename of the created temporary file. * * @throw mitk::Exception if the temporary file could not be created. */ static std::string CreateTemporaryFile(std::ofstream& tmpStream, std::ios_base::openmode mode, const std::string& templateName = "XXXXXX", std::string path = std::string()); /** * Creates an empty temporary file. * * This method generates a unique temporary filename from \c templateName and creates * this file. * * The file is created with read and write permissions for owner only. * * --- * This version is potentially unsafe because the created temporary file is not kept open * and could be used by another process between calling this method and opening the returned * file path for reading or writing. * --- * * @return The filename of the created temporary file. * @param templateName An optional template for the filename. * @param path An optional path where the temporary file should be created. Defaults * to the default temp path as returned by GetTempPath(). * @throw mitk::Exception if the temporary file could not be created. */ static std::string CreateTemporaryFile(const std::string& templateName = "XXXXXX", std::string path = std::string()); /** * Create a temporary directory. * * This method generates a uniquely named temporary directory from \c templateName. * The last set of six consecutive 'X' characters in \c templateName is replaced * with a string that makes the directory name unique. * * The directory is created with read, write and executable permissions for owner only. * * @param templateName An optional template for the directory name. * @param path An optional path where the temporary directory should be created. Defaults * to the default temp path as returned by GetTempPath(). * @return The filename of the created temporary file. * * @throw mitk::Exception if the temporary directory could not be created. */ static std::string CreateTemporaryDirectory(const std::string& templateName = "XXXXXX", std::string path = std::string()); /** * @brief Load a file into the given DataStorage. * * This method calls Load(const std::vector&, DataStorage&) with a * one-element vector. * * @param path The absolute file name including the file extension. * @param storage A DataStorage object to which the loaded data will be added. * @return The set of added DataNode objects. * @throws mitk::Exception if \c path could not be loaded. * * @sa Load(const std::vector&, DataStorage&) */ static DataStorage::SetOfObjects::Pointer Load(const std::string& path, DataStorage& storage); static DataStorage::SetOfObjects::Pointer Load(const std::string& path, const IFileReader::Options& options, DataStorage& storage); static std::vector Load(const std::string& path); static std::vector Load(const std::string& path, const IFileReader::Options& options); /** * @brief Loads a list of file paths into the given DataStorage. * * If an entry in \c paths cannot be loaded, this method will continue to load * the remaining entries into \c storage and throw an exception afterwards. * * @param paths A list of absolute file names including the file extension. * @param storage A DataStorage object to which the loaded data will be added. * @return The set of added DataNode objects. * @throws mitk::Exception if an entry in \c paths could not be loaded. */ static DataStorage::SetOfObjects::Pointer Load(const std::vector& paths, DataStorage& storage); static std::vector Load(const std::vector& paths); /** - * Load a files in fileNames and add the constructed mitk::DataNode instances + * Load files in fileNames and add the constructed mitk::DataNode instances * to the mitk::DataStorage storage * * @param fileNames A list (vector) of absolute file name paths. * @param storage The data storage to which the constructed data nodes are added. * @return The number of added mitk::DataNode instances. * * @deprecatedSince{2014_03} Use Load() instead */ DEPRECATED(static int LoadFiles(const std::vector&fileNames, DataStorage& storage)); /** * This method will create a new mitk::DataStorage instance and pass it to * LoadFiles(std::vector,DataStorage). * * @param fileNames A list (vector) of absolute file name paths. * @return The new mitk::DataStorage containing the constructed data nodes. * * @see LoadFiles(std::vector,DataStorage) * * @deprecatedSince{2014_03} Use Load() instead */ DEPRECATED(static DataStorage::Pointer LoadFiles(const std::vector& fileNames)); /** * @brief Create a BaseData object from the given file. * @param path The path to the file including file name and file extension. * @throws mitk::Exception In case of an error when reading the file. * @return Returns the created BaseData object. * * @deprecatedSince{2014_03} Use Load() or FileReaderRegistry::Read() instead. */ DEPRECATED(static mitk::BaseData::Pointer LoadBaseData(const std::string& path)); /** * @brief LoadDataNode Method to load an arbitrary DataNode. * @param path The path to the file including file name and file extension. * @throws mitk::Exception This exception is thrown when the DataNodeFactory is not able to read/find the file * or the DataNode is NULL. * @return Returns the DataNode. * * @deprecatedSince{2014_03} Use Load() instead. */ DEPRECATED(static mitk::DataNode::Pointer LoadDataNode(const std::string& path)); /** * @brief LoadImage Convenience method to load an arbitrary mitkImage. * @param path The path to the image including file name and file extension. * @throws mitk::Exception This exception is thrown when the Image is NULL. * @return Returns the mitkImage. */ static mitk::Image::Pointer LoadImage(const std::string& path); /** * @brief LoadSurface Convenience method to load an arbitrary mitkSurface. * @param path The path to the surface including file name and file extension. * @throws mitk::Exception This exception is thrown when the Surface is NULL. * @return Returns the mitkSurface. */ static mitk::Surface::Pointer LoadSurface(const std::string& path); /** * @brief LoadPointSet Convenience method to load an arbitrary mitkPointSet. * @param path The path to the pointset including file name and file extension (currently, only .mps is supported). * @throws mitk::Exception This exception is thrown when the PointSet is NULL. * @return Returns the mitkPointSet. */ static mitk::PointSet::Pointer LoadPointSet(const std::string& path); /** - * @brief Convenience method to save mitk::BaseData instances. - * @param path The path to the image including file name and file extension. - * If no extention is set, the default extension is used. + * @brief Save a mitk::BaseData instance. * @param data The data to save. + * @param path The path to the image including file name and and optional file extension. + * If no extension is set, the default extension and mime-type for the + * BaseData type of \c data is used. * @throws mitk::Exception if no writer for \c data is available or the writer * is not able to write the image. */ static void Save(const mitk::BaseData* data, const std::string& path); + /** + * @brief Save a mitk::BaseData instance. + * @param data The data to save. + * @param path The path to the image including file name and an optional file extension. + * If no extension is set, the default extension and mime-type for the + * BaseData type of \c data is used. + * @param options The IFileWriter options to use for the selected writer. + * @throws mitk::Exception if no writer for \c data is available or the writer + * is not able to write the image. + */ static void Save(const mitk::BaseData* data, const std::string& path, const IFileWriter::Options& options); - static void Save(const mitk::BaseData* data, const std::string& mimeType, const std::string& path); + /** + * @brief Save a mitk::BaseData instance. + * @param data The data to save. + * @param mimeType The mime-type to use for writing \c data. + * @param path The path to the image including file name and an optional file extension. + * @param addExtension If \c true, an extension according to the given \c mimeType + * is added to \c path if it does not contain one. If \c path already contains + * a file name extension, it is not checked for compatibility with \c mimeType. + * + * @throws mitk::Exception if no writer for the combination of \c data and \c mimeType is + * available or the writer is not able to write the image. + */ + static void Save(const mitk::BaseData* data, const std::string& mimeType, const std::string& path, + bool addExtension = true); /** - * @brief Convenience method to save mitk::BaseData instances. - * @param path The path to the image including file name and file extension. - * If no extention is set, the default extension is used. + * @brief Save a mitk::BaseData instance. * @param data The data to save. - * @param mimeType The mime-type to use for the written file - * @parma options Configuration data for the used IFileWriter instance. - * @throws mitk::Exception if no writer for \c data is available or the writer - * is not able to write the image. + * @param mimeType The mime-type to use for writing \c data. + * @param path The path to the image including file name and an optional file extension. + * @param options Configuration data for the used IFileWriter instance. + * @param addExtension If \c true, an extension according to the given \c mimeType + * is added to \c path if it does not contain one. If \c path already contains + * a file name extension, it is not checked for compatibility with \c mimeType. + * + * @throws mitk::Exception if no writer for the combination of \c data and \c mimeType is + * available or the writer is not able to write the image. */ - static void Save(const mitk::BaseData* data, const std::string& mimeType, const std::string& path, const mitk::IFileWriter::Options& options); + static void Save(const mitk::BaseData* data, const std::string& mimeType, const std::string& path, + const mitk::IFileWriter::Options& options, bool addExtension = true); - static void Save(const std::vector& saveInfos); + /** + * @brief Use SaveInfo objects to save BaseData instances. + * + * This is a low-level method for directly working with SaveInfo objects. Usually, + * the Save() methods taking a BaseData object as an argument are more appropriate. + * + * @param saveInfos A list of SaveInfo objects for saving contained BaseData objects. + * + * @see Save(const mitk::BaseData*, const std::string&) + */ + static void Save(std::vector& saveInfos); /** * @brief SaveImage Convenience method to save an arbitrary mitkImage. * @param path The path to the image including file name and file extension. * If no extention is set, the default value (defined in DEFAULTIMAGEEXTENSION) is used. * @param image The image to save. * @throws mitk::Exception This exception is thrown when the writer is not able to write the image. * @return Returns true for success else false. * * @deprecatedSince{2014_03} Use Save() instead. */ DEPRECATED(static bool SaveImage(mitk::Image::Pointer image, const std::string& path)); /** * @brief SaveBaseData Convenience method to save arbitrary baseData. * @param path The path to the image including file name and file extension. * If no extention is set, the default extension is used. * @param data The data to save. * @throws mitk::Exception This exception is thrown when the writer is not able to write the image. * @return Returns true for success else false. * * @deprecatedSince{2014_03} Use Save() instead. */ DEPRECATED(static bool SaveBaseData(mitk::BaseData* data, const std::string& path)); /** * @brief SaveSurface Convenience method to save an arbitrary mitkSurface. * @param path The path to the surface including file name and file extension. * If no extention is set, the default extension is used. * @throws mitk::Exception This exception is thrown when the writer is not able to write the surface. * or if the fileextension is not suitable for writing. * @return Returns true for success else false. * * @deprecatedSince{2014_03} Use Save() instead. */ DEPRECATED(static bool SaveSurface(mitk::Surface::Pointer surface, const std::string& path)); /** * @brief SavePointSet Convenience method to save an mitkPointSet. * @param path The path to the pointset including file name and file extension. * If no extention is set, the default extension is used. * @throws mitk::Exception This exception is thrown when the writer is not able to write the pointset. * @return Returns true for success else false. * * @deprecatedSince{2014_03} Use Save() instead. */ DEPRECATED(static bool SavePointSet(mitk::PointSet::Pointer pointset, const std::string& path)); /** @deprecatedSince{2014_03} Use GetDefaultWriteExtension() instead */ DEPRECATED(static const std::string DEFAULTIMAGEEXTENSION); /** @deprecatedSince{2014_03} Use GetDefaultWriteExtension() instead */ DEPRECATED(static const std::string DEFAULTSURFACEEXTENSION); /** @deprecatedSince{2014_03} Use GetDefaultWriteExtension() instead */ DEPRECATED(static const std::string DEFAULTPOINTSETEXTENSION); protected: struct ReaderOptionsFunctorBase { - virtual bool operator()(const std::string& path, const std::vector& readerLabels, - const std::vector& readers, IFileReader*& selectedReader) = 0; + virtual bool operator()(LoadInfo& loadInfo) = 0; }; struct WriterOptionsFunctorBase { - virtual bool operator()(const std::string& path, const std::vector& writerLabels, - const std::vector& readers, IFileWriter*& selectedWriter) = 0; + virtual bool operator()(SaveInfo& saveInfo) = 0; }; - static std::string Load(const std::vector& paths, std::vector* result, - DataStorage::SetOfObjects* nodeResult, DataStorage* ds, ReaderOptionsFunctorBase* optionsCallback); + static std::string Load(std::vector& loadInfos, DataStorage::SetOfObjects* nodeResult, + DataStorage* ds, ReaderOptionsFunctorBase* optionsCallback); static std::string Save(const BaseData* data, const std::string& mimeType, const std::string& path, - WriterOptionsFunctorBase* optionsCallback); + WriterOptionsFunctorBase* optionsCallback, bool addExtension); - static std::string Save(const std::vector& saveInfos, + static std::string Save(std::vector& saveInfos, WriterOptionsFunctorBase* optionsCallback); private: struct Impl; }; } #endif // MITKIOUTIL_H diff --git a/Core/Code/IO/mitkMimeType.cpp b/Core/Code/IO/mitkMimeType.cpp new file mode 100644 index 0000000000..005d7d4092 --- /dev/null +++ b/Core/Code/IO/mitkMimeType.cpp @@ -0,0 +1,136 @@ +/*=================================================================== + +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 "mitkMimeType.h" + +#include "mitkCustomMimeType.h" + +namespace mitk { + +struct MimeType::Impl : us::SharedData +{ + Impl() + : m_Rank(-1) + , m_Id(-1) + {} + + Impl(const CustomMimeType& x, int rank, long id) + : m_Name(x.GetName()) + , m_Category(x.GetCategory()) + , m_Extensions(x.GetExtensions()) + , m_Comment(x.GetComment()) + , m_Rank(rank) + , m_Id(id) + {} + + std::string m_Name; + std::string m_Category; + std::vector m_Extensions; + std::string m_Comment; + + int m_Rank; + long m_Id; +}; + +MimeType::MimeType() + : m_Data(new Impl) +{ +} + +MimeType::MimeType(const MimeType& other) + : m_Data(other.m_Data) +{ +} + +MimeType::MimeType(const CustomMimeType& x, int rank, long id) + : m_Data(new Impl(x, rank, id)) +{ +} + +MimeType::~MimeType() +{ +} + +MimeType& MimeType::operator=(const MimeType& other) +{ + m_Data = other.m_Data; + return *this; +} + +bool MimeType::operator==(const MimeType& other) const +{ + return m_Data->m_Name == other.GetName(); +} + +bool MimeType::operator<(const MimeType& other) const +{ + if (m_Data->m_Rank != other.m_Data->m_Rank) + { + return m_Data->m_Rank < other.m_Data->m_Rank; + } + return other.m_Data->m_Id < m_Data->m_Id; +} + +std::string MimeType::GetName() const +{ + return m_Data->m_Name; +} + +std::string MimeType::GetCategory() const +{ + return m_Data->m_Category; +} + +std::vector MimeType::GetExtensions() const +{ + return m_Data->m_Extensions; +} + +std::string MimeType::GetComment() const +{ + return m_Data->m_Comment; +} + +bool MimeType::IsValid() const +{ + return m_Data.Data() != NULL && !m_Data->m_Name.empty(); +} + +void MimeType::Swap(MimeType& m) +{ + m_Data.Swap(m.m_Data); +} + +void swap(MimeType& m1, MimeType& m2) +{ + m1.Swap(m2); +} + +std::ostream& operator<<(std::ostream& os, const MimeType& mimeType) +{ + os << mimeType.GetName() << " (" << mimeType.GetCategory() << ", " << mimeType.GetComment() + << ") "; + std::vector extensions = mimeType.GetExtensions(); + for (std::vector::const_iterator iter = extensions.begin(), + endIter = extensions.end(); iter != endIter; ++iter) + { + if (iter != extensions.begin()) os << ", "; + os << *iter; + } + return os; +} + +} diff --git a/Core/Code/IO/mitkMimeType.h b/Core/Code/IO/mitkMimeType.h new file mode 100644 index 0000000000..e08b35511e --- /dev/null +++ b/Core/Code/IO/mitkMimeType.h @@ -0,0 +1,69 @@ +/*=================================================================== + +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 MITKMIMETYPE_H +#define MITKMIMETYPE_H + +#include + +#include + +#include + +namespace mitk { + +class CustomMimeType; + +class MITK_CORE_EXPORT MimeType +{ + +public: + + MimeType(); + MimeType(const MimeType& other); + MimeType(const CustomMimeType& x, int rank, long id); + + ~MimeType(); + + MimeType& operator=(const MimeType& other); + bool operator==(const MimeType& other) const; + + bool operator<(const MimeType& other) const; + + std::string GetName() const; + std::string GetCategory() const; + std::vector GetExtensions() const; + std::string GetComment() const; + + bool IsValid() const; + + void Swap(MimeType& m); + +private: + + struct Impl; + + // Use C++11 shared_ptr instead + us::SharedDataPointer m_Data; +}; + +void swap(MimeType& m1, MimeType& m2); + +std::ostream& operator<<(std::ostream& os, const MimeType& mimeType); + +} + +#endif // MITKMIMETYPE_H diff --git a/Core/Code/IO/mitkSimpleMimeType.cpp b/Core/Code/IO/mitkSimpleMimeType.cpp deleted file mode 100644 index dcc76ca9b9..0000000000 --- a/Core/Code/IO/mitkSimpleMimeType.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/*=================================================================== - -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 "mitkSimpleMimeType.h" - -std::string mitk::SimpleMimeType::GetMagicPatterns() const -{ - return std::string(); -} diff --git a/Core/Code/IO/mitkSimpleMimeType.h b/Core/Code/IO/mitkSimpleMimeType.h deleted file mode 100644 index 9b45a34f19..0000000000 --- a/Core/Code/IO/mitkSimpleMimeType.h +++ /dev/null @@ -1,35 +0,0 @@ -/*=================================================================== - -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 MITKSIMPLEMIMETYPE_H -#define MITKSIMPLEMIMETYPE_H - -#include "mitkIMimeType.h" - -namespace mitk { - -class MITK_CORE_EXPORT SimpleMimeType : public IMimeType -{ - -public: - - virtual std::string GetMagicPatterns() const; - -}; - -} - -#endif // MITKSIMPLEMIMETYPE_H diff --git a/Core/Code/Interfaces/mitkIFileReader.h b/Core/Code/Interfaces/mitkIFileReader.h index d60a0eeaf4..82486e0518 100644 --- a/Core/Code/Interfaces/mitkIFileReader.h +++ b/Core/Code/Interfaces/mitkIFileReader.h @@ -1,159 +1,159 @@ /*=================================================================== 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 IFileReader_H_HEADER_INCLUDED_C1E7E521 #define IFileReader_H_HEADER_INCLUDED_C1E7E521 // Macro #include // Microservices #include #include // MITK #include #include namespace mitk { class BaseData; } namespace itk { template class SmartPointer; } namespace mitk { + /** * \brief The common interface for all MITK file readers. * * Implementations of this interface must be registered as a service * to make themselve available via the service registry. If the * implementation is state-full, the service should be registered using * a PrototypeServiceFactory. * * The file reader implementation is associated with a mime-type, specified * in the service property PROP_MIMETYPE(). The specified mime-type should - * have a corresponding IMimeType service object, registered by the reader + * have a corresponding CustomMimeType service object, registered by the reader * or some other party. * * It is recommended to derive new implementations from AbstractFileReader, * which provides correct service registration semantics. * * \sa AbstractFileReader - * \sa IMimeType + * \sa CustomMimeType * \sa FileReaderRegistry * \sa IFileWriter */ struct MITK_CORE_EXPORT IFileReader { + + // The order of the enum values is important: it is used + // to rank writer implementations + enum ConfidenceLevel + { + Unsupported = 0, + PartiallySupported = 8, + Supported = 16 + }; + virtual ~IFileReader(); typedef std::map Options; typedef mitk::MessageAbstractDelegate1 ProgressCallback; /** * \brief Reads the specified file and returns its contents. */ virtual std::vector > Read(const std::string& path) = 0; /** * \brief Reads the specified input stream and returns its contents. */ virtual std::vector > Read(std::istream& stream) = 0; /** * \brief Reads the specified file, loading its contents into the provided DataStorage. * * \param path The absolute file path include the file name extension. * \param ds The DataStorage to which the data is added. * \return The set of add DataNodes to \c ds. */ virtual DataStorage::SetOfObjects::Pointer Read(const std::string& path, mitk::DataStorage& ds) = 0; /** * \brief Reads the specified input stream and returns its contents. */ virtual DataStorage::SetOfObjects::Pointer Read(std::istream& stream, mitk::DataStorage& ds) = 0; + virtual ConfidenceLevel GetConfidenceLevel(const std::string& path) const = 0; + /** * \brief returns a list of the supported Options * * Initially, the reader contains a set of standard options. These can be retrieved, * manipulated and set again. To activate or deactivate an option, just set it's bool * value accordingly. All supported options are in the default set, it does not * make sense to add strings artificially after retrieving a reader - the specific * implementation decides which options it wants to support. * If no options are supported, an empty list is returned. */ virtual Options GetOptions() const = 0; virtual us::Any GetOption(const std::string& name) const = 0; /** * \brief Sets the options for this reader * * The best way to use this method is to retireve the options via GetOptions, manipulate the bool values, * and then set the options again. */ virtual void SetOptions(const Options& options) = 0; virtual void SetOption(const std::string& name, const us::Any& value) = 0; - /** - * \brief Returns true if this writer can confirm that it can read this file and false otherwise. - */ - virtual bool CanRead(const std::string& path) const = 0; - - /** - * \brief Returns true if this writer can read from the specified stream. - * - * @param stream The input stream. - * @return \c true if the stream can be read, \c false otherwise. - */ - virtual bool CanRead(std::istream& stream) const = 0; - virtual void AddProgressCallback(const ProgressCallback& callback) = 0; virtual void RemoveProgressCallback(const ProgressCallback& callback) = 0; /** * @brief Service property name for a description. * * The property value must be of type \c std::string. * * @return The property name. */ static std::string PROP_DESCRIPTION(); /** * @brief Service property name for the mime-type associated with this file reader. * * The property value must be of type \c std::string. * * @return The property name. */ static std::string PROP_MIMETYPE(); }; } // namespace mitk US_DECLARE_SERVICE_INTERFACE(mitk::IFileReader, "org.mitk.IFileReader") #endif /* IFileReader_H_HEADER_INCLUDED_C1E7E521 */ diff --git a/Core/Code/Interfaces/mitkIFileWriter.h b/Core/Code/Interfaces/mitkIFileWriter.h index d43d49cdaa..dc743effc6 100644 --- a/Core/Code/Interfaces/mitkIFileWriter.h +++ b/Core/Code/Interfaces/mitkIFileWriter.h @@ -1,126 +1,137 @@ /*=================================================================== 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 IFileWriter_H_HEADER_INCLUDED_C1E7E521 #define IFileWriter_H_HEADER_INCLUDED_C1E7E521 // Macro #include // Microservices #include #include // MITK #include namespace mitk { class BaseData; } namespace mitk { /** * \brief The common interface of all MITK file writers. * * Implementations of this interface must be registered as a service * to make themselve available via the service registry. If the * implementation is state-full, the service should be registered using * a PrototypeServiceFactory. * * The file writer implementation is associated with a mime-type, specified * in the service property PROP_MIMETYPE() and a mitk::BaseData sub-class * as specified in the PROP_BASEDATA_TYPE() service property. - * The specified mime-type should have a corresponding IMimeType service + * The specified mime-type should have a corresponding CustomMimeType service * object, registered by the reader or some other party. * * It is recommended to derive new implementations from AbstractFileWriter, * which provides correct service registration semantics. * * \sa AbstractFileWriter - * \sa IMimeType + * \sa CustomMimeType * \sa FileWriterRegistry * \sa IFileReader */ struct MITK_CORE_EXPORT IFileWriter { + // The order of the enum values is important: it is used + // to rank writer implementations + enum ConfidenceLevel + { + Unsupported = 0, + PartiallySupported = 8, + Supported = 16 + }; + virtual ~IFileWriter(); typedef std::map Options; typedef mitk::MessageAbstractDelegate1 ProgressCallback; virtual void Write(const BaseData* data, const std::string& path ) = 0; virtual void Write(const BaseData* data, std::ostream& stream ) = 0; + virtual ConfidenceLevel GetConfidenceLevel(const BaseData* data) const = 0; + /** * \brief returns a list of the supported Options * * Options are strings that are treated as flags when passed to the write method. */ virtual Options GetOptions() const = 0; virtual us::Any GetOption(const std::string& name) const = 0; virtual void SetOptions(const Options& options) = 0; virtual void SetOption(const std::string& name, const us::Any& value) = 0; /** * \brief Returns a value between 0 and 1 depending on the progress of the writing process. * This method need not necessarily be implemented meaningfully, always returning zero is accepted. */ virtual void AddProgressCallback(const ProgressCallback& callback) = 0; virtual void RemoveProgressCallback(const ProgressCallback& callback) = 0; // Microservice properties /** * @brief Service property name for the supported mitk::BaseData sub-class * * The property value must be of type \c std::string. * * @return The property name. */ static std::string PROP_BASEDATA_TYPE(); /** * @brief Service property name for a description. * * The property value must be of type \c std::string. * * @return The property name. */ static std::string PROP_DESCRIPTION(); /** * @brief Service property name for the mime-type associated with this file writer. * * The property value must be of type \c std::string. * * @return The property name. */ static std::string PROP_MIMETYPE(); }; } // namespace mitk US_DECLARE_SERVICE_INTERFACE(mitk::IFileWriter, "org.mitk.IFileWriter") #endif /* IFileWriter_H_HEADER_INCLUDED_C1E7E521 */ diff --git a/Core/Code/Interfaces/mitkIMimeType.cpp b/Core/Code/Interfaces/mitkIMimeType.cpp deleted file mode 100644 index 3f9a1b5363..0000000000 --- a/Core/Code/Interfaces/mitkIMimeType.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/*=================================================================== - -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 "mitkIMimeType.h" - -namespace mitk { - -IMimeType::~IMimeType() -{ -} - -std::string IMimeType::PROP_ID() -{ - static std::string s = "org.mitk.IMimeType.id"; - return s; -} - -std::string IMimeType::PROP_CATEGORY() -{ - static std::string s = "org.mitk.IMimeType.category"; - return s; -} - -std::string IMimeType::PROP_EXTENSIONS() -{ - static std::string s = "org.mitk.IMimeType.extensions"; - return s; -} - -std::string IMimeType::PROP_DESCRIPTION() -{ - static std::string s = "org.mitk.IMimeType.description"; - return s; -} - -} diff --git a/Core/Code/Interfaces/mitkIMimeType.h b/Core/Code/Interfaces/mitkIMimeType.h deleted file mode 100644 index d2a6e6596c..0000000000 --- a/Core/Code/Interfaces/mitkIMimeType.h +++ /dev/null @@ -1,54 +0,0 @@ -/*=================================================================== - -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 MITKIMIMETYPE_H -#define MITKIMIMETYPE_H - -#include - -#include "usServiceInterface.h" - -#include - -namespace mitk { - -/** - * @brief A service interface for mime type information. - * - * The service property PROP_ID() contains the actual mime-type, - * e.g. "image/png". PROP_CATEGORY() is used in file dialogs to - * group related types. The extensions associated with a mime-type - * are specified in PROP_EXTENSIONS() (typcially only one, but - * sometimes more) and a longer format description can be provided - * with the PROP_DESCRIPTION() property. - */ -struct MITK_CORE_EXPORT IMimeType -{ - virtual ~IMimeType(); - - virtual std::string GetMagicPatterns() const = 0; - - static std::string PROP_ID(); - static std::string PROP_CATEGORY(); - static std::string PROP_EXTENSIONS(); - static std::string PROP_DESCRIPTION(); -}; - -} - -US_DECLARE_SERVICE_INTERFACE(mitk::IMimeType, "org.mitk.IMimeType") - -#endif // MITKIMIMETYPE_H diff --git a/Core/Code/Interfaces/mitkIMimeTypeProvider.h b/Core/Code/Interfaces/mitkIMimeTypeProvider.h index 8378f2a564..f8431a2ccd 100644 --- a/Core/Code/Interfaces/mitkIMimeTypeProvider.h +++ b/Core/Code/Interfaces/mitkIMimeTypeProvider.h @@ -1,74 +1,73 @@ /*=================================================================== 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 MITKIMIMETYPEPROVIDER_H #define MITKIMIMETYPEPROVIDER_H #include +#include + #include +#include #include namespace mitk { /** * @brief The IMimeTypeProvider service interface allows to query all registered * mime types. * * Mime types are added to the system by registering a service object of type - * IMimeType and the registered mime types can be queried bei either using direct + * CustomMimeType and the registered mime types can be queried bei either using direct * look-ups in the service registry or calling the methods of this service interface. * * This service interface also allows to infer the mime type of a file on the file * system. The heuristics for infering the actual mime type is implementation specific. * * @note This is a core service * - * @sa IMimeType + * @sa CustomMimeType * @sa CoreServices::GetMimeTypeProvider() */ struct MITK_CORE_EXPORT IMimeTypeProvider { virtual ~IMimeTypeProvider(); - virtual std::vector GetMimeTypes() const = 0; - - virtual std::vector GetMimeTypesForFile(const std::string& filePath) const = 0; - - virtual std::vector GetMimeTypesForExtension(const std::string& extension) const = 0; + virtual std::vector GetMimeTypes() const = 0; - virtual std::vector GetMimeTypesForCategory(const std::string& category) const = 0; + virtual std::vector GetMimeTypesForFile(const std::string& filePath) const = 0; - virtual std::string GetDescription(const std::string& mimeType) const = 0; + virtual std::vector GetMimeTypesForExtension(const std::string& extension) const = 0; - virtual std::vector GetExtensions(const std::string& mimeType) const = 0; + virtual std::vector GetMimeTypesForCategory(const std::string& category) const = 0; - virtual std::string GetCategory(const std::string& mimeType) const = 0; + virtual MimeType GetMimeTypeForName(const std::string& name) const = 0; /** * @brief Get a sorted and unique list of mime-type categories. * @return A sorted, unique list of mime-type categories. */ virtual std::vector GetCategories() const = 0; }; } US_DECLARE_SERVICE_INTERFACE(mitk::IMimeTypeProvider, "org.mitk.IMimeTypeProvider") #endif // MITKIMIMETYPEPROVIDER_H diff --git a/Core/Code/Internal/mitkCoreActivator.cpp b/Core/Code/Internal/mitkCoreActivator.cpp index 04c581ed48..09097e5236 100644 --- a/Core/Code/Internal/mitkCoreActivator.cpp +++ b/Core/Code/Internal/mitkCoreActivator.cpp @@ -1,391 +1,374 @@ /*=================================================================== 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 "mitkCoreActivator.h" // File IO #include #include #include #include #include #include // Micro Services #include #include #include #include #include #include #include #include #include #include #include void HandleMicroServicesMessages(us::MsgType type, const char* msg) { switch (type) { case us::DebugMsg: MITK_DEBUG << msg; break; case us::InfoMsg: MITK_INFO << msg; break; case us::WarningMsg: MITK_WARN << msg; break; case us::ErrorMsg: MITK_ERROR << msg; break; } } void AddMitkAutoLoadPaths(const std::string& programPath) { us::ModuleSettings::AddAutoLoadPath(programPath); #ifdef __APPLE__ // Walk up three directories since that is where the .dylib files are located // for build trees. std::string additionalPath = programPath; bool addPath = true; for(int i = 0; i < 3; ++i) { std::size_t index = additionalPath.find_last_of('/'); if (index != std::string::npos) { additionalPath = additionalPath.substr(0, index); } else { addPath = false; break; } } if (addPath) { us::ModuleSettings::AddAutoLoadPath(additionalPath); } #endif } class ShaderRepositoryTracker : public us::ServiceTracker { public: ShaderRepositoryTracker() : Superclass(us::GetModuleContext()) { } virtual void Close() { us::GetModuleContext()->RemoveModuleListener(this, &ShaderRepositoryTracker::HandleModuleEvent); Superclass::Close(); } virtual void Open() { us::GetModuleContext()->AddModuleListener(this, &ShaderRepositoryTracker::HandleModuleEvent); Superclass::Open(); } private: typedef us::ServiceTracker Superclass; TrackedType AddingService(const ServiceReferenceType &reference) { mitk::IShaderRepository* shaderRepo = Superclass::AddingService(reference); if (shaderRepo) { // Add all existing shaders from modules to the new shader repository. // If the shader repository is registered in a modules activator, the // GetLoadedModules() function call below will also return the module // which is currently registering the repository. The HandleModuleEvent // method contains code to avoid double registrations due to a fired // ModuleEvent::LOADED event after the activators Load() method finished. std::vector modules = us::ModuleRegistry::GetLoadedModules(); for (std::vector::const_iterator iter = modules.begin(), endIter = modules.end(); iter != endIter; ++iter) { this->AddModuleShaderToRepository(*iter, shaderRepo); } m_ShaderRepositories.push_back(shaderRepo); } return shaderRepo; } void RemovedService(const ServiceReferenceType& /*reference*/, TrackedType tracked) { m_ShaderRepositories.erase(std::remove(m_ShaderRepositories.begin(), m_ShaderRepositories.end(), tracked), m_ShaderRepositories.end()); } void HandleModuleEvent(const us::ModuleEvent moduleEvent) { if (moduleEvent.GetType() == us::ModuleEvent::LOADED) { std::vector shaderRepos; for (std::map > >::const_iterator shaderMapIter = m_ModuleIdToShaderIds.begin(), shaderMapEndIter = m_ModuleIdToShaderIds.end(); shaderMapIter != shaderMapEndIter; ++shaderMapIter) { if (shaderMapIter->second.find(moduleEvent.GetModule()->GetModuleId()) == shaderMapIter->second.end()) { shaderRepos.push_back(shaderMapIter->first); } } AddModuleShadersToRepositories(moduleEvent.GetModule(), shaderRepos); } else if (moduleEvent.GetType() == us::ModuleEvent::UNLOADED) { RemoveModuleShadersFromRepositories(moduleEvent.GetModule(), m_ShaderRepositories); } } void AddModuleShadersToRepositories(us::Module* module, const std::vector& shaderRepos) { // search and load shader files std::vector shaderResources = module->FindResources("Shaders", "*.xml", true); for (std::vector::iterator i = shaderResources.begin(); i != shaderResources.end(); ++i) { if (*i) { us::ModuleResourceStream rs(*i); for (std::vector::const_iterator shaderRepoIter = shaderRepos.begin(), shaderRepoEndIter = shaderRepos.end(); shaderRepoIter != shaderRepoEndIter; ++shaderRepoIter) { int id = (*shaderRepoIter)->LoadShader(rs, i->GetBaseName()); if (id >= 0) { m_ModuleIdToShaderIds[*shaderRepoIter][module->GetModuleId()].push_back(id); } } rs.seekg(0, std::ios_base::beg); } } } void AddModuleShaderToRepository(us::Module* module, mitk::IShaderRepository* shaderRepo) { std::vector shaderRepos; shaderRepos.push_back(shaderRepo); this->AddModuleShadersToRepositories(module, shaderRepos); } void RemoveModuleShadersFromRepositories(us::Module* module, const std::vector& shaderRepos) { for (std::vector::const_iterator shaderRepoIter = shaderRepos.begin(), shaderRepoEndIter = shaderRepos.end(); shaderRepoIter != shaderRepoEndIter; ++shaderRepoIter) { std::map >& moduleIdToShaderIds = m_ModuleIdToShaderIds[*shaderRepoIter]; std::map >::iterator shaderIdsIter = moduleIdToShaderIds.find(module->GetModuleId()); if (shaderIdsIter != moduleIdToShaderIds.end()) { for (std::vector::iterator idIter = shaderIdsIter->second.begin(); idIter != shaderIdsIter->second.end(); ++idIter) { (*shaderRepoIter)->UnloadShader(*idIter); } moduleIdToShaderIds.erase(shaderIdsIter); } } } private: // Maps to each shader repository a map containing module ids and related // shader registration ids std::map > > m_ModuleIdToShaderIds; std::vector m_ShaderRepositories; }; void MitkCoreActivator::Load(us::ModuleContext* context) { // Handle messages from CppMicroServices us::installMsgHandler(HandleMicroServicesMessages); this->m_Context = context; // Add the current application directory to the auto-load paths. // This is useful for third-party executables. std::string programPath = mitk::IOUtil::GetProgramPath(); if (programPath.empty()) { MITK_WARN << "Could not get the program path."; } else { AddMitkAutoLoadPaths(programPath); } m_ShaderRepositoryTracker.reset(new ShaderRepositoryTracker); //m_RenderingManager = mitk::RenderingManager::New(); //context->RegisterService(renderingManager.GetPointer()); m_PlanePositionManager.reset(new mitk::PlanePositionManagerService); context->RegisterService(m_PlanePositionManager.get()); m_PropertyAliases.reset(new mitk::PropertyAliases); context->RegisterService(m_PropertyAliases.get()); m_PropertyDescriptions.reset(new mitk::PropertyDescriptions); context->RegisterService(m_PropertyDescriptions.get()); m_PropertyExtensions.reset(new mitk::PropertyExtensions); context->RegisterService(m_PropertyExtensions.get()); m_PropertyFilters.reset(new mitk::PropertyFilters); context->RegisterService(m_PropertyFilters.get()); m_MimeTypeProvider.reset(new mitk::MimeTypeProvider); m_MimeTypeProvider->Start(); m_MimeTypeProviderReg = context->RegisterService(m_MimeTypeProvider.get()); - this->RegisterMimeTypes(); + this->RegisterDefaultMimeTypes(); this->RegisterItkReaderWriter(); // Add custom Reader / Writer Services m_FileReaders.push_back(new mitk::PointSetReaderService()); m_FileWriters.push_back(new mitk::PointSetWriterService()); m_FileReaders.push_back(new mitk::RawImageFileReader()); // Explicitly load the LegacyIO module us::SharedLibrary legacyIOLib(programPath, "MitkLegacyIO"); legacyIOLib.Load(); m_ShaderRepositoryTracker->Open(); /* There IS an option to exchange ALL vtkTexture instances against vtkNeverTranslucentTextureFactory. This code is left here as a reminder, just in case we might need to do that some time. vtkNeverTranslucentTextureFactory* textureFactory = vtkNeverTranslucentTextureFactory::New(); vtkObjectFactory::RegisterFactory( textureFactory ); textureFactory->Delete(); */ } void MitkCoreActivator::Unload(us::ModuleContext* ) { for(std::vector::iterator iter = m_FileReaders.begin(), endIter = m_FileReaders.end(); iter != endIter; ++iter) { delete *iter; } for(std::vector::iterator iter = m_FileWriters.begin(), endIter = m_FileWriters.end(); iter != endIter; ++iter) { delete *iter; } for(std::vector::iterator iter = m_FileIOs.begin(), endIter = m_FileIOs.end(); iter != endIter; ++iter) { delete *iter; } // The mitk::ModuleContext* argument of the Unload() method // will always be 0 for the Mitk library. It makes no sense // to use it at this stage anyway, since all libraries which // know about the module system have already been unloaded. // we need to close the internal service tracker of the // MimeTypeProvider class here. Otherwise it // would hold on to the ModuleContext longer than it is // actually valid. m_MimeTypeProviderReg.Unregister(); m_MimeTypeProvider->Stop(); m_ShaderRepositoryTracker->Close(); } -void MitkCoreActivator::RegisterMimeTypes() +void MitkCoreActivator::RegisterDefaultMimeTypes() { // Register some default mime-types - // 3D Images - std::vector mimeTypeExtensions; - mimeTypeExtensions.push_back("dc3"); - mimeTypeExtensions.push_back("dcm"); - RegisterMimeType("application/dicom", "Images", "Dicom Images", mimeTypeExtensions); - RegisterMimeType("application/vnd.mitk.pic", "Images", "DKFZ PIC Format", "pic"); - RegisterMimeType("application/vnd.mitk.pic+gz", "Images", "DKFZ Compressed PIC Format", "pic.gz"); - - // REMOVE: Test multiple mime types for same extension - //RegisterMimeType("application/vnd.fancy", "Images", "Fancy Compressed PIC Format", "pic.gz"); - - // 2D Images - RegisterMimeType("image/bmp", "2D Images", "Bitmap Image", "bmp"); + // Custom MITK point set format + mitk::CustomMimeType pointSetMimeType("application/vnd.mitk.pointset"); + pointSetMimeType.AddExtension("mps"); + pointSetMimeType.SetCategory("Point Sets"); + pointSetMimeType.SetComment("MITK Point Set"); + m_DefaultMimeTypes.push_back(pointSetMimeType); + m_Context->RegisterService(&m_DefaultMimeTypes.back()); + + // Register the NRRD format early on + mitk::CustomMimeType nrrdMimeType("application/vnd.mitk.nrrd"); + nrrdMimeType.AddExtension("nrrd"); + nrrdMimeType.AddExtension("nhdr"); + nrrdMimeType.SetCategory("Images"); + nrrdMimeType.SetComment("NRRD"); + m_DefaultMimeTypes.push_back(nrrdMimeType); + m_Context->RegisterService(&m_DefaultMimeTypes.back()); } void MitkCoreActivator::RegisterItkReaderWriter() { std::list allobjects = itk::ObjectFactoryBase::CreateAllInstance("itkImageIOBase"); for (std::list::iterator i = allobjects.begin(), endIter = allobjects.end(); i != endIter; ++i) { itk::ImageIOBase* io = dynamic_cast(i->GetPointer()); if (io) { m_FileIOs.push_back(new mitk::ItkImageIO(io)); } else { MITK_WARN << "Error ImageIO factory did not return an ImageIOBase: " << ( *i )->GetNameOfClass(); } } } -void MitkCoreActivator::RegisterMimeType(const std::string& id, const std::string& category, - const std::string& description, const std::string& extension) -{ - std::vector extensions; - extensions.push_back(extension); - this->RegisterMimeType(id, category, description, extensions); -} - -void MitkCoreActivator::RegisterMimeType(const std::string& id, const std::string& category, - const std::string& description, const std::vector& extensions) -{ - us::ServiceProperties mimeTypeProps; - mimeTypeProps[mitk::IMimeType::PROP_ID()] = id; - mimeTypeProps[mitk::IMimeType::PROP_CATEGORY()] = category; - mimeTypeProps[mitk::IMimeType::PROP_DESCRIPTION()] = description; - mimeTypeProps[mitk::IMimeType::PROP_EXTENSIONS()] = extensions; - mimeTypeProps[us::ServiceConstants::SERVICE_RANKING()] = -100; - m_Context->RegisterService(&m_MimeType, mimeTypeProps); -} - US_EXPORT_MODULE_ACTIVATOR(MitkCore, MitkCoreActivator) // Call CppMicroservices initialization code at the end of the file. // This especially ensures that VTK object factories have already // been registered (VTK initialization code is injected by implicitly // include VTK header files at the top of this file). US_INITIALIZE_MODULE("MitkCore", "MitkCore") diff --git a/Core/Code/Internal/mitkCoreActivator.h b/Core/Code/Internal/mitkCoreActivator.h index 9c72057d0e..cbb803c14b 100644 --- a/Core/Code/Internal/mitkCoreActivator.h +++ b/Core/Code/Internal/mitkCoreActivator.h @@ -1,89 +1,82 @@ /*=================================================================== 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 MITKCOREACTIVATOR_H_ #define MITKCOREACTIVATOR_H_ // File IO #include #include #include -#include #include #include #include #include #include #include #include // Micro Services #include #include #include #include #include /* * This is the module activator for the "Mitk" module. It registers core services * like ... */ class MitkCoreActivator : public us::ModuleActivator { public: void Load(us::ModuleContext* context); void Unload(us::ModuleContext* ); private: void HandleModuleEvent(const us::ModuleEvent moduleEvent); - void RegisterMimeTypes(); + void RegisterDefaultMimeTypes(); void RegisterItkReaderWriter(); - void RegisterMimeType(const std::string& id, const std::string& category, - const std::string& description, const std::string& extension); - - void RegisterMimeType(const std::string& id, const std::string& category, - const std::string& description, const std::vector& extensions); - std::auto_ptr > m_ShaderRepositoryTracker; //mitk::RenderingManager::Pointer m_RenderingManager; std::auto_ptr m_PlanePositionManager; std::auto_ptr m_PropertyAliases; std::auto_ptr m_PropertyDescriptions; std::auto_ptr m_PropertyExtensions; std::auto_ptr m_PropertyFilters; std::auto_ptr m_MimeTypeProvider; // File IO std::vector m_FileReaders; std::vector m_FileWriters; std::vector m_FileIOs; - us::ServiceRegistration m_MimeTypeProviderReg; + std::vector m_DefaultMimeTypes; - mitk::SimpleMimeType m_MimeType; + us::ServiceRegistration m_MimeTypeProviderReg; us::ModuleContext* m_Context; }; #endif // MITKCOREACTIVATOR_H_ diff --git a/Core/Code/Internal/mitkFileReaderWriterBase.cpp b/Core/Code/Internal/mitkFileReaderWriterBase.cpp index 5551b7fb8a..1b38f28c76 100644 --- a/Core/Code/Internal/mitkFileReaderWriterBase.cpp +++ b/Core/Code/Internal/mitkFileReaderWriterBase.cpp @@ -1,253 +1,209 @@ /*=================================================================== 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 "mitkFileReaderWriterBase.h" #include "mitkLogMacros.h" #include "mitkCoreServices.h" #include "mitkIMimeTypeProvider.h" #include #include namespace mitk { FileReaderWriterBase::FileReaderWriterBase() : m_Ranking(0) { } +FileReaderWriterBase::~FileReaderWriterBase() +{ + this->UnregisterMimeType(); +} + FileReaderWriterBase::FileReaderWriterBase(const FileReaderWriterBase& other) - : m_MimeType(other.m_MimeType) - , m_Category(other.m_Category) - , m_Extensions(other.m_Extensions) - , m_Description(other.m_Description) + : m_Description(other.m_Description) , m_Ranking(other.m_Ranking) , m_Options(other.m_Options) , m_DefaultOptions(other.m_DefaultOptions) + , m_CustomMimeType(other.m_CustomMimeType) { } FileReaderWriterBase::Options FileReaderWriterBase::GetOptions() const { Options options = m_Options; options.insert(m_DefaultOptions.begin(), m_DefaultOptions.end()); return options; } us::Any FileReaderWriterBase::GetOption(const std::string& name) const { Options::const_iterator iter = m_Options.find(name); if (iter != m_Options.end()) { return iter->second; } iter = m_DefaultOptions.find(name); if (iter != m_DefaultOptions.end()) { return iter->second; } return us::Any(); } void FileReaderWriterBase::SetOptions(const FileReaderWriterBase::Options& options) { for(Options::const_iterator iter = options.begin(), iterEnd = options.end(); iter != iterEnd; ++iter) { this->SetOption(iter->first, iter->second); } } void FileReaderWriterBase::SetOption(const std::string& name, const us::Any& value) { if (m_DefaultOptions.find(name) == m_DefaultOptions.end()) { MITK_WARN << "Ignoring unknown IFileReader option '" << name << "'"; } else { if (value.Empty()) { // an empty Any signals 'reset to default value' m_Options.erase(name); } else { m_Options[name] = value; } } } void FileReaderWriterBase::SetDefaultOptions(const FileReaderWriterBase::Options& defaultOptions) { m_DefaultOptions = defaultOptions; } FileReaderWriterBase::Options FileReaderWriterBase::GetDefaultOptions() const { return m_DefaultOptions; } void FileReaderWriterBase::SetRanking(int ranking) { m_Ranking = ranking; } int FileReaderWriterBase::GetRanking() const { return m_Ranking; } -void FileReaderWriterBase::SetMimeType(const std::string& mimeType) -{ - m_MimeType = mimeType; -} - -std::string FileReaderWriterBase::GetMimeType() const -{ - return m_MimeType; -} - -void FileReaderWriterBase::AddExtension(const std::string& extension) +void FileReaderWriterBase::SetMimeType(const CustomMimeType& mimeType) { - m_Extensions.push_back(extension); + m_CustomMimeType = mimeType; } -std::vector FileReaderWriterBase::GetExtensions() const +CustomMimeType FileReaderWriterBase::GetMimeType() const { - return m_Extensions; + return m_CustomMimeType; } -bool FileReaderWriterBase::HasExtension(const std::string& extension) +CustomMimeType&FileReaderWriterBase::GetMimeType() { - return std::find(m_Extensions.begin(), m_Extensions.end(), extension) != m_Extensions.end(); + return m_CustomMimeType; } void FileReaderWriterBase::SetDescription(const std::string& description) { m_Description = description; } std::string FileReaderWriterBase::GetDescription() const { return m_Description; } -void FileReaderWriterBase::SetCategory(const std::string& category) -{ - m_Category = category; -} - -std::string FileReaderWriterBase::GetCategory() const -{ - return m_Category; -} - void FileReaderWriterBase::AddProgressCallback(const FileReaderWriterBase::ProgressCallback& callback) { m_ProgressMessage += callback; } void FileReaderWriterBase::RemoveProgressCallback(const FileReaderWriterBase::ProgressCallback& callback) { m_ProgressMessage -= callback; } -us::ServiceRegistration FileReaderWriterBase::RegisterMimeType(us::ModuleContext* context) +us::ServiceRegistration FileReaderWriterBase::RegisterMimeType(us::ModuleContext* context) { if (context == NULL) throw std::invalid_argument("The context argument must not be NULL."); - const std::string mimeType = this->GetMimeType(); - std::vector extensions = this->GetExtensions(); - const std::string primaryExtension = extensions.empty() ? "" : extensions.front(); - std::sort(extensions.begin(), extensions.end()); - extensions.erase(std::unique(extensions.begin(), extensions.end()), extensions.end()); - - us::ServiceProperties props; + CoreServicePointer mimeTypeProvider(CoreServices::GetMimeTypeProvider(context)); - props[IMimeType::PROP_ID()] = mimeType; - props[IMimeType::PROP_CATEGORY()] = this->GetCategory(); - props[IMimeType::PROP_EXTENSIONS()] = extensions; - props[IMimeType::PROP_DESCRIPTION()] = std::string("Synthesized MIME type"); - props[us::ServiceConstants::SERVICE_RANKING()] = this->GetRanking(); + const std::vector extensions = m_CustomMimeType.GetExtensions(); - // If the mime type is set and the list of extensions is not empty, - // register a new IMimeType service - if (!mimeType.empty() && !extensions.empty()) - { - return context->RegisterService(&m_SimpleMimeType, props); - } - - // If the mime type is set and the list of extensions is empty, + // If the mime type name is set and the list of extensions is empty, // look up the mime type in the registry and print a warning if // there is none - if (!mimeType.empty() && extensions.empty()) + if (!m_CustomMimeType.GetName().empty() && extensions.empty()) { - if(us::GetModuleContext()->GetServiceReferences(us::LDAPProp(IMimeType::PROP_ID()) == mimeType).empty()) + if(!mimeTypeProvider->GetMimeTypeForName(m_CustomMimeType.GetName()).IsValid()) { - MITK_WARN << "Registering a MITK reader or writer with an unknown MIME type " << mimeType; + MITK_WARN << "Registering a MITK reader or writer with an unknown MIME type " << m_CustomMimeType.GetName(); } - return us::ServiceRegistration(); + return m_MimeTypeReg; } - // If the mime type is empty, get a mime type using the extensions list - assert(mimeType.empty()); - mitk::CoreServicePointer mimeTypeProvider(mitk::CoreServices::GetMimeTypeProvider()); - - if(extensions.empty()) + // If the mime type name is empty, get a mime type using the extensions list + if(m_CustomMimeType.GetName().empty() && extensions.empty()) { - MITK_WARN << "Trying to register a MITK reader or writer with an empty mime type and empty extension list."; - return us::ServiceRegistration(); - } - else if(extensions.size() == 1) - { - // If there is only one extension, try to look-up an existing mime tpye - std::vector mimeTypes = mimeTypeProvider->GetMimeTypesForExtension(extensions.front()); - if (!mimeTypes.empty()) - { - m_MimeType = mimeTypes.front(); - } + MITK_WARN << "Trying to register a MITK reader or writer with an empty mime type name and empty extension list."; + return m_MimeTypeReg; } - if (m_MimeType.empty()) + // extensions is not empty, so register a mime-type + if(m_CustomMimeType.GetName().empty()) { - // There is no registered mime type for the extension or the extensions - // list contains more than one entry. - // Register a new mime type by creating a synthetic mime type id from the + // Register a new mime type by creating a synthetic mime type name from the // first extension in the list - m_MimeType = "application/vnd.mitk." + primaryExtension; - props[IMimeType::PROP_ID()] = m_MimeType; - return context->RegisterService(&m_SimpleMimeType, props); - } - else - { - // A mime type for one of the listed extensions was found, do nothing. - return us::ServiceRegistration(); + m_CustomMimeType.SetName("application/vnd.mitk." + extensions.front()); } + m_MimeTypeReg = context->RegisterService(&m_CustomMimeType); + + return m_MimeTypeReg; } void FileReaderWriterBase::UnregisterMimeType() { if (m_MimeTypeReg) { - m_MimeTypeReg.Unregister(); + try + { + m_MimeTypeReg.Unregister(); + } + catch (const std::logic_error&) + { + // service already unregistered + } } } } diff --git a/Core/Code/Internal/mitkFileReaderWriterBase.h b/Core/Code/Internal/mitkFileReaderWriterBase.h index a7c0888234..f9ed3cdb58 100644 --- a/Core/Code/Internal/mitkFileReaderWriterBase.h +++ b/Core/Code/Internal/mitkFileReaderWriterBase.h @@ -1,114 +1,106 @@ /*=================================================================== 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 MITKFILEREADERWRITERBASE_H #define MITKFILEREADERWRITERBASE_H #include -#include +#include #include #include #include namespace mitk { class FileReaderWriterBase { public: typedef std::map Options; typedef mitk::MessageAbstractDelegate1 ProgressCallback; FileReaderWriterBase(); + ~FileReaderWriterBase(); Options GetOptions() const; us::Any GetOption(const std::string &name) const; void SetOptions(const Options& options); void SetOption(const std::string& name, const us::Any& value); void SetDefaultOptions(const Options& defaultOptions); Options GetDefaultOptions() const; /** * \brief Set the service ranking for this file reader. * * Default is zero and should only be chosen differently for a reason. * The ranking is used to determine which reader to use if several * equivalent readers have been found. * It may be used to replace a default reader from MITK in your own project. * E.g. if you want to use your own reader for nrrd files instead of the default, * implement it and give it a higher ranking than zero. */ void SetRanking(int ranking); int GetRanking() const; - void SetMimeType(const std::string& mimeType); - std::string GetMimeType() const; - - void AddExtension(const std::string& extension); - std::vector GetExtensions() const; - bool HasExtension(const std::string& extension); + void SetMimeType(const CustomMimeType& mimeType); + CustomMimeType GetMimeType() const; + CustomMimeType& GetMimeType(); void SetDescription(const std::string& description); std::string GetDescription() const; - void SetCategory(const std::string& category); - std::string GetCategory() const; - void AddProgressCallback(const ProgressCallback& callback); void RemoveProgressCallback(const ProgressCallback& callback); - us::ServiceRegistration RegisterMimeType(us::ModuleContext* context); + us::ServiceRegistration RegisterMimeType(us::ModuleContext* context); void UnregisterMimeType(); protected: FileReaderWriterBase(const FileReaderWriterBase& other); - std::string m_MimeType; - std::string m_Category; - std::vector m_Extensions; std::string m_Description; int m_Ranking; /** * \brief Options supported by this reader. Set sensible default values! * * Can be left emtpy if no special options are required. */ Options m_Options; Options m_DefaultOptions; //us::PrototypeServiceFactory* m_PrototypeFactory; Message1 m_ProgressMessage; - SimpleMimeType m_SimpleMimeType; - us::ServiceRegistration m_MimeTypeReg; + CustomMimeType m_CustomMimeType; + us::ServiceRegistration m_MimeTypeReg; private: // purposely not implemented FileReaderWriterBase& operator=(const FileReaderWriterBase& other); }; } #endif // MITKFILEREADERWRITERBASE_H diff --git a/Core/Code/Internal/mitkItkImageIO.cpp b/Core/Code/Internal/mitkItkImageIO.cpp index a77779ec3f..26c89810b2 100644 --- a/Core/Code/Internal/mitkItkImageIO.cpp +++ b/Core/Code/Internal/mitkItkImageIO.cpp @@ -1,313 +1,486 @@ /*=================================================================== 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 "mitkItkImageIO.h" #include -#include +#include +#include #include #include #include #include #include namespace mitk { ItkImageIO::ItkImageIO(const ItkImageIO& other) : AbstractFileIO(other) + , m_ImageIO(dynamic_cast(other.m_ImageIO->Clone().GetPointer())) { } std::vector ItkImageIO::FixUpImageIOExtensions(const std::string& imageIOName) { std::vector extensions; // Try to fix-up some known ITK image IO classes if (imageIOName == "GiplImageIO") { extensions.push_back("gipl"); extensions.push_back("gipl.gz"); } else if (imageIOName == "GDCMImageIO") { extensions.push_back("gdcm"); } else if (imageIOName == "PNGImageIO") { extensions.push_back("png"); extensions.push_back("PNG"); } else if (imageIOName == "StimulateImageIO") { extensions.push_back("spr"); } else if (imageIOName == "HDF5ImageIO") { extensions.push_back("hdf"); extensions.push_back("h4"); extensions.push_back("hdf4"); extensions.push_back("h5"); extensions.push_back("hdf5"); extensions.push_back("he4"); extensions.push_back("he5"); extensions.push_back("hd5"); } if (!extensions.empty()) { MITK_WARN << "Fixing up known extensions for " << imageIOName; } return extensions; } ItkImageIO::ItkImageIO(itk::ImageIOBase::Pointer imageIO) - : AbstractFileIO() + : AbstractFileIO(Image::GetStaticNameOfClass()) , m_ImageIO(imageIO) { - std::vector extensions = imageIO->GetSupportedReadExtensions(); - if (extensions.empty()) + if (m_ImageIO.IsNull() ) { - std::string imageIOName = imageIO->GetNameOfClass(); + mitkThrow() << "ITK ImageIOBase argument must not be NULL"; + } + + std::vector readExtensions = m_ImageIO->GetSupportedReadExtensions(); + if (readExtensions.empty()) + { + std::string imageIOName = m_ImageIO->GetNameOfClass(); MITK_WARN << "ITK ImageIOBase " << imageIOName << " does not provide read extensions"; - extensions = FixUpImageIOExtensions(imageIOName); + readExtensions = FixUpImageIOExtensions(imageIOName); } - for(std::vector::const_iterator iter = extensions.begin(), - endIter = extensions.end(); iter != endIter; ++iter) + + CustomMimeType customReaderMimeType; + customReaderMimeType.SetCategory("Images"); + for(std::vector::const_iterator iter = readExtensions.begin(), + endIter = readExtensions.end(); iter != endIter; ++iter) { std::string extension = *iter; if (!extension.empty() && extension[0] == '.') { - extension.assign(extension.begin()+1, extension.end()); + extension.assign(iter->begin()+1, iter->end()); } - this->AbstractFileReader::AddExtension(extension); + customReaderMimeType.AddExtension(extension); } + this->AbstractFileReader::SetMimeType(customReaderMimeType); - extensions = imageIO->GetSupportedWriteExtensions(); - if (extensions.empty()) + std::vector writeExtensions = imageIO->GetSupportedWriteExtensions(); + if (writeExtensions.empty()) { std::string imageIOName = imageIO->GetNameOfClass(); MITK_WARN << "ITK ImageIOBase " << imageIOName << " does not provide write extensions"; - extensions = FixUpImageIOExtensions(imageIOName); + writeExtensions = FixUpImageIOExtensions(imageIOName); } - for(std::vector::const_iterator iter = extensions.begin(), - endIter = extensions.end(); iter != endIter; ++iter) + + CustomMimeType customWriterMimeType; + customWriterMimeType.SetCategory("Images"); + if (writeExtensions == readExtensions) { - std::string extension = *iter; - if (!extension.empty() && extension[0] == '.') + customWriterMimeType.AddExtension(customReaderMimeType.GetExtensions().front()); + } + else + { + for(std::vector::const_iterator iter = writeExtensions.begin(), + endIter = writeExtensions.end(); iter != endIter; ++iter) { - extension.assign(extension.begin()+1, extension.end()); + std::string extension = *iter; + if (!extension.empty() && extension[0] == '.') + { + extension.assign(iter->begin()+1, iter->end()); + } + customWriterMimeType.AddExtension(extension); } - this->AbstractFileWriter::AddExtension(extension); } - - this->SetCategory("Images"); + this->AbstractFileWriter::SetMimeType(customWriterMimeType); std::string description = std::string("ITK ") + imageIO->GetNameOfClass(); this->SetReaderDescription(description); this->SetWriterDescription(description); this->RegisterService(); } std::vector ItkImageIO::Read(std::istream& stream) { return mitk::AbstractFileReader::Read(stream); } std::vector ItkImageIO::Read(const std::string& path) { std::vector result; const std::string& locale = "C"; const std::string& currLocale = setlocale( LC_ALL, NULL ); if ( locale.compare(currLocale)!=0 ) { try { setlocale(LC_ALL, locale.c_str()); } catch(...) { MITK_INFO << "Could not set locale " << locale; } } Image::Pointer image = Image::New(); const unsigned int MINDIM = 2; const unsigned int MAXDIM = 4; MITK_INFO << "loading " << path << " via itk::ImageIOFactory... " << std::endl; // Check to see if we can read the file given the name or prefix if (path.empty()) { mitkThrow() << "Empty filename in mitk::ItkImageIO "; } - itk::ImageIOBase::Pointer imageIO = itk::ImageIOFactory::CreateImageIO( path.c_str(), itk::ImageIOFactory::ReadMode ); - if ( imageIO.IsNull() ) - { - mitkThrow() << "Could not create itk::ImageIOBase object for filename " << path; - } - // Got to allocate space for the image. Determine the characteristics of // the image. - imageIO->SetFileName( path.c_str() ); - imageIO->ReadImageInformation(); + m_ImageIO->SetFileName( path.c_str() ); + m_ImageIO->ReadImageInformation(); - unsigned int ndim = imageIO->GetNumberOfDimensions(); + unsigned int ndim = m_ImageIO->GetNumberOfDimensions(); if ( ndim < MINDIM || ndim > MAXDIM ) { MITK_WARN << "Sorry, only dimensions 2, 3 and 4 are supported. The given file has " << ndim << " dimensions! Reading as 4D."; ndim = MAXDIM; } itk::ImageIORegion ioRegion( ndim ); itk::ImageIORegion::SizeType ioSize = ioRegion.GetSize(); itk::ImageIORegion::IndexType ioStart = ioRegion.GetIndex(); unsigned int dimensions[ MAXDIM ]; dimensions[ 0 ] = 0; dimensions[ 1 ] = 0; dimensions[ 2 ] = 0; dimensions[ 3 ] = 0; ScalarType spacing[ MAXDIM ]; spacing[ 0 ] = 1.0f; spacing[ 1 ] = 1.0f; spacing[ 2 ] = 1.0f; spacing[ 3 ] = 1.0f; Point3D origin; origin.Fill(0); unsigned int i; for ( i = 0; i < ndim ; ++i ) { ioStart[ i ] = 0; - ioSize[ i ] = imageIO->GetDimensions( i ); + ioSize[ i ] = m_ImageIO->GetDimensions( i ); if(iGetDimensions( i ); - spacing[ i ] = imageIO->GetSpacing( i ); + dimensions[ i ] = m_ImageIO->GetDimensions( i ); + spacing[ i ] = m_ImageIO->GetSpacing( i ); if(spacing[ i ] <= 0) spacing[ i ] = 1.0f; } if(i<3) { - origin[ i ] = imageIO->GetOrigin( i ); + origin[ i ] = m_ImageIO->GetOrigin( i ); } } ioRegion.SetSize( ioSize ); ioRegion.SetIndex( ioStart ); MITK_INFO << "ioRegion: " << ioRegion << std::endl; - imageIO->SetIORegion( ioRegion ); - void* buffer = new unsigned char[imageIO->GetImageSizeInBytes()]; - imageIO->Read( buffer ); + m_ImageIO->SetIORegion( ioRegion ); + void* buffer = new unsigned char[m_ImageIO->GetImageSizeInBytes()]; + m_ImageIO->Read( buffer ); - image->Initialize( MakePixelType(imageIO), ndim, dimensions ); + image->Initialize( MakePixelType(m_ImageIO), ndim, dimensions ); image->SetImportChannel( buffer, 0, Image::ManageMemory ); // access direction of itk::Image and include spacing mitk::Matrix3D matrix; matrix.SetIdentity(); unsigned int j, itkDimMax3 = (ndim >= 3? 3 : ndim); for ( i=0; i < itkDimMax3; ++i) for( j=0; j < itkDimMax3; ++j ) - matrix[i][j] = imageIO->GetDirection(j)[i]; + matrix[i][j] = m_ImageIO->GetDirection(j)[i]; // re-initialize PlaneGeometry with origin and direction PlaneGeometry* planeGeometry = image->GetSlicedGeometry(0)->GetPlaneGeometry(0); planeGeometry->SetOrigin(origin); planeGeometry->GetIndexToWorldTransform()->SetMatrix(matrix); // re-initialize SlicedGeometry3D SlicedGeometry3D* slicedGeometry = image->GetSlicedGeometry(0); slicedGeometry->InitializeEvenlySpaced(planeGeometry, image->GetDimension(2)); slicedGeometry->SetSpacing(spacing); MITK_INFO << slicedGeometry->GetCornerPoint(false,false,false); MITK_INFO << slicedGeometry->GetCornerPoint(true,true,true); // re-initialize TimeGeometry ProportionalTimeGeometry::Pointer timeGeometry = ProportionalTimeGeometry::New(); timeGeometry->Initialize(slicedGeometry, image->GetDimension(3)); image->SetTimeGeometry(timeGeometry); buffer = NULL; MITK_INFO << "number of image components: "<< image->GetPixelType().GetNumberOfComponents() << std::endl; - const itk::MetaDataDictionary& dictionary = imageIO->GetMetaDataDictionary(); + const itk::MetaDataDictionary& dictionary = m_ImageIO->GetMetaDataDictionary(); for (itk::MetaDataDictionary::ConstIterator iter = dictionary.Begin(), iterEnd = dictionary.End(); iter != iterEnd; ++iter) { std::string key = std::string("meta.") + iter->first; if (iter->second->GetMetaDataObjectTypeInfo() == typeid(std::string)) { std::string value = dynamic_cast*>(iter->second.GetPointer())->GetMetaDataObjectValue(); image->SetProperty(key.c_str(), mitk::StringProperty::New(value)); } } MITK_INFO << "...finished!" << std::endl; try { setlocale(LC_ALL, currLocale.c_str()); } catch(...) { MITK_INFO << "Could not reset locale " << currLocale; } result.push_back(image.GetPointer()); return result; } - -bool mitk::ItkImageIO::CanRead(const std::string& path) const +AbstractFileIO::ReaderConfidenceLevel ItkImageIO::GetReaderConfidenceLevel(const std::string& path) const { - if (AbstractFileReader::CanRead(path) == false) return false; - - itk::ImageIOBase::Pointer imageIO = itk::ImageIOFactory::CreateImageIO(path.c_str(), itk::ImageIOFactory::ReadMode); - if (imageIO.IsNull()) - return false; - - return imageIO->CanReadFile(path.c_str()); + return m_ImageIO->CanReadFile(path.c_str()) ? IFileReader::Supported : IFileReader::Unsupported; } void ItkImageIO::Write(const BaseData* data, const std::string& path) { + const mitk::Image* image = dynamic_cast(data); + + if (image == NULL) + { + mitkThrow() << "Cannot write non-image data"; + } + + struct LocaleSwitch + { + LocaleSwitch(const std::string& newLocale) + : m_OldLocale(std::setlocale(LC_ALL, NULL)) + , m_NewLocale(newLocale) + { + if (m_OldLocale == NULL) + { + m_OldLocale = ""; + } + else if (m_NewLocale != m_OldLocale) + { + // set the locale + if (std::setlocale(LC_ALL, m_NewLocale.c_str()) == NULL) + { + MITK_INFO << "Could not set locale " << m_NewLocale; + m_OldLocale = NULL; + } + } + } + + ~LocaleSwitch() + { + if (m_OldLocale != NULL && std::setlocale(LC_ALL, m_OldLocale) == NULL) + { + MITK_INFO << "Could not reset locale " << m_OldLocale; + } + } + + private: + const char* m_OldLocale; + const std::string m_NewLocale; + }; + + // Switch the current locale to "C" + LocaleSwitch localeSwitch("C"); + + // Clone the image geometry, because we might have to change it + // for writing purposes + BaseGeometry::Pointer geometry = image->GetGeometry()->Clone(); + + // Check if geometry information will be lost + if (image->GetDimension() == 2 && + !geometry->Is2DConvertable()) + { + MITK_WARN << "Saving a 2D image with 3D geometry information. Geometry information will be lost! You might consider using Convert2Dto3DImageFilter before saving."; + + // set matrix to identity + mitk::AffineTransform3D::Pointer affTrans = mitk::AffineTransform3D::New(); + affTrans->SetIdentity(); + mitk::Vector3D spacing = geometry->GetSpacing(); + mitk::Point3D origin = geometry->GetOrigin(); + geometry->SetIndexToWorldTransform(affTrans); + geometry->SetSpacing(spacing); + geometry->SetOrigin(origin); + } + + MITK_INFO << "Writing image: " << path << std::endl; + + try + { + // Implementation of writer using itkImageIO directly. This skips the use + // of templated itkImageFileWriter, which saves the multiplexing on MITK side. + + const unsigned int dimension = image->GetDimension(); + const unsigned int* const dimensions = image->GetDimensions(); + const mitk::PixelType pixelType = image->GetPixelType(); + const mitk::Vector3D mitkSpacing = geometry->GetSpacing(); + const mitk::Point3D mitkOrigin = geometry->GetOrigin(); + + // Due to templating in itk, we are forced to save a 4D spacing and 4D Origin, + // though they are not supported in MITK + itk::Vector spacing4D; + spacing4D[0] = mitkSpacing[0]; + spacing4D[1] = mitkSpacing[1]; + spacing4D[2] = mitkSpacing[2]; + spacing4D[3] = 1; // There is no support for a 4D spacing. However, we should have a valid value here + + itk::Vector origin4D; + origin4D[0] = mitkOrigin[0]; + origin4D[1] = mitkOrigin[1]; + origin4D[2] = mitkOrigin[2]; + origin4D[3] = 0; // There is no support for a 4D origin. However, we should have a valid value here + + // Set the necessary information for imageIO + m_ImageIO->SetNumberOfDimensions(dimension); + m_ImageIO->SetPixelType(pixelType.GetPixelType()); + m_ImageIO->SetComponentType(pixelType.GetComponentType() < PixelComponentUserType ? + static_cast(pixelType.GetComponentType()) : + itk::ImageIOBase::UNKNOWNCOMPONENTTYPE); + m_ImageIO->SetNumberOfComponents( pixelType.GetNumberOfComponents() ); + + itk::ImageIORegion ioRegion( dimension ); + + for(unsigned int i = 0; i < dimension; i++) + { + m_ImageIO->SetDimensions(i, dimensions[i]); + m_ImageIO->SetSpacing(i, spacing4D[i]); + m_ImageIO->SetOrigin(i, origin4D[i]); + + mitk::Vector3D mitkDirection; + mitkDirection.SetVnlVector(geometry->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(i)); + itk::Vector direction4D; + direction4D[0] = mitkDirection[0]; + direction4D[1] = mitkDirection[1]; + direction4D[2] = mitkDirection[2]; + + // MITK only supports a 3x3 direction matrix. Due to templating in itk, however, we must + // save a 4x4 matrix for 4D images. in this case, add an homogneous component to the matrix. + if (i == 3) + { + direction4D[3] = 1; // homogenous component + } + else + { + direction4D[3] = 0; + } + vnl_vector axisDirection(dimension); + for(unsigned int j = 0; j < dimension; j++) + { + axisDirection[j] = direction4D[j] / spacing4D[i]; + } + m_ImageIO->SetDirection(i, axisDirection); + + ioRegion.SetSize(i, image->GetLargestPossibleRegion().GetSize(i)); + ioRegion.SetIndex(i, image->GetLargestPossibleRegion().GetIndex(i)); + } + //use compression if available + m_ImageIO->UseCompressionOn(); + + m_ImageIO->SetIORegion(ioRegion); + m_ImageIO->SetFileName(path); + + // ***** Remove const_cast after bug 17952 is fixed **** + ImageReadAccessor imageAccess(const_cast(image)); + m_ImageIO->Write(imageAccess.GetData()); + } + catch (const std::exception& e) + { + mitkThrow() << e.what(); + } } void ItkImageIO::Write(const BaseData* data, std::ostream& stream) { AbstractFileWriter::Write(data, stream); } +AbstractFileIO::WriterConfidenceLevel ItkImageIO::GetWriterConfidenceLevel(const BaseData* data) const +{ + // Check if the image dimension is supported + const Image* image = dynamic_cast(data); + if (image == NULL || !m_ImageIO->SupportsDimension(image->GetDimension())) + { + return IFileWriter::Unsupported; + } + + // Check if geometry information will be lost + if (image->GetDimension() == 2 && + !image->GetGeometry()->Is2DConvertable()) + { + return IFileWriter::PartiallySupported; + } + return IFileWriter::Supported; +} + ItkImageIO* ItkImageIO::Clone() const { return new ItkImageIO(*this); } } diff --git a/Core/Code/Internal/mitkItkImageIO.h b/Core/Code/Internal/mitkItkImageIO.h index 0b25600207..24736212a3 100644 --- a/Core/Code/Internal/mitkItkImageIO.h +++ b/Core/Code/Internal/mitkItkImageIO.h @@ -1,64 +1,64 @@ /*=================================================================== 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 MITKITKFILEIO_H #define MITKITKFILEIO_H #include "mitkAbstractFileIO.h" #include namespace mitk { // This class wraps ITK image IO objects registered via the // ITK object factory system class ItkImageIO : public AbstractFileIO { public: ItkImageIO(itk::ImageIOBase::Pointer imageIO); // -------------- AbstractFileReader ------------- using AbstractFileReader::Read; virtual std::vector > Read(const std::string& path); - virtual std::vector > Read(std::istream& stream); - using AbstractFileReader::CanRead; - virtual bool CanRead(const std::string& path) const; + virtual ReaderConfidenceLevel GetReaderConfidenceLevel(const std::string& path) const; // -------------- AbstractFileWriter ------------- virtual void Write(const BaseData* data, const std::string& path); virtual void Write(const BaseData* data, std::ostream& stream); + virtual WriterConfidenceLevel GetWriterConfidenceLevel(const BaseData *data) const; + private: ItkImageIO(const ItkImageIO& other); ItkImageIO* Clone() const; std::vector FixUpImageIOExtensions(const std::string& imageIOName); itk::ImageIOBase::Pointer m_ImageIO; }; } // namespace mitk #endif /* MITKITKFILEIO_H */ diff --git a/Core/Code/Internal/mitkLegacyFileReaderService.cpp b/Core/Code/Internal/mitkLegacyFileReaderService.cpp index 7ba95ca1aa..4065e5b409 100644 --- a/Core/Code/Internal/mitkLegacyFileReaderService.cpp +++ b/Core/Code/Internal/mitkLegacyFileReaderService.cpp @@ -1,129 +1,133 @@ /*=================================================================== 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 "mitkLegacyFileReaderService.h" #include #include #include +#include mitk::LegacyFileReaderService::LegacyFileReaderService(const mitk::LegacyFileReaderService& other) : mitk::AbstractFileReader(other) { } mitk::LegacyFileReaderService::LegacyFileReaderService(const std::vector& extensions, const std::string& category) : AbstractFileReader() { + CustomMimeType customMimeType; + customMimeType.SetCategory(category); + for(std::vector::const_iterator iter = extensions.begin(), endIter = extensions.end(); iter != endIter; ++iter) { std::string extension = *iter; if (!extension.empty() && extension[0] == '.') { extension.assign(extension.begin()+1, extension.end()); } - this->AddExtension(extension); + customMimeType.AddExtension(extension); } this->SetDescription(category); - this->SetCategory(category); + this->SetMimeType(customMimeType); m_ServiceReg = this->RegisterService(); } mitk::LegacyFileReaderService::~LegacyFileReaderService() { try { m_ServiceReg.Unregister(); } catch (const std::exception&) {} } ////////////////////// Reading ///////////////////////// std::vector > mitk::LegacyFileReaderService::Read(std::istream& stream) { return mitk::AbstractFileReader::Read(stream); } std::vector > mitk::LegacyFileReaderService::Read(const std::string& path) { std::vector result; std::list possibleIOAdapter; std::list allobjects = itk::ObjectFactoryBase::CreateAllInstance("mitkIOAdapter"); for( std::list::iterator i = allobjects.begin(); i != allobjects.end(); ++i) { IOAdapterBase* io = dynamic_cast(i->GetPointer()); if(io) { possibleIOAdapter.push_back(io); } else { MITK_ERROR << "Error BaseDataIO factory did not return an IOAdapterBase: " << (*i)->GetNameOfClass() << std::endl; } } for( std::list::iterator k = possibleIOAdapter.begin(); k != possibleIOAdapter.end(); ++k ) { bool canReadFile = (*k)->CanReadFile(path, "", ""); // they could read the file if( canReadFile ) { BaseProcess::Pointer ioObject = (*k)->CreateIOProcessObject(path, "", ""); ioObject->Update(); int numberOfContents = static_cast(ioObject->GetNumberOfOutputs()); if (numberOfContents > 0) { BaseData::Pointer baseData; for(int i=0; i(ioObject->GetOutputs()[i].GetPointer()); if (baseData) // this is what's wanted, right? { result.push_back( baseData ); } } } break; } } if (result.empty()) { mitkThrow() << "Could not read file '" << path << "'"; } return result; } mitk::LegacyFileReaderService* mitk::LegacyFileReaderService::Clone() const { return new LegacyFileReaderService(*this); } diff --git a/Core/Code/Internal/mitkMimeTypeProvider.cpp b/Core/Code/Internal/mitkMimeTypeProvider.cpp index b91841fda0..49d4cbd11b 100644 --- a/Core/Code/Internal/mitkMimeTypeProvider.cpp +++ b/Core/Code/Internal/mitkMimeTypeProvider.cpp @@ -1,200 +1,193 @@ /*=================================================================== 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 "mitkMimeTypeProvider.h" +#include "mitkLogMacros.h" + #include #include #include #ifdef _MSC_VER #pragma warning(disable:4503) // decorated name length exceeded, name was truncated #pragma warning(disable:4355) #endif namespace mitk { MimeTypeProvider::MimeTypeProvider() : m_Tracker(NULL) { } void MimeTypeProvider::Start() { if (m_Tracker == NULL) { - m_Tracker = new us::ServiceTracker(us::GetModuleContext(), this); + m_Tracker = new us::ServiceTracker(us::GetModuleContext(), this); } m_Tracker->Open(); } void MimeTypeProvider::Stop() { m_Tracker->Close(); } -std::vector MimeTypeProvider::GetMimeTypes() const +std::vector MimeTypeProvider::GetMimeTypes() const { - std::vector result; - for (MapType::const_iterator iter = m_MimeTypeToRefs.begin(), - end = m_MimeTypeToRefs.end(); iter != end; ++iter) + std::vector result; + for (std::map::const_iterator iter = m_NameToMimeType.begin(), + end = m_NameToMimeType.end(); iter != end; ++iter) { - result.push_back(iter->first); + result.push_back(iter->second); } return result; } -std::vector MimeTypeProvider::GetMimeTypesForFile(const std::string& filePath) const +std::vector MimeTypeProvider::GetMimeTypesForFile(const std::string& filePath) const { // For now, just use the file extension to look-up the registered mime-types. std::string extension = itksys::SystemTools::GetFilenameExtension(filePath); if (!extension.empty()) { extension = extension.substr(1, extension.size()-1); } return this->GetMimeTypesForExtension(extension); } -std::vector MimeTypeProvider::GetMimeTypesForExtension(const std::string& extension) const +std::vector MimeTypeProvider::GetMimeTypesForExtension(const std::string& extension) const { - std::vector result; - std::vector > mimeTypeRefs; - for (MapType::const_iterator iter = m_MimeTypeToRefs.begin(), - end = m_MimeTypeToRefs.end(); iter != end; ++iter) + std::vector result; + for (std::map::const_iterator iter = m_NameToMimeType.begin(), + iterEnd = m_NameToMimeType.end(); iter != iterEnd; ++iter) { - us::Any any = iter->second.rbegin()->GetProperty(IMimeType::PROP_EXTENSIONS()); - if (!any.Empty() && any.Type() == typeid(std::vector)) + const std::vector extensions = iter->second.GetExtensions(); + if (std::find(extensions.begin(), extensions.end(), extension) != extensions.end()) { - const std::vector& extensions = us::ref_any_cast >(any); - if (std::find(extensions.begin(), extensions.end(), extension) != extensions.end()) - { - mimeTypeRefs.push_back(*(iter->second.rbegin())); - } + result.push_back(iter->second); } } - std::sort(mimeTypeRefs.begin(), mimeTypeRefs.end()); - for (std::vector >::reverse_iterator iter = mimeTypeRefs.rbegin(); - iter != mimeTypeRefs.rend(); ++iter) - { - result.push_back(us::ref_any_cast(iter->GetProperty(IMimeType::PROP_ID()))); - } + std::sort(result.begin(), result.end()); + std::reverse(result.begin(), result.end()); return result; } -std::vector MimeTypeProvider::GetMimeTypesForCategory(const std::string& category) const +std::vector MimeTypeProvider::GetMimeTypesForCategory(const std::string& category) const { - std::vector result; - for (MapType::const_iterator iter = m_MimeTypeToRefs.begin(), - end = m_MimeTypeToRefs.end(); iter != end; ++iter) + std::vector result; + for (std::map::const_iterator iter = m_NameToMimeType.begin(), + end = m_NameToMimeType.end(); iter != end; ++iter) { - us::Any cat = iter->second.rbegin()->GetProperty(IMimeType::PROP_CATEGORY()); - if (!cat.Empty() && cat.Type() == typeid(std::string) && - us::ref_any_cast(cat) == category) + if (iter->second.GetCategory() == category) { - result.push_back(iter->first); + result.push_back(iter->second); } } return result; } -std::string MimeTypeProvider::GetDescription(const std::string& mimeType) const -{ - MapType::const_iterator iter = m_MimeTypeToRefs.find(mimeType); - if (iter == m_MimeTypeToRefs.end()) return std::string(); - - us::Any description = iter->second.rbegin()->GetProperty(IMimeType::PROP_DESCRIPTION()); - if (!description.Empty() && description.Type() == typeid(std::string)) - { - return us::ref_any_cast(description); - } - return std::string(); -} - -std::vector MimeTypeProvider::GetExtensions(const std::string& mimeType) const +MimeType MimeTypeProvider::GetMimeTypeForName(const std::string& name) const { - MapType::const_iterator iter = m_MimeTypeToRefs.find(mimeType); - if (iter == m_MimeTypeToRefs.end()) return std::vector(); - - us::Any extensions = iter->second.rbegin()->GetProperty(IMimeType::PROP_EXTENSIONS()); - if (!extensions.Empty() && extensions.Type() == typeid(std::vector)) - { - return us::ref_any_cast >(extensions); - } - return std::vector(); -} - -std::string MimeTypeProvider::GetCategory(const std::string& mimeType) const -{ - MapType::const_iterator iter = m_MimeTypeToRefs.find(mimeType); - if (iter == m_MimeTypeToRefs.end()) return std::string(); - - us::Any category = iter->second.rbegin()->GetProperty(IMimeType::PROP_CATEGORY()); - if (!category.Empty() && category.Type() == typeid(std::string)) - { - return us::ref_any_cast(category); - } - return std::string(); + std::map::const_iterator iter = m_NameToMimeType.find(name); + if (iter != m_NameToMimeType.end()) return iter->second; + return MimeType(); } std::vector MimeTypeProvider::GetCategories() const { std::vector result; - for (MapType::const_iterator iter = m_MimeTypeToRefs.begin(), - end = m_MimeTypeToRefs.end(); iter != end; ++iter) + for (std::map::const_iterator iter = m_NameToMimeType.begin(), + end = m_NameToMimeType.end(); iter != end; ++iter) { - us::Any category = iter->second.rbegin()->GetProperty(IMimeType::PROP_CATEGORY()); - if (!category.Empty() && category.Type() == typeid(std::string)) + std::string category = iter->second.GetCategory(); + if (!category.empty()) { - std::string s = us::ref_any_cast(category); - if (!s.empty()) - { - result.push_back(s); - } + result.push_back(category); } } std::sort(result.begin(), result.end()); result.erase(std::unique(result.begin(), result.end()), result.end()); return result; } -us::ServiceReference MimeTypeProvider::AddingService(const ServiceReferenceType& reference) +MimeTypeProvider::TrackedType MimeTypeProvider::AddingService(const ServiceReferenceType& reference) { - us::Any id = reference.GetProperty(IMimeType::PROP_ID()); - if (!id.Empty() && id.Type() == typeid(std::string)) + MimeType result = this->GetMimeType(reference); + if (result.IsValid()) { - m_MimeTypeToRefs[us::ref_any_cast(id)].insert(reference); - return reference; + std::string name = result.GetName(); + m_NameToMimeTypes[name].insert(result); + + // get the highest ranked mime-type + m_NameToMimeType[name] = *(m_NameToMimeTypes[name].rbegin()); } - return ServiceReferenceType(); + return result; } -void MimeTypeProvider::ModifiedService(const ServiceReferenceType& /*reference*/, ServiceReferenceType /*service*/) +void MimeTypeProvider::ModifiedService(const ServiceReferenceType& /*reference*/, TrackedType /*mimetype*/) { + // should we track changes in the ranking property? } -void MimeTypeProvider::RemovedService(const ServiceReferenceType& /*reference*/, ServiceReferenceType service) +void MimeTypeProvider::RemovedService(const ServiceReferenceType& /*reference*/, TrackedType mimeType) { - std::string id = us::ref_any_cast(service.GetProperty(IMimeType::PROP_ID())); - std::set& refs = m_MimeTypeToRefs[id]; - refs.erase(service); - if (refs.empty()) + std::string name = mimeType.GetName(); + std::set& mimeTypes = m_NameToMimeTypes[name]; + mimeTypes.erase(mimeType); + if (mimeTypes.empty()) { - m_MimeTypeToRefs.erase(id); + m_NameToMimeTypes.erase(name); + m_NameToMimeType.erase(name); } + else + { + // get the highest ranked mime-type + m_NameToMimeType[name] = *(mimeTypes.rbegin()); + } +} + +MimeType MimeTypeProvider::GetMimeType(const ServiceReferenceType& reference) const +{ + MimeType result; + if (!reference) return result; + + CustomMimeType* mimeType = us::GetModuleContext()->GetService(reference); + if (mimeType != NULL) + { + try + { + int rank = 0; + us::Any rankProp = reference.GetProperty(us::ServiceConstants::SERVICE_RANKING()); + if (!rankProp.Empty()) + { + rank = us::any_cast(rankProp); + } + long id = us::any_cast(reference.GetProperty(us::ServiceConstants::SERVICE_ID())); + result = MimeType(*mimeType, rank, id); + } + catch (const us::BadAnyCastException& e) + { + MITK_WARN << "Unexpected exception: " << e.what(); + } + us::GetModuleContext()->UngetService(reference); + } + return result; } } diff --git a/Core/Code/Internal/mitkMimeTypeProvider.h b/Core/Code/Internal/mitkMimeTypeProvider.h index 1b6a789681..357b5cf8a8 100644 --- a/Core/Code/Internal/mitkMimeTypeProvider.h +++ b/Core/Code/Internal/mitkMimeTypeProvider.h @@ -1,88 +1,85 @@ /*=================================================================== 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 MITKMIMETYPEPROVIDER_H #define MITKMIMETYPEPROVIDER_H #include "mitkIMimeTypeProvider.h" -#include "mitkIMimeType.h" +#include "mitkCustomMimeType.h" #include "usServiceTracker.h" #include "usServiceTrackerCustomizer.h" #include namespace mitk { -struct MimeTypeTrackerTypeTraits : public us::TrackedTypeTraitsBase,MimeTypeTrackerTypeTraits> +struct MimeTypeTrackerTypeTraits : public us::TrackedTypeTraitsBase { - typedef us::ServiceReference TrackedType; + typedef MimeType TrackedType; static bool IsValid(const TrackedType& t) { - return t; + return t.IsValid(); } static TrackedType DefaultValue() { return TrackedType(); } - static void Dispose(TrackedType& t) + static void Dispose(TrackedType& /*t*/) { - t = 0; } }; class MimeTypeProvider : public IMimeTypeProvider, - private us::ServiceTrackerCustomizer > + private us::ServiceTrackerCustomizer { public: MimeTypeProvider(); void Start(); void Stop(); - virtual std::vector GetMimeTypes() const; - virtual std::vector GetMimeTypesForFile(const std::string& filePath) const; - virtual std::vector GetMimeTypesForExtension(const std::string& extension) const; - virtual std::vector GetMimeTypesForCategory(const std::string& category) const; - - virtual std::string GetDescription(const std::string& mimeType) const; - - virtual std::vector GetExtensions(const std::string& mimeType) const; - - virtual std::string GetCategory(const std::string& mimeType) const; + virtual std::vector GetMimeTypes() const; + virtual std::vector GetMimeTypesForFile(const std::string& filePath) const; + virtual std::vector GetMimeTypesForExtension(const std::string& extension) const; + virtual std::vector GetMimeTypesForCategory(const std::string& category) const; + virtual MimeType GetMimeTypeForName(const std::string& name) const; virtual std::vector GetCategories() const; private: - virtual ServiceReferenceType AddingService(const ServiceReferenceType& reference); - virtual void ModifiedService(const ServiceReferenceType& reference, ServiceReferenceType service); - virtual void RemovedService(const ServiceReferenceType& reference, ServiceReferenceType service); + virtual TrackedType AddingService(const ServiceReferenceType& reference); + virtual void ModifiedService(const ServiceReferenceType& reference, TrackedType service); + virtual void RemovedService(const ServiceReferenceType& reference, TrackedType service); + + MimeType GetMimeType(const ServiceReferenceType& reference) const; - us::ServiceTracker* m_Tracker; + us::ServiceTracker* m_Tracker; - typedef std::map > MapType; - MapType m_MimeTypeToRefs; + typedef std::map > MapType; + MapType m_NameToMimeTypes; + std::map m_NameToMimeType; }; } #endif // MITKMIMETYPEPROVIDER_H diff --git a/Core/Code/Internal/mitkPointSetReaderService.cpp b/Core/Code/Internal/mitkPointSetReaderService.cpp index 9ae975d4f6..f74dbdb5ac 100644 --- a/Core/Code/Internal/mitkPointSetReaderService.cpp +++ b/Core/Code/Internal/mitkPointSetReaderService.cpp @@ -1,127 +1,127 @@ /*=================================================================== 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. ===================================================================*/ // MITK #include "mitkPointSetReaderService.h" +#include "mitkCustomMimeType.h" // STL #include #include #include #include mitk::PointSetReaderService::PointSetReaderService() - : AbstractFileReader(MimeType("application/vnd.mitk.pointset"), "MITK Point Set Reader") + : AbstractFileReader(CustomMimeType("application/vnd.mitk.pointset"), "MITK Point Set Reader") { - this->AddExtension("mps"); RegisterService(); } mitk::PointSetReaderService::~PointSetReaderService() {} std::vector< itk::SmartPointer > mitk::PointSetReaderService::Read(std::istream& stream) { std::locale::global(std::locale("C")); std::vector< itk::SmartPointer > result; TiXmlDocument doc; stream >> doc; if (!doc.Error()) { TiXmlHandle docHandle( &doc ); //unsigned int pointSetCounter(0); for( TiXmlElement* currentPointSetElement = docHandle.FirstChildElement("point_set_file").FirstChildElement("point_set").ToElement(); currentPointSetElement != NULL; currentPointSetElement = currentPointSetElement->NextSiblingElement()) { mitk::PointSet::Pointer newPointSet = mitk::PointSet::New(); if(currentPointSetElement->FirstChildElement("time_series") != NULL) { for( TiXmlElement* currentTimeSeries = currentPointSetElement->FirstChildElement("time_series")->ToElement(); currentTimeSeries != NULL; currentTimeSeries = currentTimeSeries->NextSiblingElement()) { unsigned int currentTimeStep(0); TiXmlElement* currentTimeSeriesID = currentTimeSeries->FirstChildElement("time_series_id"); currentTimeStep = atoi(currentTimeSeriesID->GetText()); newPointSet = this->ReadPoint(newPointSet, currentTimeSeries, currentTimeStep); } } else { newPointSet = this->ReadPoint(newPointSet, currentPointSetElement, 0); } result.push_back( newPointSet.GetPointer() ); } } else { mitkThrow() << "Parsing error at line " << doc.ErrorRow() << ", col " << doc.ErrorCol() << ": " << doc.ErrorDesc(); } return result; } mitk::PointSet::Pointer mitk::PointSetReaderService::ReadPoint(mitk::PointSet::Pointer newPointSet, TiXmlElement* currentTimeSeries, unsigned int currentTimeStep) { if(currentTimeSeries->FirstChildElement("point") != NULL) { for( TiXmlElement* currentPoint = currentTimeSeries->FirstChildElement("point")->ToElement(); currentPoint != NULL; currentPoint = currentPoint->NextSiblingElement()) { unsigned int id(0); mitk::PointSpecificationType spec((mitk::PointSpecificationType) 0); double x(0.0); double y(0.0); double z(0.0); id = atoi(currentPoint->FirstChildElement("id")->GetText()); if(currentPoint->FirstChildElement("specification") != NULL) { spec = (mitk::PointSpecificationType) atoi(currentPoint->FirstChildElement("specification")->GetText()); } x = atof(currentPoint->FirstChildElement("x")->GetText()); y = atof(currentPoint->FirstChildElement("y")->GetText()); z = atof(currentPoint->FirstChildElement("z")->GetText()); mitk::Point3D point; mitk::FillVector3D(point, x, y, z); newPointSet->SetPoint(id, point, spec, currentTimeStep); } } else { if(currentTimeStep != newPointSet->GetTimeSteps()+1) { newPointSet->Expand(currentTimeStep+1); // expand time step series with empty time step } } return newPointSet; } mitk::PointSetReaderService::PointSetReaderService(const mitk::PointSetReaderService& other) : mitk::AbstractFileReader(other) { } mitk::PointSetReaderService* mitk::PointSetReaderService::Clone() const { return new mitk::PointSetReaderService(*this); } diff --git a/Core/Code/Internal/mitkPointSetWriterService.cpp b/Core/Code/Internal/mitkPointSetWriterService.cpp index c4e413688a..d035bbe8c7 100644 --- a/Core/Code/Internal/mitkPointSetWriterService.cpp +++ b/Core/Code/Internal/mitkPointSetWriterService.cpp @@ -1,189 +1,190 @@ /*=================================================================== 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 "mitkPointSetWriterService.h" +#include "mitkCustomMimeType.h" + #include #include #include // // Initialization of the xml tags. // const std::string mitk::PointSetWriterService::XML_POINT_SET_FILE = "point_set_file" ; const std::string mitk::PointSetWriterService::XML_FILE_VERSION = "file_version" ; const std::string mitk::PointSetWriterService::XML_POINT_SET = "point_set" ; const std::string mitk::PointSetWriterService::XML_TIME_SERIES = "time_series"; const std::string mitk::PointSetWriterService::XML_TIME_SERIES_ID = "time_series_id"; const std::string mitk::PointSetWriterService::XML_POINT = "point" ; const std::string mitk::PointSetWriterService::XML_ID = "id" ; const std::string mitk::PointSetWriterService::XML_SPEC = "specification" ; const std::string mitk::PointSetWriterService::XML_X = "x" ; const std::string mitk::PointSetWriterService::XML_Y = "y" ; const std::string mitk::PointSetWriterService::XML_Z = "z" ; const std::string mitk::PointSetWriterService::VERSION_STRING = "0.1" ; mitk::PointSetWriterService::PointSetWriterService() - : AbstractFileWriter(PointSet::GetStaticNameOfClass(), MimeType("application/vnd.mitk.pointset"), "MITK Point Set Writer") + : AbstractFileWriter(PointSet::GetStaticNameOfClass(), CustomMimeType("application/vnd.mitk.pointset"), "MITK Point Set Writer") , m_IndentDepth(0) , m_Indent(2) { - this->AddExtension("mps"); RegisterService(); } mitk::PointSetWriterService::PointSetWriterService(const mitk::PointSetWriterService& other) : AbstractFileWriter(other) , m_IndentDepth(other.m_IndentDepth) , m_Indent(other.m_Indent) { } mitk::PointSetWriterService::~PointSetWriterService() {} void mitk::PointSetWriterService::Write( const BaseData* baseData, std::ostream& out ) { if ( !out.good() ) { mitkThrow() << "Stream not good."; } std::locale previousLocale(out.getloc()); std::locale I("C"); out.imbue(I); // // Here the actual xml writing begins // WriteXMLHeader( out ); WriteStartElement( XML_POINT_SET_FILE, out ); WriteStartElement( XML_FILE_VERSION, out ); out << VERSION_STRING; WriteEndElement( XML_FILE_VERSION, out, false ); WriteXML( static_cast(baseData), out ); WriteEndElement( XML_POINT_SET_FILE, out ); out.imbue(previousLocale); if ( !out.good() ) // some error during output { mitkThrow() << "Some error during point set writing."; } } mitk::PointSetWriterService*mitk::PointSetWriterService::Clone() const { return new PointSetWriterService(*this); } void mitk::PointSetWriterService::WriteXML( const mitk::PointSet* pointSet, std::ostream& out ) { WriteStartElement( XML_POINT_SET, out ); unsigned int timecount = pointSet->GetTimeSteps(); for(unsigned int i=0; i< timecount; i++) { WriteStartElement( XML_TIME_SERIES, out ); WriteStartElement( XML_TIME_SERIES_ID, out ); out << ConvertToString( i ); WriteEndElement( XML_TIME_SERIES_ID, out, false ); mitk::PointSet::PointsContainer* pointsContainer = pointSet->GetPointSet(i)->GetPoints(); mitk::PointSet::PointsContainer::Iterator it; for ( it = pointsContainer->Begin(); it != pointsContainer->End(); ++it ) { WriteStartElement( XML_POINT, out ); WriteStartElement( XML_ID, out ); out << ConvertToString( it->Index() ); WriteEndElement( XML_ID, out, false ); mitk::PointSet::PointType point = it->Value(); WriteStartElement( XML_SPEC, out ); out << ConvertToString( pointSet->GetSpecificationTypeInfo(it->Index(), i) ); WriteEndElement( XML_SPEC, out, false ); WriteStartElement( XML_X, out ); out << ConvertToString( point[ 0 ] ); WriteEndElement( XML_X, out, false ); WriteStartElement( XML_Y, out ); out << ConvertToString( point[ 1 ] ); WriteEndElement( XML_Y, out, false ); WriteStartElement( XML_Z, out ); out << ConvertToString( point[ 2 ] ); WriteEndElement( XML_Z, out, false ); WriteEndElement( XML_POINT, out ); } WriteEndElement( XML_TIME_SERIES, out ); } WriteEndElement( XML_POINT_SET, out ); } template < typename T> std::string mitk::PointSetWriterService::ConvertToString( T value ) { std::ostringstream o; std::locale I("C"); o.imbue(I); if ( o << value ) { return o.str(); } else { return "conversion error"; } } void mitk::PointSetWriterService::WriteXMLHeader( std::ostream &file ) { file << ""; } void mitk::PointSetWriterService::WriteStartElement( const std::string& tag, std::ostream &file ) { file << std::endl; WriteIndent( file ); file << '<' << tag << '>'; m_IndentDepth++; } void mitk::PointSetWriterService::WriteEndElement( const std::string& tag, std::ostream &file, const bool& indent ) { m_IndentDepth--; if ( indent ) { file << std::endl; WriteIndent( file ); } file << '<' << '/' << tag << '>'; } void mitk::PointSetWriterService::WriteIndent( std::ostream& file ) { std::string spaces( m_IndentDepth * m_Indent, ' ' ); file << spaces; } diff --git a/Core/Code/Testing/mitkFileReaderRegistryTest.cpp b/Core/Code/Testing/mitkFileReaderRegistryTest.cpp index e85398abd6..34967e3154 100644 --- a/Core/Code/Testing/mitkFileReaderRegistryTest.cpp +++ b/Core/Code/Testing/mitkFileReaderRegistryTest.cpp @@ -1,210 +1,220 @@ /*=================================================================== 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 "mitkTestingMacros.h" #include "mitkAbstractFileReader.h" #include "mitkIFileReader.h" #include "mitkFileReaderRegistry.h" #include #include +#include class DummyReader : public mitk::AbstractFileReader { public: DummyReader(const DummyReader& other) : mitk::AbstractFileReader(other) { } - DummyReader(const std::string& mimeType, const std::string& extension, int priority) - : mitk::AbstractFileReader(MimeType(mimeType), "This is a dummy description") + DummyReader(const std::string& mimeTypeName, const std::string& extension, int priority) + : mitk::AbstractFileReader() { - this->AddExtension(extension); + mitk::CustomMimeType mimeType(mimeTypeName); + mimeType.AddExtension(extension); + mimeType.SetComment("This is a dummy description"); + + this->SetMimeType(mimeType); + this->SetRanking(priority); m_ServiceReg = this->RegisterService(); } ~DummyReader() { if (m_ServiceReg) m_ServiceReg.Unregister(); } using mitk::AbstractFileReader::Read; virtual std::vector< itk::SmartPointer > Read(std::istream& /*stream*/) { std::vector result; return result; } private: DummyReader* Clone() const { return new DummyReader(*this); } us::ServiceRegistration m_ServiceReg; }; // End of internal dummy reader class DummyReader2 : public mitk::AbstractFileReader { public: DummyReader2(const DummyReader2& other) : mitk::AbstractFileReader(other) { } - DummyReader2(const std::string& mimeType, const std::string& extension, int priority) - : mitk::AbstractFileReader(MimeType(mimeType), "This is a second dummy description") + DummyReader2(const std::string& mimeTypeName, const std::string& extension, int priority) + : mitk::AbstractFileReader() { - this->AddExtension(extension); + mitk::CustomMimeType mimeType(mimeTypeName); + mimeType.AddExtension(extension); + mimeType.SetComment("This is a second dummy description"); + this->SetMimeType(mimeType); + this->SetRanking(priority); m_ServiceReg = this->RegisterService(); } ~DummyReader2() { if (m_ServiceReg) m_ServiceReg.Unregister(); } using mitk::AbstractFileReader::Read; virtual std::vector< itk::SmartPointer > Read(std::istream& /*stream*/) { std::vector result; return result; } private: DummyReader2* Clone() const { return new DummyReader2(*this); } us::ServiceRegistration m_ServiceReg; }; // End of internal dummy reader 2 /** * TODO */ int mitkFileReaderRegistryTest(int /*argc*/ , char* /*argv*/[]) { // always start with this! MITK_TEST_BEGIN("FileReaderRegistry"); // mitk::FileReaderRegistry::Pointer frm = mitk::FileReaderRegistry::New(); // MITK_TEST_CONDITION_REQUIRED(argc == 2,"Testing FileReaderRegistry instantiation"); - DummyReader testDR("application/dummy", "test",1); - DummyReader otherDR("application/dummy2", "other",1); + //DummyReader testDR("application/dummy", "test",1); + //DummyReader otherDR("application/dummy2", "other",1); - MITK_TEST_CONDITION_REQUIRED(!testDR.CanRead("/this/is/a/folder/file.tes"),"Negative test of default CanRead() implementation"); + //MITK_TEST_CONDITION_REQUIRED(!testDR.CanRead("/this/is/a/folder/file.tes"),"Negative test of default CanRead() implementation"); - mitk::FileReaderRegistry* readerRegistry = new mitk::FileReaderRegistry; - mitk::IFileReader* returned = readerRegistry->GetReader("test"); + //mitk::FileReaderRegistry* readerRegistry = new mitk::FileReaderRegistry; + //mitk::IFileReader* returned = readerRegistry->GetReader("bla.test"); - MITK_TEST_CONDITION_REQUIRED(returned && &static_cast(testDR) != returned,"Testing correct retrieval of FileReader 1/2"); + //MITK_TEST_CONDITION_REQUIRED(returned && &static_cast(testDR) != returned,"Testing correct retrieval of FileReader 1/2"); - returned = readerRegistry->GetReader("other"); + //returned = readerRegistry->GetReader("other"); - MITK_TEST_CONDITION_REQUIRED(returned && &static_cast(otherDR) != returned,"Testing correct retrieval of FileReader 2/2"); + //MITK_TEST_CONDITION_REQUIRED(returned && &static_cast(otherDR) != returned,"Testing correct retrieval of FileReader 2/2"); - DummyReader mediocreTestDR("application/dummy", "test", 20); - DummyReader prettyFlyTestDR("application/dummy", "test", 50); - DummyReader2 awesomeTestDR("application/dummy", "test", 100); + //DummyReader mediocreTestDR("application/dummy", "test", 20); + //DummyReader prettyFlyTestDR("application/dummy", "test", 50); + //DummyReader2 awesomeTestDR("application/dummy", "test", 100); - returned = readerRegistry->GetReader("test"); - MITK_TEST_CONDITION_REQUIRED(dynamic_cast(returned), "Testing correct priorized retrieval of FileReader: Best reader"); + //returned = readerRegistry->GetReader("test"); + //MITK_TEST_CONDITION_REQUIRED(dynamic_cast(returned), "Testing correct priorized retrieval of FileReader: Best reader"); // Now to give those readers some options, then we will try again // mitk::IFileReader::OptionList options; // options.push_back(std::make_pair("isANiceGuy", true)); // mediocreTestDR.SetOptions(options); // options.clear(); // options.push_back(std::make_pair("canFly", true)); // prettyFlyTestDR.SetOptions(options); // options.push_back(std::make_pair("isAwesome", true)); // awesomeTestDR.SetOptions(options); //note: awesomeReader canFly and isAwesome // // Reset Options, use to define what we want the reader to do // options.clear(); // mitk::IFileReader::OptionNames optionsFilter; // optionsFilter.push_back("canFly"); // returned = readerRegistry->GetReader("test", optionsFilter); // MITK_TEST_CONDITION_REQUIRED(returned && &static_cast(awesomeTestDR) != returned, "Testing correct retrieval of FileReader with Options: Best reader with options"); // optionsFilter.push_back("isAwesome"); // returned = readerRegistry->GetReader("test", optionsFilter); // MITK_TEST_CONDITION_REQUIRED(returned && &static_cast(awesomeTestDR) != returned, "Testing correct retrieval of FileReader with multiple Options: Best reader with options"); // optionsFilter.clear(); // optionsFilter.push_back("isANiceGuy"); // returned = readerRegistry->GetReader("test", optionsFilter); // MITK_TEST_CONDITION_REQUIRED(returned && &static_cast(mediocreTestDR) != returned, "Testing correct retrieval of specific FileReader with Options: Low priority reader with specific option"); // optionsFilter.push_back("canFly"); // returned = readerRegistry->GetReader("test", optionsFilter); // MITK_TEST_CONDITION_REQUIRED(returned == NULL, "Testing correct return of 0 value when no matching reader was found"); // // Onward to test the retrieval of multiple readers // std::vector< mitk::IFileReader* > returnedList; // returnedList = readerRegistry->GetReaders("test", optionsFilter); // MITK_TEST_CONDITION_REQUIRED(returnedList.empty(), "Testing correct return of zero readers when no matching reader was found, asking for all compatibles"); // optionsFilter.clear(); // optionsFilter.push_back("canFly"); // returnedList = readerRegistry->GetReaders("test", optionsFilter); // MITK_TEST_CONDITION_REQUIRED(returnedList.size() == 2, "Testing correct return of two readers when two matching reader was found, asking for all compatibles"); // MITK_TEST_CONDITION_REQUIRED(dynamic_cast(returnedList.front()), "Testing correct priorization of returned Readers with options 1/2"); // optionsFilter.clear(); // optionsFilter.push_back("isAwesome"); // returnedList = readerRegistry->GetReaders("test", optionsFilter); // MITK_TEST_CONDITION_REQUIRED(returnedList.size() == 1, "Testing correct return of one readers when one matching reader was found, asking for all compatibles"); // MITK_TEST_CONDITION_REQUIRED(dynamic_cast(returnedList.front()), "Testing correctness of result from former query"); // And now to verify a working read chain for a mps file: //mitk::PointSetReader::Pointer psr = mitk::PointSetReader::New(); //std::vector basedata; //basedata = mitk::FileReaderRegistry::Read("F://Build//MITK-Data//pointSet.mps"); //MITK_TEST_CONDITION_REQUIRED(basedata.size() > 0, "Testing correct read of PointSet"); // Testing templated call to ReaderRegistry //mitk::PointSet::Pointer pointset = mitk::FileReaderRegistry::Read< mitk::PointSet >("F://Build//MITK-Data//pointSet.mps"); //MITK_TEST_CONDITION_REQUIRED(pointset.IsNotNull(), "Testing templated call of Read()"); // And now for something completely different... (Debug) // mitk::LegacyFileReaderService::Pointer lfr = mitk::LegacyFileReaderService::New(".nrrd", "Nearly Raw Raster Data"); //returned = mitk::FileReaderRegistry::GetReader(".nrrd"); //MITK_TEST_CONDITION_REQUIRED(lfr == returned, "Testing correct retrieval of specific FileReader with Options: Low priority reader with specific option"); //std::vector image = mitk::FileReaderRegistry::Read("F://Build//MITK-Data//Pic2DplusT.nrrd"); //MITK_TEST_CONDITION_REQUIRED(image.size() > 0, "Testing whether image was returned or not"); //mitk::Image::Pointer image2 = dynamic_cast (image.front().GetPointer()); //MITK_TEST_CONDITION_REQUIRED(image2.IsNotNull(), "Testing if BaseData is an image"); // Delete this here because it will call the PrototypeServiceFactory::Unget() method // of the dummy readers. - delete readerRegistry; + //delete readerRegistry; // always end with this! MITK_TEST_END(); } diff --git a/Core/Code/Testing/mitkPointSetReaderTest.cpp b/Core/Code/Testing/mitkPointSetReaderTest.cpp index fa5b8585b2..3e8341851f 100644 --- a/Core/Code/Testing/mitkPointSetReaderTest.cpp +++ b/Core/Code/Testing/mitkPointSetReaderTest.cpp @@ -1,66 +1,67 @@ /*=================================================================== 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 "mitkPointSet.h" #include "mitkTestingMacros.h" #include "mitkFileReaderRegistry.h" +#include "mitkMimeType.h" /** * Test for the class "mitkPointSetReader". * * argc and argv are the command line parameters which were passed to * the ADD_TEST command in the CMakeLists.txt file. For the automatic * tests, argv is either empty for the simple tests or contains the filename * of a test data set for the tests (see CMakeLists.txt). */ int mitkPointSetReaderTest(int argc , char* argv[]) { // always start with this! MITK_TEST_BEGIN("PointSetReader") MITK_TEST_CONDITION_REQUIRED(argc == 2,"Testing invocation") mitk::FileReaderRegistry readerRegistry; // Get PointSet reader(s) - std::vector readers = readerRegistry.GetReaders("mps"); + std::vector readers = readerRegistry.GetReaders(mitk::FileReaderRegistry::GetMimeTypeForExtension("mps")); MITK_TEST_CONDITION_REQUIRED(!readers.empty(), "Testing for registered readers") for (std::vector::const_iterator iter = readers.begin(), end = readers.end(); iter != end; ++iter) { std::string testName = "test1"; mitk::IFileReader* reader = *iter; // testing file reading with invalid data - MITK_TEST_CONDITION_REQUIRED( !reader->CanRead(testName), "Testing CanRead() method with invalid input file name!"); + MITK_TEST_CONDITION_REQUIRED(reader->GetConfidenceLevel(testName) == mitk::IFileReader::Unsupported, "Testing confidence level with invalid input file name!"); CPPUNIT_ASSERT_THROW(reader->Read(testName), mitk::Exception); // testing file reading with valid data std::string filePath = argv[1]; - MITK_TEST_CONDITION_REQUIRED( reader->CanRead(filePath), "Testing CanReadFile() method with valid input file name!"); + MITK_TEST_CONDITION_REQUIRED( reader->GetConfidenceLevel(filePath) == mitk::IFileReader::Supported, "Testing confidence level with valid input file name!"); std::vector data = reader->Read(filePath); MITK_TEST_CONDITION_REQUIRED( !data.empty(), "Testing non-empty data with valid input file name!"); // evaluate if the read point set is correct mitk::PointSet::Pointer resultPS = dynamic_cast(data.front().GetPointer()); MITK_TEST_CONDITION_REQUIRED( resultPS.IsNotNull(), "Testing correct BaseData type"); MITK_TEST_CONDITION_REQUIRED( resultPS->GetTimeSteps() == 14, "Testing output time step generation!"); // CAVE: Only valid with the specified test data! MITK_TEST_CONDITION_REQUIRED( resultPS->GetPointSet(resultPS->GetTimeSteps()-1)->GetNumberOfPoints() == 0, "Testing output time step generation with empty time step!"); // CAVE: Only valid with the specified test data! } // always end with this! MITK_TEST_END() } diff --git a/Core/Code/Testing/mitkPointSetWriterTest.cpp b/Core/Code/Testing/mitkPointSetWriterTest.cpp index fc5196caaa..6cee924473 100644 --- a/Core/Code/Testing/mitkPointSetWriterTest.cpp +++ b/Core/Code/Testing/mitkPointSetWriterTest.cpp @@ -1,80 +1,79 @@ /*=================================================================== 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 "mitkPointSet.h" #include "mitkTestingMacros.h" -#include "mitkFileWriterRegistry.h" +#include "mitkFileWriterSelector.h" #include #include /** * Test for the class "mitkPointSetFileWriter". * * argc and argv are the command line parameters which were passed to * the ADD_TEST command in the CMakeLists.txt file. For the automatic * tests, argv is either empty for the simple tests or contains the filename * of a test image for the image tests (see CMakeLists.txt). */ int mitkPointSetWriterTest(int /* argc */, char* /*argv*/[]) { // always start with this! MITK_TEST_BEGIN("PointSetWriter") - mitk::FileWriterRegistry writerRegistry; - - // Get PointSet writer(s) - std::vector writers = writerRegistry.GetWriters(mitk::PointSet::GetStaticNameOfClass()); - MITK_TEST_CONDITION_REQUIRED(!writers.empty(), "Testing for registered writers") - // create pointSet srand(time(NULL)); mitk::PointSet::Pointer pointSet = mitk::PointSet::New(); int numberOfPoints = rand()%100; for (int i=0; i<=numberOfPoints+1;i++) { mitk::Point3D point; point[0] = rand()%1000; point[1] = rand()%1000; point[2] = rand()%1000; pointSet->SetPoint(i,point); } MITK_TEST_CONDITION_REQUIRED(pointSet.IsNotNull(),"PointSet creation") - for (std::vector::const_iterator iter = writers.begin(), + // Get PointSet writer(s) + mitk::FileWriterSelector writerSelector(pointSet.GetPointer()); + std::vector writers = writerSelector.Get(); + MITK_TEST_CONDITION_REQUIRED(!writers.empty(), "Testing for registered writers") + + for (std::vector::const_iterator iter = writers.begin(), end = writers.end(); iter != end; ++iter) { // test for exception handling try { - (*iter)->Write(pointSet, "/usr/bin"); + iter->GetWriter()->Write(pointSet, "/usr/bin"); MITK_TEST_FAILED_MSG( << "itk::ExceptionObject expected" ) } catch (const itk::ExceptionObject&) { /* this is expected */ } catch(...) { //this means that a wrong exception (i.e. no itk:Exception) has been thrown MITK_TEST_FAILED_MSG( << "Wrong exception (i.e. no itk:Exception) caught during write [FAILED]") } } // always end with this! MITK_TEST_END() } diff --git a/Core/Code/files.cmake b/Core/Code/files.cmake index d3ae8f12c3..1bb4cfae7d 100644 --- a/Core/Code/files.cmake +++ b/Core/Code/files.cmake @@ -1,410 +1,412 @@ set(H_FILES Algorithms/itkImportMitkImageContainer.h Algorithms/itkImportMitkImageContainer.txx Algorithms/itkMITKScalarImageToHistogramGenerator.h Algorithms/itkMITKScalarImageToHistogramGenerator.txx Algorithms/mitkInstantiateAccessFunctions.h Algorithms/mitkPixelTypeList.h Algorithms/mitkPPArithmeticDec.h Algorithms/mitkPPArgCount.h Algorithms/mitkPPCat.h Algorithms/mitkPPConfig.h Algorithms/mitkPPControlExprIIf.h Algorithms/mitkPPControlIf.h Algorithms/mitkPPControlIIf.h Algorithms/mitkPPDebugError.h Algorithms/mitkPPDetailAutoRec.h Algorithms/mitkPPDetailDMCAutoRec.h Algorithms/mitkPPExpand.h Algorithms/mitkPPFacilitiesEmpty.h Algorithms/mitkPPFacilitiesExpand.h Algorithms/mitkPPLogicalBool.h Algorithms/mitkPPRepetitionDetailDMCFor.h Algorithms/mitkPPRepetitionDetailEDGFor.h Algorithms/mitkPPRepetitionDetailFor.h Algorithms/mitkPPRepetitionDetailMSVCFor.h Algorithms/mitkPPRepetitionFor.h Algorithms/mitkPPSeqElem.h Algorithms/mitkPPSeqForEach.h Algorithms/mitkPPSeqForEachProduct.h Algorithms/mitkPPSeq.h Algorithms/mitkPPSeqEnum.h Algorithms/mitkPPSeqSize.h Algorithms/mitkPPSeqToTuple.h Algorithms/mitkPPStringize.h Algorithms/mitkPPTupleEat.h Algorithms/mitkPPTupleElem.h Algorithms/mitkPPTupleRem.h Algorithms/mitkClippedSurfaceBoundsCalculator.h Algorithms/mitkExtractSliceFilter.h Algorithms/mitkConvert2Dto3DImageFilter.h Algorithms/mitkPlaneClipping.h Common/mitkCommon.h Common/mitkExceptionMacro.h DataManagement/mitkProportionalTimeGeometry.h DataManagement/mitkTimeGeometry.h DataManagement/mitkImageAccessByItk.h DataManagement/mitkImageCast.h DataManagement/mitkImagePixelAccessor.h DataManagement/mitkImagePixelReadAccessor.h DataManagement/mitkImagePixelWriteAccessor.h DataManagement/mitkImageReadAccessor.h DataManagement/mitkImageWriteAccessor.h DataManagement/mitkITKImageImport.h DataManagement/mitkITKImageImport.txx DataManagement/mitkImageToItk.h DataManagement/mitkShaderProperty.h DataManagement/mitkImageToItk.txx DataManagement/mitkTimeSlicedGeometry.h # Deprecated, empty for compatibility reasons. DataManagement/mitkPropertyListReplacedObserver.cpp DataManagement/mitkVectorDeprecated.h DataManagement/mitkArray.h DataManagement/mitkQuaternion.h DataManagement/mitkNumericTypes.h DataManagement/mitkVector.h DataManagement/mitkPoint.h DataManagement/mitkMatrix.h Interactions/mitkEventMapperAddOn.h Interfaces/mitkIDataNodeReader.h Interfaces/mitkIFileWriter.h Interfaces/mitkIFileWriter.cpp Interfaces/mitkIFileReader.h Interfaces/mitkIFileReader.cpp Rendering/mitkLocalStorageHandler.h Rendering/Colortables/HotIron.h Rendering/Colortables/Jet.h Rendering/Colortables/PET20.h Rendering/Colortables/PETColor.h IO/mitkPixelTypeTraits.h ) set(CPP_FILES Algorithms/mitkBaseDataSource.cpp Algorithms/mitkCompareImageDataFilter.cpp Algorithms/mitkMultiComponentImageDataComparisonFilter.cpp Algorithms/mitkDataNodeSource.cpp Algorithms/mitkPlaneGeometryDataToSurfaceFilter.cpp Algorithms/mitkHistogramGenerator.cpp Algorithms/mitkImageChannelSelector.cpp Algorithms/mitkImageSliceSelector.cpp Algorithms/mitkImageSource.cpp Algorithms/mitkImageTimeSelector.cpp Algorithms/mitkImageToImageFilter.cpp Algorithms/mitkImageToSurfaceFilter.cpp Algorithms/mitkPointSetSource.cpp Algorithms/mitkPointSetToPointSetFilter.cpp Algorithms/mitkRGBToRGBACastImageFilter.cpp Algorithms/mitkSubImageSelector.cpp Algorithms/mitkSurfaceSource.cpp Algorithms/mitkSurfaceToImageFilter.cpp Algorithms/mitkSurfaceToSurfaceFilter.cpp Algorithms/mitkUIDGenerator.cpp Algorithms/mitkVolumeCalculator.cpp Algorithms/mitkClippedSurfaceBoundsCalculator.cpp Algorithms/mitkExtractSliceFilter.cpp Algorithms/mitkConvert2Dto3DImageFilter.cpp Controllers/mitkBaseController.cpp Controllers/mitkCallbackFromGUIThread.cpp Controllers/mitkCameraController.cpp Controllers/mitkCameraRotationController.cpp Controllers/mitkFocusManager.cpp Controllers/mitkLimitedLinearUndo.cpp Controllers/mitkOperationEvent.cpp Controllers/mitkPlanePositionManager.cpp Controllers/mitkProgressBar.cpp Controllers/mitkRenderingManager.cpp Controllers/mitkSliceNavigationController.cpp Controllers/mitkSlicesCoordinator.cpp Controllers/mitkSlicesRotator.cpp Controllers/mitkSlicesSwiveller.cpp Controllers/mitkStatusBar.cpp Controllers/mitkStepper.cpp Controllers/mitkTestManager.cpp Controllers/mitkUndoController.cpp Controllers/mitkVerboseLimitedLinearUndo.cpp Controllers/mitkVtkInteractorCameraController.cpp Controllers/mitkVtkLayerController.cpp DataManagement/mitkProportionalTimeGeometry.cpp DataManagement/mitkTimeGeometry.cpp DataManagement/mitkAbstractTransformGeometry.cpp DataManagement/mitkAnnotationProperty.cpp DataManagement/mitkApplicationCursor.cpp DataManagement/mitkBaseData.cpp DataManagement/mitkBaseGeometry.cpp DataManagement/mitkBaseProperty.cpp DataManagement/mitkClippingProperty.cpp DataManagement/mitkChannelDescriptor.cpp DataManagement/mitkColorProperty.cpp DataManagement/mitkDataStorage.cpp # DataManagement/mitkDataTree.cpp DataManagement/mitkDataNode.cpp # DataManagement/mitkDataTreeStorage.cpp DataManagement/mitkDisplayGeometry.cpp DataManagement/mitkEnumerationProperty.cpp DataManagement/mitkPlaneGeometryData.cpp DataManagement/mitkGeometry3D.cpp DataManagement/mitkGeometryData.cpp DataManagement/mitkGroupTagProperty.cpp DataManagement/mitkImage.cpp DataManagement/mitkImageAccessorBase.cpp DataManagement/mitkImageCaster.cpp DataManagement/mitkImageCastPart1.cpp DataManagement/mitkImageCastPart2.cpp DataManagement/mitkImageCastPart3.cpp DataManagement/mitkImageCastPart4.cpp DataManagement/mitkImageDataItem.cpp DataManagement/mitkImageDescriptor.cpp DataManagement/mitkImageVtkAccessor.cpp DataManagement/mitkImageStatisticsHolder.cpp DataManagement/mitkLandmarkProjectorBasedCurvedGeometry.cpp DataManagement/mitkLandmarkProjector.cpp DataManagement/mitkLevelWindow.cpp DataManagement/mitkLevelWindowManager.cpp DataManagement/mitkLevelWindowPreset.cpp DataManagement/mitkLevelWindowProperty.cpp DataManagement/mitkLookupTable.cpp DataManagement/mitkLookupTableProperty.cpp DataManagement/mitkLookupTables.cpp # specializations of GenericLookupTable DataManagement/mitkMemoryUtilities.cpp DataManagement/mitkModalityProperty.cpp DataManagement/mitkModeOperation.cpp DataManagement/mitkModifiedLock.cpp DataManagement/mitkNodePredicateAnd.cpp DataManagement/mitkNodePredicateBase.cpp DataManagement/mitkNodePredicateCompositeBase.cpp DataManagement/mitkNodePredicateData.cpp DataManagement/mitkNodePredicateDataType.cpp DataManagement/mitkNodePredicateDimension.cpp DataManagement/mitkNodePredicateFirstLevel.cpp DataManagement/mitkNodePredicateNot.cpp DataManagement/mitkNodePredicateOr.cpp DataManagement/mitkNodePredicateProperty.cpp DataManagement/mitkNodePredicateSource.cpp DataManagement/mitkPlaneOrientationProperty.cpp DataManagement/mitkPlaneGeometry.cpp DataManagement/mitkPlaneOperation.cpp DataManagement/mitkPointOperation.cpp DataManagement/mitkPointSet.cpp DataManagement/mitkProperties.cpp DataManagement/mitkPropertyList.cpp DataManagement/mitkPropertyObserver.cpp DataManagement/mitkRestorePlanePositionOperation.cpp DataManagement/mitkApplyTransformMatrixOperation.cpp DataManagement/mitkRotationOperation.cpp DataManagement/mitkSlicedData.cpp DataManagement/mitkSlicedGeometry3D.cpp DataManagement/mitkSmartPointerProperty.cpp DataManagement/mitkStandaloneDataStorage.cpp DataManagement/mitkStateTransitionOperation.cpp DataManagement/mitkStringProperty.cpp DataManagement/mitkSurface.cpp DataManagement/mitkSurfaceOperation.cpp DataManagement/mitkThinPlateSplineCurvedGeometry.cpp DataManagement/mitkTransferFunction.cpp DataManagement/mitkTransferFunctionProperty.cpp DataManagement/mitkTransferFunctionInitializer.cpp DataManagement/mitkVector.cpp DataManagement/mitkNumericConstants.cpp DataManagement/mitkVtkInterpolationProperty.cpp DataManagement/mitkVtkRepresentationProperty.cpp DataManagement/mitkVtkResliceInterpolationProperty.cpp DataManagement/mitkVtkScalarModeProperty.cpp DataManagement/mitkVtkVolumeRenderingProperty.cpp DataManagement/mitkWeakPointerProperty.cpp DataManagement/mitkRenderingModeProperty.cpp DataManagement/mitkResliceMethodProperty.cpp DataManagement/mitkMaterial.cpp DataManagement/mitkPointSetShapeProperty.cpp DataManagement/mitkFloatPropertyExtension.cpp DataManagement/mitkIntPropertyExtension.cpp DataManagement/mitkPropertyExtension.cpp DataManagement/mitkPropertyFilter.cpp DataManagement/mitkPropertyAliases.cpp DataManagement/mitkPropertyDescriptions.cpp DataManagement/mitkPropertyExtensions.cpp DataManagement/mitkPropertyFilters.cpp DataManagement/mitkShaderProperty.cpp Interactions/mitkAction.cpp Interactions/mitkAffineInteractor.cpp Interactions/mitkBindDispatcherInteractor.cpp Interactions/mitkCoordinateSupplier.cpp Interactions/mitkDataInteractor.cpp Interactions/mitkDispatcher.cpp Interactions/mitkDisplayCoordinateOperation.cpp Interactions/mitkDisplayInteractor.cpp Interactions/mitkDisplayPositionEvent.cpp # Interactions/mitkDisplayVectorInteractorLevelWindow.cpp # legacy, prob even now unneeded # Interactions/mitkDisplayVectorInteractorScroll.cpp Interactions/mitkEvent.cpp Interactions/mitkEventConfig.cpp Interactions/mitkEventDescription.cpp Interactions/mitkEventFactory.cpp Interactions/mitkInteractionEventHandler.cpp Interactions/mitkEventMapper.cpp Interactions/mitkEventRecorder.cpp Interactions/mitkEventStateMachine.cpp Interactions/mitkGlobalInteraction.cpp Interactions/mitkInteractor.cpp Interactions/mitkInternalEvent.cpp Interactions/mitkInteractionEvent.cpp Interactions/mitkInteractionEventConst.cpp Interactions/mitkInteractionPositionEvent.cpp Interactions/mitkInteractionKeyEvent.cpp Interactions/mitkMousePressEvent.cpp Interactions/mitkMouseMoveEvent.cpp Interactions/mitkMouseReleaseEvent.cpp Interactions/mitkMouseWheelEvent.cpp Interactions/mitkMouseDoubleClickEvent.cpp Interactions/mitkMouseModeSwitcher.cpp Interactions/mitkMouseMovePointSetInteractor.cpp Interactions/mitkMoveBaseDataInteractor.cpp Interactions/mitkNodeDepententPointSetInteractor.cpp Interactions/mitkPointSetDataInteractor.cpp Interactions/mitkPointSetInteractor.cpp Interactions/mitkPositionEvent.cpp Interactions/mitkPositionTracker.cpp Interactions/mitkSinglePointDataInteractor.cpp Interactions/mitkStateMachineAction.cpp Interactions/mitkStateMachineCondition.cpp Interactions/mitkStateMachineState.cpp Interactions/mitkStateMachineTransition.cpp Interactions/mitkState.cpp Interactions/mitkStateMachineContainer.cpp Interactions/mitkStateEvent.cpp Interactions/mitkStateMachine.cpp Interactions/mitkStateMachineFactory.cpp Interactions/mitkTransition.cpp Interactions/mitkWheelEvent.cpp Interactions/mitkKeyEvent.cpp Interactions/mitkVtkEventAdapter.cpp Interactions/mitkVtkInteractorStyle.cxx Interactions/mitkCrosshairPositionEvent.cpp Interactions/mitkXML2EventParser.cpp - Interfaces/mitkIMimeType.cpp Interfaces/mitkIMimeTypeProvider.cpp Interfaces/mitkInteractionEventObserver.cpp Interfaces/mitkIShaderRepository.cpp Interfaces/mitkIPropertyAliases.cpp Interfaces/mitkIPropertyDescriptions.cpp Interfaces/mitkIPropertyExtensions.cpp Interfaces/mitkIPropertyFilters.cpp Interfaces/mitkIPersistenceService.cpp IO/mitkAbstractFileReader.cpp IO/mitkAbstractFileWriter.cpp IO/mitkAbstractFileIO.cpp + IO/mitkCustomMimeType.cpp IO/mitkDicomSeriesReader.cpp IO/mitkDicomSR_LoadDICOMScalar.cpp IO/mitkDicomSR_LoadDICOMScalar4D.cpp IO/mitkDicomSR_LoadDICOMRGBPixel.cpp IO/mitkDicomSR_LoadDICOMRGBPixel4D.cpp IO/mitkDicomSR_ImageBlockDescriptor.cpp IO/mitkDicomSR_GantryTiltInformation.cpp IO/mitkDicomSR_SliceGroupingResult.cpp IO/mitkFileReader.cpp - IO/mitkFileWriter.cpp IO/mitkFileReaderRegistry.cpp + IO/mitkFileReaderSelector.cpp + IO/mitkFileWriter.cpp IO/mitkFileWriterRegistry.cpp + IO/mitkFileWriterSelector.cpp # IO/mitkIpPicGet.c IO/mitkImageGenerator.cpp IO/mitkIOConstants.cpp IO/mitkIOUtil.cpp IO/mitkItkLoggingAdapter.cpp + IO/mitkMimeType.cpp IO/mitkOperation.cpp # IO/mitkPicFileIOFactory.cpp # IO/mitkPicFileReader.cpp # IO/mitkPicFileWriter.cpp # IO/mitkPicHelper.cpp # IO/mitkPicVolumeTimeSeriesIOFactory.cpp # IO/mitkPicVolumeTimeSeriesReader.cpp IO/mitkPixelType.cpp - IO/mitkSimpleMimeType.cpp IO/mitkStandardFileLocations.cpp IO/mitkVtkLoggingAdapter.cpp IO/mitkLog.cpp Rendering/mitkBaseRenderer.cpp Rendering/mitkVtkMapper.cpp Rendering/mitkRenderWindowFrame.cpp Rendering/mitkPlaneGeometryDataMapper2D.cpp Rendering/mitkPlaneGeometryDataVtkMapper3D.cpp Rendering/mitkGLMapper.cpp Rendering/mitkGradientBackground.cpp Rendering/mitkManufacturerLogo.cpp Rendering/mitkMapper.cpp Rendering/mitkPointSetGLMapper2D.cpp Rendering/mitkPointSetVtkMapper2D.cpp Rendering/mitkPointSetVtkMapper3D.cpp Rendering/mitkSurfaceGLMapper2D.cpp Rendering/mitkSurfaceVtkMapper3D.cpp Rendering/mitkVolumeDataVtkMapper3D.cpp Rendering/mitkVtkPropRenderer.cpp Rendering/mitkVtkWidgetRendering.cpp Rendering/vtkMitkRectangleProp.cpp Rendering/vtkMitkRenderProp.cpp Rendering/mitkVtkEventProvider.cpp Rendering/mitkRenderWindow.cpp Rendering/mitkRenderWindowBase.cpp Rendering/mitkImageVtkMapper2D.cpp Rendering/vtkMitkThickSlicesFilter.cpp Rendering/vtkMitkLevelWindowFilter.cpp Rendering/vtkNeverTranslucentTexture.cpp Rendering/mitkOverlay.cpp Rendering/mitkVtkOverlay.cpp Rendering/mitkVtkOverlay2D.cpp Rendering/mitkVtkOverlay3D.cpp Rendering/mitkOverlayManager.cpp Rendering/mitkAbstractOverlayLayouter.cpp Rendering/mitkTextOverlay2D.cpp Rendering/mitkTextOverlay3D.cpp Rendering/mitkLabelOverlay3D.cpp Rendering/mitkOverlay2DLayouter.cpp Rendering/mitkScaleLegendOverlay Common/mitkException.cpp Common/mitkCommon.h Common/mitkCoreObjectFactoryBase.cpp Common/mitkCoreObjectFactory.cpp Common/mitkCoreServices.cpp Internal/mitkCoreActivator.cpp Internal/mitkFileReaderWriterBase.cpp Internal/mitkItkImageIO.cpp Internal/mitkLegacyFileReaderService.cpp #Internal/mitkLegacyFileWriterService.cpp Internal/mitkMimeTypeProvider.cpp Internal/mitkPointSetReaderService.cpp Internal/mitkPointSetWriterService.cpp Internal/mitkRawImageFileReader.cpp ) set(RESOURCE_FILES Interactions/globalConfig.xml Interactions/DisplayInteraction.xml Interactions/DisplayConfig.xml Interactions/DisplayConfigPACS.xml Interactions/DisplayConfigPACSPan.xml Interactions/DisplayConfigPACSScroll.xml Interactions/DisplayConfigPACSZoom.xml Interactions/DisplayConfigPACSLevelWindow.xml Interactions/DisplayConfigMITK.xml Interactions/PointSet.xml Interactions/Legacy/StateMachine.xml Interactions/Legacy/DisplayConfigMITKTools.xml Interactions/PointSetConfig.xml mitkLevelWindowPresets.xml ) diff --git a/Core/Documentation/Doxygen/Concepts/Concepts.dox b/Core/Documentation/Doxygen/Concepts/Concepts.dox index 549334e725..5a0594d3fe 100644 --- a/Core/Documentation/Doxygen/Concepts/Concepts.dox +++ b/Core/Documentation/Doxygen/Concepts/Concepts.dox @@ -1,32 +1,33 @@ /** \page Concepts MITK Concepts The following items describe some issues about MITK on a more abstract level. -# \subpage OverviewPage -# \subpage CodingPage "Coding Concepts" -# \ref CodingPageGeneral -# \ref CodingPageStyle -# \ref CodingPageMITKMacros -# \subpage MicroServices_Overview -# Data Concepts -# \subpage BasicDataTypesPage -# \subpage DataManagementPage + -# \subpage ReaderWriterPage -# \subpage MitkImagePage -# \subpage PropertiesPage -# \subpage GeometryOverviewPage -# \subpage PipelineingConceptPage -# \subpage OverlaysPage -# \subpage PersistenceConceptPage -# \subpage QVTKRendering -# Interaction -# \subpage DataInteractionPage -# \subpage InteractionPage -# \subpage LoggingPage -# \subpage ExceptionPage -# \subpage ModularizationPage "Modularization Concept" -# \ref ModularizationPageOverview -# \ref ModularizationPageHowTo If you want to start using MITK, you also want to see the chapter \ref Development. */ diff --git a/Core/Documentation/Doxygen/Concepts/ReaderWriterPage.md b/Core/Documentation/Doxygen/Concepts/ReaderWriterPage.md new file mode 100644 index 0000000000..380491c3fb --- /dev/null +++ b/Core/Documentation/Doxygen/Concepts/ReaderWriterPage.md @@ -0,0 +1,37 @@ +Reader and Writer # ReaderWriterPage +================= + + +## Mime Types + +## The IFileReader interface + +## The IFileWriter interface + +## Convenience classes + +### mitk:IOUtil + +For loading data into a data storage or just returning BaseData objects. +Handles all the details for you. + +### QmitkIOUtil + +### mitk::FileReaderRegistry and mitk::FileWriterRegistry + +Access to IFileReader and IFileWriter objects and their service references. + +## Meta Data + +## Options + +#### raw image file reader + +### ITK Reader and Writer + +Dynamic object factory registration? + + +### VTK Reader and Writer + +## Error handling and recovery diff --git a/Modules/LegacyIO/mitkActivator.cpp b/Modules/LegacyIO/mitkActivator.cpp index f92c233371..6f3f0a8ac3 100644 --- a/Modules/LegacyIO/mitkActivator.cpp +++ b/Modules/LegacyIO/mitkActivator.cpp @@ -1,86 +1,85 @@ /*=================================================================== 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 "mitkSurfaceVtkWriterFactory.h" #include "mitkPointSetIOFactory.h" #include "mitkPointSetWriterFactory.h" #include "mitkSTLFileIOFactory.h" #include "mitkVtkSurfaceIOFactory.h" #include "mitkVtkImageIOFactory.h" #include "mitkVtiFileIOFactory.h" #include "mitkItkImageFileIOFactory.h" #include "mitkImageWriterFactory.h" -#include "mitkSimpleMimeType.h" #include #include class US_ABI_LOCAL Activator : public us::ModuleActivator { public: void Load(us::ModuleContext* context) { //m_CoreDataNodeReader.reset(new mitk::CoreDataNodeReader); //context->RegisterService(m_CoreDataNodeReader.get()); this->m_Context = context; m_ObjectFactories.push_back(mitk::PointSetIOFactory::New().GetPointer()); m_ObjectFactories.push_back(mitk::STLFileIOFactory::New().GetPointer()); m_ObjectFactories.push_back(mitk::VtkSurfaceIOFactory::New().GetPointer()); m_ObjectFactories.push_back(mitk::VtkImageIOFactory::New().GetPointer()); m_ObjectFactories.push_back(mitk::VtiFileIOFactory::New().GetPointer()); m_ObjectFactories.push_back(mitk::ItkImageFileIOFactory::New().GetPointer()); for(std::vector::const_iterator iter = m_ObjectFactories.begin(), end = m_ObjectFactories.end(); iter != end; ++iter) { itk::ObjectFactoryBase::RegisterFactory(*iter); } mitk::SurfaceVtkWriterFactory::RegisterOneFactory(); mitk::PointSetWriterFactory::RegisterOneFactory(); mitk::ImageWriterFactory::RegisterOneFactory(); } void Unload(us::ModuleContext* ) { for(std::vector::const_iterator iter = m_ObjectFactories.begin(), end = m_ObjectFactories.end(); iter != end; ++iter) { itk::ObjectFactoryBase::UnRegisterFactory(*iter); } // FIXME: There is no "UnRegisterOneFactory" method } private: //std::auto_ptr m_CoreDataNodeReader; us::ModuleContext* m_Context; std::vector m_ObjectFactories; }; US_EXPORT_MODULE_ACTIVATOR(MitkLegacyIO, Activator) diff --git a/Modules/QtWidgets/QmitkFileReaderOptionsDialog.cpp b/Modules/QtWidgets/QmitkFileReaderOptionsDialog.cpp index d1abc942d7..f1ac94ea90 100644 --- a/Modules/QtWidgets/QmitkFileReaderOptionsDialog.cpp +++ b/Modules/QtWidgets/QmitkFileReaderOptionsDialog.cpp @@ -1,86 +1,91 @@ /*=================================================================== 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 "QmitkFileReaderOptionsDialog.h" #include "ui_QmitkFileReaderOptionsDialog.h" #include "QmitkFileReaderWriterOptionsWidget.h" #include "mitkIFileReader.h" -QmitkFileReaderOptionsDialog::QmitkFileReaderOptionsDialog(const QString& filePath, - const QStringList& labels, - const QList& readers, +QmitkFileReaderOptionsDialog::QmitkFileReaderOptionsDialog(mitk::IOUtil::LoadInfo& loadInfo, QWidget *parent) : QDialog(parent) , ui(new Ui::QmitkFileReaderOptionsDialog) - , m_Readers(readers) + , m_LoadInfo(loadInfo) + { ui->setupUi(this); - const int count = qMin(labels.size(), readers.size()); + m_ReaderItems = loadInfo.m_ReaderSelector.Get(); + bool hasOptions = false; - for (int i = 0; i < count; ++i) + int selectedIndex = 0; + long selectedReaderId = loadInfo.m_ReaderSelector.GetSelectedId(); + int i = 0; + for (std::vector::const_reverse_iterator iter = m_ReaderItems.rbegin(), + iterEnd = m_ReaderItems.rend(); iter != iterEnd; ++iter) { - ui->m_ReaderComboBox->addItem(labels[i]); - mitk::IFileReader::Options options = readers[i]->GetOptions(); + ui->m_ReaderComboBox->addItem(QString::fromStdString(iter->GetDescription())); + mitk::IFileReader::Options options = iter->GetReader()->GetOptions(); if (!options.empty()) { hasOptions = true; } ui->m_StackedOptionsWidget->addWidget(new QmitkFileReaderWriterOptionsWidget(options)); + if (iter->GetServiceId() == selectedReaderId) + { + selectedIndex = i; + } } + ui->m_ReaderComboBox->setCurrentIndex(selectedIndex); if(!hasOptions) { ui->m_OptionsBox->setVisible(false); } - if (count < 2) + if (m_ReaderItems.size() < 2) { ui->m_ReaderLabel->setVisible(false); ui->m_ReaderComboBox->setVisible(false); - ui->m_FilePathLabel->setText(QString("File: %1").arg(filePath)); + ui->m_FilePathLabel->setText(QString("File: %1").arg(QString::fromStdString(loadInfo.m_Path))); } else { - ui->m_FilePathLabel->setText(QString("for %1").arg(filePath)); + ui->m_FilePathLabel->setText(QString("for %1").arg(QString::fromStdString(loadInfo.m_Path))); } this->setWindowTitle("File reading options"); } QmitkFileReaderOptionsDialog::~QmitkFileReaderOptionsDialog() { delete ui; } -mitk::IFileReader* QmitkFileReaderOptionsDialog::GetReader() const -{ - return m_Readers[ui->m_ReaderComboBox->currentIndex()]; -} - bool QmitkFileReaderOptionsDialog::ReuseOptions() const { return ui->m_ReuseOptionsCheckBox->isChecked(); } void QmitkFileReaderOptionsDialog::accept() { - const int index = ui->m_ReaderComboBox->currentIndex(); - m_Readers[index]->SetOptions( - qobject_cast(ui->m_StackedOptionsWidget->widget(index))->GetOptions()); + const int index = m_ReaderItems.size() - ui->m_ReaderComboBox->currentIndex() - 1; + m_ReaderItems[index].GetReader()->SetOptions( + qobject_cast(ui->m_StackedOptionsWidget->currentWidget())->GetOptions()); + m_LoadInfo.m_ReaderSelector.Select(m_ReaderItems[index]); QDialog::accept(); } diff --git a/Modules/QtWidgets/QmitkFileReaderOptionsDialog.h b/Modules/QtWidgets/QmitkFileReaderOptionsDialog.h index ad26954de7..fc7ebc7043 100644 --- a/Modules/QtWidgets/QmitkFileReaderOptionsDialog.h +++ b/Modules/QtWidgets/QmitkFileReaderOptionsDialog.h @@ -1,56 +1,51 @@ /*=================================================================== 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 QMITKFILEREADEROPTIONSDIALOG_H #define QMITKFILEREADEROPTIONSDIALOG_H -#include +#include "mitkIOUtil.h" -namespace mitk { -class IFileReader; -} +#include namespace Ui { class QmitkFileReaderOptionsDialog; } class QmitkFileReaderWriterOptionsWidget; class QmitkFileReaderOptionsDialog : public QDialog { Q_OBJECT public: - explicit QmitkFileReaderOptionsDialog(const QString& filePath, - const QStringList& labels, - const QList& readers, + explicit QmitkFileReaderOptionsDialog(mitk::IOUtil::LoadInfo& loadInfo, QWidget *parent = 0); ~QmitkFileReaderOptionsDialog(); - mitk::IFileReader* GetReader() const; - bool ReuseOptions() const; virtual void accept(); private: Ui::QmitkFileReaderOptionsDialog* ui; - const QList m_Readers; + mitk::IOUtil::LoadInfo& m_LoadInfo; + std::vector m_ReaderItems; }; #endif // QMITKFILEREADEROPTIONSDIALOG_H diff --git a/Modules/QtWidgets/QmitkFileReaderOptionsDialog.ui b/Modules/QtWidgets/QmitkFileReaderOptionsDialog.ui index 720fdce914..3ee173c788 100644 --- a/Modules/QtWidgets/QmitkFileReaderOptionsDialog.ui +++ b/Modules/QtWidgets/QmitkFileReaderOptionsDialog.ui @@ -1,147 +1,147 @@ QmitkFileReaderOptionsDialog 0 0 458 343 Dialog true true Choose file reader true 0 0 Options false Qt::Vertical 20 10 Remember settings for all remaining files of the same type Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() QmitkFileReaderOptionsDialog accept() 248 254 157 274 buttonBox rejected() QmitkFileReaderOptionsDialog reject() 316 260 286 274 m_ReaderComboBox - activated(int) + currentIndexChanged(int) m_StackedOptionsWidget setCurrentIndex(int) 199 44 203 167 diff --git a/Modules/QtWidgets/QmitkFileWriterOptionsDialog.cpp b/Modules/QtWidgets/QmitkFileWriterOptionsDialog.cpp index a8d7cf4393..63de538c19 100644 --- a/Modules/QtWidgets/QmitkFileWriterOptionsDialog.cpp +++ b/Modules/QtWidgets/QmitkFileWriterOptionsDialog.cpp @@ -1,86 +1,92 @@ /*=================================================================== 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 "QmitkFileWriterOptionsDialog.h" #include "ui_QmitkFileWriterOptionsDialog.h" #include "QmitkFileReaderWriterOptionsWidget.h" #include "mitkIFileWriter.h" +#include "mitkFileWriterSelector.h" -QmitkFileWriterOptionsDialog::QmitkFileWriterOptionsDialog(const QString& filePath, - const QStringList& labels, - const QList& writers, +QmitkFileWriterOptionsDialog::QmitkFileWriterOptionsDialog(mitk::IOUtil::SaveInfo& saveInfo, QWidget *parent) : QDialog(parent) , ui(new Ui::QmitkFileWriterOptionsDialog) - , m_Writers(writers) + , m_SaveInfo(saveInfo) { ui->setupUi(this); - const int count = qMin(labels.size(), writers.size()); + m_WriterItems = saveInfo.m_WriterSelector.Get(saveInfo.m_MimeType.GetName()); + bool hasOptions = false; - for (int i = 0; i < count; ++i) + int selectedIndex = 0; + long selectedWriterId = saveInfo.m_WriterSelector.GetSelectedId(); + int i = 0; + // Fill the combo box such that at the first entry is the best matching writer + for (std::vector::const_reverse_iterator iter = m_WriterItems.rbegin(), + iterEnd = m_WriterItems.rend(); iter != iterEnd; ++iter, ++i) { - ui->m_WriterComboBox->addItem(labels[i]); - mitk::IFileWriter::Options options = writers[i]->GetOptions(); + ui->m_WriterComboBox->addItem(QString::fromStdString(iter->GetDescription())); + mitk::IFileWriter::Options options = iter->GetWriter()->GetOptions(); if (!options.empty()) { hasOptions = true; } ui->m_StackedOptionsWidget->addWidget(new QmitkFileReaderWriterOptionsWidget(options)); + if (iter->GetServiceId() == selectedWriterId) + { + selectedIndex = i; + } } + ui->m_WriterComboBox->setCurrentIndex(selectedIndex); if(!hasOptions) { ui->m_OptionsBox->setVisible(false); } - if (count < 2) + if (m_WriterItems.size() < 2) { ui->m_WriterLabel->setVisible(false); ui->m_WriterComboBox->setVisible(false); - ui->m_FilePathLabel->setText(QString("File: %1").arg(filePath)); + ui->m_FilePathLabel->setText(QString("File: %1").arg(QString::fromStdString(saveInfo.m_Path))); } else { - ui->m_FilePathLabel->setText(QString("for %1").arg(filePath)); + ui->m_FilePathLabel->setText(QString("for %1").arg(QString::fromStdString(saveInfo.m_Path))); } this->setWindowTitle("File writing options"); } QmitkFileWriterOptionsDialog::~QmitkFileWriterOptionsDialog() { delete ui; } -mitk::IFileWriter* QmitkFileWriterOptionsDialog::GetWriter() const -{ - return m_Writers[ui->m_WriterComboBox->currentIndex()]; -} - bool QmitkFileWriterOptionsDialog::ReuseOptions() const { return ui->m_ReuseOptionsCheckBox->isChecked(); } void QmitkFileWriterOptionsDialog::accept() { - const int index = ui->m_WriterComboBox->currentIndex(); - m_Writers[index]->SetOptions( - qobject_cast(ui->m_StackedOptionsWidget->widget(index))->GetOptions()); + const int index = m_WriterItems.size() - ui->m_WriterComboBox->currentIndex() - 1; + m_WriterItems[index].GetWriter()->SetOptions( + qobject_cast(ui->m_StackedOptionsWidget->currentWidget())->GetOptions()); + m_SaveInfo.m_WriterSelector.Select(m_WriterItems[index]); QDialog::accept(); } diff --git a/Modules/QtWidgets/QmitkFileWriterOptionsDialog.h b/Modules/QtWidgets/QmitkFileWriterOptionsDialog.h index a2e279c2b6..31538a1d59 100644 --- a/Modules/QtWidgets/QmitkFileWriterOptionsDialog.h +++ b/Modules/QtWidgets/QmitkFileWriterOptionsDialog.h @@ -1,56 +1,50 @@ /*=================================================================== 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 QMITKFILEWRITEROPTIONSDIALOG_H #define QMITKFILEWRITEROPTIONSDIALOG_H -#include +#include -namespace mitk { -class IFileWriter; -} +#include namespace Ui { class QmitkFileWriterOptionsDialog; } class QmitkFileReaderWriterOptionsWidget; class QmitkFileWriterOptionsDialog : public QDialog { Q_OBJECT public: - explicit QmitkFileWriterOptionsDialog(const QString& filePath, - const QStringList& labels, - const QList& writers, - QWidget *parent = 0); + explicit QmitkFileWriterOptionsDialog(mitk::IOUtil::SaveInfo& saveInfo, QWidget *parent = 0); ~QmitkFileWriterOptionsDialog(); - mitk::IFileWriter* GetWriter() const; - bool ReuseOptions() const; virtual void accept(); private: Ui::QmitkFileWriterOptionsDialog* ui; - const QList m_Writers; + mitk::IOUtil::SaveInfo& m_SaveInfo; + std::vector m_WriterItems; }; #endif // QMITKFILEREADEROPTIONSDIALOG_H diff --git a/Modules/QtWidgets/QmitkFileWriterOptionsDialog.ui b/Modules/QtWidgets/QmitkFileWriterOptionsDialog.ui index ec979c3825..a86d37ed1a 100644 --- a/Modules/QtWidgets/QmitkFileWriterOptionsDialog.ui +++ b/Modules/QtWidgets/QmitkFileWriterOptionsDialog.ui @@ -1,147 +1,147 @@ QmitkFileWriterOptionsDialog 0 0 458 343 Dialog true true Choose file writer true 0 0 Options false Qt::Vertical 20 10 Remember settings for all remaining files of the same type Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() QmitkFileWriterOptionsDialog accept() 248 254 157 274 buttonBox rejected() QmitkFileWriterOptionsDialog reject() 316 260 286 274 m_WriterComboBox - activated(int) + currentIndexChanged(int) m_StackedOptionsWidget setCurrentIndex(int) 199 44 203 167 diff --git a/Modules/QtWidgets/QmitkIOUtil.cpp b/Modules/QtWidgets/QmitkIOUtil.cpp index d704106635..0aaab5f758 100644 --- a/Modules/QtWidgets/QmitkIOUtil.cpp +++ b/Modules/QtWidgets/QmitkIOUtil.cpp @@ -1,545 +1,529 @@ /*=================================================================== 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()(const std::string& path, const std::vector& readerLabels, - const std::vector& readers, mitk::IFileReader*& selectedReader) + virtual bool operator()(LoadInfo& loadInfo) { - QStringList qLabels; - for (std::vector::const_iterator iter = readerLabels.begin(), iterEnd = readerLabels.end(); - iter != iterEnd; ++iter) - { - qLabels.push_back(QString::fromStdString(*iter)); - } - QList qReaders; - for (std::vector::const_iterator iter = readers.begin(), iterEnd = readers.end(); - iter != iterEnd; ++iter) - { - qReaders.push_back(*iter); - } - - QmitkFileReaderOptionsDialog dialog(QString::fromStdString(path), qLabels, qReaders); + QmitkFileReaderOptionsDialog dialog(loadInfo); if (dialog.exec() == QDialog::Accepted) { - selectedReader = dialog.GetReader(); return !dialog.ReuseOptions(); } else { - selectedReader = NULL; + loadInfo.m_Cancel = true; return true; } } }; struct WriterOptionsDialogFunctor : public WriterOptionsFunctorBase { - virtual bool operator()(const std::string& path, const std::vector& writerLabels, - const std::vector& writers, mitk::IFileWriter*& selectedWriter) + virtual bool operator()(SaveInfo& saveInfo) { - QStringList qLabels; - for (std::vector::const_iterator iter = writerLabels.begin(), iterEnd = writerLabels.end(); - iter != iterEnd; ++iter) - { - qLabels.push_back(QString::fromStdString(*iter)); - } - QList qWriters; - for (std::vector::const_iterator iter = writers.begin(), iterEnd = writers.end(); - iter != iterEnd; ++iter) - { - qWriters.push_back(*iter); - } - - QmitkFileWriterOptionsDialog dialog(QString::fromStdString(path), qLabels, qWriters); + QmitkFileWriterOptionsDialog dialog(saveInfo); if (dialog.exec() == QDialog::Accepted) { - selectedWriter = dialog.GetWriter(); return !dialog.ReuseOptions(); } else { - selectedWriter = NULL; + 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 mimeTypes = mimeTypeProvider->GetMimeTypesForCategory(*cat); + for (std::vector::iterator mt = mimeTypes.begin(); mt != mimeTypes.end(); ++mt) { - std::vector extensions = mimeTypeProvider->GetExtensions(*mt); + std::cout << "Got " << mt->GetName() << " for cat " << *cat << std::endl; + 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; } -QmitkIOUtil::SaveFilter QmitkIOUtil::GetFileSaveFilter(const mitk::BaseData* baseData) -{ - return SaveFilter(baseData); -} - -QmitkIOUtil::SaveFilter QmitkIOUtil::GetFileSaveFilter(const std::string& baseDataType) -{ - return SaveFilter(baseDataType); -} - QList QmitkIOUtil::Load(const QStringList& paths, QWidget* parent) { - std::vector qPaths; + std::vector loadInfos; foreach(const QString& file, paths) { - qPaths.push_back(file.toStdString()); + loadInfos.push_back(LoadInfo(file.toStdString())); } - std::vector result; Impl::ReaderOptionsDialogFunctor optionsCallback; - std::string errMsg = Load(qPaths, &result, NULL, NULL, &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 = result.begin(), - iterEnd = result.end(); iter != iterEnd; ++iter) + for(std::vector::const_iterator iter = loadInfos.begin(), iterEnd = loadInfos.end(); + iter != iterEnd; ++iter) { - qResult << *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 qPaths; + std::vector loadInfos; foreach(const QString& file, paths) { - qPaths.push_back(file.toStdString()); + loadInfos.push_back(LoadInfo(file.toStdString())); } mitk::DataStorage::SetOfObjects::Pointer nodeResult = mitk::DataStorage::SetOfObjects::New(); Impl::ReaderOptionsDialogFunctor optionsCallback; - std::string errMsg = Load(qPaths, NULL, nodeResult, &storage, &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) { - SaveFilter filters(*dataIter); + SaveInfo saveInfo(*dataIter); + + 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]; - std::pair defaultExt = mitk::FileWriterRegistry::GetDefaultExtension(*dataIter); - if (!defaultExt.first.empty()) + // 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 += "." + QString::fromStdString(defaultExt.first); - QString filter = filters.GetFilterForMimeType(defaultExt.second); - if (!filter.isEmpty()) - { - selectedFilter = filter; - } + fileName += "." + defaultExt; } + */ } // Ask the user for a file name QString nextName = QFileDialog::getSaveFileName(parent, dialogTitle, fileName, filterString, &selectedFilter); if (nextName.isEmpty()) { - continue; + // We stop asking for further file names, but we still save the + // data where the user already confirmed the save dialog. + break; } fileName = nextName; QFileInfo fileInfo(fileName); currentPath = fileInfo.absolutePath(); QString suffix = fileInfo.completeSuffix(); - std::string mimeType = filters.GetMimeTypeForFilter(selectedFilter); + mitk::MimeType mimeType = filters.GetMimeTypeForFilter(selectedFilter); mitk::CoreServicePointer mimeTypeProvider(mitk::CoreServices::GetMimeTypeProvider()); // If the filename contains a suffix, use it but check if it is valid if (!suffix.isEmpty()) { - std::vector availableTypes = mimeTypeProvider->GetMimeTypesForExtension(suffix.toStdString()); + std::vector availableTypes = mimeTypeProvider->GetMimeTypesForExtension(suffix.toStdString()); // 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.clear(); - for (std::vector::const_iterator availIter = availableTypes.begin(), + mimeType = mitk::MimeType(); + for (std::vector::const_iterator availIter = availableTypes.begin(), availIterEnd = availableTypes.end(); availIter != availIterEnd; ++availIter) { - if (filters.ContainsMimeType(*availIter)) + if (filters.ContainsMimeType(availIter->GetName())) { mimeType = *availIter; break; } } } - if (mimeType.empty()) + if (!mimeType.IsValid()) { // 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; } } else { // 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) + if (mimeType == SaveFilter::ALL_MIMETYPE()) { // Use the highest ranked mime-type from the list mimeType = filters.GetDefaultMimeType(); } if (!fileInfo.exists()) { - suffix = QString::fromStdString( - mimeTypeProvider->GetExtensions(mimeType).front()); + 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 (!fileInfo.isFile()) { QMessageBox::warning(parent, "Saving not possible", QString("The path \"%1\" is not a file").arg(fileName)); continue; } - if (fileInfo.exists()) + if (QMessageBox::question(parent, "Replace File", + QString("A file named \"%1\" already exists. Do you want to replace it?").arg(fileName)) == + QMessageBox::No) { - if (QMessageBox::question(parent, "Replace File", - "A file named \"%1\" already exists. Do you want to replace it?") == - QMessageBox::No) - { - continue; - } + 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); - saveInfos.push_back(SaveInfo(*dataIter, mimeType, fileName.toStdString())); + saveInfo.m_Path = fileName.toStdString(); + saveInfo.m_MimeType = mimeType; + // pre-select the best writer for the chosen mime-type + saveInfo.m_WriterSelector.Select(mimeType.GetName()); + saveInfos.push_back(saveInfo); MITK_INFO << "****** SAVING TO FILENAME: " << fileName.toStdString(); } - Impl::WriterOptionsDialogFunctor optionsCallback; - std::string errMsg = Save(saveInfos, &optionsCallback); - if (!errMsg.empty()) + if (!saveInfos.empty()) { - QMessageBox::warning(parent, "Error writing files", QString::fromStdString(errMsg)); - mitkThrow() << errMsg; + 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 { - void Init(const std::string& baseDataType) + Impl(const mitk::IOUtil::SaveInfo& saveInfo) + : m_SaveInfo(saveInfo) { // Add an artifical filter for "All" - m_MimeTypes.push_back(ALL_MIMETYPE); + m_MimeTypes.push_back(ALL_MIMETYPE()); m_FilterStrings.push_back("All (*.*)"); // Get all writers and their mime types for the given base data type - std::vector mimeTypes; - std::vector refs = mitk::FileWriterRegistry::GetReferences(baseDataType); - for (std::vector::const_iterator iter = refs.begin(), - iterEnd = refs.end(); iter != iterEnd; ++iter) - { - std::string mimeType = iter->GetProperty(mitk::IFileWriter::PROP_MIMETYPE()).ToString(); - if (!mimeType.empty() && std::find(mimeTypes.begin(), mimeTypes.end(), mimeType) == mimeTypes.end()) - { - mimeTypes.push_back(mimeType); - } - } + // (this is sorted already) + std::vector mimeTypes = saveInfo.m_WriterSelector.GetMimeTypes(); - mitk::CoreServicePointer mimeTypeProvider(mitk::CoreServices::GetMimeTypeProvider()); - for (std::vector::const_iterator iter = mimeTypes.begin(), iterEnd = mimeTypes.end(); - iter != iterEnd; ++iter) + for (std::vector::const_reverse_iterator iter = mimeTypes.rbegin(), + iterEnd = mimeTypes.rend(); iter != iterEnd; ++iter) { QSet filterExtensions; - std::vector extensions = mimeTypeProvider->GetExtensions(*iter); + 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(mimeTypeProvider->GetDescription(*iter)) + " ("; + QString filter = QString::fromStdString(mimeType.GetComment()) + " ("; foreach(const QString& extension, filterExtensions) { filter += "*." + extension + " "; } filter = filter.replace(filter.size()-1, 1, ')'); - m_MimeTypes.push_back(*iter); + m_MimeTypes.push_back(mimeType); m_FilterStrings.push_back(filter); } } - std::vector m_MimeTypes; + const mitk::IOUtil::SaveInfo m_SaveInfo; + std::vector m_MimeTypes; QStringList m_FilterStrings; + QString m_DefaultExtension; }; -std::string QmitkIOUtil::SaveFilter::ALL_MIMETYPE = "__all__"; +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 std::string& baseDataType) - : d(new Impl) +QmitkIOUtil::SaveFilter::SaveFilter(const SaveInfo& saveInfo) + : d(new Impl(saveInfo)) { - if (!baseDataType.empty()) - { - d->Init(baseDataType); - } -} - -QmitkIOUtil::SaveFilter::SaveFilter(const mitk::BaseData* baseData) - : d(new Impl) -{ - if (baseData != NULL) - { - d->Init(baseData->GetNameOfClass()); - } } QmitkIOUtil::SaveFilter& QmitkIOUtil::SaveFilter::operator=(const QmitkIOUtil::SaveFilter& other) { d.reset(new Impl(*other.d)); return *this; } QString QmitkIOUtil::SaveFilter::GetFilterForMimeType(const std::string& mimeType) const { - std::vector::const_iterator iter = - std::find(d->m_MimeTypes.begin(), d->m_MimeTypes.end(), mimeType); + 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]; } -std::string QmitkIOUtil::SaveFilter::GetMimeTypeForFilter(const QString& filter) const +mitk::MimeType QmitkIOUtil::SaveFilter::GetMimeTypeForFilter(const QString& filter) const { int index = d->m_FilterStrings.indexOf(filter); if (index < 0) { - return std::string(); + 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(); } -std::string QmitkIOUtil::SaveFilter::GetDefaultMimeType() const +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 std::string(); + 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(d->m_MimeTypes.begin(), d->m_MimeTypes.end(), mimeType) != d->m_MimeTypes.end(); + 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 664935d916..0faec01333 100644 --- a/Modules/QtWidgets/QmitkIOUtil.h +++ b/Modules/QtWidgets/QmitkIOUtil.h @@ -1,170 +1,232 @@ /*=================================================================== 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 std::string ALL_MIMETYPE; + static mitk::MimeType ALL_MIMETYPE(); SaveFilter(const SaveFilter& other); - SaveFilter(const std::string& baseDataType); - SaveFilter(const mitk::BaseData* baseData); + SaveFilter(const SaveInfo& saveInfo); SaveFilter& operator=(const SaveFilter& other); QString GetFilterForMimeType(const std::string& mimeType) const; - std::string GetMimeTypeForFilter(const QString& filter) const; + mitk::MimeType GetMimeTypeForFilter(const QString& filter) const; QString GetDefaultFilter() const; - std::string GetDefaultMimeType() 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(); - static SaveFilter GetFileSaveFilter(const mitk::BaseData* baseData); - static SaveFilter GetFileSaveFilter(const std::string& baseDataType); - /** * @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 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.
  7. + *
+ * + * 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_03} 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_03} 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_03} 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_03} Use Save() instead. */ DEPRECATED(static void SavePointSetWithDialog(mitk::PointSet::Pointer pointset, std::string fileName = "", QWidget* parent = NULL)); private: struct Impl; }; #endif // _QmitkIOUtil__h_ diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkFileSaveAction.cpp b/Plugins/org.mitk.gui.qt.application/src/QmitkFileSaveAction.cpp index c77babfb69..5f031db919 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkFileSaveAction.cpp +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkFileSaveAction.cpp @@ -1,183 +1,186 @@ /*=================================================================== 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 "QmitkFileSaveAction.h" #include "internal/org_mitk_gui_qt_application_Activator.h" #include #include #include -#include +#include #include #include #include class QmitkFileSaveActionPrivate { private: void HandleSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, berry::ISelection::ConstPointer selection) { this->setEnabled(selection); } berry::ISelectionListener::Pointer m_SelectionListener; public: QmitkFileSaveActionPrivate() - : m_SelectionListener(new berry::SelectionChangedAdapter( + : m_SelectionListener(new berry::NullSelectionChangedAdapter( this, &QmitkFileSaveActionPrivate::HandleSelectionChanged)) { } ~QmitkFileSaveActionPrivate() { m_Window.Lock()->GetSelectionService()->RemoveSelectionListener(m_SelectionListener); } void init ( berry::IWorkbenchWindow::Pointer window, QmitkFileSaveAction* action ) { m_Window = window; m_Action = action; action->setParent(static_cast(m_Window.Lock()->GetShell()->GetControl())); action->setText("&Save..."); action->setToolTip("Save data objects (images, surfaces,...)"); berry::ISelectionService* selectionService = m_Window.Lock()->GetSelectionService(); setEnabled(selectionService->GetSelection()); selectionService->AddSelectionListener(m_SelectionListener); QObject::connect(action, SIGNAL(triggered(bool)), action, SLOT(Run())); } berry::IPreferences::Pointer GetPreferences() const { berry::IPreferencesService::Pointer prefService = mitk::PluginActivator::GetInstance()->GetPreferencesService(); if (prefService.IsNotNull()) { return prefService->GetSystemPreferences()->Node("/General"); } return berry::IPreferences::Pointer(0); } QString getLastFileSavePath() const { berry::IPreferences::Pointer prefs = GetPreferences(); if(prefs.IsNotNull()) { return QString::fromStdString(prefs->Get("LastFileSavePath", "")); } return QString(); } void setLastFileSavePath(const QString& path) const { berry::IPreferences::Pointer prefs = GetPreferences(); if(prefs.IsNotNull()) { prefs->Put("LastFileSavePath", path.toStdString()); prefs->Flush(); } } void setEnabled(berry::ISelection::ConstPointer selection) { mitk::DataNodeSelection::ConstPointer nodeSelection = selection.Cast(); if (nodeSelection.IsNotNull() && !selection->IsEmpty()) { bool enable = false; std::list dataNodes = nodeSelection->GetSelectedDataNodes(); for (std::list::const_iterator nodeIter = dataNodes.begin(), nodeIterEnd = dataNodes.end(); nodeIter != nodeIterEnd; ++nodeIter) { if ((*nodeIter)->GetData() != NULL) { qDebug() << "Got non-empty data-node: " << (*nodeIter)->GetData()->GetNameOfClass(); enable = true; break; } } m_Action->setEnabled(enable); } else { m_Action->setEnabled(false); } } berry::IWorkbenchWindow::WeakPtr m_Window; QAction* m_Action; }; QmitkFileSaveAction::QmitkFileSaveAction(berry::IWorkbenchWindow::Pointer window) : QAction(0), d(new QmitkFileSaveActionPrivate) { d->init(window, this); } QmitkFileSaveAction::QmitkFileSaveAction(const QIcon & icon, berry::IWorkbenchWindow::Pointer window) : QAction(0), d(new QmitkFileSaveActionPrivate) { d->init(window, this); this->setIcon(icon); } QmitkFileSaveAction::~QmitkFileSaveAction() { } void QmitkFileSaveAction::Run() { // Get the list of selected base data objects mitk::DataNodeSelection::ConstPointer selection = d->m_Window.Lock()->GetSelectionService()->GetSelection().Cast(); if (selection.IsNull() || selection->IsEmpty()) { MITK_ERROR << "Assertion failed: data node selection is NULL or empty"; return; } std::list dataNodes = selection->GetSelectedDataNodes(); std::vector data; QStringList names; for (std::list::const_iterator nodeIter = dataNodes.begin(), nodeIterEnd = dataNodes.end(); nodeIter != nodeIterEnd; ++nodeIter) { data.push_back((*nodeIter)->GetData()); std::string name; (*nodeIter)->GetStringProperty("name", name); names.push_back(QString::fromStdString(name)); } try { QStringList fileNames = QmitkIOUtil::Save(data, names, d->getLastFileSavePath(), d->m_Action->parentWidget()); - d->setLastFileSavePath(QFileInfo(fileNames.back()).absolutePath()); + if (!fileNames.empty()) + { + d->setLastFileSavePath(QFileInfo(fileNames.back()).absolutePath()); + } } catch (const mitk::Exception& e) { MITK_INFO << e; return; } }