diff --git a/Core/Code/Common/mitkException.cpp b/Core/Code/Common/mitkException.cpp index c347e28629..9398f876d5 100644 --- a/Core/Code/Common/mitkException.cpp +++ b/Core/Code/Common/mitkException.cpp @@ -1,43 +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. ===================================================================*/ #include "mitkException.h" void mitk::Exception::AddRethrowData(const char *file, unsigned int lineNumber, const char *message) { mitk::Exception::ReThrowData data = {file, lineNumber, message}; this->m_RethrowData.push_back(data); } int mitk::Exception::GetNumberOfRethrows() { return (int)m_RethrowData.size(); } void mitk::Exception::GetRethrowData(int rethrowNumber, std::string &file, int &line, std::string &message) { if ((rethrowNumber >= (int)m_RethrowData.size()) || (rethrowNumber<0)) { file = ""; line = 0; message = ""; return; } file = m_RethrowData.at(rethrowNumber).RethrowClassname; line = m_RethrowData.at(rethrowNumber).RethrowLine; message = m_RethrowData.at(rethrowNumber).RethrowMessage; - } +} + + +std::ostream& operator<<(std::ostream& os, const mitk::Exception& e) +{ + os << e.GetDescription(); + return os; +} diff --git a/Core/Code/Common/mitkException.h b/Core/Code/Common/mitkException.h index 311f3f1fd8..dfcabfab8a 100644 --- a/Core/Code/Common/mitkException.h +++ b/Core/Code/Common/mitkException.h @@ -1,113 +1,116 @@ /*=================================================================== 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 MITKEXCEPTION_H_INCLUDED #define MITKEXCEPTION_H_INCLUDED #include #include #include namespace mitk { /**Documentation * \brief An object of this class represents an exception of MITK. * Please don't instantiate exceptions manually, but use the * exception macros (file mitkExceptionMacro.h) instead. * Simple use in your code is: * * mitkThrow() << "optional exception message"; * * You can also define specialized exceptions which must inherit * from this class. Please always use the mitkExceptionClassMacro * when implementing specialized exceptions. A simple implementation * can look like: * * class MyException : public mitk::Exception * { * public: * mitkExceptionClassMacro(MyException,mitk::Exception); * }; * * You can then throw your specialized exceptions by using the macro * * mitkThrowException(MyException) << "optional exception message"; */ class MITK_CORE_EXPORT Exception : public itk::ExceptionObject { public: Exception(const char *file, unsigned int lineNumber=0, const char *desc="None", const char *loc="Unknown") : itk::ExceptionObject(file,lineNumber,desc,loc){} virtual ~Exception() throw() {} itkTypeMacro(ClassName, SuperClassName); /** \brief Adds rethrow data to this exception. */ void AddRethrowData(const char *file, unsigned int lineNumber, const char *message); /** \return Returns how often the exception was rethrown. */ int GetNumberOfRethrows(); /** @return Returns the rethrow data of the specified rethrow number. Returns empty data, if the rethrowNumber doesn't exist. * @param rethrowNumber The internal number of the rethrow. * @param file (returnvalue) This varaiable will be filled with the file of the specified rethrow. * @param file (returnvalue) This varaiable will be filled with the line of the specified rethrow. * @param file (returnvalue) This varaiable will be filled with the message of the specified rethrow. */ void GetRethrowData(int rethrowNumber, std::string &file, int &line, std::string &message); /** \brief Definition of the bit shift operator for this class.*/ template inline Exception& operator<<(const T& data) { std::stringstream ss; ss << this->GetDescription() << data; this->SetDescription(ss.str()); return *this; } /** \brief Definition of the bit shift operator for this class (for non const data).*/ template inline Exception& operator<<(T& data) { std::stringstream ss; ss << this->GetDescription() << data; this->SetDescription(ss.str()); return *this; } /** \brief Definition of the bit shift operator for this class (for functions).*/ inline Exception& operator<<(std::ostream& (*func)(std::ostream&)) { std::stringstream ss; ss << this->GetDescription() << func; this->SetDescription(ss.str()); return *this; } protected: struct ReThrowData { std::string RethrowClassname; unsigned int RethrowLine; std::string RethrowMessage; }; std::vector m_RethrowData; }; } // namespace mitk + +MITK_CORE_EXPORT std::ostream& operator<<(std::ostream& os, const mitk::Exception& e); + #endif diff --git a/Core/Code/IO/mitkAbstractFileWriter.cpp b/Core/Code/IO/mitkAbstractFileWriter.cpp index 006708ec75..df219b0e74 100644 --- a/Core/Code/IO/mitkAbstractFileWriter.cpp +++ b/Core/Code/IO/mitkAbstractFileWriter.cpp @@ -1,300 +1,310 @@ /*=================================================================== 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 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; }; AbstractFileWriter::AbstractFileWriter() : d(new Impl) { } AbstractFileWriter::~AbstractFileWriter() { 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, 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); } ////////////////////// 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(); } } 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()) { MITK_WARN << "Not registering writer " << typeid(this).name() << " 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(); return context->RegisterService(d->m_PrototypeFactory, props); } us::ServiceProperties AbstractFileWriter::GetServiceProperties() const { us::ServiceProperties result; result[IFileWriter::PROP_DESCRIPTION()] = this->GetDescription(); result[IFileWriter::PROP_MIMETYPE()] = this->GetMimeType(); 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 { return d->GetMimeType(); } us::ServiceRegistration AbstractFileWriter::RegisterMimeType(us::ModuleContext* context) { return d->RegisterMimeType(context); } void AbstractFileWriter::SetMimeType(const std::string& 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/mitkFileWriterRegistry.cpp b/Core/Code/IO/mitkFileWriterRegistry.cpp index 4407513e9a..306f853730 100644 --- a/Core/Code/IO/mitkFileWriterRegistry.cpp +++ b/Core/Code/IO/mitkFileWriterRegistry.cpp @@ -1,127 +1,211 @@ /*=================================================================== 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::string mitk::FileWriterRegistry::GetDefaultExtension(const mitk::FileWriterRegistry::WriterReference& ref, us::ModuleContext* context) +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::string(); - return extensions.front(); + 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); } +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); 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(); +} + std::vector mitk::FileWriterRegistry::GetReferences(const mitk::BaseData* baseData, us::ModuleContext* context) { return GetReferences(baseData->GetNameOfClass(), 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()) == baseDataType && + (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) { 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) { return GetWriter(baseData->GetNameOfClass(), context); } +mitk::IFileWriter*mitk::FileWriterRegistry::GetWriter(const mitk::BaseData* baseData, const std::string& mimeType, us::ModuleContext* context) +{ + return GetWriter(baseData->GetNameOfClass(), mimeType, context); +} + std::vector mitk::FileWriterRegistry::GetWriters(const std::string& baseDataType, us::ModuleContext* context) +{ + return GetWriters(baseDataType, std::string(), context); +} + +std::vector mitk::FileWriterRegistry::GetWriters(const std::string& baseDataType, const std::string& mimeType, us::ModuleContext* context) { std::vector result; - std::vector > refs = GetReferences(baseDataType, context); + std::vector > refs; + if (mimeType.empty()) + { + refs = GetReferences(baseDataType, context); + } + else + { + refs = GetReferences(baseDataType, 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 0b07bd21dd..bf6fc6375d 100644 --- a/Core/Code/IO/mitkFileWriterRegistry.h +++ b/Core/Code/IO/mitkFileWriterRegistry.h @@ -1,97 +1,107 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #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 * * 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::string GetDefaultExtension(const WriterReference& ref, us::ModuleContext* context = us::GetModuleContext()); + 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/mitkIOUtil.cpp b/Core/Code/IO/mitkIOUtil.cpp index 7b1f2165c6..8ba3832c78 100644 --- a/Core/Code/IO/mitkIOUtil.cpp +++ b/Core/Code/IO/mitkIOUtil.cpp @@ -1,955 +1,1160 @@ /*=================================================================== 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 //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 FixedOptionsFunctor : public OptionsFunctorBase + struct FixedReaderOptionsFunctor : public ReaderOptionsFunctorBase { - FixedOptionsFunctor(const IFileReader::Options& options) + 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) { selectedReader = readers.front(); selectedReader->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) + { + selectedWriter = writers.front(); + selectedWriter->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); DataStorage::SetOfObjects::Pointer nodeResult = DataStorage::SetOfObjects::New(); - Impl::FixedOptionsFunctor optionsCallback(options); + Impl::FixedReaderOptionsFunctor optionsCallback(options); std::string errMsg = Load(paths, NULL, 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; - Impl::FixedOptionsFunctor optionsCallback(options); + Impl::FixedReaderOptionsFunctor optionsCallback(options); std::string errMsg = Load(paths, &result, NULL, NULL, &optionsCallback); if (!errMsg.empty()) { mitkThrow() << errMsg; } return result; } 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); 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); if (!errMsg.empty()) { mitkThrow() << errMsg; } 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, DataStorage::SetOfObjects* nodeResult, DataStorage* ds, - OptionsFunctorBase* optionsCallback) + ReaderOptionsFunctorBase* optionsCallback) { if (paths.empty()) { return "No input files given"; } - mitk::ProgressBar::GetInstance()->AddStepsToDo(2*paths.size()); + int filesToRead = paths.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::vector mimeTypes = mimeTypeProvider->GetMimeTypesForFile(*selectedFileIter); if (!mimeTypes.empty()) { fileSorter.AddFile(*selectedFileIter, mimeTypes); } else { noMimeTypeError += " * " + *selectedFileIter + "\n"; } } if (!noMimeTypeError.empty()) { errMsg += "Unknown file format for\n\n" + noMimeTypeError + "\n\n"; } FileReaderRegistry readerRegistry; 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) { // 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) { mitk::IFileReader* reader = readerRegistry.GetReader(*readerRef); try { if (reader->CanRead(currentFiles.front())) { finalReaders.push_back(reader); finalReaderLabels.push_back(readerRef->GetProperty(mitk::IFileReader::PROP_DESCRIPTION()).ToString()); } } catch (const std::exception& e) { MITK_ERROR << "Calling CanRead('" << currentFiles.front() << "') on " << typeid(reader).name() << "failed: " << e.what(); } } } if (finalReaders.empty()) { errMsg += "No reader available for files\n\n"; for(FileSorter::FileVector::const_iterator fileIter = currentFiles.begin(), fileIterEnd = currentFiles.end(); fileIter != fileIterEnd; ++fileIter) { errMsg += " * " + *fileIter + "\n"; } } else { // TODO check if the reader can read a series of files and if yes, // pass the complete file list to one "Read" call. bool callOptionsCallback = finalReaders.size() > 1 || !finalReaders.front()->GetOptions().empty(); mitk::IFileReader* selectedReader = finalReaders.front(); - MITK_INFO << "******* USING READER " << typeid(*selectedReader).name() << "*********"; + for(FileSorter::FileVector::const_iterator fileIter = currentFiles.begin(), fileIterEnd = currentFiles.end(); fileIter != fileIterEnd; ++fileIter) { if (callOptionsCallback && optionsCallback) { callOptionsCallback = (*optionsCallback)(*fileIter, finalReaderLabels, finalReaders, selectedReader); } if (selectedReader == NULL) { errMsg += "Reading operation(s) cancelled."; break; } + MITK_INFO << "******* USING READER " << typeid(*selectedReader).name() << "*********"; + // Do the actual reading try { // 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); } } } 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()); } } if ((result && result->empty()) || (nodeResult && nodeResult->Size() == 0)) { errMsg += "Unknown read error occurred reading " + stdFile; } } catch (const std::exception& e) { errMsg += "Exception occured when reading file " + *fileIter + ":\n" + e.what() + "\n\n"; } mitk::ProgressBar::GetInstance()->Progress(2); + --filesToRead; + } + + if (selectedReader == NULL) + { + // reading was cancelled within the optionsCallback, + // break outer loop as well + break; } } for(std::vector::const_iterator readerIter = finalReaders.begin(), readerIterEnd = finalReaders.end(); readerIter != readerIterEnd; ++readerIter) { readerRegistry.UngetReader(*readerIter); } } if (!errMsg.empty()) { MITK_ERROR << errMsg; } + mitk::ProgressBar::GetInstance()->Progress(2*filesToRead); + return errMsg; } -void IOUtil::Save(BaseData* data, const std::string& path) +void IOUtil::Save(const BaseData* data, const std::string& path) { Save(data, path, IFileWriter::Options()); } -void IOUtil::Save(BaseData* data, const std::string& path, const IFileWriter::Options& options) +void IOUtil::Save(const BaseData* data, const std::string& path, const IFileWriter::Options& options) { - if (data == NULL) - { - mitkThrow() << "Cannot write a NULL" << data->GetNameOfClass() << " object."; - } - if (path.empty()) - { - mitkThrow() << "Cannot write a " << data->GetNameOfClass() << " object to an empty path."; - } + Save(data, std::string(), path, options); +} - FileWriterRegistry writerRegistry; - us::ServiceReference writerRef = writerRegistry.GetReference(data); - // Throw exception if no compatible Writer was found - if (!writerRef) +void IOUtil::Save(const BaseData* data, const std::string& mimeType, const std::string& path) +{ + Save(data, mimeType, path, IFileWriter::Options()); +} + +void IOUtil::Save(const BaseData* data, const std::string& mimeType, const std::string& path, + const IFileWriter::Options& options) +{ + std::string errMsg; + if (options.empty()) { - mitkThrow() << "No writer for " << data->GetNameOfClass() << " available."; + errMsg = Save(data, mimeType, path, NULL); } - -// std::string extension = itksys::SystemTools::GetFilenameExtension( path ); -// if(extension.empty()) -// { -// std::string defaultExtension = writerRegistry.GetDefaultExtension(writerRef); -// MITK_WARN << "Using default extension '" << defaultExtension << "' for writing to " << path; -// extension = "." + defaultExtension; -// } - - IFileWriter* writer = writerRegistry.GetWriter(writerRef); - if (writer == NULL) + else { - mitkThrow() << "Got a NULL IFileWriter service for writing " << data->GetNameOfClass(); + Impl::FixedWriterOptionsFunctor optionsCallback(options); + errMsg = Save(data, mimeType, path, &optionsCallback); } - try + if (!errMsg.empty()) { - if (!options.empty()) - { - writer->SetOptions(options); - } - writer->Write(data, path); + mitkThrow() << errMsg; } - catch(const std::exception& e) +} + +void IOUtil::Save(const std::vector& saveInfos) +{ + std::string errMsg = Save(saveInfos, NULL); + if (!errMsg.empty()) { - mitkThrow() << " Writing a " << data->GetNameOfClass() << " to " << path << " failed: " - << e.what(); + 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) +{ + if (path.empty()) + { + return "No output filename given"; + } + + std::vector infos; + infos.push_back(SaveInfo(data, mimeType, path)); + return Save(infos, optionsCallback); +} + +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 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 (iter->m_BaseData == NULL) + { + infoError += "Cannot save NULL data to path " + (iter->m_Path.empty() ? "(NULL)" : iter->m_Path) + "\n"; + continue; + } + if (iter->m_Path.empty()) + { + infoError += std::string("Cannot save ") + (iter->m_BaseData == NULL ? "(NULL)" : iter->m_BaseData->GetNameOfClass()) + + " data to unknown file path.\n"; + continue; + } + infoSorter.AddSaveInfo(*iter); + } + + if(!infoError.empty()) + { + errMsg += "Invalid information:\n\n" + infoError + "\n\n"; + } + + FileWriterRegistry writerRegistry; + + for (SaveInfoSorter::Iterator iter = infoSorter.Begin(), endIter = infoSorter.End(); + iter != endIter; ++iter) + { + const SaveInfoSorter::SaveInfoVector& currentInfos = iter->second; + + const std::string baseDataType = currentInfos.front().m_BaseData->GetNameOfClass(); + const std::string mimeType = currentInfos.front().m_MimeType; + + // 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()); + + 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()); + } + } + + // Error out if no compatible Writer was found + if (writers.empty()) + { + errMsg += std::string("No writer available for ") + baseDataType + " data.\n"; + } + 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) + { + if (callOptionsCallback && optionsCallback) + { + callOptionsCallback = (*optionsCallback)(infoIter->m_Path, writerLabels, writers, selectedWriter); + } + if (selectedWriter == NULL) + { + errMsg += "Writing operation(s) cancelled."; + 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) + { + // writing was cancelled within the optionsCallback, + // break outer loop as well + break; + } + } + + for(std::vector::const_iterator writerIter = writers.begin(), + writerIterEnd = writers.end(); writerIter != writerIterEnd; ++writerIter) + { + writerRegistry.UngetWriter(*writerIter); + } + } + + 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) + : m_BaseData(baseData) + , m_MimeType(mimeType) + , m_Path(path) +{ +} + } diff --git a/Core/Code/IO/mitkIOUtil.h b/Core/Code/IO/mitkIOUtil.h index 75d429e1bc..d768a3e056 100644 --- a/Core/Code/IO/mitkIOUtil.h +++ b/Core/Code/IO/mitkIOUtil.h @@ -1,365 +1,393 @@ /*=================================================================== 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 namespace mitk { /** * \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 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 */ class MITK_CORE_EXPORT IOUtil { public: + struct SaveInfo + { + SaveInfo(const BaseData* baseData, const std::string& mimeType, const std::string& path); + + const BaseData* m_BaseData; + std::string m_MimeType; + std::string m_Path; + }; + /** * 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 * 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. * @param data The data to save. * @throws mitk::Exception if no writer for \c data is available or the writer * is not able to write the image. */ - static void Save(mitk::BaseData* data, const std::string& path); + static void Save(const mitk::BaseData* data, const std::string& path); + + 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 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. * @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. */ - static void Save(mitk::BaseData* data, 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); + + static void Save(const 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 OptionsFunctorBase + struct ReaderOptionsFunctorBase { virtual bool operator()(const std::string& path, const std::vector& readerLabels, const std::vector& readers, IFileReader*& selectedReader) = 0; }; + struct WriterOptionsFunctorBase + { + virtual bool operator()(const std::string& path, const std::vector& writerLabels, + const std::vector& readers, IFileWriter*& selectedWriter) = 0; + }; + static std::string Load(const std::vector& paths, std::vector* result, - DataStorage::SetOfObjects* nodeResult, DataStorage* ds, OptionsFunctorBase* optionsCallback); + DataStorage::SetOfObjects* nodeResult, DataStorage* ds, ReaderOptionsFunctorBase* optionsCallback); + + static std::string Save(const BaseData* data, const std::string& mimeType, const std::string& path, + WriterOptionsFunctorBase* optionsCallback); + + static std::string Save(const std::vector& saveInfos, + WriterOptionsFunctorBase* optionsCallback); private: struct Impl; }; } #endif // MITKIOUTIL_H diff --git a/Modules/QtWidgets/QmitkFileReaderOptionsDialog.cpp b/Modules/QtWidgets/QmitkFileReaderOptionsDialog.cpp index 5dff291e22..d1abc942d7 100644 --- a/Modules/QtWidgets/QmitkFileReaderOptionsDialog.cpp +++ b/Modules/QtWidgets/QmitkFileReaderOptionsDialog.cpp @@ -1,86 +1,86 @@ /*=================================================================== 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, QWidget *parent) : QDialog(parent) , ui(new Ui::QmitkFileReaderOptionsDialog) , m_Readers(readers) { ui->setupUi(this); const int count = qMin(labels.size(), readers.size()); bool hasOptions = false; for (int i = 0; i < count; ++i) { ui->m_ReaderComboBox->addItem(labels[i]); mitk::IFileReader::Options options = readers[i]->GetOptions(); if (!options.empty()) { hasOptions = true; } ui->m_StackedOptionsWidget->addWidget(new QmitkFileReaderWriterOptionsWidget(options)); } if(!hasOptions) { ui->m_OptionsBox->setVisible(false); } if (count < 2) { ui->m_ReaderLabel->setVisible(false); ui->m_ReaderComboBox->setVisible(false); ui->m_FilePathLabel->setText(QString("File: %1").arg(filePath)); } else { ui->m_FilePathLabel->setText(QString("for %1").arg(filePath)); } - this->setWindowTitle("File Reading Options"); + 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()); QDialog::accept(); } diff --git a/Modules/QtWidgets/QmitkFileReaderOptionsDialog.cpp b/Modules/QtWidgets/QmitkFileWriterOptionsDialog.cpp similarity index 61% copy from Modules/QtWidgets/QmitkFileReaderOptionsDialog.cpp copy to Modules/QtWidgets/QmitkFileWriterOptionsDialog.cpp index 5dff291e22..a8d7cf4393 100644 --- a/Modules/QtWidgets/QmitkFileReaderOptionsDialog.cpp +++ b/Modules/QtWidgets/QmitkFileWriterOptionsDialog.cpp @@ -1,86 +1,86 @@ /*=================================================================== 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 "QmitkFileWriterOptionsDialog.h" +#include "ui_QmitkFileWriterOptionsDialog.h" #include "QmitkFileReaderWriterOptionsWidget.h" -#include "mitkIFileReader.h" +#include "mitkIFileWriter.h" -QmitkFileReaderOptionsDialog::QmitkFileReaderOptionsDialog(const QString& filePath, +QmitkFileWriterOptionsDialog::QmitkFileWriterOptionsDialog(const QString& filePath, const QStringList& labels, - const QList& readers, + const QList& writers, QWidget *parent) : QDialog(parent) - , ui(new Ui::QmitkFileReaderOptionsDialog) - , m_Readers(readers) + , ui(new Ui::QmitkFileWriterOptionsDialog) + , m_Writers(writers) { ui->setupUi(this); - const int count = qMin(labels.size(), readers.size()); + const int count = qMin(labels.size(), writers.size()); bool hasOptions = false; for (int i = 0; i < count; ++i) { - ui->m_ReaderComboBox->addItem(labels[i]); - mitk::IFileReader::Options options = readers[i]->GetOptions(); + ui->m_WriterComboBox->addItem(labels[i]); + mitk::IFileWriter::Options options = writers[i]->GetOptions(); if (!options.empty()) { hasOptions = true; } ui->m_StackedOptionsWidget->addWidget(new QmitkFileReaderWriterOptionsWidget(options)); } if(!hasOptions) { ui->m_OptionsBox->setVisible(false); } if (count < 2) { - ui->m_ReaderLabel->setVisible(false); - ui->m_ReaderComboBox->setVisible(false); + ui->m_WriterLabel->setVisible(false); + ui->m_WriterComboBox->setVisible(false); ui->m_FilePathLabel->setText(QString("File: %1").arg(filePath)); } else { ui->m_FilePathLabel->setText(QString("for %1").arg(filePath)); } - this->setWindowTitle("File Reading Options"); + this->setWindowTitle("File writing options"); } -QmitkFileReaderOptionsDialog::~QmitkFileReaderOptionsDialog() +QmitkFileWriterOptionsDialog::~QmitkFileWriterOptionsDialog() { delete ui; } -mitk::IFileReader* QmitkFileReaderOptionsDialog::GetReader() const +mitk::IFileWriter* QmitkFileWriterOptionsDialog::GetWriter() const { - return m_Readers[ui->m_ReaderComboBox->currentIndex()]; + return m_Writers[ui->m_WriterComboBox->currentIndex()]; } -bool QmitkFileReaderOptionsDialog::ReuseOptions() const +bool QmitkFileWriterOptionsDialog::ReuseOptions() const { return ui->m_ReuseOptionsCheckBox->isChecked(); } -void QmitkFileReaderOptionsDialog::accept() +void QmitkFileWriterOptionsDialog::accept() { - const int index = ui->m_ReaderComboBox->currentIndex(); - m_Readers[index]->SetOptions( + const int index = ui->m_WriterComboBox->currentIndex(); + m_Writers[index]->SetOptions( qobject_cast(ui->m_StackedOptionsWidget->widget(index))->GetOptions()); QDialog::accept(); } diff --git a/Modules/QtWidgets/QmitkFileWriterOptionsDialog.h b/Modules/QtWidgets/QmitkFileWriterOptionsDialog.h new file mode 100644 index 0000000000..a2e279c2b6 --- /dev/null +++ b/Modules/QtWidgets/QmitkFileWriterOptionsDialog.h @@ -0,0 +1,56 @@ +/*=================================================================== + +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 + +namespace mitk { +class IFileWriter; +} + +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); + ~QmitkFileWriterOptionsDialog(); + + mitk::IFileWriter* GetWriter() const; + + bool ReuseOptions() const; + + virtual void accept(); + +private: + + Ui::QmitkFileWriterOptionsDialog* ui; + const QList m_Writers; +}; + +#endif // QMITKFILEREADEROPTIONSDIALOG_H diff --git a/Modules/QtWidgets/QmitkFileWriterOptionsDialog.ui b/Modules/QtWidgets/QmitkFileWriterOptionsDialog.ui new file mode 100644 index 0000000000..ec979c3825 --- /dev/null +++ b/Modules/QtWidgets/QmitkFileWriterOptionsDialog.ui @@ -0,0 +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) + m_StackedOptionsWidget + setCurrentIndex(int) + + + 199 + 44 + + + 203 + 167 + + + + + diff --git a/Modules/QtWidgets/QmitkIOUtil.cpp b/Modules/QtWidgets/QmitkIOUtil.cpp index 5651a440fa..16626b1934 100644 --- a/Modules/QtWidgets/QmitkIOUtil.cpp +++ b/Modules/QtWidgets/QmitkIOUtil.cpp @@ -1,470 +1,546 @@ /*=================================================================== 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 "mitkFileReaderRegistry.h" +#include "mitkFileWriterRegistry.h" #include "QmitkFileReaderOptionsDialog.h" +#include "QmitkFileWriterOptionsDialog.h" // QT #include #include #include //ITK #include struct QmitkIOUtil::Impl { - struct OptionsDialogFunctor : public OptionsFunctorBase + struct ReaderOptionsDialogFunctor : public ReaderOptionsFunctorBase { virtual bool operator()(const std::string& path, const std::vector& readerLabels, const std::vector& readers, mitk::IFileReader*& selectedReader) { 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); if (dialog.exec() == QDialog::Accepted) { selectedReader = dialog.GetReader(); return !dialog.ReuseOptions(); } else { selectedReader = NULL; return true; } } }; + struct WriterOptionsDialogFunctor : public WriterOptionsFunctorBase + { + + virtual bool operator()(const std::string& path, const std::vector& writerLabels, + const std::vector& writers, mitk::IFileWriter*& selectedWriter) + { + 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); + if (dialog.exec() == QDialog::Accepted) + { + selectedWriter = dialog.GetWriter(); + return !dialog.ReuseOptions(); + } + else + { + selectedWriter = NULL; + return true; + } + } + }; + }; -QString QmitkIOUtil::GetFilterString() +QString QmitkIOUtil::GetFileOpenFilterString() { QString filters; mitk::CoreServicePointer mimeTypeProvider(mitk::CoreServices::GetMimeTypeProvider()); std::vector categories = mimeTypeProvider->GetCategories(); std::sort(categories.begin(), categories.end()); for (std::vector::iterator cat = categories.begin(); cat != categories.end(); ++cat) { QSet filterExtensions; std::vector mimeTypes = mimeTypeProvider->GetMimeTypesForCategory(*cat); for (std::vector::iterator mt = mimeTypes.begin(); mt != mimeTypes.end(); ++mt) { std::vector extensions = mimeTypeProvider->GetExtensions(*mt); for (std::vector::iterator ext = extensions.begin(); ext != extensions.end(); ++ext) { filterExtensions << QString::fromStdString(*ext); } } QString filter = QString::fromStdString(*cat) + " ("; foreach(const QString& extension, filterExtensions) { filter += "*." + extension + " "; } filter = filter.replace(filter.size()-1, 1, ')'); filters += ";;" + filter; } filters.prepend("All (*.*)"); return filters; } -QList QmitkIOUtil::Load(const QStringList& paths) +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; foreach(const QString& file, paths) { qPaths.push_back(file.toStdString()); } std::vector result; - Impl::OptionsDialogFunctor optionsCallback; + Impl::ReaderOptionsDialogFunctor optionsCallback; std::string errMsg = Load(qPaths, &result, NULL, NULL, &optionsCallback); if (!errMsg.empty()) { - QMessageBox::warning(NULL, "Error reading files", QString::fromStdString(errMsg)); + 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) { qResult << *iter; } return qResult; } -mitk::DataStorage::SetOfObjects::Pointer QmitkIOUtil::Load(const QStringList& paths, mitk::DataStorage& storage) +mitk::DataStorage::SetOfObjects::Pointer QmitkIOUtil::Load(const QStringList& paths, mitk::DataStorage& storage, QWidget* parent) { std::vector qPaths; foreach(const QString& file, paths) { qPaths.push_back(file.toStdString()); } mitk::DataStorage::SetOfObjects::Pointer nodeResult = mitk::DataStorage::SetOfObjects::New(); - Impl::OptionsDialogFunctor optionsCallback; + Impl::ReaderOptionsDialogFunctor optionsCallback; std::string errMsg = Load(qPaths, NULL, nodeResult, &storage, &optionsCallback); if (!errMsg.empty()) { - QMessageBox::warning(NULL, "Error reading files", QString::fromStdString(errMsg)); + QMessageBox::warning(parent, "Error reading files", QString::fromStdString(errMsg)); mitkThrow() << errMsg; } return nodeResult; } -QList QmitkIOUtil::Load(const QString& path) +QList QmitkIOUtil::Load(const QString& path, QWidget* parent) { QStringList paths; paths << path; - return Load(paths); + return Load(paths, parent); } -mitk::DataStorage::SetOfObjects::Pointer QmitkIOUtil::Load(const QString& path, mitk::DataStorage& storage) +mitk::DataStorage::SetOfObjects::Pointer QmitkIOUtil::Load(const QString& path, mitk::DataStorage& storage, + QWidget* parent) { QStringList paths; paths << path; - return Load(paths, storage); + return Load(paths, storage, parent); } -void QmitkIOUtil::SaveBaseDataWithDialog(mitk::BaseData* data, std::string fileName, QWidget* parent) +QString QmitkIOUtil::Save(const mitk::BaseData* data, const QString& defaultBaseName, + const QString& defaultPath, QWidget* parent) { - try - { - if (data != NULL) - { - /* //########### Check if we can save as standard image type via itkImageWriter - mitk::Image::Pointer image = dynamic_cast(data); - QString classname(data->GetNameOfClass()); - if ( image.IsNotNull() && (classname.compare("Image")==0 || classname.compare("SeedsImage")==0 ) ) - { - SaveImageWithDialog(image, fileName, parent); - return; //succes. we can return - } - //########### End Check if we can save as standard image type via itkImageWriter -*/ - //########### Check if we can save as standard pointset type via mitkPointSetWriter - mitk::PointSet::Pointer pointset = dynamic_cast(data); - if(pointset.IsNotNull()) - { - SavePointSetWithDialog(pointset, fileName, parent); - return; //succes. we can return - } - //########### End Check if we can save as standard pointset type via mitkPointSetWriter - - //########### Check if we can save as standard surface type via mitkVtkSurfaceWriter - mitk::Surface::Pointer surface = dynamic_cast(data); - if(surface.IsNotNull()) - { - SaveSurfaceWithDialog(surface, fileName, parent); - return; //succes. we can return - } - //########### End Check if we can save as standard surface type via mitkVtkSurfaceWriter - - //########### None standard data type was found, try to save with extensions. - // now try the file writers provided by the CoreObjectFactory + std::vector dataVector; + dataVector.push_back(data); + QStringList defaultBaseNames; + defaultBaseNames.push_back(defaultBaseName); + return Save(dataVector, defaultBaseNames, defaultPath, parent).back(); +} - mitk::CoreObjectFactory::FileWriterList fileWriters = mitk::CoreObjectFactory::GetInstance()->GetFileWriters(); +QStringList QmitkIOUtil::Save(const std::vector& data, + const QStringList& defaultBaseNames, + const QString& defaultPath, + QWidget* parent) +{ + QStringList fileNames; + QString currentPath = defaultPath; - mitk::CoreObjectFactory::FileWriterList fileWriterCandidates; - QString fileDialogPattern; - for (mitk::CoreObjectFactory::FileWriterList::iterator it = fileWriters.begin() ; it != fileWriters.end() ; ++it) - { - if ( (*it)->CanWriteBaseDataType(data) ) - { - fileWriterCandidates.push_back(*it); - fileDialogPattern += QString::fromStdString((*it)->GetFileDialogPattern()) + ";;"; - } - } + std::vector saveInfos; - if (!fileWriterCandidates.empty()) - { - // remove last ';;' from pattern - fileDialogPattern.remove( fileDialogPattern.size()-2, 2); - - // Ensure a valid filename - QString qFileName(QString::fromStdString(fileName)); - QString qProposedFileName( qFileName ); - QString selectedFilter; - if(qFileName.isEmpty()) - { - qProposedFileName.append(fileWriterCandidates.front()->GetDefaultFilename()); - } - qProposedFileName.append(fileWriterCandidates.front()->GetDefaultExtension()); - qFileName = GetFileNameWithQDialog("Save file", qProposedFileName, - fileDialogPattern, &selectedFilter); - //do nothing if the user presses cancel - if ( qFileName.isEmpty() ) - return; - - std::string ext = itksys::SystemTools::GetFilenameLastExtension(qFileName.toStdString()); - QString extension = QString::fromStdString(ext); - - //QString extension = "."+QFileInfo(qFileName).completeSuffix(); - for (mitk::CoreObjectFactory::FileWriterList::iterator it = fileWriterCandidates.begin() ; - it != fileWriterCandidates.end() ; ++it) - { - if ((*it)->IsExtensionValid(extension.toStdString())) - { - (*it)->SetFileName( qPrintable(qFileName) ); - (*it)->DoWrite( data ); - return; - } - } - - // if the image extension consists of two parts (e.g. *.nii.gz) we need to check again - // with the two last extensions. This is to allow points within the image name. - QString qFileNameCopy(qFileName); - qFileNameCopy.remove(QString::fromStdString(ext)); - std::string ext2 = itksys::SystemTools::GetFilenameLastExtension(qFileNameCopy.toStdString()); - ext2.append(ext); - extension = QString::fromStdString(ext2); - for (mitk::CoreObjectFactory::FileWriterList::iterator it = fileWriterCandidates.begin() ; - it != fileWriterCandidates.end() ; ++it) - { - if ((*it)->IsExtensionValid(extension.toStdString())) - { - (*it)->SetFileName( qPrintable(qFileName) ); - (*it)->DoWrite( data ); - return; - } - } - // returns earlier when successful - } + int counter = 0; + for(std::vector::const_iterator dataIter = data.begin(), + dataIterEnd = data.end(); dataIter != dataIterEnd; ++dataIter, ++counter) + { + SaveFilter filters(*dataIter); - // no appropriate writer has been found - QMessageBox::critical(parent,"ERROR","Could not find file writer for this data type"); - return; - } - }catch(itk::ExceptionObject e) + // If there is only the "__all__" filter string, it means there is no writer for this base data + if (filters.Size() < 2) { - QMessageBox::critical( parent, "Exception during saving", e.GetDescription(),QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton); + QMessageBox::warning(parent, + "Saving not possible", + QString("No writer available for type \"%1\"").arg( + QString::fromStdString((*dataIter)->GetNameOfClass()))); + continue; } -} -void QmitkIOUtil::SaveSurfaceWithDialog(mitk::Surface::Pointer surface, std::string fileName, QWidget* parent) -{ - //default selected suffix for surfaces - QString selected_suffix("STL File (*.stl)"); - QString possible_suffixes("STL File (*.stl);; VTK File (*.vtk);; VTP File (*.vtp)"); - //default initial file name - QString initialFilename("NewSurface"); - //default image extension - initialFilename.append((mitk::IOUtil::DEFAULTSURFACEEXTENSION).c_str()); - - //if any filename is supplied by the user, use it - if( !fileName.empty() ) + // 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()) { - initialFilename = fileName.c_str(); + dialogTitle += " \"" + defaultBaseNames[counter] + "\""; + fileName += QDir::separator() + defaultBaseNames[counter]; + std::pair defaultExt = mitk::FileWriterRegistry::GetDefaultExtension(*dataIter); + if (!defaultExt.first.empty()) + { + fileName += "." + QString::fromStdString(defaultExt.first); + QString filter = filters.GetFilterForMimeType(defaultExt.second); + if (!filter.isEmpty()) + { + selectedFilter = filter; + } + } } - QString qfileName = GetFileNameWithQDialog("Save Surface", initialFilename , possible_suffixes, &selected_suffix, parent); + // Ask the user for a file name + QString nextName = QFileDialog::getSaveFileName(parent, + dialogTitle, + fileName, + filterString, + &selectedFilter); - //do nothing if the user presses cancel - if ( qfileName.isEmpty() ) return; - try{ - mitk::IOUtil::SaveSurface(surface,qfileName.toLocal8Bit().constData()); + if (nextName.isEmpty()) + { + continue; } - catch(mitk::Exception &e) + + fileName = nextName; + QFileInfo fileInfo(fileName); + currentPath = fileInfo.absolutePath(); + QString suffix = fileInfo.completeSuffix(); + std::string 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()) { - MITK_ERROR << "error saving file: " << e.what(); + std::vector availableTypes = mimeTypeProvider->GetMimeTypesForExtension(suffix.toStdString()); - std::string msg("Could not save surface.\n Error: "); - msg.append(e.what()); + // 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(), + availIterEnd = availableTypes.end(); availIter != availIterEnd; ++availIter) + { + if (filters.ContainsMimeType(*availIter)) + { + mimeType = *availIter; + break; + } + } + } - QMessageBox::critical( NULL, "Exception during saving", msg.c_str(), - QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton); + if (mimeType.empty()) + { + // 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; + } } -} - -void QmitkIOUtil::SaveImageWithDialog(mitk::Image::Pointer image, std::string fileName, QWidget *parent) -{ - //default selected suffix for images - QString selected_suffix("Nearly Raw Raster Data (*.nrrd)"); - //default initial file name - QString initialFilename("NewImage"); - //default image extension - initialFilename.append((mitk::IOUtil::DEFAULTIMAGEEXTENSION).c_str()); - - //if any filename is supplied by the user, use it - if( !fileName.empty() ) + else { - initialFilename = fileName.c_str(); + // Create a default suffix, unless the file already exists and the user + // already confirmed to overwrite it (without using a suffix) + if (mimeType == SaveFilter::ALL_MIMETYPE) + { + // Use the highest ranked mime-type from the list + mimeType = filters.GetDefaultMimeType(); + } + if (!fileInfo.exists()) + { + suffix = QString::fromStdString( + mimeTypeProvider->GetExtensions(mimeType).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", + "A file named \"%1\" already exists. Do you want to replace it?") == + QMessageBox::No) + { + continue; + } + } + } + } } - QString qfileName = GetFileNameWithQDialog("Save Image", initialFilename, - mitk::ImageWriter::New()->GetFileDialogPattern(), - &selected_suffix,parent); - - //do nothing if the user presses cancel - if ( qfileName.isEmpty() ) return; - - try + if (!QFileInfo(fileInfo.absolutePath()).isWritable()) { - mitk::IOUtil::SaveImage(image, qfileName.toLocal8Bit().constData()); + QMessageBox::warning(parent, "Saving not possible", QString("The path \"%1\" is not writable").arg(fileName)); + continue; } - catch(mitk::Exception &e) - { - MITK_ERROR << "error saving file: " << e.what(); - std::string msg("Could not save image.\n Error: "); - msg.append(e.what()); + fileNames.push_back(fileName); + saveInfos.push_back(SaveInfo(*dataIter, mimeType, fileName.toStdString())); + MITK_INFO << "****** SAVING TO FILENAME: " << fileName.toStdString(); + } - QMessageBox::critical( NULL, "Exception during saving", msg.c_str(), - QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton); - } + 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::SavePointSetWithDialog(mitk::PointSet::Pointer pointset, std::string fileName, QWidget *parent) -{ - //default selected suffix for point sets - QString selected_suffix("MITK Point-Sets (*.mps)"); - QString possible_suffixes("MITK Point-Sets (*.mps)"); - //default initial file name - QString initialFilename("NewPointSet"); - //default image extension - initialFilename.append((mitk::IOUtil::DEFAULTPOINTSETEXTENSION).c_str()); - - //if any filename is supplied by the user, use it - if( !fileName.empty() ) - { - initialFilename = fileName.c_str(); - } - QString qfileName = GetFileNameWithQDialog("Save PointSet", initialFilename , possible_suffixes, &selected_suffix, parent); +void QmitkIOUtil::SaveBaseDataWithDialog(mitk::BaseData* data, std::string fileName, QWidget* /*parent*/) +{ + Save(data, fileName); +} - //do nothing if the user presses cancel - if ( qfileName.isEmpty() ) return; - try{ - mitk::IOUtil::SavePointSet(pointset,qfileName.toLocal8Bit().constData()); - } - catch(mitk::Exception &e) - { - MITK_ERROR << "error saving file: " << e.what(); +void QmitkIOUtil::SaveSurfaceWithDialog(mitk::Surface::Pointer surface, std::string fileName, QWidget* /*parent*/) +{ + Save(surface, fileName); +} - std::string msg("Could not save pointset.\n Error: "); - msg.append(e.what()); +void QmitkIOUtil::SaveImageWithDialog(mitk::Image::Pointer image, std::string fileName, QWidget* /*parent*/) +{ + Save(image, fileName); +} - QMessageBox::critical( NULL, "Exception during saving", msg.c_str(), - QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton); - } +void QmitkIOUtil::SavePointSetWithDialog(mitk::PointSet::Pointer pointset, std::string fileName, QWidget* /*parent*/) +{ + Save(pointset, fileName); } -QString QmitkIOUtil::GetFileNameWithQDialog(QString caption, QString defaultFilename, QString filter, QString* selectedFilter, QWidget* parent) +struct QmitkIOUtil::SaveFilter::Impl { - QString returnfileName = ""; - static QString lastDirectory = ""; - QString filename = lastDirectory +"/"+ defaultFilename; - QString selectedFilterInternal = selectedFilter ? *selectedFilter : QString::null; - returnfileName = QFileDialog::getSaveFileName(parent,caption,filename,filter,&selectedFilterInternal, QFileDialog::DontConfirmOverwrite); - if (selectedFilter) + void Init(const std::string& baseDataType) + { + // Add an artifical filter for "All" + m_MimeTypes.push_back(ALL_MIMETYPE); + m_FilterStrings.push_back("All (*.*)"); + + // Get all writers and their mime types for the given base data type + std::vector mimeTypes; + std::vector refs = mitk::FileWriterRegistry::GetReferences(baseDataType); + for (std::vector::const_iterator iter = refs.begin(), + iterEnd = refs.end(); iter != iterEnd; ++iter) { - *selectedFilter = selectedFilterInternal; + 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); + } } - if (!returnfileName.isEmpty()) + + mitk::CoreServicePointer mimeTypeProvider(mitk::CoreServices::GetMimeTypeProvider()); + for (std::vector::const_iterator iter = mimeTypes.begin(), iterEnd = mimeTypes.end(); + iter != iterEnd; ++iter) { - QFileInfo fileInfo(returnfileName); - lastDirectory = fileInfo.absolutePath(); // remember path for next save dialog - if(fileInfo.completeSuffix().isEmpty()) // if no extension has been entered manually into the filename + QSet filterExtensions; + std::vector extensions = mimeTypeProvider->GetExtensions(*iter); + for (std::vector::iterator extIter = extensions.begin(), extIterEnd = extensions.end(); + extIter != extIterEnd; ++extIter) { - // get from combobox selected file extension - QString selectedExtensions = selectedFilterInternal.split(" (", QString::SkipEmptyParts).back().trimmed(); - selectedExtensions = selectedExtensions.split(")", QString::SkipEmptyParts).front().trimmed(); - QString selectedExtension = selectedExtensions.split(" ", QString::SkipEmptyParts).front(); - if (selectedExtension.size() < 3) // at least something like "*.?" - { - QMessageBox::critical(parent, "File extension error", "Unable to deduce a valid file extension."); - return QString::null; - } - selectedExtension = selectedExtension.mid(1); - returnfileName += selectedExtension; //add it to the path which is returned + filterExtensions << QString::fromStdString(*extIter); } - //check if the file exists - if(fileInfo.exists()) + QString filter = QString::fromStdString(mimeTypeProvider->GetDescription(*iter)) + " ("; + foreach(const QString& extension, filterExtensions) { - int answer = QMessageBox::question( parent, "Warning", - QString("File %1 already exists. Overwrite?").arg( returnfileName ), - QMessageBox::Yes, - QMessageBox::No ); - if( answer == QMessageBox::No ) - { - returnfileName.clear(); - } + filter += "*." + extension + " "; } + filter = filter.replace(filter.size()-1, 1, ')'); + m_MimeTypes.push_back(*iter); + m_FilterStrings.push_back(filter); } + } + + std::vector m_MimeTypes; + QStringList m_FilterStrings; +}; - return returnfileName; +std::string QmitkIOUtil::SaveFilter::ALL_MIMETYPE = "__all__"; + +QmitkIOUtil::SaveFilter::SaveFilter(const QmitkIOUtil::SaveFilter& other) + : d(new Impl(*other.d)) +{ } -bool QmitkIOUtil::SaveToFileWriter( mitk::FileWriterWithInformation::Pointer fileWriter, mitk::BaseData::Pointer data, const std::string fileName ) +QmitkIOUtil::SaveFilter::SaveFilter(const std::string& baseDataType) + : d(new Impl) { - // Ensure a valid filename - QString qFileName(QString::fromStdString(fileName)); - QString qProposedFileName(qFileName); - if(qFileName.isEmpty()) - { - qProposedFileName.append(fileWriter->GetDefaultFilename()); - } - qProposedFileName.append(fileWriter->GetDefaultExtension()); - qFileName = GetFileNameWithQDialog("Save file", qProposedFileName, - QString::fromAscii(fileWriter->GetFileDialogPattern())); - //do nothing if the user presses cancel - if ( qFileName.isEmpty() ) - return false; - - // Check if an extension exists already and if not, append the default extension - if ( !qFileName.contains( QRegExp("\\.\\w+$") ) ) - { - qFileName.append( fileWriter->GetDefaultExtension() ); - } - else - { - std::string extension = itksys::SystemTools::GetFilenameLastExtension( qFileName.toLocal8Bit().constData() ); - if (!fileWriter->IsExtensionValid(extension)) - { - return false; - } - } - //Write only if a valid name was set - if(qFileName.isEmpty() == false) - { - fileWriter->SetFileName( qFileName.toLocal8Bit().constData() ); - fileWriter->DoWrite( data ); - } + 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); + 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 +{ + int index = d->m_FilterStrings.indexOf(filter); + if (index < 0) + { + return std::string(); + } + 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 +{ + 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 true; +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(); } diff --git a/Modules/QtWidgets/QmitkIOUtil.h b/Modules/QtWidgets/QmitkIOUtil.h index affb48f820..664935d916 100644 --- a/Modules/QtWidgets/QmitkIOUtil.h +++ b/Modules/QtWidgets/QmitkIOUtil.h @@ -1,145 +1,170 @@ /*=================================================================== 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; 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; + + SaveFilter(const SaveFilter& other); + + SaveFilter(const std::string& baseDataType); + SaveFilter(const mitk::BaseData* baseData); + + SaveFilter& operator=(const SaveFilter& other); + + QString GetFilterForMimeType(const std::string& mimeType) const; + std::string GetMimeTypeForFilter(const QString& filter) const; + QString GetDefaultFilter() const; + std::string 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 GetFilterString(); + 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); + static QList Load(const QStringList& paths, QWidget* parent = NULL); - static mitk::DataStorage::SetOfObjects::Pointer Load(const QStringList& paths, mitk::DataStorage& storage); + static mitk::DataStorage::SetOfObjects::Pointer Load(const QStringList& paths, mitk::DataStorage& storage, + QWidget* parent = NULL); - static QList Load(const QString& path); + static QList Load(const QString& path, QWidget* parent = NULL); - static mitk::DataStorage::SetOfObjects::Pointer Load(const QString& path, mitk::DataStorage& storage); + 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); + + 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. */ - static void SaveBaseDataWithDialog(mitk::BaseData *data, std::string fileName, QWidget* parent = NULL); + 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. */ - static void SaveSurfaceWithDialog(mitk::Surface::Pointer surface, std::string fileName = "", QWidget* parent = NULL); + 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. */ - static void SaveImageWithDialog(mitk::Image::Pointer image, std::string fileName = "", QWidget* parent = NULL); + 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. */ - static void SavePointSetWithDialog(mitk::PointSet::Pointer pointset, std::string fileName = "", QWidget* parent = NULL); - -protected: - - /** - * @brief GetFileNameWithQDialog Opens a QDialog and returns the filename. - * @param caption Caption for the QDialog. - * @param defaultFilename Default filename (e.g. "NewImage.nrrd" for images). - * @param filter Filters the data according to data types (e.g. *.nrrd; *.png; etc. for images). - * @param selectedFilter Default selected filter for the data. - * @return The file name as QString. - */ - static QString GetFileNameWithQDialog(QString caption, QString defaultFilename, QString filter, QString* selectedFilter = 0, QWidget* parent = NULL); - - /** - * @brief SaveToFileWriter Internal helper method to save data with writer's which have been supplied by extensions (e.g. TensorImage etc.). - * @param fileWriter The writer supplied by an extension. - * @param data The data to save in a specific format. - * @param aFileName The filename. - * @param propFileName Proposed file name? - * @return false if writing attempt failed, true otherwise - */ - static bool SaveToFileWriter(mitk::FileWriterWithInformation::Pointer fileWriter, mitk::BaseData::Pointer data, const std::string fileName); + DEPRECATED(static void SavePointSetWithDialog(mitk::PointSet::Pointer pointset, std::string fileName = "", QWidget* parent = NULL)); private: struct Impl; }; #endif // _QmitkIOUtil__h_ diff --git a/Modules/QtWidgets/files.cmake b/Modules/QtWidgets/files.cmake index 9ba8dc7607..d27b08016f 100644 --- a/Modules/QtWidgets/files.cmake +++ b/Modules/QtWidgets/files.cmake @@ -1,72 +1,75 @@ set(CPP_FILES QmitkApplicationCursor.cpp QmitkEnums.h QmitkCustomVariants.h QmitkDataStorageComboBox.cpp QmitkDataStorageListModel.cpp QmitkDataStorageTableModel.cpp QmitkDataStorageTreeModel.cpp QmitkEventAdapter.cpp QmitkFileReaderOptionsDialog.cpp QmitkFileReaderWriterOptionsWidget.cpp +QmitkFileWriterOptionsDialog.cpp QmitkIOUtil.cpp QmitkLevelWindowPresetDefinitionDialog.cpp QmitkLevelWindowRangeChangeDialog.cpp QmitkLevelWindowWidgetContextMenu.cpp QmitkLevelWindowWidget.cpp QmitkLineEditLevelWindowWidget.cpp QmitkMemoryUsageIndicatorView.cpp QmitkNodeDescriptor.cpp QmitkNodeDescriptorManager.cpp QmitkRenderWindowMenu.cpp QmitkProgressBar.cpp QmitkPropertiesTableEditor.cpp QmitkPropertiesTableModel.cpp QmitkPropertyDelegate.cpp QmitkRegisterClasses.cpp QmitkRenderingManager.cpp QmitkRenderingManagerFactory.cpp QmitkRenderWindow.cpp QmitkServiceListWidget.cpp QmitkSliderLevelWindowWidget.cpp QmitkStdMultiWidget.cpp QmitkMouseModeSwitcher.cpp ) set(MOC_H_FILES QmitkDataStorageComboBox.h QmitkDataStorageTableModel.h QmitkFileReaderOptionsDialog.h QmitkFileReaderWriterOptionsWidget.h +QmitkFileWriterOptionsDialog.h QmitkLevelWindowPresetDefinitionDialog.h QmitkLevelWindowRangeChangeDialog.h QmitkLevelWindowWidgetContextMenu.h QmitkLevelWindowWidget.h QmitkLineEditLevelWindowWidget.h QmitkMemoryUsageIndicatorView.h QmitkNodeDescriptor.h QmitkNodeDescriptorManager.h QmitkRenderWindowMenu.h QmitkProgressBar.h QmitkPropertiesTableEditor.h QmitkPropertyDelegate.h QmitkRenderingManager.h QmitkRenderWindow.h QmitkServiceListWidget.h QmitkSliderLevelWindowWidget.h QmitkStdMultiWidget.h QmitkMouseModeSwitcher.h ) set(UI_FILES QmitkFileReaderOptionsDialog.ui +QmitkFileWriterOptionsDialog.ui QmitkLevelWindowPresetDefinition.ui QmitkLevelWindowWidget.ui QmitkLevelWindowRangeChange.ui QmitkMemoryUsageIndicator.ui QmitkServiceListWidgetControls.ui ) set(QRC_FILES Qmitk.qrc ) diff --git a/Plugins/org.mitk.gui.common/src/mitkWorkbenchUtil.cpp b/Plugins/org.mitk.gui.common/src/mitkWorkbenchUtil.cpp index c692d3f4e8..fcd4aed2f0 100644 --- a/Plugins/org.mitk.gui.common/src/mitkWorkbenchUtil.cpp +++ b/Plugins/org.mitk.gui.common/src/mitkWorkbenchUtil.cpp @@ -1,341 +1,350 @@ /*=================================================================== 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 "mitkWorkbenchUtil.h" #include #include #include #include #include #include "mitkIDataStorageService.h" #include "mitkDataStorageEditorInput.h" #include "mitkRenderingManager.h" #include "mitkIRenderWindowPart.h" #include "mitkIRenderingManager.h" #include "mitkProperties.h" #include "mitkNodePredicateData.h" #include "mitkNodePredicateNot.h" #include "mitkNodePredicateProperty.h" #include "mitkCoreObjectFactory.h" #include "QmitkIOUtil.h" #include #include #include #include "internal/org_mitk_gui_common_Activator.h" namespace mitk { struct WorkbenchUtilPrivate { /** * Get the editor descriptor for a given name using the editorDescriptor * passed in as a default as a starting point. * * @param name * The name of the element to open. * @param editorReg * The editor registry to do the lookups from. * @param defaultDescriptor * IEditorDescriptor or null * @return IEditorDescriptor * @throws PartInitException * if no valid editor can be found */ static berry::IEditorDescriptor::Pointer GetEditorDescriptor(const QString& name, berry::IEditorRegistry* editorReg, berry::IEditorDescriptor::Pointer defaultDescriptor) { if (defaultDescriptor.IsNotNull()) { return defaultDescriptor; } berry::IEditorDescriptor::Pointer editorDesc = defaultDescriptor; // next check the OS for in-place editor (OLE on Win32) if (editorReg->IsSystemInPlaceEditorAvailable(name.toStdString())) { editorDesc = editorReg->FindEditor(berry::IEditorRegistry::SYSTEM_INPLACE_EDITOR_ID); } // next check with the OS for an external editor if (editorDesc.IsNull() && editorReg->IsSystemExternalEditorAvailable(name.toStdString())) { editorDesc = editorReg->FindEditor(berry::IEditorRegistry::SYSTEM_EXTERNAL_EDITOR_ID); } // if no valid editor found, bail out if (editorDesc.IsNull()) { throw berry::PartInitException("No editor found"); } return editorDesc; } }; // //! [UtilLoadFiles] void WorkbenchUtil::LoadFiles(const QStringList &fileNames, berry::IWorkbenchWindow::Pointer window, bool openEditor) // //! [UtilLoadFiles] { if (fileNames.empty()) return; mitk::IDataStorageReference::Pointer dataStorageRef; { ctkPluginContext* context = mitk::PluginActivator::GetContext(); mitk::IDataStorageService* dss = 0; ctkServiceReference dsRef = context->getServiceReference(); if (dsRef) { dss = context->getService(dsRef); } if (!dss) { QString msg = "IDataStorageService service not available. Unable to open files."; MITK_WARN << msg.toStdString(); QMessageBox::warning(QApplication::activeWindow(), "Unable to open files", msg); return; } // Get the active data storage (or the default one, if none is active) dataStorageRef = dss->GetDataStorage(); context->ungetService(dsRef); } mitk::DataStorage::Pointer dataStorage = dataStorageRef->GetDataStorage(); // Do the actual work of loading the data into the data storage // Turn off ASSERT #if defined(_MSC_VER) && !defined(NDEBUG) && defined(_DEBUG) && defined(_CRT_ERROR) int lastCrtReportType = _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_DEBUG ); #endif - DataStorage::SetOfObjects::Pointer data = QmitkIOUtil::Load(fileNames, *dataStorage); + DataStorage::SetOfObjects::Pointer data; + try + { + data = QmitkIOUtil::Load(fileNames, *dataStorage); + } + catch (const mitk::Exception& e) + { + MITK_INFO << e; + return; + } const bool dsmodified = !data->empty(); // Set ASSERT status back to previous status. #if defined(_MSC_VER) && !defined(NDEBUG) && defined(_DEBUG) && defined(_CRT_ERROR) if (lastCrtReportType) _CrtSetReportMode( _CRT_ASSERT, lastCrtReportType ); #endif // Check if there is an open perspective. If not, open the default perspective. if (window->GetActivePage().IsNull()) { std::string defaultPerspId = window->GetWorkbench()->GetPerspectiveRegistry()->GetDefaultPerspective(); window->GetWorkbench()->ShowPerspective(defaultPerspId, window); } bool globalReinitOnNodeAdded = true; berry::IPreferencesService::Pointer prefService = berry::Platform::GetServiceRegistry().GetServiceById(berry::IPreferencesService::ID); if (prefService.IsNotNull()) { berry::IBerryPreferences::Pointer prefs = (prefService->GetSystemPreferences()->Node("org.mitk.views.datamanager")).Cast(); if(prefs.IsNotNull()) globalReinitOnNodeAdded = prefs->GetBool("Call global reinit if node is added", true); } if (openEditor && globalReinitOnNodeAdded) { try { // Activate the editor using the same data storage or open the default editor mitk::DataStorageEditorInput::Pointer input(new mitk::DataStorageEditorInput(dataStorageRef)); berry::IEditorPart::Pointer editor = mitk::WorkbenchUtil::OpenEditor(window->GetActivePage(), input, true); mitk::IRenderWindowPart* renderEditor = dynamic_cast(editor.GetPointer()); mitk::IRenderingManager* renderingManager = renderEditor == 0 ? 0 : renderEditor->GetRenderingManager(); if(dsmodified && renderingManager) { mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(dataStorage); } } catch (const berry::PartInitException& e) { QString msg = "An error occurred when displaying the file(s): %1"; QMessageBox::warning(QApplication::activeWindow(), "Error displaying file", msg.arg(QString::fromStdString(e.message()))); } } } berry::IEditorPart::Pointer WorkbenchUtil::OpenEditor(berry::IWorkbenchPage::Pointer page, berry::IEditorInput::Pointer input, const QString &editorId, bool activate) { // sanity checks if (page.IsNull()) { throw std::invalid_argument("page argument must not be NULL"); } // open the editor on the input return page->OpenEditor(input, editorId.toStdString(), activate); } berry::IEditorPart::Pointer WorkbenchUtil::OpenEditor(berry::IWorkbenchPage::Pointer page, mitk::DataStorageEditorInput::Pointer input, bool activate, bool determineContentType) { // sanity checks if (page.IsNull()) { throw std::invalid_argument("page argument must not be NULL"); } // open the editor on the data storage QString name = QString::fromStdString(input->GetName()) + ".mitk"; berry::IEditorDescriptor::Pointer editorDesc = WorkbenchUtilPrivate::GetEditorDescriptor(name, berry::PlatformUI::GetWorkbench()->GetEditorRegistry(), GetDefaultEditor(name, determineContentType)); return page->OpenEditor(input, editorDesc->GetId(), activate); } berry::IEditorDescriptor::Pointer WorkbenchUtil::GetEditorDescriptor( const QString& name, bool /*inferContentType*/) { if (name.isEmpty()) { throw std::invalid_argument("name argument must not be empty"); } // no used for now //IContentType contentType = inferContentType ? Platform // .getContentTypeManager().findContentTypeFor(name) : null; berry::IEditorRegistry* editorReg = berry::PlatformUI::GetWorkbench()->GetEditorRegistry(); return WorkbenchUtilPrivate::GetEditorDescriptor(name, editorReg, editorReg->GetDefaultEditor(name.toStdString() /*, contentType*/)); } berry::IEditorDescriptor::Pointer WorkbenchUtil::GetDefaultEditor(const QString& name, bool /*determineContentType*/) { // Try file specific editor. berry::IEditorRegistry* editorReg = berry::PlatformUI::GetWorkbench()->GetEditorRegistry(); try { QString editorID; // = file.getPersistentProperty(EDITOR_KEY); if (!editorID.isEmpty()) { berry::IEditorDescriptor::Pointer desc = editorReg->FindEditor(editorID.toStdString()); if (desc.IsNotNull()) { return desc; } } } catch (const berry::CoreException&) { // do nothing } // IContentType contentType = null; // if (determineContentType) // { // contentType = getContentType(file); // } // Try lookup with filename return editorReg->GetDefaultEditor(name.toStdString()); //, contentType); } bool WorkbenchUtil::SetDepartmentLogoPreference(const QString &logoResource, ctkPluginContext *context) { // The logo must be available in the local filesystem. We check if we have not already extracted the // logo from the plug-in or if this plug-ins timestamp is newer then the already extracted logo timestamp. // If one of the conditions is true, extract it and write it to the plug-in specific storage location. const QString logoFileName = logoResource.mid(logoResource.lastIndexOf('/')+1); const QString logoPath = context->getDataFile("").absoluteFilePath(); bool extractLogo = true; QFileInfo logoFileInfo(logoPath + "/" + logoFileName); if (logoFileInfo.exists()) { // The logo has been extracted previously. Check if the plugin timestamp is newer, which // means it might contain an updated logo. QString pluginLocation = QUrl(context->getPlugin()->getLocation()).toLocalFile(); if (!pluginLocation.isEmpty()) { QFileInfo pluginFileInfo(pluginLocation); if (logoFileInfo.lastModified() > pluginFileInfo.lastModified()) { extractLogo = false; } } } if (extractLogo) { // Extract the logo from the shared library and write it to disk. QFile logo(logoResource); if (logo.open(QIODevice::ReadOnly)) { QFile localLogo(logoPath + "/" + logoFileName); if (localLogo.open(QIODevice::WriteOnly)) { localLogo.write(logo.readAll()); } } } logoFileInfo.refresh(); if (logoFileInfo.exists()) { // Get the preferences service ctkServiceReference prefServiceRef = context->getServiceReference(); berry::IPreferencesService* prefService = NULL; if (prefServiceRef) { prefService = context->getService(prefServiceRef); } if (prefService) { prefService->GetSystemPreferences()->Put("DepartmentLogo", qPrintable(logoFileInfo.absoluteFilePath())); } else { BERRY_WARN << "Preferences service not available, unable to set custom logo."; return false; } } else { BERRY_WARN << "Custom logo at " << logoFileInfo.absoluteFilePath().toStdString() << " does not exist"; return false; } return true; } } // namespace mitk diff --git a/Plugins/org.mitk.gui.qt.application/files.cmake b/Plugins/org.mitk.gui.qt.application/files.cmake index 2482c478e3..6d3966687a 100644 --- a/Plugins/org.mitk.gui.qt.application/files.cmake +++ b/Plugins/org.mitk.gui.qt.application/files.cmake @@ -1,47 +1,49 @@ set(SRC_CPP_FILES QmitkCloseProjectAction.cpp QmitkDefaultDropTargetListener.cpp QmitkFileExitAction.cpp QmitkFileOpenAction.cpp + QmitkFileSaveAction.cpp QmitkPreferencesDialog.cpp QmitkStatusBar.cpp ) set(INTERNAL_CPP_FILES org_mitk_gui_qt_application_Activator.cpp QmitkEditorsPreferencePage.cpp QmitkGeneralPreferencePage.cpp ) set(MOC_H_FILES src/QmitkCloseProjectAction.h src/QmitkFileExitAction.h src/QmitkFileOpenAction.h + src/QmitkFileSaveAction.h src/QmitkPreferencesDialog.h src/internal/org_mitk_gui_qt_application_Activator.h src/internal/QmitkEditorsPreferencePage.h src/internal/QmitkGeneralPreferencePage.h ) set(UI_FILES src/QmitkPreferencesDialog.ui ) set(CACHED_RESOURCE_FILES plugin.xml ) set(QRC_FILES resources/resources.qrc ) set(CPP_FILES ) foreach(file ${SRC_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/${file}) endforeach(file ${SRC_CPP_FILES}) foreach(file ${INTERNAL_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/internal/${file}) endforeach(file ${INTERNAL_CPP_FILES}) diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkFileOpenAction.cpp b/Plugins/org.mitk.gui.qt.application/src/QmitkFileOpenAction.cpp index ff1390a63a..ebec196cc0 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkFileOpenAction.cpp +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkFileOpenAction.cpp @@ -1,114 +1,114 @@ /*=================================================================== 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 "QmitkFileOpenAction.h" #include "internal/org_mitk_gui_qt_application_Activator.h" #include #include #include class QmitkFileOpenActionPrivate { public: void init ( berry::IWorkbenchWindow::Pointer window, QmitkFileOpenAction* action ) { m_Window = window; action->setParent(static_cast(m_Window.Lock()->GetShell()->GetControl())); action->setText("&Open..."); action->setToolTip("Open data files (images, surfaces,...)"); 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 getLastFileOpenPath() const { berry::IPreferences::Pointer prefs = GetPreferences(); if(prefs.IsNotNull()) { return QString::fromStdString(prefs->Get("LastFileOpenPath", "")); } return QString(); } void setLastFileOpenPath(const QString& path) const { berry::IPreferences::Pointer prefs = GetPreferences(); if(prefs.IsNotNull()) { prefs->Put("LastFileOpenPath", path.toStdString()); prefs->Flush(); } } bool GetOpenEditor() const { berry::IPreferences::Pointer prefs = GetPreferences(); if(prefs.IsNotNull()) { return prefs->GetBool("OpenEditor", true); } return true; } berry::IWorkbenchWindow::WeakPtr m_Window; }; QmitkFileOpenAction::QmitkFileOpenAction(berry::IWorkbenchWindow::Pointer window) : QAction(0), d(new QmitkFileOpenActionPrivate) { d->init(window, this); } QmitkFileOpenAction::QmitkFileOpenAction(const QIcon & icon, berry::IWorkbenchWindow::Pointer window) : QAction(0), d(new QmitkFileOpenActionPrivate) { d->init(window, this); this->setIcon(icon); } QmitkFileOpenAction::~QmitkFileOpenAction() { } void QmitkFileOpenAction::Run() { // Ask the user for a list of files to open QStringList fileNames = QFileDialog::getOpenFileNames(NULL, "Open", d->getLastFileOpenPath(), - QmitkIOUtil::GetFilterString()); + QmitkIOUtil::GetFileOpenFilterString()); if (fileNames.empty()) return; d->setLastFileOpenPath(fileNames.front()); mitk::WorkbenchUtil::LoadFiles(fileNames, d->m_Window.Lock(), d->GetOpenEditor()); } diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkFileSaveAction.cpp b/Plugins/org.mitk.gui.qt.application/src/QmitkFileSaveAction.cpp new file mode 100644 index 0000000000..c77babfb69 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkFileSaveAction.cpp @@ -0,0 +1,183 @@ +/*=================================================================== + +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 + +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( + 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()); + } + catch (const mitk::Exception& e) + { + MITK_INFO << e; + return; + } +} diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkFileSaveAction.h b/Plugins/org.mitk.gui.qt.application/src/QmitkFileSaveAction.h new file mode 100644 index 0000000000..d80f54bf6c --- /dev/null +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkFileSaveAction.h @@ -0,0 +1,55 @@ +/*=================================================================== + +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 QMITKFILESAVEACTION_H_ +#define QMITKFILESAVEACTION_H_ + +#include +#include + +#include + +#include + +#include + +class QmitkFileSaveActionPrivate; + +/** + * \ingroup org_mitk_gui_qt_application + */ +class MITK_QT_APP QmitkFileSaveAction : public QAction +{ + Q_OBJECT + +public: + QmitkFileSaveAction(berry::IWorkbenchWindow::Pointer window); + QmitkFileSaveAction(const QIcon & icon, berry::IWorkbenchWindow::Pointer window); + + ~QmitkFileSaveAction(); + +protected slots: + + virtual void Run(); + +private: + + const QScopedPointer d; + +}; + + +#endif /*QMITKFILESAVEACTION_H_*/ diff --git a/Plugins/org.mitk.gui.qt.datamanager/manifest_headers.cmake b/Plugins/org.mitk.gui.qt.datamanager/manifest_headers.cmake index bf7062d863..c72b4ecb98 100644 --- a/Plugins/org.mitk.gui.qt.datamanager/manifest_headers.cmake +++ b/Plugins/org.mitk.gui.qt.datamanager/manifest_headers.cmake @@ -1,5 +1,5 @@ set(Plugin-Name "MITK Data Manager") set(Plugin-Version "1.0.0") set(Plugin-Vendor "DKFZ, Medical and Biological Informatics") set(Plugin-ContactAddress "http://www.mitk.org") -set(Require-Plugin org.mitk.gui.qt.common) +set(Require-Plugin org.mitk.gui.qt.application org.mitk.gui.qt.common) diff --git a/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerHotkeysPrefPage.cpp b/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerHotkeysPrefPage.cpp index 499f9ffead..0198058075 100644 --- a/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerHotkeysPrefPage.cpp +++ b/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerHotkeysPrefPage.cpp @@ -1,159 +1,155 @@ /*=================================================================== 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 "QmitkDataManagerHotkeysPrefPage.h" #include #include "berryIPreferencesService.h" #include "berryPlatform.h" #include #include #include #include #include #include #include using namespace berry; QmitkDataManagerHotkeysPrefPage::QmitkDataManagerHotkeysPrefPage() : m_MainControl(0) { } void QmitkDataManagerHotkeysPrefPage::Init(berry::IWorkbench::Pointer ) { } void QmitkDataManagerHotkeysPrefPage::CreateQtControl(QWidget* parent) { IPreferencesService::Pointer prefService = Platform::GetServiceRegistry().GetServiceById(IPreferencesService::ID); berry::IPreferences::Pointer _DataManagerHotkeysPreferencesNode = prefService->GetSystemPreferences()->Node("/Data Manager/Hotkeys"); m_DataManagerHotkeysPreferencesNode = _DataManagerHotkeysPreferencesNode; m_HotkeyEditors["Make all nodes invisible"] = new QmitkHotkeyLineEdit("Ctrl+, V"); m_HotkeyEditors["Toggle visibility of selected nodes"] = new QmitkHotkeyLineEdit("V"); m_HotkeyEditors["Delete selected nodes"] = new QmitkHotkeyLineEdit("Del"); m_HotkeyEditors["Reinit selected nodes"] = new QmitkHotkeyLineEdit("R"); m_HotkeyEditors["Global Reinit"] = new QmitkHotkeyLineEdit("Ctrl+, R"); - m_HotkeyEditors["Save selected nodes"] = new QmitkHotkeyLineEdit("Ctrl+, S"); - - m_HotkeyEditors["Load"] = new QmitkHotkeyLineEdit("Ctrl+, L"); - m_HotkeyEditors["Show Node Information"] = new QmitkHotkeyLineEdit("Ctrl+, I"); m_MainControl = new QWidget(parent); QGridLayout* layout = new QGridLayout; int i = 0; for (std::map::iterator it = m_HotkeyEditors.begin() ; it != m_HotkeyEditors.end(); ++it) { layout->addWidget(new QLabel(it->first), i,0); layout->addWidget(it->second, i,1); layout->setRowStretch(i,0); ++i; } layout->setRowStretch(i+1,10); m_MainControl->setLayout(layout); this->Update(); } QWidget* QmitkDataManagerHotkeysPrefPage::GetQtControl() const { return m_MainControl; } bool QmitkDataManagerHotkeysPrefPage::PerformOk() { IPreferences::Pointer _DataManagerHotkeysPreferencesNode = m_DataManagerHotkeysPreferencesNode.Lock(); if(_DataManagerHotkeysPreferencesNode.IsNotNull()) { bool duplicate = false; QString keyString; QString errString; for (std::map::iterator it = m_HotkeyEditors.begin() ; it != m_HotkeyEditors.end(); ++it) { keyString = it->second->GetKeySequenceAsString(); if(keyString.isEmpty()) errString = QString("No valid key sequence for \"%1\"").arg(it->first); if(errString.isEmpty()) { std::map::iterator it2; // search for duplicated key for (it2 = m_HotkeyEditors.begin(); it2 != m_HotkeyEditors.end(); ++it2) { if(it->first != it2->first && keyString == it2->second->GetKeySequenceAsString()) { duplicate = true; break; } } if(duplicate == true) errString = QString("Duplicate hot key for \"%1\" and \"%2\"").arg(it->first).arg(it2->first); } if(!errString.isEmpty()) { QMessageBox::critical(QApplication::activeWindow(), "Error", errString); return false; } } //# no errors -> save all values and flush to file for (std::map::iterator it = m_HotkeyEditors.begin() ; it != m_HotkeyEditors.end(); ++it) _DataManagerHotkeysPreferencesNode->Put(it->first.toStdString() , it->second->GetKeySequenceAsString().toStdString()); _DataManagerHotkeysPreferencesNode->Flush(); return true; } return false; } void QmitkDataManagerHotkeysPrefPage::PerformCancel() { } void QmitkDataManagerHotkeysPrefPage::Update() { IPreferences::Pointer _DataManagerHotkeysPreferencesNode = m_DataManagerHotkeysPreferencesNode.Lock(); if(_DataManagerHotkeysPreferencesNode.IsNotNull()) { for (std::map::iterator it = m_HotkeyEditors.begin() ; it != m_HotkeyEditors.end(); ++it) { it->second->setText(QString::fromStdString(_DataManagerHotkeysPreferencesNode->Get(it->first.toStdString() , it->second->text().toStdString()))); } } } diff --git a/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerView.cpp b/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerView.cpp index f3f152e935..f4286d1e09 100644 --- a/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerView.cpp +++ b/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerView.cpp @@ -1,1026 +1,949 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkDataManagerView.h" #include //# Own Includes //## mitk #include "mitkDataStorageEditorInput.h" #include "mitkIDataStorageReference.h" #include "mitkNodePredicateDataType.h" #include "mitkCoreObjectFactory.h" #include "mitkDataNodeFactory.h" #include "mitkColorProperty.h" #include "mitkCommon.h" #include "mitkNodePredicateData.h" #include "mitkNodePredicateNot.h" #include "mitkNodePredicateProperty.h" #include "mitkEnumerationProperty.h" #include "mitkLookupTableProperty.h" #include "mitkProperties.h" #include #include #include #include #include //## Qmitk #include #include #include #include #include +#include #include "src/internal/QmitkNodeTableViewKeyFilter.h" #include "src/internal/QmitkInfoDialog.h" #include "src/internal/QmitkDataManagerItemDelegate.h" //## Berry #include #include #include #include #include #include //# Toolkit Includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mitkDataNodeObject.h" #include "mitkIContextMenuAction.h" #include "berryIExtensionPointService.h" #include "mitkRenderingModeProperty.h" const std::string QmitkDataManagerView::VIEW_ID = "org.mitk.views.datamanager"; QmitkDataManagerView::QmitkDataManagerView() : m_GlobalReinitOnNodeDelete(true), m_ItemDelegate(NULL) { } QmitkDataManagerView::~QmitkDataManagerView() { //Remove all registered actions from each descriptor for (std::vector< std::pair< QmitkNodeDescriptor*, QAction* > >::iterator it = m_DescriptorActionList.begin();it != m_DescriptorActionList.end(); it++) { // first== the NodeDescriptor; second== the registered QAction (it->first)->RemoveAction(it->second); } } void QmitkDataManagerView::CreateQtPartControl(QWidget* parent) { m_CurrentRowCount = 0; m_Parent = parent; //# Preferences berry::IPreferencesService::Pointer prefService = berry::Platform::GetServiceRegistry() .GetServiceById(berry::IPreferencesService::ID); berry::IBerryPreferences::Pointer prefs = (prefService->GetSystemPreferences()->Node(VIEW_ID)) .Cast(); assert( prefs ); prefs->OnChanged.AddListener( berry::MessageDelegate1( this , &QmitkDataManagerView::OnPreferencesChanged ) ); //# GUI m_NodeTreeModel = new QmitkDataStorageTreeModel(this->GetDataStorage()); m_NodeTreeModel->setParent( parent ); m_NodeTreeModel->SetPlaceNewNodesOnTop( prefs->GetBool("Place new nodes on top", true) ); m_NodeTreeModel->SetShowHelperObjects( prefs->GetBool("Show helper objects", false) ); m_NodeTreeModel->SetShowNodesContainingNoData( prefs->GetBool("Show nodes containing no data", false) ); m_SurfaceDecimation = prefs->GetBool("Use surface decimation", false); //# Tree View (experimental) m_NodeTreeView = new QTreeView; m_NodeTreeView->setHeaderHidden(true); m_NodeTreeView->setSelectionMode( QAbstractItemView::ExtendedSelection ); m_NodeTreeView->setSelectionBehavior( QAbstractItemView::SelectRows ); m_NodeTreeView->setAlternatingRowColors(true); m_NodeTreeView->setDragEnabled(true); m_NodeTreeView->setDropIndicatorShown(true); m_NodeTreeView->setAcceptDrops(true); m_NodeTreeView->setContextMenuPolicy(Qt::CustomContextMenu); m_NodeTreeView->setModel(m_NodeTreeModel); m_NodeTreeView->setTextElideMode(Qt::ElideMiddle); m_NodeTreeView->installEventFilter(new QmitkNodeTableViewKeyFilter(this)); m_ItemDelegate = new QmitkDataManagerItemDelegate(m_NodeTreeView); m_NodeTreeView->setItemDelegate(m_ItemDelegate); QObject::connect( m_NodeTreeView, SIGNAL(customContextMenuRequested(const QPoint&)) , this, SLOT(NodeTableViewContextMenuRequested(const QPoint&)) ); QObject::connect( m_NodeTreeModel, SIGNAL(rowsInserted (const QModelIndex&, int, int)) , this, SLOT(NodeTreeViewRowsInserted ( const QModelIndex&, int, int )) ); QObject::connect( m_NodeTreeModel, SIGNAL(rowsRemoved (const QModelIndex&, int, int)) , this, SLOT(NodeTreeViewRowsRemoved( const QModelIndex&, int, int )) ); QObject::connect( m_NodeTreeView->selectionModel() , SIGNAL( selectionChanged ( const QItemSelection &, const QItemSelection & ) ) , this , SLOT( NodeSelectionChanged ( const QItemSelection &, const QItemSelection & ) ) ); //# m_NodeMenu m_NodeMenu = new QMenu(m_NodeTreeView); // # Actions berry::IEditorRegistry* editorRegistry = berry::PlatformUI::GetWorkbench()->GetEditorRegistry(); std::list editors = editorRegistry->GetEditors("*.mitk"); if (editors.size() > 1) { m_ShowInMapper = new QSignalMapper(this); foreach(berry::IEditorDescriptor::Pointer descriptor, editors) { QAction* action = new QAction(QString::fromStdString(descriptor->GetLabel()), this); m_ShowInActions << action; m_ShowInMapper->connect(action, SIGNAL(triggered()), m_ShowInMapper, SLOT(map())); m_ShowInMapper->setMapping(action, QString::fromStdString(descriptor->GetId())); } connect(m_ShowInMapper, SIGNAL(mapped(QString)), this, SLOT(ShowIn(QString))); } QmitkNodeDescriptor* unknownDataNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetUnknownDataNodeDescriptor(); QmitkNodeDescriptor* imageDataNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("Image"); QmitkNodeDescriptor* surfaceDataNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("Surface"); QAction* globalReinitAction = new QAction(QIcon(":/org.mitk.gui.qt.datamanager/Refresh_48.png"), "Global Reinit", this); QObject::connect( globalReinitAction, SIGNAL( triggered(bool) ) , this, SLOT( GlobalReinit(bool) ) ); unknownDataNodeDescriptor->AddAction(globalReinitAction); m_DescriptorActionList.push_back(std::pair(unknownDataNodeDescriptor, globalReinitAction)); - QAction* saveAction = new QAction(QIcon(":/org.mitk.gui.qt.datamanager/Save_48.png"), "Save...", this); - QObject::connect( saveAction, SIGNAL( triggered(bool) ) - , this, SLOT( SaveSelectedNodes(bool) ) ); + QAction* saveAction = new QmitkFileSaveAction(QIcon(":/org.mitk.gui.qt.datamanager/Save_48.png"), + this->GetSite()->GetWorkbenchWindow()); unknownDataNodeDescriptor->AddAction(saveAction); m_DescriptorActionList.push_back(std::pair(unknownDataNodeDescriptor,saveAction)); QAction* removeAction = new QAction(QIcon(":/org.mitk.gui.qt.datamanager/Remove_48.png"), "Remove", this); QObject::connect( removeAction, SIGNAL( triggered(bool) ) , this, SLOT( RemoveSelectedNodes(bool) ) ); unknownDataNodeDescriptor->AddAction(removeAction); m_DescriptorActionList.push_back(std::pair(unknownDataNodeDescriptor,removeAction)); QAction* reinitAction = new QAction(QIcon(":/org.mitk.gui.qt.datamanager/Refresh_48.png"), "Reinit", this); QObject::connect( reinitAction, SIGNAL( triggered(bool) ) , this, SLOT( ReinitSelectedNodes(bool) ) ); unknownDataNodeDescriptor->AddAction(reinitAction); m_DescriptorActionList.push_back(std::pair(unknownDataNodeDescriptor,reinitAction)); // find contextMenuAction extension points and add them to the node descriptor berry::IExtensionPointService::Pointer extensionPointService = berry::Platform::GetExtensionPointService(); berry::IConfigurationElement::vector cmActions( extensionPointService->GetConfigurationElementsFor("org.mitk.gui.qt.datamanager.contextMenuActions") ); berry::IConfigurationElement::vector::iterator cmActionsIt; std::string cmNodeDescriptorName; std::string cmLabel; std::string cmIcon; std::string cmClass; QmitkNodeDescriptor* tmpDescriptor; QAction* contextMenuAction; QVariant cmActionDataIt; m_ConfElements.clear(); int i=1; for (cmActionsIt = cmActions.begin() ; cmActionsIt != cmActions.end() ; ++cmActionsIt) { cmIcon.erase(); if((*cmActionsIt)->GetAttribute("nodeDescriptorName", cmNodeDescriptorName) && (*cmActionsIt)->GetAttribute("label", cmLabel) && (*cmActionsIt)->GetAttribute("class", cmClass)) { (*cmActionsIt)->GetAttribute("icon", cmIcon); // create context menu entry here tmpDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor(QString::fromStdString(cmNodeDescriptorName)); if(!tmpDescriptor) { MITK_WARN << "cannot add action \"" << cmLabel << "\" because descriptor " << cmNodeDescriptorName << " does not exist"; continue; } contextMenuAction = new QAction( QString::fromStdString(cmLabel), parent); tmpDescriptor->AddAction(contextMenuAction); m_DescriptorActionList.push_back(std::pair(tmpDescriptor,contextMenuAction)); m_ConfElements[contextMenuAction] = *cmActionsIt; cmActionDataIt.setValue(i); contextMenuAction->setData( cmActionDataIt ); connect( contextMenuAction, SIGNAL( triggered(bool) ) , this, SLOT( ContextMenuActionTriggered(bool) ) ); ++i; } } m_OpacitySlider = new QSlider; m_OpacitySlider->setMinimum(0); m_OpacitySlider->setMaximum(100); m_OpacitySlider->setOrientation(Qt::Horizontal); QObject::connect( m_OpacitySlider, SIGNAL( valueChanged(int) ) , this, SLOT( OpacityChanged(int) ) ); QLabel* _OpacityLabel = new QLabel("Opacity: "); QHBoxLayout* _OpacityWidgetLayout = new QHBoxLayout; _OpacityWidgetLayout->setContentsMargins(4,4,4,4); _OpacityWidgetLayout->addWidget(_OpacityLabel); _OpacityWidgetLayout->addWidget(m_OpacitySlider); QWidget* _OpacityWidget = new QWidget; _OpacityWidget->setLayout(_OpacityWidgetLayout); QWidgetAction* opacityAction = new QWidgetAction(this); opacityAction ->setDefaultWidget(_OpacityWidget); QObject::connect( opacityAction , SIGNAL( changed() ) , this, SLOT( OpacityActionChanged() ) ); unknownDataNodeDescriptor->AddAction(opacityAction , false); m_DescriptorActionList.push_back(std::pair(unknownDataNodeDescriptor,opacityAction)); m_ColorButton = new QPushButton; m_ColorButton->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Minimum); //m_ColorButton->setText("Change color"); QObject::connect( m_ColorButton, SIGNAL( clicked() ) , this, SLOT( ColorChanged() ) ); QLabel* _ColorLabel = new QLabel("Color: "); _ColorLabel->setSizePolicy(QSizePolicy::Minimum,QSizePolicy::Minimum); QHBoxLayout* _ColorWidgetLayout = new QHBoxLayout; _ColorWidgetLayout->setContentsMargins(4,4,4,4); _ColorWidgetLayout->addWidget(_ColorLabel); _ColorWidgetLayout->addWidget(m_ColorButton); QWidget* _ColorWidget = new QWidget; _ColorWidget->setLayout(_ColorWidgetLayout); QWidgetAction* colorAction = new QWidgetAction(this); colorAction->setDefaultWidget(_ColorWidget); QObject::connect( colorAction, SIGNAL( changed() ) , this, SLOT( ColorActionChanged() ) ); unknownDataNodeDescriptor->AddAction(colorAction, false); m_DescriptorActionList.push_back(std::pair(unknownDataNodeDescriptor,colorAction)); m_TextureInterpolation = new QAction("Texture Interpolation", this); m_TextureInterpolation->setCheckable ( true ); QObject::connect( m_TextureInterpolation, SIGNAL( changed() ) , this, SLOT( TextureInterpolationChanged() ) ); QObject::connect( m_TextureInterpolation, SIGNAL( toggled(bool) ) , this, SLOT( TextureInterpolationToggled(bool) ) ); imageDataNodeDescriptor->AddAction(m_TextureInterpolation, false); m_DescriptorActionList.push_back(std::pair(imageDataNodeDescriptor,m_TextureInterpolation)); m_ColormapAction = new QAction("Colormap", this); m_ColormapAction->setMenu(new QMenu); QObject::connect( m_ColormapAction->menu(), SIGNAL( aboutToShow() ) , this, SLOT( ColormapMenuAboutToShow() ) ); imageDataNodeDescriptor->AddAction(m_ColormapAction, false); m_DescriptorActionList.push_back(std::pair(imageDataNodeDescriptor, m_ColormapAction)); m_SurfaceRepresentation = new QAction("Surface Representation", this); m_SurfaceRepresentation->setMenu(new QMenu); QObject::connect( m_SurfaceRepresentation->menu(), SIGNAL( aboutToShow() ) , this, SLOT( SurfaceRepresentationMenuAboutToShow() ) ); surfaceDataNodeDescriptor->AddAction(m_SurfaceRepresentation, false); m_DescriptorActionList.push_back(std::pair(surfaceDataNodeDescriptor, m_SurfaceRepresentation)); QAction* showOnlySelectedNodes = new QAction(QIcon(":/org.mitk.gui.qt.datamanager/ShowSelectedNode_48.png") , "Show only selected nodes", this); QObject::connect( showOnlySelectedNodes, SIGNAL( triggered(bool) ) , this, SLOT( ShowOnlySelectedNodes(bool) ) ); unknownDataNodeDescriptor->AddAction(showOnlySelectedNodes); m_DescriptorActionList.push_back(std::pair(unknownDataNodeDescriptor, showOnlySelectedNodes)); QAction* toggleSelectedVisibility = new QAction(QIcon(":/org.mitk.gui.qt.datamanager/InvertShowSelectedNode_48.png") , "Toggle visibility", this); QObject::connect( toggleSelectedVisibility, SIGNAL( triggered(bool) ) , this, SLOT( ToggleVisibilityOfSelectedNodes(bool) ) ); unknownDataNodeDescriptor->AddAction(toggleSelectedVisibility); m_DescriptorActionList.push_back(std::pair(unknownDataNodeDescriptor,toggleSelectedVisibility)); QAction* actionShowInfoDialog = new QAction(QIcon(":/org.mitk.gui.qt.datamanager/ShowDataInfo_48.png") , "Details...", this); QObject::connect( actionShowInfoDialog, SIGNAL( triggered(bool) ) , this, SLOT( ShowInfoDialogForSelectedNodes(bool) ) ); unknownDataNodeDescriptor->AddAction(actionShowInfoDialog); m_DescriptorActionList.push_back(std::pair(unknownDataNodeDescriptor,actionShowInfoDialog)); //obsolete... //QAction* otsuFilterAction = new QAction("Apply Otsu Filter", this); //QObject::connect( otsuFilterAction, SIGNAL( triggered(bool) ) // , this, SLOT( OtsuFilter(bool) ) ); // //Otsu filter does not work properly, remove it temporarily // imageDataNodeDescriptor->AddAction(otsuFilterAction); // m_DescriptorActionList.push_back(std::pair(imageDataNodeDescriptor,otsuFilterAction)); QGridLayout* _DndFrameWidgetLayout = new QGridLayout; _DndFrameWidgetLayout->addWidget(m_NodeTreeView, 0, 0); _DndFrameWidgetLayout->setContentsMargins(0,0,0,0); m_DndFrameWidget = new QmitkDnDFrameWidget(m_Parent); m_DndFrameWidget->setLayout(_DndFrameWidgetLayout); QVBoxLayout* layout = new QVBoxLayout(parent); layout->addWidget(m_DndFrameWidget); layout->setContentsMargins(0,0,0,0); m_Parent->setLayout(layout); } void QmitkDataManagerView::SetFocus() { } void QmitkDataManagerView::ContextMenuActionTriggered( bool ) { QAction* action = qobject_cast ( sender() ); std::map::iterator it = m_ConfElements.find( action ); if( it == m_ConfElements.end() ) { MITK_WARN << "associated conf element for action " << action->text().toStdString() << " not found"; return; } berry::IConfigurationElement::Pointer confElem = it->second; mitk::IContextMenuAction* contextMenuAction = confElem->CreateExecutableExtension("class"); std::string className; std::string smoothed; confElem->GetAttribute("class", className); confElem->GetAttribute("smoothed", smoothed); if(className == "QmitkCreatePolygonModelAction") { contextMenuAction->SetDataStorage(this->GetDataStorage()); if(smoothed == "false") { contextMenuAction->SetSmoothed(false); } else { contextMenuAction->SetSmoothed(true); } contextMenuAction->SetDecimated(m_SurfaceDecimation); } else if(className == "QmitkStatisticsAction") { contextMenuAction->SetFunctionality(this); } else if(className == "QmitkCreateSimulationAction") { contextMenuAction->SetDataStorage(this->GetDataStorage()); } contextMenuAction->Run( this->GetCurrentSelection() ); // run the action } void QmitkDataManagerView::OnPreferencesChanged(const berry::IBerryPreferences* prefs) { if( m_NodeTreeModel->GetPlaceNewNodesOnTopFlag() != prefs->GetBool("Place new nodes on top", true) ) m_NodeTreeModel->SetPlaceNewNodesOnTop( !m_NodeTreeModel->GetPlaceNewNodesOnTopFlag() ); if( m_NodeTreeModel->GetShowHelperObjectsFlag()!= prefs->GetBool("Show helper objects", false) ) m_NodeTreeModel->SetShowHelperObjects( !m_NodeTreeModel->GetShowHelperObjectsFlag() ); if( m_NodeTreeModel->GetShowNodesContainingNoDataFlag()!= prefs->GetBool("Show nodes containing no data", false) ) m_NodeTreeModel->SetShowNodesContainingNoData( !m_NodeTreeModel->GetShowNodesContainingNoDataFlag() ); m_GlobalReinitOnNodeDelete = prefs->GetBool("Call global reinit if node is deleted", true); m_NodeTreeView->expandAll(); m_SurfaceDecimation = prefs->GetBool("Use surface decimation", false); this->GlobalReinit(); } void QmitkDataManagerView::NodeTableViewContextMenuRequested( const QPoint & pos ) { QModelIndex selected = m_NodeTreeView->indexAt ( pos ); mitk::DataNode::Pointer node = m_NodeTreeModel->GetNode(selected); QList selectedNodes = this->GetCurrentSelection(); if(!selectedNodes.isEmpty()) { m_NodeMenu->clear(); QList actions; if(selectedNodes.size() == 1 ) { actions = QmitkNodeDescriptorManager::GetInstance()->GetActions(node); for(QList::iterator it = actions.begin(); it != actions.end(); ++it) { (*it)->setData(QVariant::fromValue(node.GetPointer())); } } else actions = QmitkNodeDescriptorManager::GetInstance()->GetActions(selectedNodes); if (!m_ShowInActions.isEmpty()) { QMenu* showInMenu = m_NodeMenu->addMenu("Show In"); showInMenu->addActions(m_ShowInActions); } m_NodeMenu->addActions(actions); m_NodeMenu->popup(QCursor::pos()); } } void QmitkDataManagerView::OpacityChanged(int value) { mitk::DataNode* node = m_NodeTreeModel->GetNode(m_NodeTreeView->selectionModel()->currentIndex()); if(node) { float opacity = static_cast(value)/100.0f; node->SetFloatProperty("opacity", opacity); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkDataManagerView::OpacityActionChanged() { mitk::DataNode* node = m_NodeTreeModel->GetNode(m_NodeTreeView->selectionModel()->currentIndex()); if(node) { float opacity = 0.0; if(node->GetFloatProperty("opacity", opacity)) { m_OpacitySlider->setValue(static_cast(opacity*100)); } } } void QmitkDataManagerView::ColorChanged() { mitk::DataNode* node = m_NodeTreeModel->GetNode(m_NodeTreeView->selectionModel()->currentIndex()); if(node) { mitk::Color color; mitk::ColorProperty::Pointer colorProp; node->GetProperty(colorProp,"color"); if(colorProp.IsNull()) return; color = colorProp->GetValue(); QColor initial(color.GetRed()*255,color.GetGreen()*255,color.GetBlue()*255); QColor qcolor = QColorDialog::getColor(initial,0,QString("Change color")); if (!qcolor.isValid()) return; m_ColorButton->setAutoFillBackground(true); node->SetProperty("color",mitk::ColorProperty::New(qcolor.red()/255.0,qcolor.green()/255.0,qcolor.blue()/255.0)); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkDataManagerView::ColorActionChanged() { mitk::DataNode* node = m_NodeTreeModel->GetNode(m_NodeTreeView->selectionModel()->currentIndex()); if(node) { mitk::Color color; mitk::ColorProperty::Pointer colorProp; node->GetProperty(colorProp,"color"); if(colorProp.IsNull()) return; color = colorProp->GetValue(); QString styleSheet = "background-color:rgb("; styleSheet.append(QString::number(color[0]*255)); styleSheet.append(","); styleSheet.append(QString::number(color[1]*255)); styleSheet.append(","); styleSheet.append(QString::number(color[2]*255)); styleSheet.append(")"); m_ColorButton->setStyleSheet(styleSheet); } } void QmitkDataManagerView::TextureInterpolationChanged() { mitk::DataNode* node = m_NodeTreeModel->GetNode(m_NodeTreeView->selectionModel()->currentIndex()); if(node) { bool textureInterpolation = false; node->GetBoolProperty("texture interpolation", textureInterpolation); m_TextureInterpolation->setChecked(textureInterpolation); } } void QmitkDataManagerView::TextureInterpolationToggled( bool checked ) { mitk::DataNode* node = m_NodeTreeModel->GetNode(m_NodeTreeView->selectionModel()->currentIndex()); if(node) { node->SetBoolProperty("texture interpolation", checked); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkDataManagerView::ColormapActionToggled( bool /*checked*/ ) { mitk::DataNode* node = m_NodeTreeModel->GetNode(m_NodeTreeView->selectionModel()->currentIndex()); if(!node) return; mitk::LookupTableProperty::Pointer lookupTableProperty = dynamic_cast(node->GetProperty("LookupTable")); if (!lookupTableProperty) return; QAction* senderAction = qobject_cast(QObject::sender()); if(!senderAction) return; std::string activatedItem = senderAction->text().toStdString(); mitk::LookupTable::Pointer lookupTable = lookupTableProperty->GetValue(); if (!lookupTable) return; lookupTable->SetType(activatedItem); lookupTableProperty->SetValue(lookupTable); mitk::RenderingModeProperty::Pointer renderingMode = dynamic_cast(node->GetProperty("Image Rendering.Mode")); renderingMode->SetValue(mitk::RenderingModeProperty::LOOKUPTABLE_LEVELWINDOW_COLOR); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkDataManagerView::ColormapMenuAboutToShow() { mitk::DataNode* node = m_NodeTreeModel->GetNode(m_NodeTreeView->selectionModel()->currentIndex()); if(!node) return; mitk::LookupTableProperty::Pointer lookupTableProperty = dynamic_cast(node->GetProperty("LookupTable")); if (!lookupTableProperty) { mitk::LookupTable::Pointer mitkLut = mitk::LookupTable::New(); lookupTableProperty = mitk::LookupTableProperty::New(); lookupTableProperty->SetLookupTable(mitkLut); node->SetProperty("LookupTable", lookupTableProperty); } mitk::LookupTable::Pointer lookupTable = lookupTableProperty->GetValue(); if (!lookupTable) return; m_ColormapAction->menu()->clear(); QAction* tmp; int i = 0; std::string lutType = lookupTable->typenameList[i]; while (lutType != "END_OF_ARRAY") { tmp = m_ColormapAction->menu()->addAction(QString::fromStdString(lutType)); tmp->setCheckable(true); if (lutType == lookupTable->GetActiveTypeAsString()) { tmp->setChecked(true); } QObject::connect(tmp, SIGNAL(triggered(bool)), this, SLOT(ColormapActionToggled(bool))); lutType = lookupTable->typenameList[++i]; } } void QmitkDataManagerView::SurfaceRepresentationMenuAboutToShow() { mitk::DataNode* node = m_NodeTreeModel->GetNode(m_NodeTreeView->selectionModel()->currentIndex()); if(!node) return; mitk::EnumerationProperty* representationProp = dynamic_cast (node->GetProperty("material.representation")); if(!representationProp) return; // clear menu m_SurfaceRepresentation->menu()->clear(); QAction* tmp; // create menu entries for(mitk::EnumerationProperty::EnumConstIterator it=representationProp->Begin(); it!=representationProp->End() ; it++) { tmp = m_SurfaceRepresentation->menu()->addAction(QString::fromStdString(it->second)); tmp->setCheckable(true); if(it->second == representationProp->GetValueAsString()) { tmp->setChecked(true); } QObject::connect( tmp, SIGNAL( triggered(bool) ) , this, SLOT( SurfaceRepresentationActionToggled(bool) ) ); } } void QmitkDataManagerView::SurfaceRepresentationActionToggled( bool /*checked*/ ) { mitk::DataNode* node = m_NodeTreeModel->GetNode(m_NodeTreeView->selectionModel()->currentIndex()); if(!node) return; mitk::EnumerationProperty* representationProp = dynamic_cast (node->GetProperty("material.representation")); if(!representationProp) return; QAction* senderAction = qobject_cast ( QObject::sender() ); if(!senderAction) return; std::string activatedItem = senderAction->text().toStdString(); if ( activatedItem != representationProp->GetValueAsString() ) { if ( representationProp->IsValidEnumerationValue( activatedItem ) ) { representationProp->SetValue( activatedItem ); representationProp->InvokeEvent( itk::ModifiedEvent() ); representationProp->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } } -void QmitkDataManagerView::SaveSelectedNodes( bool ) -{ - QModelIndexList indexesOfSelectedRows = m_NodeTreeView->selectionModel()->selectedRows(); - - mitk::DataNode* node = 0; - unsigned int indexesOfSelectedRowsSize = indexesOfSelectedRows.size(); - for (unsigned int i = 0; iGetNode(indexesOfSelectedRows.at(i)); - // if node is not defined or if the node contains geometry data do not remove it - if ( node != 0 ) - { - mitk::BaseData::Pointer data = node->GetData(); - if (data.IsNotNull()) - { - QString error; - try - { - QmitkIOUtil::SaveBaseDataWithDialog( data.GetPointer(), node->GetName().c_str(), m_Parent ); - } - catch(std::exception& e) - { - error = e.what(); - } - catch(...) - { - error = "Unknown error occured"; - } - if( !error.isEmpty() ) - QMessageBox::critical( m_Parent, "Error saving...", error ); - } - } - } -} - void QmitkDataManagerView::ReinitSelectedNodes( bool ) { mitk::IRenderWindowPart* renderWindow = this->GetRenderWindowPart(); if (renderWindow == NULL) renderWindow = this->OpenRenderWindowPart(false); QList selectedNodes = this->GetCurrentSelection(); foreach(mitk::DataNode::Pointer node, selectedNodes) { mitk::BaseData::Pointer basedata = node->GetData(); if ( basedata.IsNotNull() && basedata->GetTimeGeometry()->IsValid() ) { renderWindow->GetRenderingManager()->InitializeViews( basedata->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); renderWindow->GetRenderingManager()->RequestUpdateAll(); } } } void QmitkDataManagerView::RemoveSelectedNodes( bool ) { QModelIndexList indexesOfSelectedRows = m_NodeTreeView->selectionModel()->selectedRows(); if(indexesOfSelectedRows.size() < 1) { return; } std::vector selectedNodes; mitk::DataNode* node = 0; QString question = tr("Do you really want to remove "); for (QModelIndexList::iterator it = indexesOfSelectedRows.begin() ; it != indexesOfSelectedRows.end(); it++) { node = m_NodeTreeModel->GetNode(*it); // if node is not defined or if the node contains geometry data do not remove it if ( node != 0 /*& strcmp(node->GetData()->GetNameOfClass(), "PlaneGeometryData") != 0*/ ) { selectedNodes.push_back(node); question.append(QString::fromStdString(node->GetName())); question.append(", "); } } // remove the last two characters = ", " question = question.remove(question.size()-2, 2); question.append(" from data storage?"); QMessageBox::StandardButton answerButton = QMessageBox::question( m_Parent , tr("DataManager") , question , QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); if(answerButton == QMessageBox::Yes) { for (std::vector::iterator it = selectedNodes.begin() ; it != selectedNodes.end(); it++) { node = *it; this->GetDataStorage()->Remove(node); if (m_GlobalReinitOnNodeDelete) this->GlobalReinit(false); } } } void QmitkDataManagerView::MakeAllNodesInvisible( bool ) { QList nodes = m_NodeTreeModel->GetNodeSet(); foreach(mitk::DataNode::Pointer node, nodes) { node->SetVisibility(false); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkDataManagerView::ShowOnlySelectedNodes( bool ) { QList selectedNodes = this->GetCurrentSelection(); QList allNodes = m_NodeTreeModel->GetNodeSet(); foreach(mitk::DataNode::Pointer node, allNodes) { node->SetVisibility(selectedNodes.contains(node)); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkDataManagerView::ToggleVisibilityOfSelectedNodes( bool ) { QList selectedNodes = this->GetCurrentSelection(); bool isVisible = false; foreach(mitk::DataNode::Pointer node, selectedNodes) { isVisible = false; node->GetBoolProperty("visible", isVisible); node->SetVisibility(!isVisible); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkDataManagerView::ShowInfoDialogForSelectedNodes( bool ) { QList selectedNodes = this->GetCurrentSelection(); QmitkInfoDialog _QmitkInfoDialog(selectedNodes, this->m_Parent); _QmitkInfoDialog.exec(); } -void QmitkDataManagerView::Load( bool ) -{ - QStringList fileNames = QFileDialog::getOpenFileNames(NULL, "Load data", "", mitk::CoreObjectFactory::GetInstance()->GetFileExtensions()); - for ( QStringList::Iterator it = fileNames.begin(); it != fileNames.end(); ++it ) - { - FileOpen((*it).toAscii(), 0); - } -} - -void QmitkDataManagerView::FileOpen( const char * fileName, mitk::DataNode* parentNode ) -{ - mitk::DataNodeFactory::Pointer factory = mitk::DataNodeFactory::New(); - - try - { - factory->SetFileName( fileName ); - - QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); - - factory->Update(); - - for ( unsigned int i = 0 ; i < factory->GetNumberOfOutputs( ); ++i ) - { - mitk::DataNode::Pointer node = factory->GetOutput( i ); - if ( ( node.IsNotNull() ) && ( node->GetData() != NULL ) ) - { - this->GetDataStorage()->Add(node, parentNode); - mitk::BaseData::Pointer basedata = node->GetData(); - mitk::RenderingManager::GetInstance()->InitializeViews( - basedata->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); - //mitk::RenderingManager::GetInstance()->RequestUpdateAll(); - } - } - } - catch ( itk::ExceptionObject & ex ) - { - itkGenericOutputMacro( << "Exception during file open: " << ex ); - } - - QApplication::restoreOverrideCursor(); -} - QItemSelectionModel *QmitkDataManagerView::GetDataNodeSelectionModel() const { return m_NodeTreeView->selectionModel(); } void QmitkDataManagerView::GlobalReinit( bool ) { mitk::IRenderWindowPart* renderWindow = this->GetRenderWindowPart(); if (renderWindow == NULL) renderWindow = this->OpenRenderWindowPart(false); // no render window available if (renderWindow == NULL) return; mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(this->GetDataStorage()); } void QmitkDataManagerView::OtsuFilter( bool ) { QList selectedNodes = this->GetCurrentSelection(); mitk::Image::Pointer mitkImage = 0; foreach(mitk::DataNode::Pointer node, selectedNodes) { mitkImage = dynamic_cast( node->GetData() ); if(mitkImage.IsNull()) continue; try { // get selected mitk image const unsigned short dim = 3; typedef short InputPixelType; typedef unsigned char OutputPixelType; typedef itk::Image< InputPixelType, dim > InputImageType; typedef itk::Image< OutputPixelType, dim > OutputImageType; typedef itk::OtsuThresholdImageFilter< InputImageType, OutputImageType > FilterType; FilterType::Pointer filter = FilterType::New(); filter->SetOutsideValue( 1 ); filter->SetInsideValue( 0 ); InputImageType::Pointer itkImage; mitk::CastToItkImage(mitkImage, itkImage); filter->SetInput( itkImage ); filter->Update(); mitk::DataNode::Pointer resultNode = mitk::DataNode::New(); std::string nameOfResultImage = node->GetName(); nameOfResultImage.append("Otsu"); resultNode->SetProperty("name", mitk::StringProperty::New(nameOfResultImage) ); resultNode->SetProperty("binary", mitk::BoolProperty::New(true) ); resultNode->SetData( mitk::ImportItkImage(filter->GetOutput())->Clone()); this->GetDataStorage()->Add(resultNode, node); } catch( std::exception& err ) { MITK_ERROR(this->GetClassName()) << err.what(); } } } void QmitkDataManagerView::NodeTreeViewRowsRemoved ( const QModelIndex & /*parent*/, int /*start*/, int /*end*/ ) { m_CurrentRowCount = m_NodeTreeModel->rowCount(); } void QmitkDataManagerView::NodeTreeViewRowsInserted( const QModelIndex & parent, int, int ) { m_NodeTreeView->setExpanded(parent, true); // a new row was inserted if( m_CurrentRowCount == 0 && m_NodeTreeModel->rowCount() == 1 ) { this->OpenRenderWindowPart(); m_CurrentRowCount = m_NodeTreeModel->rowCount(); /* std::vector nodes = m_NodeTreeModel->GetNodeSet(); if(nodes.size() == 1) { QModelIndex treeIndex = m_NodeTreeModel->GetIndex(nodes.front()); m_NodeTreeView->selectionModel()->setCurrentIndex( treeIndex, QItemSelectionModel::ClearAndSelect ); } */ } } void QmitkDataManagerView::NodeSelectionChanged( const QItemSelection & /*selected*/, const QItemSelection & /*deselected*/ ) { QList nodes = m_NodeTreeModel->GetNodeSet(); foreach(mitk::DataNode::Pointer node, nodes) { if ( node.IsNotNull() ) node->SetBoolProperty("selected", false); } nodes.clear(); nodes = this->GetCurrentSelection(); foreach(mitk::DataNode::Pointer node, nodes) { if ( node.IsNotNull() ) node->SetBoolProperty("selected", true); } //changing the selection does NOT require any rendering processes! //mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkDataManagerView::ShowIn(const QString &editorId) { berry::IWorkbenchPage::Pointer page = this->GetSite()->GetPage(); berry::IEditorInput::Pointer input(new mitk::DataStorageEditorInput(this->GetDataStorageReference())); page->OpenEditor(input, editorId.toStdString(), false, berry::IWorkbenchPage::MATCH_ID); } mitk::IRenderWindowPart* QmitkDataManagerView::OpenRenderWindowPart(bool activatedEditor) { if (activatedEditor) { return this->GetRenderWindowPart(QmitkAbstractView::ACTIVATE | QmitkAbstractView::OPEN); } else { return this->GetRenderWindowPart(QmitkAbstractView::BRING_TO_FRONT | QmitkAbstractView::OPEN); } } diff --git a/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerView.h b/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerView.h index bd222ad948..ceadc57f24 100644 --- a/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerView.h +++ b/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerView.h @@ -1,262 +1,254 @@ /*=================================================================== 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 QMITKDATAMANAGERVIEW_H_ #define QMITKDATAMANAGERVIEW_H_ // BlueBerry includes #include /// Qmitk #include #include /// Qt #include #include // Forward declarations class QMenu; class QAction; class QComboBox; class QWidgetAction; class QSlider; class QModelIndex; class QTreeView; class QPushButton; class QToolBar; class QMenu; class QSignalMapper; class QmitkDnDFrameWidget; class QmitkDataStorageTreeModel; class QmitkDataManagerItemDelegate; /// /// \ingroup org_mitk_gui_qt_datamanager_internal /// /// \brief A View class that can show all data tree nodes of a certain DataStorage /// /// \TODO: complete PACS support, in save dialog show regular filename /// class MITK_QT_DATAMANAGER QmitkDataManagerView : public QmitkAbstractView { Q_OBJECT public: static const std::string VIEW_ID; // = "org.mitk.extapp.defaultperspective" /// /// \brief Standard ctor. /// QmitkDataManagerView(); /// /// \brief Standard dtor. /// virtual ~QmitkDataManagerView(); public slots: /// /// Invoked when the opacity slider changed /// void OpacityChanged(int value); /// /// Invoked when the opacity action changed /// In this function the the opacity slider is set to the selected nodes opacity value /// void OpacityActionChanged(); /// /// Invoked when the color button is pressed /// void ColorChanged(); /// /// Invoked when the color action changed /// void ColorActionChanged(); /// /// Invoked when the color button is pressed /// void TextureInterpolationChanged(); /// /// Invoked when the color action changed /// void TextureInterpolationToggled ( bool checked ); /// /// \brief Agreggates available colormaps /// void ColormapMenuAboutToShow (); /// /// \brief changes the active colormap /// void ColormapActionToggled (bool); /// /// SurfaceRepresentationActionToggled /// void SurfaceRepresentationMenuAboutToShow (); /// /// SurfaceRepresentationActionToggled /// void SurfaceRepresentationActionToggled ( bool checked ); /// /// \brief Shows a node context menu. /// void NodeTableViewContextMenuRequested( const QPoint & index ); /// - /// \brief Invoked when an element should be saved. - /// - void SaveSelectedNodes( bool checked = false ); - /// /// \brief Invoked when an element should be removed. /// void RemoveSelectedNodes( bool checked = false ); /// /// \brief Invoked when an element should be reinitiliased. /// void ReinitSelectedNodes( bool checked = false ); /// /// \brief Invoked when the visibility of the selected nodes should be toggled. /// void MakeAllNodesInvisible ( bool checked = false ); /// /// \brief Makes all selected nodes visible, all other nodes invisible. /// void ShowOnlySelectedNodes ( bool checked = false ); /// /// \brief Invoked when the visibility of the selected nodes should be toggled. /// void ToggleVisibilityOfSelectedNodes ( bool checked = false ); /// /// \brief Invoked when infos of the selected nodes should be shown in a dialog. /// void ShowInfoDialogForSelectedNodes ( bool checked = false ); /// - /// \brief Shows a load dialog. - /// - void Load ( bool checked = false ); - /// /// \brief Reinits everything. /// void GlobalReinit ( bool checked = false ); /// /// Invoked when the preferences were changed /// void OnPreferencesChanged(const berry::IBerryPreferences*); /// /// \brief will be toggled when a extension point context menu action is toggled /// this is a proxy method which will load the corresponding extension class /// and run IContextMenuAction /// void ContextMenuActionTriggered( bool ); /// Invoked when the median action is invoked void OtsuFilter( bool checked = false ); /// When rows are inserted auto expand them void NodeTreeViewRowsInserted ( const QModelIndex & parent, int start, int end ); /// will setup m_CurrentRowCount void NodeTreeViewRowsRemoved ( const QModelIndex & parent, int start, int end ); /// Whenever the selection changes set the "selected" property respectively void NodeSelectionChanged( const QItemSelection & selected, const QItemSelection & deselected ); /// Opens the editor with the given id using the current data storage void ShowIn(const QString& editorId); protected: /// /// \brief Create the view here. /// virtual void CreateQtPartControl(QWidget* parent); void SetFocus(); /// /// \brief Shows a file open dialog. /// void FileOpen( const char * fileName, mitk::DataNode* parentNode ); protected: QWidget* m_Parent; QmitkDnDFrameWidget* m_DndFrameWidget; /// /// \brief A plain widget as the base pane. /// QmitkDataStorageTreeModel* m_NodeTreeModel; /// /// Holds the preferences for the datamanager. /// berry::IBerryPreferences::Pointer m_DataManagerPreferencesNode; /// /// saves the configuration elements for the context menu actions from extension points /// std::map m_ConfElements; /// /// \brief The Table view to show the selected nodes. /// QTreeView* m_NodeTreeView; /// /// \brief The context menu that shows up when right clicking on a node. /// QMenu* m_NodeMenu; /// /// \brief flag indicating whether a surface created from a selected decimation is decimated with vtkQuadricDecimation or not /// bool m_SurfaceDecimation; ///# A list of ALL actions for the Context Menu std::vector< std::pair< QmitkNodeDescriptor*, QAction* > > m_DescriptorActionList; /// A Slider widget to change the opacity of a node QSlider* m_OpacitySlider; /// button to change the color of a node QPushButton* m_ColorButton; /// TextureInterpolation action QAction* m_TextureInterpolation; /// SurfaceRepresentation action QAction* m_SurfaceRepresentation; /// Lookuptable selection action QAction* m_ColormapAction; /// Maps "Show in" actions to editor ids QSignalMapper* m_ShowInMapper; /// A list of "Show in" actions QList m_ShowInActions; /// saves the current amount of rows shown in the datamanager size_t m_CurrentRowCount; /// if true, GlobalReinit() is called if a node is deleted bool m_GlobalReinitOnNodeDelete; QmitkDataManagerItemDelegate* m_ItemDelegate; private: QItemSelectionModel* GetDataNodeSelectionModel() const; /// Reopen multi widget editor if it has been closed mitk::IRenderWindowPart *OpenRenderWindowPart(bool activatedEditor = true); }; #endif /*QMITKDATAMANAGERVIEW_H_*/ diff --git a/Plugins/org.mitk.gui.qt.datamanager/src/internal/QmitkNodeTableViewKeyFilter.cpp b/Plugins/org.mitk.gui.qt.datamanager/src/internal/QmitkNodeTableViewKeyFilter.cpp index df209a6577..2f8f15c659 100644 --- a/Plugins/org.mitk.gui.qt.datamanager/src/internal/QmitkNodeTableViewKeyFilter.cpp +++ b/Plugins/org.mitk.gui.qt.datamanager/src/internal/QmitkNodeTableViewKeyFilter.cpp @@ -1,103 +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 "QmitkNodeTableViewKeyFilter.h" #include #include #include "../QmitkDataManagerView.h" QmitkNodeTableViewKeyFilter::QmitkNodeTableViewKeyFilter( QObject* _DataManagerView ) : QObject(_DataManagerView) { m_PreferencesService = berry::Platform::GetServiceRegistry().GetServiceById(berry::IPreferencesService::ID); } bool QmitkNodeTableViewKeyFilter::eventFilter( QObject *obj, QEvent *event ) { QmitkDataManagerView* _DataManagerView = qobject_cast(this->parent()); if (event->type() == QEvent::KeyPress && _DataManagerView) { berry::IPreferencesService::Pointer prefService = m_PreferencesService.Lock(); berry::IPreferences::Pointer nodeTableKeyPrefs = prefService->GetSystemPreferences()->Node("/Data Manager/Hotkeys"); QKeySequence _MakeAllInvisible = QKeySequence(QString::fromStdString(nodeTableKeyPrefs->Get("Make all nodes invisible", "Ctrl+, V"))); QKeySequence _ToggleVisibility = QKeySequence(QString::fromStdString(nodeTableKeyPrefs->Get("Toggle visibility of selected nodes", "V"))); QKeySequence _DeleteSelectedNodes = QKeySequence(QString::fromStdString(nodeTableKeyPrefs->Get("Delete selected nodes", "Del"))); QKeySequence _Reinit = QKeySequence(QString::fromStdString(nodeTableKeyPrefs->Get("Reinit selected nodes", "R"))); QKeySequence _GlobalReinit = QKeySequence(QString::fromStdString(nodeTableKeyPrefs->Get("Global Reinit", "Ctrl+, R"))); - QKeySequence _Save = QKeySequence(QString::fromStdString(nodeTableKeyPrefs->Get("Save selected nodes", "Ctrl+, S"))); - QKeySequence _Load = QKeySequence(QString::fromStdString(nodeTableKeyPrefs->Get("Load", "Ctrl+, L"))); QKeySequence _ShowInfo = QKeySequence(QString::fromStdString(nodeTableKeyPrefs->Get("Show Node Information", "Ctrl+, I"))); QKeyEvent *keyEvent = static_cast(event); QKeySequence _KeySequence = QKeySequence(keyEvent->modifiers(), keyEvent->key()); // if no modifier was pressed the sequence is now empty if(_KeySequence.isEmpty()) _KeySequence = QKeySequence(keyEvent->key()); if(_KeySequence == _MakeAllInvisible) { // trigger deletion of selected node(s) _DataManagerView->MakeAllNodesInvisible(true); // return true: this means the delete key event is not send to the table return true; } else if(_KeySequence == _DeleteSelectedNodes) { // trigger deletion of selected node(s) _DataManagerView->RemoveSelectedNodes(true); // return true: this means the delete key event is not send to the table return true; } else if(_KeySequence == _ToggleVisibility) { // trigger deletion of selected node(s) _DataManagerView->ToggleVisibilityOfSelectedNodes(true); // return true: this means the delete key event is not send to the table return true; } else if(_KeySequence == _Reinit) { _DataManagerView->ReinitSelectedNodes(true); return true; } else if(_KeySequence == _GlobalReinit) { _DataManagerView->GlobalReinit(true); return true; } - else if(_KeySequence == _Save) - { - _DataManagerView->SaveSelectedNodes(true); - return true; - } - else if(_KeySequence == _Load) - { - _DataManagerView->Load(true); - return true; - } else if(_KeySequence == _ShowInfo) { _DataManagerView->ShowInfoDialogForSelectedNodes(true); return true; } } // standard event processing return QObject::eventFilter(obj, event); } diff --git a/Plugins/org.mitk.gui.qt.ext/src/QmitkExtWorkbenchWindowAdvisor.cpp b/Plugins/org.mitk.gui.qt.ext/src/QmitkExtWorkbenchWindowAdvisor.cpp index 2bd59abf43..33b7d43870 100644 --- a/Plugins/org.mitk.gui.qt.ext/src/QmitkExtWorkbenchWindowAdvisor.cpp +++ b/Plugins/org.mitk.gui.qt.ext/src/QmitkExtWorkbenchWindowAdvisor.cpp @@ -1,1212 +1,1218 @@ /*=================================================================== 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 "QmitkExtWorkbenchWindowAdvisor.h" #include "QmitkExtActionBarAdvisor.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // UGLYYY #include "internal/QmitkExtWorkbenchWindowAdvisorHack.h" #include "internal/QmitkCommonExtPlugin.h" #include "mitkUndoController.h" #include "mitkVerboseLimitedLinearUndo.h" #include #include #include #include QmitkExtWorkbenchWindowAdvisorHack * QmitkExtWorkbenchWindowAdvisorHack::undohack = new QmitkExtWorkbenchWindowAdvisorHack(); QString QmitkExtWorkbenchWindowAdvisor::QT_SETTINGS_FILENAME = "QtSettings.ini"; class PartListenerForTitle: public berry::IPartListener { public: PartListenerForTitle(QmitkExtWorkbenchWindowAdvisor* wa) : windowAdvisor(wa) { } Events::Types GetPartEventTypes() const { return Events::ACTIVATED | Events::BROUGHT_TO_TOP | Events::CLOSED | Events::HIDDEN | Events::VISIBLE; } void PartActivated(berry::IWorkbenchPartReference::Pointer ref) { if (ref.Cast ()) { windowAdvisor->UpdateTitle(false); } } void PartBroughtToTop(berry::IWorkbenchPartReference::Pointer ref) { if (ref.Cast ()) { windowAdvisor->UpdateTitle(false); } } void PartClosed(berry::IWorkbenchPartReference::Pointer /*ref*/) { windowAdvisor->UpdateTitle(false); } void PartHidden(berry::IWorkbenchPartReference::Pointer ref) { if (!windowAdvisor->lastActiveEditor.Expired() && ref->GetPart(false) == windowAdvisor->lastActiveEditor.Lock()) { windowAdvisor->UpdateTitle(true); } } void PartVisible(berry::IWorkbenchPartReference::Pointer ref) { if (!windowAdvisor->lastActiveEditor.Expired() && ref->GetPart(false) == windowAdvisor->lastActiveEditor.Lock()) { windowAdvisor->UpdateTitle(false); } } private: QmitkExtWorkbenchWindowAdvisor* windowAdvisor; }; class PartListenerForImageNavigator: public berry::IPartListener { public: PartListenerForImageNavigator(QAction* act) : imageNavigatorAction(act) { } Events::Types GetPartEventTypes() const { return Events::OPENED | Events::CLOSED | Events::HIDDEN | Events::VISIBLE; } void PartOpened(berry::IWorkbenchPartReference::Pointer ref) { if (ref->GetId()=="org.mitk.views.imagenavigator") { imageNavigatorAction->setChecked(true); } } void PartClosed(berry::IWorkbenchPartReference::Pointer ref) { if (ref->GetId()=="org.mitk.views.imagenavigator") { imageNavigatorAction->setChecked(false); } } void PartVisible(berry::IWorkbenchPartReference::Pointer ref) { if (ref->GetId()=="org.mitk.views.imagenavigator") { imageNavigatorAction->setChecked(true); } } void PartHidden(berry::IWorkbenchPartReference::Pointer ref) { if (ref->GetId()=="org.mitk.views.imagenavigator") { imageNavigatorAction->setChecked(false); } } private: QAction* imageNavigatorAction; }; class PerspectiveListenerForTitle: public berry::IPerspectiveListener { public: PerspectiveListenerForTitle(QmitkExtWorkbenchWindowAdvisor* wa) : windowAdvisor(wa), perspectivesClosed(false) { } Events::Types GetPerspectiveEventTypes() const { return Events::ACTIVATED | Events::SAVED_AS | Events::DEACTIVATED // remove the following line when command framework is finished | Events::CLOSED | Events::OPENED; } void PerspectiveActivated(berry::IWorkbenchPage::Pointer /*page*/, berry::IPerspectiveDescriptor::Pointer /*perspective*/) { windowAdvisor->UpdateTitle(false); } void PerspectiveSavedAs(berry::IWorkbenchPage::Pointer /*page*/, berry::IPerspectiveDescriptor::Pointer /*oldPerspective*/, berry::IPerspectiveDescriptor::Pointer /*newPerspective*/) { windowAdvisor->UpdateTitle(false); } void PerspectiveDeactivated(berry::IWorkbenchPage::Pointer /*page*/, berry::IPerspectiveDescriptor::Pointer /*perspective*/) { windowAdvisor->UpdateTitle(false); } void PerspectiveOpened(berry::IWorkbenchPage::Pointer /*page*/, berry::IPerspectiveDescriptor::Pointer /*perspective*/) { if (perspectivesClosed) { QListIterator i(windowAdvisor->viewActions); while (i.hasNext()) { i.next()->setEnabled(true); } //GetViewRegistry()->Find("org.mitk.views.imagenavigator"); if(windowAdvisor->GetWindowConfigurer()->GetWindow()->GetWorkbench()->GetEditorRegistry()->FindEditor("org.mitk.editors.dicomeditor")) { windowAdvisor->openDicomEditorAction->setEnabled(true); } if(windowAdvisor->GetWindowConfigurer()->GetWindow()->GetWorkbench()->GetEditorRegistry()->FindEditor("org.mitk.editors.xnat.browser")) { windowAdvisor->openXnatEditorAction->setEnabled(true); } windowAdvisor->fileSaveProjectAction->setEnabled(true); windowAdvisor->closeProjectAction->setEnabled(true); windowAdvisor->undoAction->setEnabled(true); windowAdvisor->redoAction->setEnabled(true); windowAdvisor->imageNavigatorAction->setEnabled(true); windowAdvisor->resetPerspAction->setEnabled(true); if( windowAdvisor->GetShowClosePerspectiveMenuItem() ) { windowAdvisor->closePerspAction->setEnabled(true); } } perspectivesClosed = false; } void PerspectiveClosed(berry::IWorkbenchPage::Pointer /*page*/, berry::IPerspectiveDescriptor::Pointer /*perspective*/) { berry::IWorkbenchWindow::Pointer wnd = windowAdvisor->GetWindowConfigurer()->GetWindow(); bool allClosed = true; if (wnd->GetActivePage()) { std::vector perspectives(wnd->GetActivePage()->GetOpenPerspectives()); allClosed = perspectives.empty(); } if (allClosed) { perspectivesClosed = true; QListIterator i(windowAdvisor->viewActions); while (i.hasNext()) { i.next()->setEnabled(false); } if(windowAdvisor->GetWindowConfigurer()->GetWindow()->GetWorkbench()->GetEditorRegistry()->FindEditor("org.mitk.editors.dicomeditor")) { windowAdvisor->openDicomEditorAction->setEnabled(false); } if(windowAdvisor->GetWindowConfigurer()->GetWindow()->GetWorkbench()->GetEditorRegistry()->FindEditor("org.mitk.editors.xnat.browser")) { windowAdvisor->openXnatEditorAction->setEnabled(false); } windowAdvisor->fileSaveProjectAction->setEnabled(false); windowAdvisor->closeProjectAction->setEnabled(false); windowAdvisor->undoAction->setEnabled(false); windowAdvisor->redoAction->setEnabled(false); windowAdvisor->imageNavigatorAction->setEnabled(false); windowAdvisor->resetPerspAction->setEnabled(false); if( windowAdvisor->GetShowClosePerspectiveMenuItem() ) { windowAdvisor->closePerspAction->setEnabled(false); } } } private: QmitkExtWorkbenchWindowAdvisor* windowAdvisor; bool perspectivesClosed; }; class PerspectiveListenerForMenu: public berry::IPerspectiveListener { public: PerspectiveListenerForMenu(QmitkExtWorkbenchWindowAdvisor* wa) : windowAdvisor(wa) { } Events::Types GetPerspectiveEventTypes() const { return Events::ACTIVATED | Events::DEACTIVATED; } void PerspectiveActivated(berry::IWorkbenchPage::Pointer /*page*/, berry::IPerspectiveDescriptor::Pointer perspective) { QAction* action = windowAdvisor->mapPerspIdToAction[perspective->GetId()]; if (action) { action->setChecked(true); } } void PerspectiveDeactivated(berry::IWorkbenchPage::Pointer /*page*/, berry::IPerspectiveDescriptor::Pointer perspective) { QAction* action = windowAdvisor->mapPerspIdToAction[perspective->GetId()]; if (action) { action->setChecked(false); } } private: QmitkExtWorkbenchWindowAdvisor* windowAdvisor; }; QmitkExtWorkbenchWindowAdvisor::QmitkExtWorkbenchWindowAdvisor(berry::WorkbenchAdvisor* wbAdvisor, berry::IWorkbenchWindowConfigurer::Pointer configurer) : berry::WorkbenchWindowAdvisor(configurer), lastInput(0), wbAdvisor(wbAdvisor), showViewToolbar(true), showPerspectiveToolbar(false), showVersionInfo(true), showMitkVersionInfo(true), showViewMenuItem(true), showNewWindowMenuItem(false), showClosePerspectiveMenuItem(true), dropTargetListener(new QmitkDefaultDropTargetListener) { productName = QCoreApplication::applicationName().toStdString(); } berry::ActionBarAdvisor::Pointer QmitkExtWorkbenchWindowAdvisor::CreateActionBarAdvisor( berry::IActionBarConfigurer::Pointer configurer) { berry::ActionBarAdvisor::Pointer actionBarAdvisor( new QmitkExtActionBarAdvisor(configurer)); return actionBarAdvisor; } void* QmitkExtWorkbenchWindowAdvisor::CreateEmptyWindowContents(void* parent) { QWidget* parentWidget = static_cast(parent); QLabel* label = new QLabel(parentWidget); label->setText("No perspectives are open. Open a perspective in the Window->Open Perspective menu."); label->setContentsMargins(10,10,10,10); label->setAlignment(Qt::AlignTop); label->setEnabled(false); parentWidget->layout()->addWidget(label); return label; } void QmitkExtWorkbenchWindowAdvisor::ShowClosePerspectiveMenuItem(bool show) { showClosePerspectiveMenuItem = show; } bool QmitkExtWorkbenchWindowAdvisor::GetShowClosePerspectiveMenuItem() { return showClosePerspectiveMenuItem; } void QmitkExtWorkbenchWindowAdvisor::ShowNewWindowMenuItem(bool show) { showNewWindowMenuItem = show; } void QmitkExtWorkbenchWindowAdvisor::ShowViewToolbar(bool show) { showViewToolbar = show; } void QmitkExtWorkbenchWindowAdvisor::ShowViewMenuItem(bool show) { showViewMenuItem = show; } void QmitkExtWorkbenchWindowAdvisor::ShowPerspectiveToolbar(bool show) { showPerspectiveToolbar = show; } void QmitkExtWorkbenchWindowAdvisor::ShowVersionInfo(bool show) { showVersionInfo = show; } void QmitkExtWorkbenchWindowAdvisor::ShowMitkVersionInfo(bool show) { showMitkVersionInfo = show; } void QmitkExtWorkbenchWindowAdvisor::SetProductName(const std::string& product) { productName = product; } void QmitkExtWorkbenchWindowAdvisor::SetWindowIcon(const std::string& wndIcon) { windowIcon = wndIcon; } void QmitkExtWorkbenchWindowAdvisor::PostWindowCreate() { // very bad hack... berry::IWorkbenchWindow::Pointer window = this->GetWindowConfigurer()->GetWindow(); QMainWindow* mainWindow = static_cast (window->GetShell()->GetControl()); if (!windowIcon.empty()) { mainWindow->setWindowIcon(QIcon(QString::fromStdString(windowIcon))); } mainWindow->setContextMenuPolicy(Qt::PreventContextMenu); /*mainWindow->setStyleSheet("color: white;" "background-color: #808080;" "selection-color: #659EC7;" "selection-background-color: #808080;" " QMenuBar {" "background-color: #808080; }");*/ // ==== Application menu ============================ QMenuBar* menuBar = mainWindow->menuBar(); menuBar->setContextMenuPolicy(Qt::PreventContextMenu); QMenu* fileMenu = menuBar->addMenu("&File"); fileMenu->setObjectName("FileMenu"); QAction* fileOpenAction = new QmitkFileOpenAction(QIcon(":/org.mitk.gui.qt.ext/Load_48.png"), window); + fileOpenAction->setShortcut(QKeySequence::Open); fileMenu->addAction(fileOpenAction); + QAction* fileSaveAction = new QmitkFileSaveAction(QIcon(":/org.mitk.gui.qt.ext/Save_48.png"), window); + fileSaveAction->setShortcut(QKeySequence::Save); + fileMenu->addAction(fileSaveAction); fileSaveProjectAction = new QmitkExtFileSaveProjectAction(window); fileSaveProjectAction->setIcon(QIcon(":/org.mitk.gui.qt.ext/Save_48.png")); fileMenu->addAction(fileSaveProjectAction); closeProjectAction = new QmitkCloseProjectAction(window); closeProjectAction->setIcon(QIcon(":/org.mitk.gui.qt.ext/Remove_48.png")); fileMenu->addAction(closeProjectAction); fileMenu->addSeparator(); QAction* fileExitAction = new QmitkFileExitAction(window); + fileExitAction->setShortcut(QKeySequence::Quit); fileExitAction->setObjectName("QmitkFileExitAction"); fileMenu->addAction(fileExitAction); if(this->GetWindowConfigurer()->GetWindow()->GetWorkbench()->GetEditorRegistry()->FindEditor("org.mitk.editors.dicomeditor")) { openDicomEditorAction = new QmitkOpenDicomEditorAction(QIcon(":/org.mitk.gui.qt.ext/dcm-icon.png"),window); } if(this->GetWindowConfigurer()->GetWindow()->GetWorkbench()->GetEditorRegistry()->FindEditor("org.mitk.editors.xnat.browser")) { openXnatEditorAction = new QmitkOpenXnatEditorAction(QIcon(":/org.mitk.gui.qt.ext/xnat-icon.png"),window); } berry::IViewRegistry* viewRegistry = berry::PlatformUI::GetWorkbench()->GetViewRegistry(); const std::vector& viewDescriptors = viewRegistry->GetViews(); // another bad hack to get an edit/undo menu... QMenu* editMenu = menuBar->addMenu("&Edit"); undoAction = editMenu->addAction(QIcon(":/org.mitk.gui.qt.ext/Undo_48.png"), "&Undo", QmitkExtWorkbenchWindowAdvisorHack::undohack, SLOT(onUndo()), QKeySequence("CTRL+Z")); undoAction->setToolTip("Undo the last action (not supported by all modules)"); redoAction = editMenu->addAction(QIcon(":/org.mitk.gui.qt.ext/Redo_48.png") , "&Redo", QmitkExtWorkbenchWindowAdvisorHack::undohack, SLOT(onRedo()), QKeySequence("CTRL+Y")); redoAction->setToolTip("execute the last action that was undone again (not supported by all modules)"); imageNavigatorAction = new QAction(QIcon(":/org.mitk.gui.qt.ext/Slider.png"), "&Image Navigator", NULL); bool imageNavigatorViewFound = window->GetWorkbench()->GetViewRegistry()->Find("org.mitk.views.imagenavigator"); if (imageNavigatorViewFound) { QObject::connect(imageNavigatorAction, SIGNAL(triggered(bool)), QmitkExtWorkbenchWindowAdvisorHack::undohack, SLOT(onImageNavigator())); imageNavigatorAction->setCheckable(true); // add part listener for image navigator imageNavigatorPartListener = new PartListenerForImageNavigator(imageNavigatorAction); window->GetPartService()->AddPartListener(imageNavigatorPartListener); berry::IViewPart::Pointer imageNavigatorView = window->GetActivePage()->FindView("org.mitk.views.imagenavigator"); imageNavigatorAction->setChecked(false); if (imageNavigatorView) { bool isImageNavigatorVisible = window->GetActivePage()->IsPartVisible(imageNavigatorView); if (isImageNavigatorVisible) imageNavigatorAction->setChecked(true); } imageNavigatorAction->setToolTip("Open image navigator for navigating through image"); } // toolbar for showing file open, undo, redo and other main actions QToolBar* mainActionsToolBar = new QToolBar; mainActionsToolBar->setObjectName("mainActionsToolBar"); mainActionsToolBar->setContextMenuPolicy(Qt::PreventContextMenu); #ifdef __APPLE__ mainActionsToolBar->setToolButtonStyle ( Qt::ToolButtonTextUnderIcon ); #else mainActionsToolBar->setToolButtonStyle ( Qt::ToolButtonTextBesideIcon ); #endif mainActionsToolBar->addAction(fileOpenAction); mainActionsToolBar->addAction(fileSaveProjectAction); mainActionsToolBar->addAction(closeProjectAction); mainActionsToolBar->addAction(undoAction); mainActionsToolBar->addAction(redoAction); if(this->GetWindowConfigurer()->GetWindow()->GetWorkbench()->GetEditorRegistry()->FindEditor("org.mitk.editors.dicomeditor")) { mainActionsToolBar->addAction(openDicomEditorAction); } if(this->GetWindowConfigurer()->GetWindow()->GetWorkbench()->GetEditorRegistry()->FindEditor("org.mitk.editors.xnat.browser")) { mainActionsToolBar->addAction(openXnatEditorAction); } if (imageNavigatorViewFound) { mainActionsToolBar->addAction(imageNavigatorAction); } mainWindow->addToolBar(mainActionsToolBar); #ifdef __APPLE__ mainWindow->setUnifiedTitleAndToolBarOnMac(true); #endif // ==== Window Menu ========================== QMenu* windowMenu = menuBar->addMenu("Window"); if (showNewWindowMenuItem) { windowMenu->addAction("&New Window", QmitkExtWorkbenchWindowAdvisorHack::undohack, SLOT(onNewWindow())); windowMenu->addSeparator(); } QMenu* perspMenu = windowMenu->addMenu("&Open Perspective"); QMenu* viewMenu; if (showViewMenuItem) { viewMenu = windowMenu->addMenu("Show &View"); viewMenu->setObjectName("Show View"); } windowMenu->addSeparator(); resetPerspAction = windowMenu->addAction("&Reset Perspective", QmitkExtWorkbenchWindowAdvisorHack::undohack, SLOT(onResetPerspective())); if(showClosePerspectiveMenuItem) closePerspAction = windowMenu->addAction("&Close Perspective", QmitkExtWorkbenchWindowAdvisorHack::undohack, SLOT(onClosePerspective())); windowMenu->addSeparator(); windowMenu->addAction("&Preferences...", QmitkExtWorkbenchWindowAdvisorHack::undohack, SLOT(onEditPreferences()), QKeySequence("CTRL+P")); // fill perspective menu berry::IPerspectiveRegistry* perspRegistry = window->GetWorkbench()->GetPerspectiveRegistry(); QActionGroup* perspGroup = new QActionGroup(menuBar); std::vector perspectives( perspRegistry->GetPerspectives()); bool skip = false; for (std::vector::iterator perspIt = perspectives.begin(); perspIt != perspectives.end(); ++perspIt) { // if perspectiveExcludeList is set, it contains the id-strings of perspectives, which // should not appear as an menu-entry in the perspective menu if (perspectiveExcludeList.size() > 0) { for (unsigned int i=0; iGetId()) { skip = true; break; } } if (skip) { skip = false; continue; } } QAction* perspAction = new berry::QtOpenPerspectiveAction(window, *perspIt, perspGroup); mapPerspIdToAction.insert(std::make_pair((*perspIt)->GetId(), perspAction)); } perspMenu->addActions(perspGroup->actions()); // sort elements (converting vector to map...) std::vector::const_iterator iter; std::map VDMap; skip = false; for (iter = viewDescriptors.begin(); iter != viewDescriptors.end(); ++iter) { // if viewExcludeList is set, it contains the id-strings of view, which // should not appear as an menu-entry in the menu if (viewExcludeList.size() > 0) { for (unsigned int i=0; iGetId()) { skip = true; break; } } if (skip) { skip = false; continue; } } if ((*iter)->GetId() == "org.blueberry.ui.internal.introview") continue; if ((*iter)->GetId() == "org.mitk.views.imagenavigator") continue; std::pair p( (*iter)->GetLabel(), (*iter)); VDMap.insert(p); } // ================================================== // ==== Perspective Toolbar ================================== QToolBar* qPerspectiveToolbar = new QToolBar; qPerspectiveToolbar->setObjectName("perspectiveToolBar"); if (showPerspectiveToolbar) { qPerspectiveToolbar->addActions(perspGroup->actions()); mainWindow->addToolBar(qPerspectiveToolbar); } else delete qPerspectiveToolbar; // ==== View Toolbar ================================== QToolBar* qToolbar = new QToolBar; qToolbar->setObjectName("viewToolBar"); std::map::const_iterator MapIter; for (MapIter = VDMap.begin(); MapIter != VDMap.end(); ++MapIter) { berry::QtShowViewAction* viewAction = new berry::QtShowViewAction(window, (*MapIter).second); viewActions.push_back(viewAction); if(showViewMenuItem) viewMenu->addAction(viewAction); if (showViewToolbar) { qToolbar->addAction(viewAction); } } if (showViewToolbar) { mainWindow->addToolBar(qToolbar); } else delete qToolbar; QSettings settings(GetQSettingsFile(), QSettings::IniFormat); mainWindow->restoreState(settings.value("ToolbarPosition").toByteArray()); // ==================================================== // ===== Help menu ==================================== QMenu* helpMenu = menuBar->addMenu("&Help"); helpMenu->addAction("&Welcome",this, SLOT(onIntro())); helpMenu->addAction("&Open Help Perspective", this, SLOT(onHelpOpenHelpPerspective())); helpMenu->addAction("&Context Help",this, SLOT(onHelp()), QKeySequence("F1")); helpMenu->addAction("&About",this, SLOT(onAbout())); // ===================================================== QStatusBar* qStatusBar = new QStatusBar(); //creating a QmitkStatusBar for Output on the QStatusBar and connecting it with the MainStatusBar QmitkStatusBar *statusBar = new QmitkStatusBar(qStatusBar); //disabling the SizeGrip in the lower right corner statusBar->SetSizeGripEnabled(false); QmitkProgressBar *progBar = new QmitkProgressBar(); qStatusBar->addPermanentWidget(progBar, 0); progBar->hide(); // progBar->AddStepsToDo(2); // progBar->Progress(1); mainWindow->setStatusBar(qStatusBar); QmitkMemoryUsageIndicatorView* memoryIndicator = new QmitkMemoryUsageIndicatorView(); qStatusBar->addPermanentWidget(memoryIndicator, 0); } void QmitkExtWorkbenchWindowAdvisor::PreWindowOpen() { berry::IWorkbenchWindowConfigurer::Pointer configurer = GetWindowConfigurer(); // show the shortcut bar and progress indicator, which are hidden by // default //configurer->SetShowPerspectiveBar(true); //configurer->SetShowFastViewBars(true); //configurer->SetShowProgressIndicator(true); // // add the drag and drop support for the editor area // configurer.addEditorAreaTransfer(EditorInputTransfer.getInstance()); // configurer.addEditorAreaTransfer(ResourceTransfer.getInstance()); // configurer.addEditorAreaTransfer(FileTransfer.getInstance()); // configurer.addEditorAreaTransfer(MarkerTransfer.getInstance()); // configurer.configureEditorAreaDropListener(new EditorAreaDropAdapter( // configurer.getWindow())); this->HookTitleUpdateListeners(configurer); menuPerspectiveListener = new PerspectiveListenerForMenu(this); configurer->GetWindow()->AddPerspectiveListener(menuPerspectiveListener); configurer->AddEditorAreaTransfer(QStringList("text/uri-list")); configurer->ConfigureEditorAreaDropListener(dropTargetListener); } void QmitkExtWorkbenchWindowAdvisor::PostWindowOpen() { // Force Rendering Window Creation on startup. berry::IWorkbenchWindowConfigurer::Pointer configurer = GetWindowConfigurer(); ctkPluginContext* context = QmitkCommonExtPlugin::getContext(); ctkServiceReference serviceRef = context->getServiceReference(); if (serviceRef) { mitk::IDataStorageService *dsService = context->getService(serviceRef); if (dsService) { mitk::IDataStorageReference::Pointer dsRef = dsService->GetDataStorage(); mitk::DataStorageEditorInput::Pointer dsInput(new mitk::DataStorageEditorInput(dsRef)); mitk::WorkbenchUtil::OpenEditor(configurer->GetWindow()->GetActivePage(),dsInput); } } } void QmitkExtWorkbenchWindowAdvisor::onIntro() { QmitkExtWorkbenchWindowAdvisorHack::undohack->onIntro(); } void QmitkExtWorkbenchWindowAdvisor::onHelp() { QmitkExtWorkbenchWindowAdvisorHack::undohack->onHelp(); } void QmitkExtWorkbenchWindowAdvisor::onHelpOpenHelpPerspective() { QmitkExtWorkbenchWindowAdvisorHack::undohack->onHelpOpenHelpPerspective(); } void QmitkExtWorkbenchWindowAdvisor::onAbout() { QmitkExtWorkbenchWindowAdvisorHack::undohack->onAbout(); } //-------------------------------------------------------------------------------- // Ugly hack from here on. Feel free to delete when command framework // and undo buttons are done. //-------------------------------------------------------------------------------- QmitkExtWorkbenchWindowAdvisorHack::QmitkExtWorkbenchWindowAdvisorHack() : QObject() { } QmitkExtWorkbenchWindowAdvisorHack::~QmitkExtWorkbenchWindowAdvisorHack() { } void QmitkExtWorkbenchWindowAdvisorHack::onUndo() { mitk::UndoModel* model = mitk::UndoController::GetCurrentUndoModel(); if (model) { if (mitk::VerboseLimitedLinearUndo* verboseundo = dynamic_cast( model )) { mitk::VerboseLimitedLinearUndo::StackDescription descriptions = verboseundo->GetUndoDescriptions(); if (descriptions.size() >= 1) { MITK_INFO << "Undo " << descriptions.front().second; } } model->Undo(); } else { MITK_ERROR << "No undo model instantiated"; } } void QmitkExtWorkbenchWindowAdvisorHack::onRedo() { mitk::UndoModel* model = mitk::UndoController::GetCurrentUndoModel(); if (model) { if (mitk::VerboseLimitedLinearUndo* verboseundo = dynamic_cast( model )) { mitk::VerboseLimitedLinearUndo::StackDescription descriptions = verboseundo->GetRedoDescriptions(); if (descriptions.size() >= 1) { MITK_INFO << "Redo " << descriptions.front().second; } } model->Redo(); } else { MITK_ERROR << "No undo model instantiated"; } } void QmitkExtWorkbenchWindowAdvisorHack::onImageNavigator() { // get ImageNavigatorView berry::IViewPart::Pointer imageNavigatorView = berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow()->GetActivePage()->FindView("org.mitk.views.imagenavigator"); if (imageNavigatorView) { bool isImageNavigatorVisible = berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow()->GetActivePage()->IsPartVisible(imageNavigatorView); if (isImageNavigatorVisible) { berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow()->GetActivePage()->HideView(imageNavigatorView); return; } } berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow()->GetActivePage()->ShowView("org.mitk.views.imagenavigator"); //berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow()->GetActivePage()->ResetPerspective(); } void QmitkExtWorkbenchWindowAdvisorHack::onEditPreferences() { QmitkPreferencesDialog _PreferencesDialog(QApplication::activeWindow()); _PreferencesDialog.exec(); } void QmitkExtWorkbenchWindowAdvisorHack::onQuit() { berry::PlatformUI::GetWorkbench()->Close(); } void QmitkExtWorkbenchWindowAdvisorHack::onResetPerspective() { berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow()->GetActivePage()->ResetPerspective(); } void QmitkExtWorkbenchWindowAdvisorHack::onClosePerspective() { berry::IWorkbenchPage::Pointer page = berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow()->GetActivePage(); page->ClosePerspective(page->GetPerspective(), true, true); } void QmitkExtWorkbenchWindowAdvisorHack::onNewWindow() { berry::PlatformUI::GetWorkbench()->OpenWorkbenchWindow(0); } void QmitkExtWorkbenchWindowAdvisorHack::onIntro() { bool hasIntro = berry::PlatformUI::GetWorkbench()->GetIntroManager()->HasIntro(); if (!hasIntro) { QRegExp reg("(.*)(\\n)*"); QRegExp reg2("(\\n)*(.*)"); QFile file(":/org.mitk.gui.qt.ext/index.html"); file.open(QIODevice::ReadOnly | QIODevice::Text); //text file only for reading QString text = QString(file.readAll()); file.close(); QString title = text; title.replace(reg, ""); title.replace(reg2, ""); std::cout << title.toStdString() << std::endl; QMessageBox::information(NULL, title, text, "Close"); } else { berry::PlatformUI::GetWorkbench()->GetIntroManager()->ShowIntro( berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow(), false); } } void QmitkExtWorkbenchWindowAdvisorHack::onHelp() { ctkPluginContext* context = QmitkCommonExtPlugin::getContext(); if (context == 0) { MITK_WARN << "Plugin context not set, unable to open context help"; return; } // Check if the org.blueberry.ui.qt.help plug-in is installed and started QList > plugins = context->getPlugins(); foreach(QSharedPointer p, plugins) { if (p->getSymbolicName() == "org.blueberry.ui.qt.help") { if (p->getState() != ctkPlugin::ACTIVE) { // try to activate the plug-in explicitly try { p->start(ctkPlugin::START_TRANSIENT); } catch (const ctkPluginException& pe) { MITK_ERROR << "Activating org.blueberry.ui.qt.help failed: " << pe.what(); return; } } } } ctkServiceReference eventAdminRef = context->getServiceReference(); ctkEventAdmin* eventAdmin = 0; if (eventAdminRef) { eventAdmin = context->getService(eventAdminRef); } if (eventAdmin == 0) { MITK_WARN << "ctkEventAdmin service not found. Unable to open context help"; } else { ctkEvent ev("org/blueberry/ui/help/CONTEXTHELP_REQUESTED"); eventAdmin->postEvent(ev); } } void QmitkExtWorkbenchWindowAdvisorHack::onHelpOpenHelpPerspective() { berry::PlatformUI::GetWorkbench()->ShowPerspective("org.blueberry.perspectives.help", berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow()); } void QmitkExtWorkbenchWindowAdvisorHack::onAbout() { QmitkAboutDialog* aboutDialog = new QmitkAboutDialog(QApplication::activeWindow(),NULL); aboutDialog->open(); } void QmitkExtWorkbenchWindowAdvisor::HookTitleUpdateListeners( berry::IWorkbenchWindowConfigurer::Pointer configurer) { // hook up the listeners to update the window title titlePartListener = new PartListenerForTitle(this); titlePerspectiveListener = new PerspectiveListenerForTitle(this); editorPropertyListener = new berry::PropertyChangeIntAdapter< QmitkExtWorkbenchWindowAdvisor>(this, &QmitkExtWorkbenchWindowAdvisor::PropertyChange); // configurer.getWindow().addPageListener(new IPageListener() { // public void pageActivated(IWorkbenchPage page) { // updateTitle(false); // } // // public void pageClosed(IWorkbenchPage page) { // updateTitle(false); // } // // public void pageOpened(IWorkbenchPage page) { // // do nothing // } // }); configurer->GetWindow()->AddPerspectiveListener(titlePerspectiveListener); configurer->GetWindow()->GetPartService()->AddPartListener(titlePartListener); } std::string QmitkExtWorkbenchWindowAdvisor::ComputeTitle() { berry::IWorkbenchWindowConfigurer::Pointer configurer = GetWindowConfigurer(); berry::IWorkbenchPage::Pointer currentPage = configurer->GetWindow()->GetActivePage(); berry::IEditorPart::Pointer activeEditor; if (currentPage) { activeEditor = lastActiveEditor.Lock(); } std::string title; //TODO Product // IProduct product = Platform.getProduct(); // if (product != null) { // title = product.getName(); // } // instead of the product name, we use a custom variable for now title = productName; if(showMitkVersionInfo) { title += std::string(" ") + MITK_VERSION_STRING; } if (showVersionInfo) { // add version informatioin QString versions = QString(" (ITK %1.%2.%3 VTK %4.%5.%6 Qt %7 MITK %8)") .arg(ITK_VERSION_MAJOR).arg(ITK_VERSION_MINOR).arg(ITK_VERSION_PATCH) .arg(VTK_MAJOR_VERSION).arg(VTK_MINOR_VERSION).arg(VTK_BUILD_VERSION) .arg(QT_VERSION_STR) .arg(MITK_VERSION_STRING); title += versions.toStdString(); } if (currentPage) { if (activeEditor) { lastEditorTitle = activeEditor->GetTitleToolTip(); if (!lastEditorTitle.empty()) title = lastEditorTitle + " - " + title; } berry::IPerspectiveDescriptor::Pointer persp = currentPage->GetPerspective(); std::string label = ""; if (persp) { label = persp->GetLabel(); } berry::IAdaptable* input = currentPage->GetInput(); if (input && input != wbAdvisor->GetDefaultPageInput()) { label = currentPage->GetLabel(); } if (!label.empty()) { title = label + " - " + title; } } title += " (Not for use in diagnosis or treatment of patients)"; return title; } void QmitkExtWorkbenchWindowAdvisor::RecomputeTitle() { berry::IWorkbenchWindowConfigurer::Pointer configurer = GetWindowConfigurer(); std::string oldTitle = configurer->GetTitle(); std::string newTitle = ComputeTitle(); if (newTitle != oldTitle) { configurer->SetTitle(newTitle); } } void QmitkExtWorkbenchWindowAdvisor::UpdateTitle(bool editorHidden) { berry::IWorkbenchWindowConfigurer::Pointer configurer = GetWindowConfigurer(); berry::IWorkbenchWindow::Pointer window = configurer->GetWindow(); berry::IEditorPart::Pointer activeEditor; berry::IWorkbenchPage::Pointer currentPage = window->GetActivePage(); berry::IPerspectiveDescriptor::Pointer persp; berry::IAdaptable* input = 0; if (currentPage) { activeEditor = currentPage->GetActiveEditor(); persp = currentPage->GetPerspective(); input = currentPage->GetInput(); } if (editorHidden) { activeEditor = 0; } // Nothing to do if the editor hasn't changed if (activeEditor == lastActiveEditor.Lock() && currentPage == lastActivePage.Lock() && persp == lastPerspective.Lock() && input == lastInput) { return; } if (!lastActiveEditor.Expired()) { lastActiveEditor.Lock()->RemovePropertyListener(editorPropertyListener); } lastActiveEditor = activeEditor; lastActivePage = currentPage; lastPerspective = persp; lastInput = input; if (activeEditor) { activeEditor->AddPropertyListener(editorPropertyListener); } RecomputeTitle(); } void QmitkExtWorkbenchWindowAdvisor::PropertyChange(berry::Object::Pointer /*source*/, int propId) { if (propId == berry::IWorkbenchPartConstants::PROP_TITLE) { if (!lastActiveEditor.Expired()) { std::string newTitle = lastActiveEditor.Lock()->GetPartName(); if (lastEditorTitle != newTitle) { RecomputeTitle(); } } } } void QmitkExtWorkbenchWindowAdvisor::SetPerspectiveExcludeList(std::vector v) { this->perspectiveExcludeList = v; } std::vector QmitkExtWorkbenchWindowAdvisor::GetPerspectiveExcludeList() { return this->perspectiveExcludeList; } void QmitkExtWorkbenchWindowAdvisor::SetViewExcludeList(std::vector v) { this->viewExcludeList = v; } std::vector QmitkExtWorkbenchWindowAdvisor::GetViewExcludeList() { return this->viewExcludeList; } void QmitkExtWorkbenchWindowAdvisor::PostWindowClose() { berry::IWorkbenchWindow::Pointer window = this->GetWindowConfigurer()->GetWindow(); QMainWindow* mainWindow = static_cast (window->GetShell()->GetControl()); QSettings settings(GetQSettingsFile(), QSettings::IniFormat); settings.setValue("ToolbarPosition", mainWindow->saveState()); } QString QmitkExtWorkbenchWindowAdvisor::GetQSettingsFile() const { QFileInfo settingsInfo = QmitkCommonExtPlugin::getContext()->getDataFile(QT_SETTINGS_FILENAME); return settingsInfo.canonicalFilePath(); }