diff --git a/Modules/Core/files.cmake b/Modules/Core/files.cmake index 08c2cdba3e..d2b402bd8e 100644 --- a/Modules/Core/files.cmake +++ b/Modules/Core/files.cmake @@ -1,317 +1,318 @@ file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") set(CPP_FILES mitkCoreActivator.cpp mitkCoreObjectFactoryBase.cpp mitkCoreObjectFactory.cpp mitkCoreServices.cpp mitkException.cpp Algorithms/mitkBaseDataSource.cpp Algorithms/mitkClippedSurfaceBoundsCalculator.cpp Algorithms/mitkCompareImageDataFilter.cpp Algorithms/mitkCompositePixelValueToString.cpp Algorithms/mitkConvert2Dto3DImageFilter.cpp Algorithms/mitkDataNodeSource.cpp Algorithms/mitkExtractSliceFilter.cpp Algorithms/mitkHistogramGenerator.cpp Algorithms/mitkImageChannelSelector.cpp Algorithms/mitkImageSliceSelector.cpp Algorithms/mitkImageSource.cpp Algorithms/mitkImageTimeSelector.cpp Algorithms/mitkImageToImageFilter.cpp Algorithms/mitkImageToSurfaceFilter.cpp Algorithms/mitkMultiComponentImageDataComparisonFilter.cpp Algorithms/mitkPlaneGeometryDataToSurfaceFilter.cpp Algorithms/mitkPointSetSource.cpp Algorithms/mitkPointSetToPointSetFilter.cpp Algorithms/mitkRGBToRGBACastImageFilter.cpp Algorithms/mitkSubImageSelector.cpp Algorithms/mitkSurfaceSource.cpp Algorithms/mitkSurfaceToImageFilter.cpp Algorithms/mitkSurfaceToSurfaceFilter.cpp Algorithms/mitkUIDGenerator.cpp Algorithms/mitkVolumeCalculator.cpp Controllers/mitkBaseController.cpp Controllers/mitkCallbackFromGUIThread.cpp Controllers/mitkCameraController.cpp Controllers/mitkCameraRotationController.cpp Controllers/mitkLimitedLinearUndo.cpp Controllers/mitkOperationEvent.cpp Controllers/mitkPlanePositionManager.cpp Controllers/mitkProgressBar.cpp Controllers/mitkRenderingManager.cpp Controllers/mitkSliceNavigationController.cpp Controllers/mitkSlicesCoordinator.cpp Controllers/mitkStatusBar.cpp Controllers/mitkStepper.cpp Controllers/mitkTestManager.cpp Controllers/mitkUndoController.cpp Controllers/mitkVerboseLimitedLinearUndo.cpp Controllers/mitkVtkLayerController.cpp DataManagement/mitkAnatomicalStructureColorPresets.cpp DataManagement/mitkArbitraryTimeGeometry.cpp DataManagement/mitkAbstractTransformGeometry.cpp DataManagement/mitkAnnotationProperty.cpp DataManagement/mitkApplicationCursor.cpp DataManagement/mitkApplyTransformMatrixOperation.cpp DataManagement/mitkBaseData.cpp DataManagement/mitkBaseGeometry.cpp DataManagement/mitkBaseProperty.cpp DataManagement/mitkChannelDescriptor.cpp DataManagement/mitkClippingProperty.cpp DataManagement/mitkColorProperty.cpp DataManagement/mitkDataNode.cpp DataManagement/mitkDataStorage.cpp DataManagement/mitkEnumerationProperty.cpp DataManagement/mitkFloatPropertyExtension.cpp DataManagement/mitkGeometry3D.cpp DataManagement/mitkGeometryData.cpp DataManagement/mitkGeometryTransformHolder.cpp DataManagement/mitkGroupTagProperty.cpp DataManagement/mitkImageAccessorBase.cpp DataManagement/mitkImageCaster.cpp DataManagement/mitkImageCastPart1.cpp DataManagement/mitkImageCastPart2.cpp DataManagement/mitkImageCastPart3.cpp DataManagement/mitkImageCastPart4.cpp DataManagement/mitkImage.cpp DataManagement/mitkImageDataItem.cpp DataManagement/mitkImageDescriptor.cpp DataManagement/mitkImageReadAccessor.cpp DataManagement/mitkImageStatisticsHolder.cpp DataManagement/mitkImageVtkAccessor.cpp DataManagement/mitkImageVtkReadAccessor.cpp DataManagement/mitkImageVtkWriteAccessor.cpp DataManagement/mitkImageWriteAccessor.cpp DataManagement/mitkIntPropertyExtension.cpp DataManagement/mitkIPersistenceService.cpp DataManagement/mitkIPropertyAliases.cpp DataManagement/mitkIPropertyDescriptions.cpp DataManagement/mitkIPropertyExtensions.cpp DataManagement/mitkIPropertyFilters.cpp DataManagement/mitkIPropertyPersistence.cpp DataManagement/mitkLandmarkProjectorBasedCurvedGeometry.cpp DataManagement/mitkLandmarkProjector.cpp DataManagement/mitkLevelWindow.cpp DataManagement/mitkLevelWindowManager.cpp DataManagement/mitkLevelWindowPreset.cpp DataManagement/mitkLevelWindowProperty.cpp DataManagement/mitkLine.cpp DataManagement/mitkLookupTable.cpp DataManagement/mitkLookupTableProperty.cpp DataManagement/mitkLookupTables.cpp # specializations of GenericLookupTable DataManagement/mitkMaterial.cpp DataManagement/mitkMemoryUtilities.cpp DataManagement/mitkModalityProperty.cpp DataManagement/mitkModifiedLock.cpp DataManagement/mitkNodePredicateAnd.cpp DataManagement/mitkNodePredicateBase.cpp DataManagement/mitkNodePredicateCompositeBase.cpp DataManagement/mitkNodePredicateData.cpp DataManagement/mitkNodePredicateDataType.cpp DataManagement/mitkNodePredicateDimension.cpp DataManagement/mitkNodePredicateFirstLevel.cpp DataManagement/mitkNodePredicateGeometry.cpp DataManagement/mitkNodePredicateNot.cpp DataManagement/mitkNodePredicateOr.cpp DataManagement/mitkNodePredicateProperty.cpp DataManagement/mitkNodePredicateDataProperty.cpp DataManagement/mitkNodePredicateSource.cpp DataManagement/mitkNumericConstants.cpp DataManagement/mitkPlaneGeometry.cpp DataManagement/mitkPlaneGeometryData.cpp DataManagement/mitkPlaneOperation.cpp DataManagement/mitkPlaneOrientationProperty.cpp DataManagement/mitkPointOperation.cpp DataManagement/mitkPointSet.cpp DataManagement/mitkPointSetShapeProperty.cpp DataManagement/mitkProperties.cpp DataManagement/mitkPropertyAliases.cpp DataManagement/mitkPropertyDescriptions.cpp DataManagement/mitkPropertyExtension.cpp DataManagement/mitkPropertyExtensions.cpp DataManagement/mitkPropertyFilter.cpp DataManagement/mitkPropertyFilters.cpp DataManagement/mitkPropertyList.cpp DataManagement/mitkPropertyListReplacedObserver.cpp DataManagement/mitkPropertyNameHelper.cpp DataManagement/mitkPropertyObserver.cpp DataManagement/mitkPropertyPersistence.cpp DataManagement/mitkPropertyPersistenceInfo.cpp DataManagement/mitkProportionalTimeGeometry.cpp DataManagement/mitkRenderingModeProperty.cpp DataManagement/mitkResliceMethodProperty.cpp DataManagement/mitkRestorePlanePositionOperation.cpp DataManagement/mitkRotationOperation.cpp DataManagement/mitkScaleOperation.cpp DataManagement/mitkShaderProperty.cpp DataManagement/mitkSlicedData.cpp DataManagement/mitkSlicedGeometry3D.cpp DataManagement/mitkSmartPointerProperty.cpp DataManagement/mitkStandaloneDataStorage.cpp DataManagement/mitkStringProperty.cpp DataManagement/mitkSurface.cpp DataManagement/mitkSurfaceOperation.cpp DataManagement/mitkThinPlateSplineCurvedGeometry.cpp DataManagement/mitkTimeGeometry.cpp DataManagement/mitkTransferFunction.cpp DataManagement/mitkTransferFunctionInitializer.cpp DataManagement/mitkTransferFunctionProperty.cpp DataManagement/mitkTemporoSpatialStringProperty.cpp DataManagement/mitkVector.cpp DataManagement/mitkVectorProperty.cpp DataManagement/mitkVtkInterpolationProperty.cpp DataManagement/mitkVtkRepresentationProperty.cpp DataManagement/mitkVtkResliceInterpolationProperty.cpp DataManagement/mitkVtkScalarModeProperty.cpp DataManagement/mitkVtkVolumeRenderingProperty.cpp DataManagement/mitkWeakPointerProperty.cpp Interactions/mitkAction.cpp Interactions/mitkBindDispatcherInteractor.cpp Interactions/mitkCrosshairPositionEvent.cpp Interactions/mitkDataInteractor.cpp Interactions/mitkDispatcher.cpp Interactions/mitkDisplayCoordinateOperation.cpp Interactions/mitkDisplayInteractor.cpp Interactions/mitkEventConfig.cpp Interactions/mitkEventFactory.cpp Interactions/mitkEventRecorder.cpp Interactions/mitkEventStateMachine.cpp Interactions/mitkInteractionEventConst.cpp Interactions/mitkInteractionEvent.cpp Interactions/mitkInteractionEventHandler.cpp Interactions/mitkInteractionEventObserver.cpp Interactions/mitkInteractionKeyEvent.cpp Interactions/mitkInteractionPositionEvent.cpp Interactions/mitkInternalEvent.cpp Interactions/mitkMouseDoubleClickEvent.cpp Interactions/mitkMouseModeSwitcher.cpp Interactions/mitkMouseMoveEvent.cpp Interactions/mitkMousePressEvent.cpp Interactions/mitkMouseReleaseEvent.cpp Interactions/mitkMouseWheelEvent.cpp Interactions/mitkPointSetDataInteractor.cpp Interactions/mitkSinglePointDataInteractor.cpp Interactions/mitkStateMachineAction.cpp Interactions/mitkStateMachineCondition.cpp Interactions/mitkStateMachineContainer.cpp Interactions/mitkStateMachineState.cpp Interactions/mitkStateMachineTransition.cpp Interactions/mitkVtkEventAdapter.cpp Interactions/mitkVtkInteractorStyle.cxx Interactions/mitkXML2EventParser.cpp IO/mitkAbstractFileIO.cpp IO/mitkAbstractFileReader.cpp IO/mitkAbstractFileWriter.cpp IO/mitkCustomMimeType.cpp IO/mitkDicomSeriesReader.cpp IO/mitkDicomSeriesReaderService.cpp IO/mitkDicomSR_GantryTiltInformation.cpp IO/mitkDicomSR_ImageBlockDescriptor.cpp IO/mitkDicomSR_LoadDICOMRGBPixel4D.cpp IO/mitkDicomSR_LoadDICOMRGBPixel.cpp IO/mitkDicomSR_LoadDICOMScalar4D.cpp IO/mitkDicomSR_LoadDICOMScalar.cpp IO/mitkDicomSR_SliceGroupingResult.cpp IO/mitkFileReader.cpp IO/mitkFileReaderRegistry.cpp IO/mitkFileReaderSelector.cpp IO/mitkFileReaderWriterBase.cpp IO/mitkFileWriter.cpp IO/mitkFileWriterRegistry.cpp IO/mitkFileWriterSelector.cpp IO/mitkGeometry3DToXML.cpp IO/mitkIFileIO.cpp IO/mitkIFileReader.cpp IO/mitkIFileWriter.cpp IO/mitkGeometryDataReaderService.cpp IO/mitkGeometryDataWriterService.cpp IO/mitkImageGenerator.cpp IO/mitkImageVtkLegacyIO.cpp IO/mitkImageVtkXmlIO.cpp IO/mitkIMimeTypeProvider.cpp IO/mitkIOConstants.cpp IO/mitkIOMimeTypes.cpp IO/mitkIOUtil.cpp IO/mitkItkImageIO.cpp IO/mitkItkLoggingAdapter.cpp IO/mitkLegacyFileReaderService.cpp IO/mitkLegacyFileWriterService.cpp IO/mitkLocaleSwitch.cpp IO/mitkLog.cpp IO/mitkMimeType.cpp IO/mitkMimeTypeProvider.cpp IO/mitkOperation.cpp IO/mitkPixelType.cpp IO/mitkPointSetReaderService.cpp IO/mitkPointSetWriterService.cpp IO/mitkProportionalTimeGeometryToXML.cpp IO/mitkRawImageFileReader.cpp IO/mitkStandardFileLocations.cpp IO/mitkSurfaceStlIO.cpp IO/mitkSurfaceVtkIO.cpp IO/mitkSurfaceVtkLegacyIO.cpp IO/mitkSurfaceVtkXmlIO.cpp IO/mitkVtkLoggingAdapter.cpp + IO/mitkPreferenceListReaderOptionsFunctor.cpp Rendering/mitkAbstractOverlayLayouter.cpp Rendering/mitkBaseRenderer.cpp #Rendering/mitkGLMapper.cpp Moved to deprecated LegacyGL Module Rendering/mitkGradientBackground.cpp Rendering/mitkImageVtkMapper2D.cpp Rendering/mitkIShaderRepository.cpp Rendering/mitkManufacturerLogo.cpp Rendering/mitkMapper.cpp Rendering/mitkOverlay.cpp Rendering/mitkOverlayManager.cpp Rendering/mitkPlaneGeometryDataMapper2D.cpp Rendering/mitkPlaneGeometryDataVtkMapper3D.cpp Rendering/mitkPointSetVtkMapper2D.cpp Rendering/mitkPointSetVtkMapper3D.cpp Rendering/mitkRenderWindowBase.cpp Rendering/mitkRenderWindow.cpp Rendering/mitkRenderWindowFrame.cpp #Rendering/mitkSurfaceGLMapper2D.cpp Moved to deprecated LegacyGL Module Rendering/mitkSurfaceVtkMapper2D.cpp Rendering/mitkSurfaceVtkMapper3D.cpp Rendering/mitkVtkEventProvider.cpp Rendering/mitkVtkMapper.cpp Rendering/mitkVtkOverlay2D.cpp Rendering/mitkVtkOverlay3D.cpp Rendering/mitkVtkOverlay.cpp Rendering/mitkVtkPropRenderer.cpp Rendering/mitkVtkWidgetRendering.cpp Rendering/vtkMitkLevelWindowFilter.cpp Rendering/vtkMitkRectangleProp.cpp Rendering/vtkMitkRenderProp.cpp Rendering/vtkMitkThickSlicesFilter.cpp Rendering/vtkNeverTranslucentTexture.cpp ) set(RESOURCE_FILES Interactions/globalConfig.xml Interactions/DisplayInteraction.xml Interactions/DisplayConfig.xml Interactions/DisplayConfigPACS.xml Interactions/DisplayConfigPACSPan.xml Interactions/DisplayConfigPACSScroll.xml Interactions/DisplayConfigPACSZoom.xml Interactions/DisplayConfigPACSLevelWindow.xml Interactions/DisplayConfigMITK.xml Interactions/DisplayConfigMITKNoCrosshair.xml Interactions/DisplayConfigMITKRotation.xml Interactions/DisplayConfigMITKRotationUnCoupled.xml Interactions/DisplayConfigMITKSwivel.xml Interactions/DisplayConfigMITKLimited.xml Interactions/PointSet.xml Interactions/Legacy/StateMachine.xml Interactions/Legacy/DisplayConfigMITKTools.xml Interactions/PointSetConfig.xml mitkLevelWindowPresets.xml mitkAnatomicalStructureColorPresets.xml ) diff --git a/Modules/Core/include/mitkIOUtil.h b/Modules/Core/include/mitkIOUtil.h index 365eda027b..0cca48810c 100644 --- a/Modules/Core/include/mitkIOUtil.h +++ b/Modules/Core/include/mitkIOUtil.h @@ -1,464 +1,542 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKIOUTIL_H #define MITKIOUTIL_H #include #include #include #include #include #include #include #include #include #include namespace us { class ModuleResource; } namespace mitk { /** * \ingroup IO * * \brief A utility class to load and save data from/to the local file system. * * 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 Load(). * * \see QmitkIOUtil */ class MITKCORE_EXPORT IOUtil { public: + /**Struct that containes information regarding the current loading process. (e.g. Path that should be loaded, + all found readers for the load path,...). It is set be IOUtil and used to pass information via the option callback + in load operations. + */ struct MITKCORE_EXPORT LoadInfo { LoadInfo(const std::string &path); std::string m_Path; std::vector m_Output; FileReaderSelector m_ReaderSelector; bool m_Cancel; }; + /**Struct that is the base class for option callbacks used in load operations. The callback is used by IOUtil, if + more than one suitable reader was found or the a reader containes options that can be set. The callback allows to + change option settings and select the reader that should be used (via loadInfo). + */ + struct MITKCORE_EXPORT ReaderOptionsFunctorBase + { + virtual bool operator()(LoadInfo &loadInfo) const = 0; + }; + struct MITKCORE_EXPORT SaveInfo { SaveInfo(const BaseData *baseData, const MimeType &mimeType, const std::string &path); bool operator<(const SaveInfo &other) const; /// The BaseData object to save. const BaseData *m_BaseData; /// Contains a set of IFileWriter objects. FileWriterSelector m_WriterSelector; /// The selected mime-type, used to restrict results from FileWriterSelector. MimeType m_MimeType; /// The path to write the BaseData object to. std::string m_Path; /// Flag indicating if sub-sequent save operations are to be canceled. bool m_Cancel; }; + /**Struct that is the base class for option callbacks used in save operations. The callback is used by IOUtil, if + more than one suitable writer was found or the a writer containes options that can be set. The callback allows to + change option settings and select the writer that should be used (via saveInfo). + */ + struct MITKCORE_EXPORT WriterOptionsFunctorBase + { + virtual bool operator()(SaveInfo &saveInfo) const = 0; + }; + /** * 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(); /** * Returns the Directory Seperator for the current OS. * * @return the Directory Seperator for the current OS, i.e. "\\" for Windows and "/" otherwise. */ static char GetDirectorySeparator(); /** * 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. + * @param optionsCallback Pointer to a callback instance. The callback is used by + * the load operation if more the suitable reader was found or the reader has options + * that can be set. * @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, DataStorage &storage, + const ReaderOptionsFunctorBase *optionsCallback = nullptr); + /** + * @brief Load a file into the given DataStorage given user defined IFileReader::Options. + * + * This method calls Load(const std::vector&, DataStorage&) with a + * one-element vector. + * + * @param path The absolute file name including the file extension. + * @param options IFileReader option instance that should be used if selected reader + * has options. + * @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, const IFileReader::Options &options, DataStorage &storage); - static std::vector Load(const std::string &path); + /** + * @brief Load a file and return the loaded data. + * + * This method calls Load(const std::vector&) with a + * one-element vector. + * + * @param path The absolute file name including the file extension. + * @param optionsCallback Pointer to a callback instance. The callback is used by + * the load operation if more the suitable reader was found or the reader has options + * that can be set. + * @return The set of added DataNode objects. + * @throws mitk::Exception if \c path could not be loaded. + * + * @sa Load(const std::vector&, DataStorage&) + */ + static std::vector Load(const std::string &path, + const ReaderOptionsFunctorBase *optionsCallback = nullptr); + /** + * @brief Load a file and return the loaded data. + * + * This method calls Load(const std::vector&) with a + * one-element vector. + * + * @param path The absolute file name including the file extension. + * @param options IFileReader option instance that should be used if selected reader + * has options. + * @return The set of added DataNode objects. + * @throws mitk::Exception if \c path could not be loaded. + * + * @sa Load(const std::vector&, DataStorage&) + */ 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. + * @param optionsCallback Pointer to a callback instance. The callback is used by + * the load operation if more the suitable reader was found or the reader has options + * that can be set. * @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 DataStorage::SetOfObjects::Pointer Load(const std::vector &paths, DataStorage &storage, + const ReaderOptionsFunctorBase *optionsCallback = nullptr); - static std::vector Load(const std::vector &paths); + static std::vector Load(const std::vector &paths, + const ReaderOptionsFunctorBase *optionsCallback = nullptr); /** * Load files in fileNames and add the constructed mitk::DataNode instances * to the mitk::DataStorage storage * * @param fileNames A list (vector) of absolute file name paths. * @param storage The data storage to which the constructed data nodes are added. * @return The number of added mitk::DataNode instances. * * @deprecatedSince{2014_10} 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_10} 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_10} 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_10} 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. + * @param optionsCallback Pointer to a callback instance. The callback is used by + * the load operation if more the suitable reader was found or the reader has options + * that can be set. * @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); + static mitk::Image::Pointer LoadImage(const std::string &path, + const ReaderOptionsFunctorBase *optionsCallback = nullptr); /** * @brief LoadSurface Convenience method to load an arbitrary mitkSurface. * @param path The path to the surface including file name and file extension. + * @param optionsCallback Pointer to a callback instance. The callback is used by + * the load operation if more the suitable reader was found or the reader has options + * that can be set. * @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); + static mitk::Surface::Pointer LoadSurface(const std::string &path, + const ReaderOptionsFunctorBase *optionsCallback = nullptr); /** * @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). + * @param optionsCallback Pointer to a callback instance. The callback is used by + * the load operation if more the suitable reader was found or the reader has options + * that can be set. * @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); + static mitk::PointSet::Pointer LoadPointSet(const std::string &path, + const ReaderOptionsFunctorBase *optionsCallback = nullptr); /** * @brief Loads the contents of a us::ModuleResource and returns the corresponding mitk::BaseData * @param usResource a ModuleResource, representing a BaseData object * @param mode Optional parameter to set the openmode of the stream * @return The set of loaded BaseData objects. \c Should contain either one or zero elements, since a resource * stream * respresents one object. * @throws mitk::Exception if no reader was found for the stream. */ static std::vector Load(const us::ModuleResource &usResource, std::ios_base::openmode mode = std::ios_base::in); /** * @brief Save a mitk::BaseData instance. * @param data The data to save. * @param path The path to the image including file name and and optional file extension. * If no extension is set, the default extension and mime-type for the * BaseData type of \c data is used. * @throws mitk::Exception if no writer for \c data is available or the writer * is not able to write the image. */ static void Save(const mitk::BaseData *data, const std::string &path); /** * @brief Save a mitk::BaseData instance. * @param data The data to save. * @param path The path to the image including file name and an optional file extension. * If no extension is set, the default extension and mime-type for the * BaseData type of \c data is used. * @param options The IFileWriter options to use for the selected writer. * @throws mitk::Exception if no writer for \c data is available or the writer * is not able to write the image. */ static void Save(const mitk::BaseData *data, const std::string &path, const IFileWriter::Options &options); /** * @brief Save a mitk::BaseData instance. * @param data The data to save. * @param mimeType The mime-type to use for writing \c data. * @param path The path to the image including file name and an optional file extension. * @param addExtension If \c true, an extension according to the given \c mimeType * is added to \c path if it does not contain one. If \c path already contains * a file name extension, it is not checked for compatibility with \c mimeType. * * @throws mitk::Exception if no writer for the combination of \c data and \c mimeType is * available or the writer is not able to write the image. */ static void Save(const mitk::BaseData *data, const std::string &mimeType, const std::string &path, bool addExtension = true); /** * @brief Save a mitk::BaseData instance. * @param data The data to save. * @param mimeType The mime-type to use for writing \c data. * @param path The path to the image including file name and an optional file extension. * @param options Configuration data for the used IFileWriter instance. * @param addExtension If \c true, an extension according to the given \c mimeType * is added to \c path if it does not contain one. If \c path already contains * a file name extension, it is not checked for compatibility with \c mimeType. * * @throws mitk::Exception if no writer for the combination of \c data and \c mimeType is * available or the writer is not able to write the image. */ static void Save(const mitk::BaseData *data, const std::string &mimeType, const std::string &path, const mitk::IFileWriter::Options &options, bool addExtension = true); /** * @brief Use SaveInfo objects to save BaseData instances. * * This is a low-level method for directly working with SaveInfo objects. Usually, * the Save() methods taking a BaseData object as an argument are more appropriate. * * @param saveInfos A list of SaveInfo objects for saving contained BaseData objects. * * @see Save(const mitk::BaseData*, const std::string&) */ static void Save(std::vector &saveInfos); /** * @brief SaveImage Convenience method to save an arbitrary mitkImage. * @param path The path to the image including file name and file extension. * If no extention is set, the default value (defined in DEFAULTIMAGEEXTENSION) is used. * @param image The image to save. * @throws mitk::Exception This exception is thrown when the writer is not able to write the image. * @return Returns true for success else false. * * @deprecatedSince{2014_10} 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_10} 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_10} 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_10} Use Save() instead. */ DEPRECATED(static bool SavePointSet(mitk::PointSet::Pointer pointset, const std::string &path)); protected: - struct ReaderOptionsFunctorBase - { - virtual bool operator()(LoadInfo &loadInfo) = 0; - }; - - struct WriterOptionsFunctorBase - { - virtual bool operator()(SaveInfo &saveInfo) = 0; - }; - static std::string Load(std::vector &loadInfos, DataStorage::SetOfObjects *nodeResult, DataStorage *ds, - ReaderOptionsFunctorBase *optionsCallback); + const ReaderOptionsFunctorBase *optionsCallback); static std::string Save(const BaseData *data, const std::string &mimeType, const std::string &path, WriterOptionsFunctorBase *optionsCallback, bool addExtension); static std::string Save(std::vector &saveInfos, WriterOptionsFunctorBase *optionsCallback); private: struct Impl; }; } #endif // MITKIOUTIL_H diff --git a/Modules/Core/include/mitkPreferenceListReaderOptionsFunctor.h b/Modules/Core/include/mitkPreferenceListReaderOptionsFunctor.h new file mode 100644 index 0000000000..17be2d169c --- /dev/null +++ b/Modules/Core/include/mitkPreferenceListReaderOptionsFunctor.h @@ -0,0 +1,61 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef MITKPREFERENCELISTREADEROPTIONSFUNCTOR_H +#define MITKPREFERENCELISTREADEROPTIONSFUNCTOR_H + +#include +#include + +#include +#include + + +namespace mitk +{ + /** + * \ingroup IO + * + * \brief Option callback functor with a preference list/ black list option selection strategy. + * + * This functor can be used if a option selection should be done without user interaction. + * Setting up the functor one can specify a preference and black lists of controller descriptions. + * Any controller description on the black list will be ignored and never selected. + * The first controller description found on the preference list will be selected. + * Any controller listed on the black list is always ignored. Even if it is also + * listed on the preference list. + * If no preference listed controller is available, the functor will use the pre selected reader. + * If no pre selected controller is available, the functor will use the first not black + * listed reader. + * + * \see IOUtil + */ + struct MITKCORE_EXPORT PreferenceListReaderOptionsFunctor : public IOUtil::ReaderOptionsFunctorBase + { + using ListType = std::vector; + + virtual bool operator()(IOUtil::LoadInfo &loadInfo) const override; + + PreferenceListReaderOptionsFunctor(); + PreferenceListReaderOptionsFunctor(const ListType& preference, const ListType& black); + + protected: + ListType m_PreferenceList; + ListType m_BlackList; + }; +} + +#endif // MITKWHITELISTREADEROPTIONSFUNCTOR_H diff --git a/Modules/Core/src/DataManagement/mitkTemporoSpatialStringProperty.cpp b/Modules/Core/src/DataManagement/mitkTemporoSpatialStringProperty.cpp index f28deb4d34..3fd6ca9580 100644 --- a/Modules/Core/src/DataManagement/mitkTemporoSpatialStringProperty.cpp +++ b/Modules/Core/src/DataManagement/mitkTemporoSpatialStringProperty.cpp @@ -1,366 +1,365 @@ /*=================================================================== 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 "mitkTemporoSpatialStringProperty.h" #ifdef _MSC_VER // has to be deactivated because of a bug in boost v1.59. see Boost bug ticket #11599 // as soon as MITK uses a boost version with a bug fix we can remove the disableling. #pragma warning(push) #pragma warning(disable : 4715) #endif #include #include #include mitk::TemporoSpatialStringProperty::TemporoSpatialStringProperty(const char *s) { if (s) { SliceMapType slices{{0, s}}; m_Values.insert(std::make_pair(0, slices)); } } mitk::TemporoSpatialStringProperty::TemporoSpatialStringProperty(const std::string &s) { SliceMapType slices{{0, s}}; m_Values.insert(std::make_pair(0, slices)); } mitk::TemporoSpatialStringProperty::TemporoSpatialStringProperty(const TemporoSpatialStringProperty &other) : BaseProperty(other), m_Values(other.m_Values) { } bool mitk::TemporoSpatialStringProperty::IsEqual(const BaseProperty &property) const { return this->m_Values == static_cast(property).m_Values; } bool mitk::TemporoSpatialStringProperty::Assign(const BaseProperty &property) { this->m_Values = static_cast(property).m_Values; return true; } std::string mitk::TemporoSpatialStringProperty::GetValueAsString() const { return GetValue(); } itk::LightObject::Pointer mitk::TemporoSpatialStringProperty::InternalClone() const { itk::LightObject::Pointer result(new Self(*this)); result->UnRegister(); return result; } mitk::TemporoSpatialStringProperty::ValueType mitk::TemporoSpatialStringProperty::GetValue() const { std::string result = ""; if (!m_Values.empty()) { if (!m_Values.begin()->second.empty()) { result = m_Values.begin()->second.begin()->second; } } return result; }; std::pair mitk::TemporoSpatialStringProperty::CheckValue( const TimeStepType &timeStep, const IndexValueType &zSlice, bool allowCloseTime, bool allowCloseSlice) const { std::string value = ""; bool found = false; TimeMapType::const_iterator timeIter = m_Values.find(timeStep); TimeMapType::const_iterator timeEnd = m_Values.end(); if (timeIter == timeEnd && allowCloseTime) { // search for closest time step (earlier preverd) timeIter = m_Values.upper_bound(timeStep); if (timeIter != m_Values.begin()) { // there is a key lower than time step timeIter = std::prev(timeIter); } } if (timeIter != timeEnd) { const SliceMapType &slices = timeIter->second; SliceMapType::const_iterator sliceIter = slices.find(zSlice); SliceMapType::const_iterator sliceEnd = slices.end(); if (sliceIter == sliceEnd && allowCloseSlice) { // search for closest slice (earlier preverd) sliceIter = slices.upper_bound(zSlice); if (sliceIter != slices.begin()) { // there is a key lower than slice sliceIter = std::prev(sliceIter); } } if (sliceIter != sliceEnd) { value = sliceIter->second; found = true; } } return std::make_pair(found, value); }; mitk::TemporoSpatialStringProperty::ValueType mitk::TemporoSpatialStringProperty::GetValue(const TimeStepType &timeStep, const IndexValueType &zSlice, bool allowCloseTime, bool allowCloseSlice) const { return CheckValue(timeStep, zSlice, allowCloseTime, allowCloseSlice).second; }; mitk::TemporoSpatialStringProperty::ValueType mitk::TemporoSpatialStringProperty::GetValueBySlice( const IndexValueType &zSlice, bool allowClose) const { return GetValue(0, zSlice, true, allowClose); }; mitk::TemporoSpatialStringProperty::ValueType mitk::TemporoSpatialStringProperty::GetValueByTimeStep( const TimeStepType &timeStep, bool allowClose) const { return GetValue(timeStep, 0, allowClose, true); }; bool mitk::TemporoSpatialStringProperty::HasValue() const { return !m_Values.empty(); }; bool mitk::TemporoSpatialStringProperty::HasValue(const TimeStepType &timeStep, const IndexValueType &zSlice, bool allowCloseTime, bool allowCloseSlice) const { return CheckValue(timeStep, zSlice, allowCloseTime, allowCloseSlice).first; }; bool mitk::TemporoSpatialStringProperty::HasValueBySlice(const IndexValueType &zSlice, bool allowClose) const { return HasValue(0, zSlice, true, allowClose); }; bool mitk::TemporoSpatialStringProperty::HasValueByTimeStep(const TimeStepType &timeStep, bool allowClose) const { return HasValue(timeStep, 0, allowClose, true); }; std::vector mitk::TemporoSpatialStringProperty::GetAvailableSlices( const TimeStepType &timeStep) const { std::vector result; TimeMapType::const_iterator timeIter = m_Values.find(timeStep); TimeMapType::const_iterator timeEnd = m_Values.end(); if (timeIter != timeEnd) { for (auto const &element : timeIter->second) { result.push_back(element.first); } } return result; }; std::vector mitk::TemporoSpatialStringProperty::GetAvailableTimeSteps() const { std::vector result; for (auto const &element : m_Values) { result.push_back(element.first); } return result; }; void mitk::TemporoSpatialStringProperty::SetValue(const TimeStepType &timeStep, const IndexValueType &zSlice, const ValueType &value) { TimeMapType::iterator timeIter = m_Values.find(timeStep); TimeMapType::iterator timeEnd = m_Values.end(); if (timeIter == timeEnd) { SliceMapType slices{{zSlice, value}}; m_Values.insert(std::make_pair(timeStep, slices)); } else { timeIter->second[zSlice] = value; } this->Modified(); }; void mitk::TemporoSpatialStringProperty::SetValue(const ValueType &value) { this->Modified(); m_Values.clear(); this->SetValue(0, 0, value); }; // Create necessary escape sequences from illegal characters // REMARK: This code is based upon code from boost::ptree::json_writer. // The corresponding boost function was not used directly, because it is not part of // the public interface of ptree::json_writer. :( // A own serialization strategy was implemented instead of using boost::ptree::json_write because // currently (<= boost 1.60) everything (even numbers) are converted into string representations // by the writer, so e.g. it becomes "t":"2" instaed of "t":2 template std::basic_string CreateJSONEscapes(const std::basic_string &s) { std::basic_string result; typename std::basic_string::const_iterator b = s.begin(); typename std::basic_string::const_iterator e = s.end(); while (b != e) { typedef typename boost::make_unsigned::type UCh; UCh c(*b); // This assumes an ASCII superset. // We escape everything outside ASCII, because this code can't // handle high unicode characters. if (c == 0x20 || c == 0x21 || (c >= 0x23 && c <= 0x2E) || (c >= 0x30 && c <= 0x5B) || (c >= 0x5D && c <= 0x7F)) result += *b; else if (*b == Ch('\b')) result += Ch('\\'), result += Ch('b'); else if (*b == Ch('\f')) result += Ch('\\'), result += Ch('f'); else if (*b == Ch('\n')) result += Ch('\\'), result += Ch('n'); else if (*b == Ch('\r')) result += Ch('\\'), result += Ch('r'); else if (*b == Ch('\t')) result += Ch('\\'), result += Ch('t'); else if (*b == Ch('/')) result += Ch('\\'), result += Ch('/'); else if (*b == Ch('"')) result += Ch('\\'), result += Ch('"'); else if (*b == Ch('\\')) result += Ch('\\'), result += Ch('\\'); else { const char *hexdigits = "0123456789ABCDEF"; unsigned long u = (std::min)(static_cast(static_cast(*b)), 0xFFFFul); int d1 = u / 4096; u -= d1 * 4096; int d2 = u / 256; u -= d2 * 256; int d3 = u / 16; u -= d3 * 16; int d4 = u; result += Ch('\\'); result += Ch('u'); result += Ch(hexdigits[d1]); result += Ch(hexdigits[d2]); result += Ch(hexdigits[d3]); result += Ch(hexdigits[d4]); } ++b; } return result; } ::std::string mitk::PropertyPersistenceSerialization::serializeTemporoSpatialStringPropertyToJSON( const mitk::BaseProperty *prop) { // REMARK: Implemented own serialization instead of using boost::ptree::json_write because // currently (<= boost 1.60) everything (even numbers) are converted into string representations // by the writer, so e.g. it becomes "t":"2" instaed of "t":2 // If this problem is fixed with boost, we shoud switch back to json_writer (and remove the custom // implementation of CreateJSONEscapes (see above)). const mitk::TemporoSpatialStringProperty *tsProp = dynamic_cast(prop); if (!tsProp) { return ""; } std::ostringstream stream; stream << "{\"values\":["; std::vector ts = tsProp->GetAvailableTimeSteps(); bool first = true; for (auto t : ts) { std::vector zs = tsProp->GetAvailableSlices(t); for (auto z : zs) { std::string value = CreateJSONEscapes(tsProp->GetValue(t, z)); if (first) { first = false; } else { stream << ", "; } stream << "{\"t\":" << t << ", \"z\":" << z << ", \"value\":\"" << value << "\"}"; } } stream << "]}"; return stream.str(); } mitk::BaseProperty::Pointer mitk::PropertyPersistenceDeserialization::deserializeJSONToTemporoSpatialStringProperty( const std::string &value) { mitk::TemporoSpatialStringProperty::Pointer prop = mitk::TemporoSpatialStringProperty::New(); boost::property_tree::ptree root; std::istringstream stream(value); boost::property_tree::read_json(stream, root); - // Iterator over all animals for (boost::property_tree::ptree::value_type &element : root.get_child("values")) { std::string value = element.second.get("value", ""); mitk::TemporoSpatialStringProperty::IndexValueType z = element.second.get("z", 0); TimeStepType t = element.second.get("t", 0); prop->SetValue(t, z, value); } return prop.GetPointer(); } #ifdef _MSC_VER #pragma warning(pop) #endif \ No newline at end of file diff --git a/Modules/Core/src/IO/mitkIOUtil.cpp b/Modules/Core/src/IO/mitkIOUtil.cpp index a2202ea75b..4080e5d471 100644 --- a/Modules/Core/src/IO/mitkIOUtil.cpp +++ b/Modules/Core/src/IO/mitkIOUtil.cpp @@ -1,1095 +1,1099 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkIOUtil.h" #include #include #include #include #include #include #include #include #include #include #include #include #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 //************************************************************** // mitk::IOUtil method definitions namespace mitk { struct IOUtil::Impl { struct FixedReaderOptionsFunctor : public ReaderOptionsFunctorBase { FixedReaderOptionsFunctor(const IFileReader::Options &options) : m_Options(options) {} - virtual bool operator()(LoadInfo &loadInfo) override + virtual bool operator()(LoadInfo &loadInfo) const override { IFileReader *reader = loadInfo.m_ReaderSelector.GetSelected().GetReader(); if (reader) { reader->SetOptions(m_Options); } return false; } private: const IFileReader::Options &m_Options; }; struct FixedWriterOptionsFunctor : public WriterOptionsFunctorBase { FixedWriterOptionsFunctor(const IFileReader::Options &options) : m_Options(options) {} - virtual bool operator()(SaveInfo &saveInfo) override + virtual bool operator()(SaveInfo &saveInfo) const override { IFileWriter *writer = saveInfo.m_WriterSelector.GetSelected().GetWriter(); if (writer) { writer->SetOptions(m_Options); } return false; } private: const IFileWriter::Options &m_Options; }; - static BaseData::Pointer LoadBaseDataFromFile(const std::string &path); + static BaseData::Pointer LoadBaseDataFromFile(const std::string &path, const ReaderOptionsFunctorBase* optionsCallback = nullptr); 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 char IOUtil::GetDirectorySeparator() { #ifdef US_PLATFORM_WINDOWS return '\\'; #else return '/'; #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 += GetDirectorySeparator() + 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) + DataStorage::SetOfObjects::Pointer IOUtil::Load(const std::string &path, DataStorage &storage, const ReaderOptionsFunctorBase *optionsCallback) { std::vector paths; paths.push_back(path); - return Load(paths, storage); + return Load(paths, storage, optionsCallback); } DataStorage::SetOfObjects::Pointer IOUtil::Load(const std::string &path, const IFileReader::Options &options, DataStorage &storage) { std::vector loadInfos; loadInfos.push_back(LoadInfo(path)); DataStorage::SetOfObjects::Pointer nodeResult = DataStorage::SetOfObjects::New(); Impl::FixedReaderOptionsFunctor optionsCallback(options); std::string errMsg = Load(loadInfos, nodeResult, &storage, &optionsCallback); if (!errMsg.empty()) { mitkThrow() << errMsg; } return nodeResult; } - std::vector IOUtil::Load(const std::string &path) + std::vector IOUtil::Load(const std::string &path, const ReaderOptionsFunctorBase *optionsCallback) { std::vector paths; paths.push_back(path); - return Load(paths); + return Load(paths, optionsCallback); } std::vector IOUtil::Load(const std::string &path, const IFileReader::Options &options) { std::vector loadInfos; loadInfos.push_back(LoadInfo(path)); Impl::FixedReaderOptionsFunctor optionsCallback(options); std::string errMsg = Load(loadInfos, NULL, NULL, &optionsCallback); if (!errMsg.empty()) { mitkThrow() << errMsg; } return loadInfos.front().m_Output; } - DataStorage::SetOfObjects::Pointer IOUtil::Load(const std::vector &paths, DataStorage &storage) + DataStorage::SetOfObjects::Pointer IOUtil::Load(const std::vector &paths, DataStorage &storage, const ReaderOptionsFunctorBase *optionsCallback) { DataStorage::SetOfObjects::Pointer nodeResult = DataStorage::SetOfObjects::New(); std::vector loadInfos; for (auto loadInfo : paths) { loadInfos.push_back(loadInfo); } - std::string errMsg = Load(loadInfos, nodeResult, &storage, NULL); + std::string errMsg = Load(loadInfos, nodeResult, &storage, optionsCallback); if (!errMsg.empty()) { mitkThrow() << errMsg; } return nodeResult; } - std::vector IOUtil::Load(const std::vector &paths) + std::vector IOUtil::Load(const std::vector &paths, const ReaderOptionsFunctorBase *optionsCallback) { std::vector result; std::vector loadInfos; for (auto loadInfo : paths) { loadInfos.push_back(loadInfo); } - std::string errMsg = Load(loadInfos, NULL, NULL, NULL); + std::string errMsg = Load(loadInfos, NULL, NULL, optionsCallback); if (!errMsg.empty()) { mitkThrow() << errMsg; } for (std::vector::const_iterator iter = loadInfos.begin(), iterEnd = loadInfos.end(); iter != iterEnd; ++iter) { result.insert(result.end(), iter->m_Output.begin(), iter->m_Output.end()); } return result; } int IOUtil::LoadFiles(const std::vector &fileNames, DataStorage &ds) { return static_cast(Load(fileNames, ds)->Size()); } DataStorage::Pointer IOUtil::LoadFiles(const std::vector &fileNames) { mitk::StandaloneDataStorage::Pointer ds = mitk::StandaloneDataStorage::New(); Load(fileNames, *ds); return ds.GetPointer(); } BaseData::Pointer IOUtil::LoadBaseData(const std::string &path) { return Impl::LoadBaseDataFromFile(path); } - BaseData::Pointer IOUtil::Impl::LoadBaseDataFromFile(const std::string &path) + BaseData::Pointer IOUtil::Impl::LoadBaseDataFromFile(const std::string &path, + const ReaderOptionsFunctorBase *optionsCallback) { - std::vector baseDataList = Load(path); + std::vector baseDataList = Load(path, optionsCallback); // 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) + Image::Pointer IOUtil::LoadImage(const std::string &path, + const ReaderOptionsFunctorBase *optionsCallback) { - BaseData::Pointer baseData = Impl::LoadBaseDataFromFile(path); + BaseData::Pointer baseData = Impl::LoadBaseDataFromFile(path, optionsCallback); 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) + Surface::Pointer IOUtil::LoadSurface(const std::string &path, + const ReaderOptionsFunctorBase *optionsCallback) { - BaseData::Pointer baseData = Impl::LoadBaseDataFromFile(path); + BaseData::Pointer baseData = Impl::LoadBaseDataFromFile(path, optionsCallback); 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) + PointSet::Pointer IOUtil::LoadPointSet(const std::string &path, + const ReaderOptionsFunctorBase *optionsCallback) { - BaseData::Pointer baseData = Impl::LoadBaseDataFromFile(path); + BaseData::Pointer baseData = Impl::LoadBaseDataFromFile(path, optionsCallback); 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(std::vector &loadInfos, DataStorage::SetOfObjects *nodeResult, DataStorage *ds, - ReaderOptionsFunctorBase *optionsCallback) + const ReaderOptionsFunctorBase *optionsCallback) { if (loadInfos.empty()) { return "No input files given"; } int filesToRead = loadInfos.size(); mitk::ProgressBar::GetInstance()->AddStepsToDo(2 * filesToRead); std::string errMsg; std::map usedReaderItems; for (auto &loadInfo : loadInfos) { std::vector readers = loadInfo.m_ReaderSelector.Get(); if (readers.empty()) { if (!itksys::SystemTools::FileExists(loadInfo.m_Path.c_str())) { errMsg += "File '" + loadInfo.m_Path + "' does not exist\n"; } else { errMsg += "No reader available for '" + loadInfo.m_Path + "'\n"; } continue; } bool callOptionsCallback = readers.size() > 1 || !readers.front().GetReader()->GetOptions().empty(); // check if we already used a reader which should be re-used std::vector currMimeTypes = loadInfo.m_ReaderSelector.GetMimeTypes(); std::string selectedMimeType; for (std::vector::const_iterator mimeTypeIter = currMimeTypes.begin(), mimeTypeIterEnd = currMimeTypes.end(); mimeTypeIter != mimeTypeIterEnd; ++mimeTypeIter) { std::map::const_iterator oldSelectedItemIter = usedReaderItems.find(mimeTypeIter->GetName()); if (oldSelectedItemIter != usedReaderItems.end()) { // we found an already used item for a mime-type which is contained // in the current reader set, check all current readers if there service // id equals the old reader for (std::vector::const_iterator currReaderItem = readers.begin(), currReaderItemEnd = readers.end(); currReaderItem != currReaderItemEnd; ++currReaderItem) { if (currReaderItem->GetMimeType().GetName() == mimeTypeIter->GetName() && currReaderItem->GetServiceId() == oldSelectedItemIter->second.GetServiceId() && currReaderItem->GetConfidenceLevel() >= oldSelectedItemIter->second.GetConfidenceLevel()) { // okay, we used the same reader already, re-use its options selectedMimeType = mimeTypeIter->GetName(); callOptionsCallback = false; loadInfo.m_ReaderSelector.Select(oldSelectedItemIter->second.GetServiceId()); loadInfo.m_ReaderSelector.GetSelected().GetReader()->SetOptions( oldSelectedItemIter->second.GetReader()->GetOptions()); break; } } if (!selectedMimeType.empty()) break; } } if (callOptionsCallback && optionsCallback) { callOptionsCallback = (*optionsCallback)(loadInfo); if (!callOptionsCallback && !loadInfo.m_Cancel) { usedReaderItems.erase(selectedMimeType); FileReaderSelector::Item selectedItem = loadInfo.m_ReaderSelector.GetSelected(); usedReaderItems.insert(std::make_pair(selectedItem.GetMimeType().GetName(), selectedItem)); } } if (loadInfo.m_Cancel) { errMsg += "Reading operation(s) cancelled."; break; } IFileReader *reader = loadInfo.m_ReaderSelector.GetSelected().GetReader(); if (reader == NULL) { errMsg += "Unexpected NULL reader."; break; } // Do the actual reading try { DataStorage::SetOfObjects::Pointer nodes; if (ds != NULL) { nodes = reader->Read(*ds); } else { nodes = DataStorage::SetOfObjects::New(); std::vector baseData = reader->Read(); 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(loadInfo.m_Path); data->SetProperty("path", pathProp); loadInfo.m_Output.push_back(data); if (nodeResult) { nodeResult->push_back(nodeIter->Value()); } } if (loadInfo.m_Output.empty() || (nodeResult && nodeResult->Size() == 0)) { errMsg += "Unknown read error occurred reading " + loadInfo.m_Path; } } catch (const std::exception &e) { errMsg += "Exception occured when reading file " + loadInfo.m_Path + ":\n" + e.what() + "\n\n"; } mitk::ProgressBar::GetInstance()->Progress(2); --filesToRead; } if (!errMsg.empty()) { MITK_ERROR << errMsg; } mitk::ProgressBar::GetInstance()->Progress(2 * filesToRead); return errMsg; } std::vector IOUtil::Load(const us::ModuleResource &usResource, std::ios_base::openmode mode) { us::ModuleResourceStream resStream(usResource, mode); mitk::CoreServicePointer mimeTypeProvider(mitk::CoreServices::GetMimeTypeProvider()); std::vector mimetypes = mimeTypeProvider->GetMimeTypesForFile(usResource.GetResourcePath()); std::vector data; if (mimetypes.empty()) { mitkThrow() << "No mimetype for resource stream: " << usResource.GetResourcePath(); return data; } mitk::FileReaderRegistry fileReaderRegistry; std::vector> refs = fileReaderRegistry.GetReferences(mimetypes[0]); if (refs.empty()) { mitkThrow() << "No reader available for resource stream: " << usResource.GetResourcePath(); return data; } mitk::IFileReader *reader = fileReaderRegistry.GetReader(refs[0]); reader->SetInput(usResource.GetResourcePath(), &resStream); data = reader->Read(); return data; } void IOUtil::Save(const BaseData *data, const std::string &path) { Save(data, path, IFileWriter::Options()); } void IOUtil::Save(const BaseData *data, const std::string &path, const IFileWriter::Options &options) { Save(data, std::string(), path, options); } void IOUtil::Save(const BaseData *data, const std::string &mimeType, const std::string &path, bool addExtension) { Save(data, mimeType, path, IFileWriter::Options(), addExtension); } void IOUtil::Save(const BaseData *data, const std::string &mimeType, const std::string &path, const IFileWriter::Options &options, bool addExtension) { if ((data == NULL) || (data->IsEmpty())) mitkThrow() << "BaseData cannotbe null or empty for save methods in IOUtil.h."; std::string errMsg; if (options.empty()) { errMsg = Save(data, mimeType, path, NULL, addExtension); } else { Impl::FixedWriterOptionsFunctor optionsCallback(options); errMsg = Save(data, mimeType, path, &optionsCallback, addExtension); } if (!errMsg.empty()) { mitkThrow() << errMsg; } } void IOUtil::Save(std::vector &saveInfos) { std::string errMsg = Save(saveInfos, NULL); if (!errMsg.empty()) { mitkThrow() << errMsg; } } bool IOUtil::SaveImage(mitk::Image::Pointer image, const std::string &path) { Save(image, path); return true; } bool IOUtil::SaveSurface(Surface::Pointer surface, const std::string &path) { Save(surface, path); return true; } bool IOUtil::SavePointSet(PointSet::Pointer pointset, const std::string &path) { Save(pointset, path); return true; } bool IOUtil::SaveBaseData(mitk::BaseData *data, const std::string &path) { Save(data, path); return true; } std::string IOUtil::Save(const BaseData *data, const std::string &mimeTypeName, const std::string &path, WriterOptionsFunctorBase *optionsCallback, bool addExtension) { if (path.empty()) { return "No output filename given"; } mitk::CoreServicePointer mimeTypeProvider(mitk::CoreServices::GetMimeTypeProvider()); MimeType mimeType = mimeTypeProvider->GetMimeTypeForName(mimeTypeName); SaveInfo saveInfo(data, mimeType, path); std::string ext = itksys::SystemTools::GetFilenameExtension(path); if (saveInfo.m_WriterSelector.IsEmpty()) { return std::string("No suitable writer found for the current data of type ") + data->GetNameOfClass() + (mimeType.IsValid() ? (std::string(" and mime-type ") + mimeType.GetName()) : std::string()) + (ext.empty() ? std::string() : (std::string(" with extension ") + ext)); } // Add an extension if not already specified if (ext.empty() && addExtension) { saveInfo.m_MimeType.GetExtensions().empty() ? std::string() : "." + saveInfo.m_MimeType.GetExtensions().front(); } std::vector infos; infos.push_back(saveInfo); return Save(infos, optionsCallback); } std::string IOUtil::Save(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; std::set usedSaveInfos; for (auto &saveInfo : saveInfos) { const std::string baseDataType = saveInfo.m_BaseData->GetNameOfClass(); std::vector writers = saveInfo.m_WriterSelector.Get(); // Error out if no compatible Writer was found if (writers.empty()) { errMsg += std::string("No writer available for ") + baseDataType + " data.\n"; continue; } bool callOptionsCallback = writers.size() > 1 || !writers[0].GetWriter()->GetOptions().empty(); // check if we already used a writer for this base data type // which should be re-used std::set::const_iterator oldSaveInfoIter = usedSaveInfos.find(saveInfo); if (oldSaveInfoIter != usedSaveInfos.end()) { // we previously saved a base data object of the same data with the same mime-type, // check if the same writer is contained in the current writer set and if the // confidence level matches FileWriterSelector::Item oldSelectedItem = oldSaveInfoIter->m_WriterSelector.Get(oldSaveInfoIter->m_WriterSelector.GetSelectedId()); for (std::vector::const_iterator currWriterItem = writers.begin(), currWriterItemEnd = writers.end(); currWriterItem != currWriterItemEnd; ++currWriterItem) { if (currWriterItem->GetServiceId() == oldSelectedItem.GetServiceId() && currWriterItem->GetConfidenceLevel() >= oldSelectedItem.GetConfidenceLevel()) { // okay, we used the same writer already, re-use its options callOptionsCallback = false; saveInfo.m_WriterSelector.Select(oldSaveInfoIter->m_WriterSelector.GetSelectedId()); saveInfo.m_WriterSelector.GetSelected().GetWriter()->SetOptions(oldSelectedItem.GetWriter()->GetOptions()); break; } } } if (callOptionsCallback && optionsCallback) { callOptionsCallback = (*optionsCallback)(saveInfo); if (!callOptionsCallback && !saveInfo.m_Cancel) { usedSaveInfos.erase(saveInfo); usedSaveInfos.insert(saveInfo); } } if (saveInfo.m_Cancel) { errMsg += "Writing operation(s) cancelled."; break; } IFileWriter *writer = saveInfo.m_WriterSelector.GetSelected().GetWriter(); if (writer == NULL) { errMsg += "Unexpected NULL writer."; break; } // Do the actual writing try { writer->SetOutputLocation(saveInfo.m_Path); writer->Write(); } catch (const std::exception &e) { errMsg += std::string("Exception occurred when writing to ") + saveInfo.m_Path + ":\n" + e.what() + "\n"; } mitk::ProgressBar::GetInstance()->Progress(2); --filesToWrite; } if (!errMsg.empty()) { MITK_ERROR << errMsg; } mitk::ProgressBar::GetInstance()->Progress(2 * filesToWrite); return errMsg; } // This method can be removed after the deprecated LoadDataNode() method was removed void IOUtil::Impl::SetDefaultDataNodeProperties(DataNode *node, const std::string &filePath) { // path mitk::StringProperty::Pointer pathProp = mitk::StringProperty::New(itksys::SystemTools::GetFilenamePath(filePath)); node->SetProperty(StringProperty::PATH, pathProp); // name already defined? mitk::StringProperty::Pointer nameProp = dynamic_cast(node->GetProperty("name")); if (nameProp.IsNull() || (strcmp(nameProp->GetValue(), "No Name!") == 0)) { // name already defined in BaseData mitk::StringProperty::Pointer baseDataNameProp = dynamic_cast(node->GetData()->GetProperty("name").GetPointer()); if (baseDataNameProp.IsNull() || (strcmp(baseDataNameProp->GetValue(), "No Name!") == 0)) { // name neither defined in node, nor in BaseData -> name = filename nameProp = mitk::StringProperty::New(itksys::SystemTools::GetFilenameWithoutExtension(filePath)); node->SetProperty("name", nameProp); } else { // name defined in BaseData! nameProp = mitk::StringProperty::New(baseDataNameProp->GetValue()); node->SetProperty("name", nameProp); } } // visibility if (!node->GetProperty("visible")) { node->SetVisibility(true); } } IOUtil::SaveInfo::SaveInfo(const BaseData *baseData, const MimeType &mimeType, const std::string &path) : m_BaseData(baseData), m_WriterSelector(baseData, mimeType.GetName(), path), m_MimeType(mimeType.IsValid() ? mimeType // use the original mime-type : (m_WriterSelector.IsEmpty() ? mimeType // no writer found, use the original invalid mime-type : m_WriterSelector.GetDefault().GetMimeType() // use the found default mime-type )), m_Path(path), m_Cancel(false) { } bool IOUtil::SaveInfo::operator<(const IOUtil::SaveInfo &other) const { int r = strcmp(m_BaseData->GetNameOfClass(), other.m_BaseData->GetNameOfClass()); if (r == 0) { return m_WriterSelector.GetSelected().GetMimeType() < other.m_WriterSelector.GetSelected().GetMimeType(); } return r < 0; } IOUtil::LoadInfo::LoadInfo(const std::string &path) : m_Path(path), m_ReaderSelector(path), m_Cancel(false) {} } diff --git a/Modules/Core/src/IO/mitkPreferenceListReaderOptionsFunctor.cpp b/Modules/Core/src/IO/mitkPreferenceListReaderOptionsFunctor.cpp new file mode 100644 index 0000000000..1736a284fc --- /dev/null +++ b/Modules/Core/src/IO/mitkPreferenceListReaderOptionsFunctor.cpp @@ -0,0 +1,76 @@ +/*=================================================================== + +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 "mitkPreferenceListReaderOptionsFunctor.h" + +mitk::PreferenceListReaderOptionsFunctor::PreferenceListReaderOptionsFunctor() +{ + +} + +mitk::PreferenceListReaderOptionsFunctor::PreferenceListReaderOptionsFunctor(const ListType& preference, const ListType& black) : m_PreferenceList(preference), m_BlackList(black) +{ + +} + +bool mitk::PreferenceListReaderOptionsFunctor::operator()(IOUtil::LoadInfo &loadInfo) const +{ + auto readerItems = loadInfo.m_ReaderSelector.Get(); + + auto selectedID = loadInfo.m_ReaderSelector.GetSelectedId(); + + //check if the pre selected ID is on the blacklist. If true, "un"select. + auto finding = std::find(m_BlackList.begin(), m_BlackList.end(), loadInfo.m_ReaderSelector.GetSelected().GetDescription()); + if (finding != m_BlackList.end()) + { + selectedID = -1; + } + + for (auto reader : readerItems) + { + finding = std::find(m_BlackList.begin(), m_BlackList.end(), reader.GetDescription()); + + if (finding != m_BlackList.end()) + { + continue; + } + + finding = std::find(m_PreferenceList.begin(), m_PreferenceList.end(), reader.GetDescription()); + + if (finding != m_PreferenceList.end()) + { + selectedID = reader.GetServiceId(); + break; + } + + if (selectedID==-1) + { + selectedID = reader.GetServiceId(); + } + } + + if (selectedID == -1) + { + mitkThrow() << "No valid reader found. All available readers are black listed."; + } + + if (!loadInfo.m_ReaderSelector.Select(selectedID)) + { + MITK_DEBUG << "Was not able to select reader found by the PreferenceListReaderOptionsFunctor"; + } + + return true; +} diff --git a/Modules/Core/test/files.cmake b/Modules/Core/test/files.cmake index 37ef8dbfe7..a79faa1555 100644 --- a/Modules/Core/test/files.cmake +++ b/Modules/Core/test/files.cmake @@ -1,199 +1,200 @@ # tests with no extra command line parameter set(MODULE_TESTS # IMPORTANT: If you plan to deactivate / comment out a test please write a bug number to the commented out line of code. # # Example: #mitkMyTest #this test is commented out because of bug 12345 # # It is important that the bug is open and that the test will be activated again before the bug is closed. This assures that # no test is forgotten after it was commented out. If there is no bug for your current problem, please add a new one and # mark it as critical. ################## DISABLED TESTS ################################################# #mitkAbstractTransformGeometryTest.cpp #seems as tested class mitkExternAbstractTransformGeometry doesnt exist any more #mitkStateMachineContainerTest.cpp #rewrite test, indirect since no longer exported Bug 14529 #mitkRegistrationBaseTest.cpp #tested class mitkRegistrationBase doesn't exist any more #mitkSegmentationInterpolationTest.cpp #file doesn't exist! #mitkPipelineSmartPointerCorrectnessTest.cpp #file doesn't exist! #mitkITKThreadingTest.cpp #test outdated because itk::Semaphore was removed from ITK #mitkAbstractTransformPlaneGeometryTest.cpp #mitkVtkAbstractTransformPlaneGeometry doesn't exist any more #mitkTestUtilSharedLibrary.cpp #Linker problem with this test... #mitkTextOverlay2DSymbolsRenderingTest.cpp #Implementation of the tested feature is not finished yet. Ask Christoph or see bug 15104 for details. ################# RUNNING TESTS ################################################### mitkAccessByItkTest.cpp mitkCoreObjectFactoryTest.cpp mitkDataNodeTest.cpp mitkMaterialTest.cpp mitkActionTest.cpp mitkDispatcherTest.cpp mitkEnumerationPropertyTest.cpp mitkFileReaderRegistryTest.cpp #mitkFileWriterRegistryTest.cpp mitkFloatToStringTest.cpp mitkGenericPropertyTest.cpp mitkGeometry3DTest.cpp mitkGeometry3DEqualTest.cpp mitkGeometryDataIOTest.cpp mitkGeometryDataToSurfaceFilterTest.cpp mitkImageCastTest.cpp mitkImageEqualTest.cpp mitkImageDataItemTest.cpp mitkImageGeneratorTest.cpp mitkIOUtilTest.cpp mitkBaseDataTest.cpp mitkImportItkImageTest.cpp mitkGrabItkImageMemoryTest.cpp mitkInstantiateAccessFunctionTest.cpp mitkLevelWindowTest.cpp mitkMessageTest.cpp mitkPixelTypeTest.cpp mitkPlaneGeometryTest.cpp mitkPointSetTest.cpp mitkPointSetEqualTest.cpp mitkPointSetFileIOTest.cpp mitkPointSetOnEmptyTest.cpp mitkPointSetLocaleTest.cpp mitkPointSetWriterTest.cpp mitkPointSetReaderTest.cpp mitkPointSetPointOperationsTest.cpp mitkProgressBarTest.cpp mitkPropertyTest.cpp mitkPropertyListTest.cpp mitkPropertyPersistenceTest.cpp mitkPropertyPersistenceInfoTest.cpp mitkSlicedGeometry3DTest.cpp mitkSliceNavigationControllerTest.cpp mitkSurfaceTest.cpp mitkSurfaceEqualTest.cpp mitkSurfaceToSurfaceFilterTest.cpp mitkTimeGeometryTest.cpp mitkProportionalTimeGeometryTest.cpp mitkUndoControllerTest.cpp mitkVtkWidgetRenderingTest.cpp mitkVerboseLimitedLinearUndoTest.cpp mitkWeakPointerTest.cpp mitkTransferFunctionTest.cpp mitkStepperTest.cpp mitkRenderingManagerTest.cpp mitkCompositePixelValueToStringTest.cpp vtkMitkThickSlicesFilterTest.cpp mitkNodePredicateSourceTest.cpp mitkNodePredicateDataPropertyTest.cpp mitkVectorTest.cpp mitkClippedSurfaceBoundsCalculatorTest.cpp mitkExceptionTest.cpp mitkExtractSliceFilterTest.cpp mitkLogTest.cpp mitkImageDimensionConverterTest.cpp mitkLoggingAdapterTest.cpp mitkUIDGeneratorTest.cpp mitkShaderRepositoryTest.cpp mitkPlanePositionManagerTest.cpp mitkAffineTransformBaseTest.cpp mitkPropertyAliasesTest.cpp mitkPropertyDescriptionsTest.cpp mitkPropertyExtensionsTest.cpp mitkPropertyFiltersTest.cpp mitkTinyXMLTest.cpp mitkRawImageFileReaderTest.cpp mitkInteractionEventTest.cpp mitkLookupTableTest.cpp mitkSTLFileReaderTest.cpp mitkPointTypeConversionTest.cpp mitkVectorTypeConversionTest.cpp mitkMatrixTypeConversionTest.cpp mitkArrayTypeConversionTest.cpp mitkSurfaceToImageFilterTest.cpp mitkBaseGeometryTest.cpp mitkImageToSurfaceFilterTest.cpp mitkEqualTest.cpp mitkLineTest.cpp mitkArbitraryTimeGeometryTest mitkItkImageIOTest.cpp mitkRotatedSlice4DTest.cpp mitkLevelWindowManagerCppUnitTest.cpp mitkVectorPropertyTest.cpp mitkTemporoSpatialStringPropertyTest.cpp mitkPropertyNameHelperTest.cpp mitkNodePredicateGeometryTest.cpp + mitkPreferenceListReaderOptionsFunctorTest.cpp ) if(MITK_ENABLE_RENDERING_TESTING) set(MODULE_TESTS ${MODULE_TESTS} mitkPlaneGeometryDataMapper2DTest.cpp mitkPointSetDataInteractorTest.cpp #since mitkInteractionTestHelper is currently creating a vtkRenderWindow mitkSurfaceVtkMapper2DTest.cpp #new rendering test in CppUnit style mitkSurfaceVtkMapper2D3DTest.cpp # comparisons/consistency 2D/3D ) endif() # test with image filename as an extra command line parameter set(MODULE_IMAGE_TESTS mitkImageTimeSelectorTest.cpp #only runs on images mitkImageAccessorTest.cpp #only runs on images ) set(MODULE_SURFACE_TESTS mitkSurfaceVtkWriterTest.cpp #only runs on surfaces ) # list of images for which the tests are run set(MODULE_TESTIMAGE US4DCyl.nrrd Pic3D.nrrd Pic2DplusT.nrrd BallBinary30x30x30.nrrd Png2D-bw.png ) set(MODULE_TESTSURFACE binary.stl ball.stl ) set(MODULE_CUSTOM_TESTS mitkDataStorageTest.cpp mitkDicomSeriesReaderTest.cpp mitkDICOMLocaleTest.cpp mitkDataNodeTest.cpp mitkEventConfigTest.cpp mitkPointSetLocaleTest.cpp mitkImageTest.cpp mitkImageVtkMapper2DTest.cpp mitkImageVtkMapper2DLevelWindowTest.cpp mitkImageVtkMapper2DOpacityTest.cpp mitkImageVtkMapper2DResliceInterpolationPropertyTest.cpp mitkImageVtkMapper2DColorTest.cpp mitkImageVtkMapper2DSwivelTest.cpp mitkImageVtkMapper2DTransferFunctionTest.cpp mitkImageVtkMapper2DOpacityTransferFunctionTest.cpp mitkImageVtkMapper2DLookupTableTest.cpp mitkSurfaceVtkMapper3DTest mitkSurfaceVtkMapper3DTexturedSphereTest.cpp mitkVolumeCalculatorTest.cpp mitkLevelWindowManagerTest.cpp mitkPointSetVtkMapper2DTest.cpp mitkPointSetVtkMapper2DImageTest.cpp mitkPointSetVtkMapper2DGlyphTypeTest.cpp mitkPointSetVtkMapper2DTransformedPointsTest.cpp mitkVTKRenderWindowSizeTest.cpp mitkMultiComponentImageDataComparisonFilterTest.cpp mitkImageToItkTest.cpp mitkImageSliceSelectorTest.cpp mitkSurfaceDepthPeelingTest.cpp ) # Currently not working on windows because of a rendering timing issue # see bug 18083 for details if(NOT WIN32) set(MODULE_CUSTOM_TESTS ${MODULE_CUSTOM_TESTS} mitkSurfaceDepthSortingTest.cpp) endif() set(RESOURCE_FILES Interactions/AddAndRemovePoints.xml Interactions/globalConfig.xml Interactions/StatemachineTest.xml Interactions/StatemachineConfigTest.xml ) diff --git a/Modules/Core/test/mitkPreferenceListReaderOptionsFunctorTest.cpp b/Modules/Core/test/mitkPreferenceListReaderOptionsFunctorTest.cpp new file mode 100644 index 0000000000..d00b0b454f --- /dev/null +++ b/Modules/Core/test/mitkPreferenceListReaderOptionsFunctorTest.cpp @@ -0,0 +1,129 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "mitkPreferenceListReaderOptionsFunctor.h" +#include "mitkTestFixture.h" +#include "mitkTestingMacros.h" + +#include + +class mitkPreferenceListReaderOptionsFunctorTestSuite : public mitk::TestFixture +{ + CPPUNIT_TEST_SUITE(mitkPreferenceListReaderOptionsFunctorTestSuite); + + MITK_TEST(UsePreferenceList); + MITK_TEST(UseBlackList); + MITK_TEST(UseNoList); + MITK_TEST(UseBlackAndPreferenceList); + MITK_TEST(UseOverlappingBlackAndPreferenceList); + MITK_TEST(UsePreferenceListWithInexistantReaders); + MITK_TEST(UseAllBlackedList); + + + CPPUNIT_TEST_SUITE_END(); + +private: + std::string m_ImagePath; + mitk::PreferenceListReaderOptionsFunctor::ListType preference; + mitk::PreferenceListReaderOptionsFunctor::ListType black; + mitk::PreferenceListReaderOptionsFunctor::ListType emptyList; + +public: + void setUp() override + { + m_ImagePath = GetTestDataFilePath("TinyCTAbdomen_DICOMReader/100"); + + preference = { "MITK DICOM Reader v2 (classic config)" }; + black = { "MITK DICOM Reader" }; + emptyList = {}; + } + + void tearDown() override + { + } + + void UsePreferenceList() + { + mitk::IOUtil::LoadInfo info(m_ImagePath); + + mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor(preference, emptyList); + CPPUNIT_ASSERT(true == functor(info)); + CPPUNIT_ASSERT_EQUAL(std::string("MITK DICOM Reader v2 (classic config)"), info.m_ReaderSelector.GetSelected().GetDescription()); + } + + void UseNoList() + { + mitk::IOUtil::LoadInfo info(m_ImagePath); + + mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor(emptyList, emptyList); + CPPUNIT_ASSERT(true == functor(info)); + CPPUNIT_ASSERT_EQUAL(std::string("MITK DICOM Reader"), info.m_ReaderSelector.GetSelected().GetDescription()); + } + + void UseBlackList() + { + mitk::IOUtil::LoadInfo info(m_ImagePath); + + mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor(emptyList, black); + CPPUNIT_ASSERT(true == functor(info)); + CPPUNIT_ASSERT(info.m_ReaderSelector.GetSelected().GetDescription() != "MITK DICOM Reader"); + } + + void UseBlackAndPreferenceList() + { + mitk::IOUtil::LoadInfo info(m_ImagePath); + + mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor(preference, black); + CPPUNIT_ASSERT(true == functor(info)); + CPPUNIT_ASSERT_EQUAL(std::string("MITK DICOM Reader v2 (classic config)"), info.m_ReaderSelector.GetSelected().GetDescription()); + } + + void UseOverlappingBlackAndPreferenceList() + { + mitk::IOUtil::LoadInfo info(m_ImagePath); + + black.push_back("MITK DICOM Reader v2 (classic config)"); + + mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor(preference, black); + CPPUNIT_ASSERT(true == functor(info)); + CPPUNIT_ASSERT_EQUAL(std::string("MITK DICOM Reader v2 (autoselect)"), info.m_ReaderSelector.GetSelected().GetDescription()); + } + + void UsePreferenceListWithInexistantReaders() + { + mitk::IOUtil::LoadInfo info(m_ImagePath); + preference.push_back("InexistantReader"); + + mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor(preference, emptyList); + CPPUNIT_ASSERT(true == functor(info)); + CPPUNIT_ASSERT_EQUAL(std::string("MITK DICOM Reader v2 (classic config)"), info.m_ReaderSelector.GetSelected().GetDescription()); + } + + void UseAllBlackedList() + { + mitk::IOUtil::LoadInfo info(m_ImagePath); + + for (auto reader : info.m_ReaderSelector.Get()) + { + black.push_back(reader.GetDescription()); + } + + mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor(emptyList, black); + CPPUNIT_ASSERT_THROW(functor(info), mitk::Exception); + } +}; + +MITK_TEST_SUITE_REGISTRATION(mitkPreferenceListReaderOptionsFunctor) diff --git a/Modules/QtWidgets/src/QmitkIOUtil.cpp b/Modules/QtWidgets/src/QmitkIOUtil.cpp index 74138d33d5..c302fe76aa 100644 --- a/Modules/QtWidgets/src/QmitkIOUtil.cpp +++ b/Modules/QtWidgets/src/QmitkIOUtil.cpp @@ -1,540 +1,540 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkIOUtil.h" #include "mitkCoreServices.h" #include "mitkCustomMimeType.h" #include "mitkFileReaderRegistry.h" #include "mitkFileWriterRegistry.h" #include "mitkIMimeTypeProvider.h" #include "mitkMimeType.h" #include #include #include "QmitkFileReaderOptionsDialog.h" #include "QmitkFileWriterOptionsDialog.h" // QT #include #include #include #include // ITK #include #include struct QmitkIOUtil::Impl { struct ReaderOptionsDialogFunctor : public ReaderOptionsFunctorBase { - virtual bool operator()(LoadInfo &loadInfo) override + virtual bool operator()(LoadInfo &loadInfo) const override { QmitkFileReaderOptionsDialog dialog(loadInfo); if (dialog.exec() == QDialog::Accepted) { return !dialog.ReuseOptions(); } else { loadInfo.m_Cancel = true; return true; } } }; struct WriterOptionsDialogFunctor : public WriterOptionsFunctorBase { - virtual bool operator()(SaveInfo &saveInfo) override + virtual bool operator()(SaveInfo &saveInfo) const override { QmitkFileWriterOptionsDialog dialog(saveInfo); if (dialog.exec() == QDialog::Accepted) { return !dialog.ReuseOptions(); } else { saveInfo.m_Cancel = true; return true; } } }; }; struct MimeTypeComparison : public std::unary_function { MimeTypeComparison(const std::string &mimeTypeName) : m_Name(mimeTypeName) {} bool operator()(const mitk::MimeType &mimeType) const { return mimeType.GetName() == m_Name; } const std::string m_Name; }; QString QmitkIOUtil::GetFileOpenFilterString() { QString filters; mitk::CoreServicePointer mimeTypeProvider(mitk::CoreServices::GetMimeTypeProvider()); std::vector categories = mimeTypeProvider->GetCategories(); for (std::vector::iterator cat = categories.begin(); cat != categories.end(); ++cat) { QSet filterExtensions; std::vector mimeTypes = mimeTypeProvider->GetMimeTypesForCategory(*cat); for (std::vector::iterator mt = mimeTypes.begin(); mt != mimeTypes.end(); ++mt) { std::vector extensions = mt->GetExtensions(); for (std::vector::iterator ext = extensions.begin(); ext != extensions.end(); ++ext) { filterExtensions << QString::fromStdString(*ext); } } QString filter = QString::fromStdString(*cat) + " ("; foreach (const QString &extension, filterExtensions) { filter += "*." + extension + " "; } filter = filter.replace(filter.size() - 1, 1, ')'); filters += ";;" + filter; } filters.prepend("All (*)"); return filters; } QList QmitkIOUtil::Load(const QStringList &paths, QWidget *parent) { std::vector loadInfos; foreach (const QString &file, paths) { loadInfos.push_back(LoadInfo(file.toStdString())); } Impl::ReaderOptionsDialogFunctor optionsCallback; std::string errMsg = Load(loadInfos, NULL, NULL, &optionsCallback); if (!errMsg.empty()) { QMessageBox::warning(parent, "Error reading files", QString::fromStdString(errMsg)); mitkThrow() << errMsg; } QList qResult; for (std::vector::const_iterator iter = loadInfos.begin(), iterEnd = loadInfos.end(); iter != iterEnd; ++iter) { for (const auto &elem : iter->m_Output) { qResult << elem; } } return qResult; } mitk::DataStorage::SetOfObjects::Pointer QmitkIOUtil::Load(const QStringList &paths, mitk::DataStorage &storage, QWidget *parent) { std::vector loadInfos; foreach (const QString &file, paths) { loadInfos.push_back(LoadInfo(QFile::encodeName(file).constData())); } mitk::DataStorage::SetOfObjects::Pointer nodeResult = mitk::DataStorage::SetOfObjects::New(); Impl::ReaderOptionsDialogFunctor optionsCallback; std::string errMsg = Load(loadInfos, nodeResult, &storage, &optionsCallback); if (!errMsg.empty()) { QMessageBox::warning(parent, "Error reading files", QString::fromStdString(errMsg)); } return nodeResult; } QList QmitkIOUtil::Load(const QString &path, QWidget *parent) { QStringList paths; paths << path; return Load(paths, parent); } mitk::DataStorage::SetOfObjects::Pointer QmitkIOUtil::Load(const QString &path, mitk::DataStorage &storage, QWidget *parent) { QStringList paths; paths << path; return Load(paths, storage, parent); } QString QmitkIOUtil::Save(const mitk::BaseData *data, const QString &defaultBaseName, const QString &defaultPath, QWidget *parent) { std::vector dataVector; dataVector.push_back(data); QStringList defaultBaseNames; defaultBaseNames.push_back(defaultBaseName); return Save(dataVector, defaultBaseNames, defaultPath, parent).back(); } QStringList QmitkIOUtil::Save(const std::vector &data, const QStringList &defaultBaseNames, const QString &defaultPath, QWidget *parent) { QStringList fileNames; QString currentPath = defaultPath; std::vector saveInfos; int counter = 0; for (std::vector::const_iterator dataIter = data.begin(), dataIterEnd = data.end(); dataIter != dataIterEnd; ++dataIter, ++counter) { SaveInfo saveInfo(*dataIter, mitk::MimeType(), std::string()); SaveFilter filters(saveInfo); // If there is only the "__all__" filter string, it means there is no writer for this base data if (filters.Size() < 2) { QMessageBox::warning( parent, "Saving not possible", QString("No writer available for type \"%1\"").arg(QString::fromStdString((*dataIter)->GetNameOfClass()))); continue; } // Construct a default path and file name QString filterString = filters.ToString(); QString selectedFilter = filters.GetDefaultFilter(); QString fileName = currentPath; QString dialogTitle = "Save " + QString::fromStdString((*dataIter)->GetNameOfClass()); if (counter < defaultBaseNames.size()) { dialogTitle += " \"" + defaultBaseNames[counter] + "\""; fileName += QDir::separator() + defaultBaseNames[counter]; // We do not append an extension to the file name by default. The extension // is chosen by the user by either selecting a filter or writing the // extension in the file name himself (in the file save dialog). /* QString defaultExt = filters.GetDefaultExtension(); if (!defaultExt.isEmpty()) { fileName += "." + defaultExt; } */ } // Ask the user for a file name QString nextName = QFileDialog::getSaveFileName(parent, dialogTitle, fileName, filterString, &selectedFilter); if (nextName.isEmpty()) { // We stop asking for further file names, but we still save the // data where the user already confirmed the save dialog. break; } fileName = nextName; std::string stdFileName = QFile::encodeName(fileName).constData(); QFileInfo fileInfo(fileName); currentPath = fileInfo.absolutePath(); QString suffix = fileInfo.completeSuffix(); mitk::MimeType filterMimeType = filters.GetMimeTypeForFilter(selectedFilter); mitk::MimeType selectedMimeType; if (fileInfo.exists() && !fileInfo.isFile()) { QMessageBox::warning(parent, "Saving not possible", QString("The path \"%1\" is not a file").arg(fileName)); continue; } // Theoretically, the user could have entered an extension that does not match the selected filter // The extension then has prioritry over the filter // Check if one of the available mime-types match the filename std::vector filterMimeTypes = filters.GetMimeTypes(); for (std::vector::const_iterator mimeTypeIter = filterMimeTypes.begin(), mimeTypeIterEnd = filterMimeTypes.end(); mimeTypeIter != mimeTypeIterEnd; ++mimeTypeIter) { if (mimeTypeIter->MatchesExtension(stdFileName)) { selectedMimeType = *mimeTypeIter; break; } } if (!selectedMimeType.IsValid()) { // The file name either does not contain an extension or the // extension is unknown. // If the file already exists, we stop here because we are unable // to (over)write the file without adding a custom suffix. If the file // does not exist, we add the default extension from the currently // selected filter. If the "All" filter was selected, we only add the // default extensions if the file name itself does not already contain // an extension. if (!fileInfo.exists()) { if (filterMimeType == SaveFilter::ALL_MIMETYPE()) { if (suffix.isEmpty()) { // Use the highest ranked mime-type from the list selectedMimeType = filters.GetDefaultMimeType(); } } else { selectedMimeType = filterMimeType; } if (selectedMimeType.IsValid()) { suffix = QString::fromStdString(selectedMimeType.GetExtensions().front()); fileName += "." + suffix; stdFileName = QFile::encodeName(fileName).constData(); // We changed the file name (added a suffix) so ask in case // the file aready exists. fileInfo = QFileInfo(fileName); if (fileInfo.exists()) { if (!fileInfo.isFile()) { QMessageBox::warning( parent, "Saving not possible", QString("The path \"%1\" is not a file").arg(fileName)); continue; } if (QMessageBox::question( parent, "Replace File", QString("A file named \"%1\" already exists. Do you want to replace it?").arg(fileName)) == QMessageBox::No) { continue; } } } } } if (!selectedMimeType.IsValid()) { // The extension/filename is not valid (no mime-type found), bail out QMessageBox::warning( parent, "Saving not possible", QString("No mime-type available which can handle \"%1\".").arg(fileName)); continue; } if (!QFileInfo(fileInfo.absolutePath()).isWritable()) { QMessageBox::warning(parent, "Saving not possible", QString("The path \"%1\" is not writable").arg(fileName)); continue; } fileNames.push_back(fileName); saveInfo.m_Path = stdFileName; saveInfo.m_MimeType = selectedMimeType; // pre-select the best writer for the chosen mime-type saveInfo.m_WriterSelector.Select(selectedMimeType.GetName()); saveInfos.push_back(saveInfo); } if (!saveInfos.empty()) { Impl::WriterOptionsDialogFunctor optionsCallback; std::string errMsg = Save(saveInfos, &optionsCallback); if (!errMsg.empty()) { QMessageBox::warning(parent, "Error writing files", QString::fromStdString(errMsg)); mitkThrow() << errMsg; } } return fileNames; } void QmitkIOUtil::SaveBaseDataWithDialog(mitk::BaseData *data, std::string fileName, QWidget * /*parent*/) { Save(data, fileName); } void QmitkIOUtil::SaveSurfaceWithDialog(mitk::Surface::Pointer surface, std::string fileName, QWidget * /*parent*/) { Save(surface, fileName); } void QmitkIOUtil::SaveImageWithDialog(mitk::Image::Pointer image, std::string fileName, QWidget * /*parent*/) { Save(image, fileName); } void QmitkIOUtil::SavePointSetWithDialog(mitk::PointSet::Pointer pointset, std::string fileName, QWidget * /*parent*/) { Save(pointset, fileName); } struct QmitkIOUtil::SaveFilter::Impl { Impl(const mitk::IOUtil::SaveInfo &saveInfo) : m_SaveInfo(saveInfo) { // Add an artifical filter for "All" m_MimeTypes.push_back(ALL_MIMETYPE()); m_FilterStrings.push_back("All (*.*)"); // Get all writers and their mime types for the given base data type // (this is sorted already) std::vector mimeTypes = saveInfo.m_WriterSelector.GetMimeTypes(); for (std::vector::const_reverse_iterator iter = mimeTypes.rbegin(), iterEnd = mimeTypes.rend(); iter != iterEnd; ++iter) { QList filterExtensions; mitk::MimeType mimeType = *iter; std::vector extensions = mimeType.GetExtensions(); for (auto &extension : extensions) { filterExtensions << QString::fromStdString(extension); } if (m_DefaultExtension.isEmpty()) { m_DefaultExtension = QString::fromStdString(extensions.front()); } QString filter = QString::fromStdString(mimeType.GetComment()) + " ("; foreach (const QString &extension, filterExtensions) { filter += "*." + extension + " "; } filter = filter.replace(filter.size() - 1, 1, ')'); m_MimeTypes.push_back(mimeType); m_FilterStrings.push_back(filter); } } const mitk::IOUtil::SaveInfo m_SaveInfo; std::vector m_MimeTypes; QStringList m_FilterStrings; QString m_DefaultExtension; }; mitk::MimeType QmitkIOUtil::SaveFilter::ALL_MIMETYPE() { static mitk::CustomMimeType allMimeType(std::string("__all__")); return mitk::MimeType(allMimeType, -1, -1); } QmitkIOUtil::SaveFilter::SaveFilter(const QmitkIOUtil::SaveFilter &other) : d(new Impl(*other.d)) { } QmitkIOUtil::SaveFilter::SaveFilter(const SaveInfo &saveInfo) : d(new Impl(saveInfo)) { } QmitkIOUtil::SaveFilter &QmitkIOUtil::SaveFilter::operator=(const QmitkIOUtil::SaveFilter &other) { d.reset(new Impl(*other.d)); return *this; } std::vector QmitkIOUtil::SaveFilter::GetMimeTypes() const { return d->m_MimeTypes; } QString QmitkIOUtil::SaveFilter::GetFilterForMimeType(const std::string &mimeType) const { std::vector::const_iterator iter = std::find_if(d->m_MimeTypes.begin(), d->m_MimeTypes.end(), MimeTypeComparison(mimeType)); if (iter == d->m_MimeTypes.end()) { return QString(); } int index = static_cast(iter - d->m_MimeTypes.begin()); if (index < 0 || index >= d->m_FilterStrings.size()) { return QString(); } return d->m_FilterStrings[index]; } mitk::MimeType QmitkIOUtil::SaveFilter::GetMimeTypeForFilter(const QString &filter) const { int index = d->m_FilterStrings.indexOf(filter); if (index < 0) { return mitk::MimeType(); } return d->m_MimeTypes[index]; } QString QmitkIOUtil::SaveFilter::GetDefaultFilter() const { if (d->m_FilterStrings.size() > 1) { return d->m_FilterStrings.at(1); } else if (d->m_FilterStrings.size() > 0) { return d->m_FilterStrings.front(); } return QString(); } QString QmitkIOUtil::SaveFilter::GetDefaultExtension() const { return d->m_DefaultExtension; } mitk::MimeType QmitkIOUtil::SaveFilter::GetDefaultMimeType() const { if (d->m_MimeTypes.size() > 1) { return d->m_MimeTypes.at(1); } else if (d->m_MimeTypes.size() > 0) { return d->m_MimeTypes.front(); } return mitk::MimeType(); } QString QmitkIOUtil::SaveFilter::ToString() const { return d->m_FilterStrings.join(";;"); } int QmitkIOUtil::SaveFilter::Size() const { return d->m_FilterStrings.size(); } bool QmitkIOUtil::SaveFilter::IsEmpty() const { return d->m_FilterStrings.isEmpty(); } bool QmitkIOUtil::SaveFilter::ContainsMimeType(const std::string &mimeType) { return std::find_if(d->m_MimeTypes.begin(), d->m_MimeTypes.end(), MimeTypeComparison(mimeType)) != d->m_MimeTypes.end(); }