diff --git a/Modules/Core/files.cmake b/Modules/Core/files.cmake index 12fa8bb201..c02fce90e1 100644 --- a/Modules/Core/files.cmake +++ b/Modules/Core/files.cmake @@ -1,319 +1,320 @@ 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/mitkIdentifiable.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/mitkIPropertyOwner.cpp DataManagement/mitkIPropertyPersistence.cpp DataManagement/mitkIPropertyProvider.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/mitkNodePredicateDataUID.cpp DataManagement/mitkNodePredicateDimension.cpp DataManagement/mitkNodePredicateFirstLevel.cpp DataManagement/mitkNodePredicateFunction.cpp DataManagement/mitkNodePredicateGeometry.cpp DataManagement/mitkNodePredicateNot.cpp DataManagement/mitkNodePredicateOr.cpp DataManagement/mitkNodePredicateProperty.cpp DataManagement/mitkNodePredicateDataProperty.cpp DataManagement/mitkNodePredicateSource.cpp DataManagement/mitkNodePredicateUID.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/mitkPropertyKeyPath.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/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/mitkUIDManipulator.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/mitkAbstractAnnotationRenderer.cpp Rendering/mitkAnnotationUtils.cpp Rendering/mitkBaseRenderer.cpp #Rendering/mitkGLMapper.cpp Moved to deprecated LegacyGL Module Rendering/mitkGradientBackground.cpp Rendering/mitkImageVtkMapper2D.cpp Rendering/mitkMapper.cpp Rendering/mitkAnnotation.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/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/mitkPropertyKeyPath.h b/Modules/Core/include/mitkPropertyKeyPath.h new file mode 100644 index 0000000000..5b7cb9b763 --- /dev/null +++ b/Modules/Core/include/mitkPropertyKeyPath.h @@ -0,0 +1,226 @@ +/*=================================================================== + +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 mitkPropertyKeyPath_h +#define mitkPropertyKeyPath_h + +#include +#include + +#include + +#include + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4251) +#endif +namespace mitk +{ + /** @brief Class that can be used to specify nested or wild carded property keys. E.g. + * for the use in context of the property persistence service or the property relation service.\n + * Following assumptions are made /preconditions are defined: + * - A property key is partitioned by "." into nodes (c.f. visualization of property keys in the PropertyView). + * - A node can either be an element or a selection. + * - An element has a name (alphanumric, - and space; "A-Za-z0-9- ") or is wildcarded ("*") + * - A selection is either an index (e.g. "[1]") or a wildcard ("[*]"). + * + * Selections are used to indicate that the preceding element has multiple occurences and which occurence is meant. + * Example property keys would be: + * - prop : A simple property key + * - prop.subprop1 : A property key consting of two nodes + * - prop.* : Any property key that starts with a node "prop" + * - prop.sub.[2] : A property key that starts with a node "prop" and a has a second node that is selection and has + * the index 2. + * - prop.sub.[*] : Any property key that starts with a node "prop" and a has a second node that is selection (with + * any index). + * + * To build a path one may use the Add* method to build up the PropertyKeyPath element by element.\n + * "first.*.third.[3]" would be equivalent to + * propKeyPath.AddElement("first"); + * propKeyPath.AddAnyElement(); + * propKeyPath.AddSelection("third",3);\n + * or the inline version + * propKeyPath.AddElement("first").AddAnyElement().AddSelection("third",3); + */ + class MITKCORE_EXPORT PropertyKeyPath final + { + public: + using ItemSelectionIndex = std::size_t; + using ElementNameType = std::string; + + struct MITKCORE_EXPORT NodeInfo + { + enum class NodeType + { + Invalid = 0, //*< Node does not exist or is invalid. + Element, //*< Selects an specific element given the node name. + ElementSelection, //*< Selects an specific item in a sequence of items and has a item selector ("[n]"). + AnySelection, //*< Selects all items of a specific element ("[*]"). + AnyElement //*< Selects any element/item. Node name is wildcarded ("*"); item selection as well implictily. + }; + + NodeType type; + ElementNameType name; + ItemSelectionIndex selection; + + NodeInfo(); + NodeInfo(const ElementNameType &name, NodeType type = NodeType::Element, ItemSelectionIndex index = 0); + bool Matches(const NodeInfo &right) const; + + bool operator==(const NodeInfo &right) const; + }; + + using NodeInfoVectorType = std::vector; + using PathIndexType = NodeInfoVectorType::size_type; + + /** Returns if the PropertyKeyPath is empty.*/ + bool IsEmpty() const; + + /** Returns if the path is explicit (has no wildcards).*/ + bool IsExplicit() const; + + /** Returns if the path has any nodes with item selection wild cards ([*]).*/ + bool HasItemSelectionWildcardsOnly() const; + + /** Number of path nodes the PropertyKeyPath contains.*/ + PathIndexType GetSize() const; + + /** Adds a new node to the end of the path. + \param [in] newNode Reference to the node that should be added. + \return Returns the index of the newly added node.*/ + PathIndexType AddNode(const NodeInfo &newNode); + + /** Function returns the node info of a path node specified by the index + * within the PropertyKeyPath. + * \pre Passed index must not be out of bounds. + * \param [in] index Index of the node whose info should be retrieved. + * \return Info of the specified path node. If the index is out of bound an InvalidPathNode exception will be + * thrown.*/ + const NodeInfo &GetNode(const PathIndexType &index) const; + + /** Function returns the node info of a path node specified by the index + * within the PropertyKeyPath. + * \pre Passed index must not be out of bounds. + * \param [in] index Index of the node whose info should be retrieved. + * \return Info of the specified path node. If the index is out of bound an InvalidPathNode exception will be + * thrown.*/ + NodeInfo &GetNode(const PathIndexType &index); + + /** Function returns the node info of the first path node within the PropertyKeyPath. + * \pre PropertyKeyPath must not be empty. + * \return Info of the first path node. If the path is empty, an InvalidPathNode exception will be thrown.*/ + NodeInfo &GetFirstNode(); + + /** Function returns the node info of the first path node within the PropertyKeyPath. + * \pre PropertyKeyPath must not be empty. + * \return Info of the first path node. If the path is empty, an InvalidPathNode exception will be thrown.*/ + const NodeInfo &GetFirstNode() const; + + /** Function returns the node info of the last path node within the PropertyKeyPath. + * \pre PropertyKeyPath must not be empty. + * \return Info of the first path node. If the path is empty, an InvalidPathNode exception will be thrown.*/ + NodeInfo &GetLastNode(); + + /** Function returns the node info of the last path node within the PropertyKeyPath. + * \pre PropertyKeyPath must not be empty. + * \return Info of the first path node. If the path is empty, an InvalidPathNode exception will be thrown.*/ + const NodeInfo &GetLastNode() const; + + const NodeInfoVectorType &GetNodes() const; + + /**Compares two PropertyKeyPaths for real equality. So it is a string comparison of their string conversion.*/ + bool operator==(const PropertyKeyPath &path) const; + + /**Operation equals like comparing the ToStr() results with operator <.*/ + bool operator<(const PropertyKeyPath &right) const; + + /**Operation equals like comparing the ToStr() results with operator <=.*/ + bool operator<=(const PropertyKeyPath &right) const; + + /**Operation equals like comparing the ToStr() results with operator >=.*/ + bool operator>=(const PropertyKeyPath &right) const; + + /**Operation equals like comparing the ToStr() results with operator >.*/ + bool operator>(const PropertyKeyPath &right) const; + + /**Checks if two PropertyKeyPaths specify the same node. Hence all wildcards will be processed.\n + * E.G.: "item1.child1.grandChild2" == "item1.*.grandChild2" is true. + * \remark If you want to check if two paths are "truly" equal and not only equal in terms of + * pointing to the same node, use the member function operator ==().*/ + bool Equals(const PropertyKeyPath &path) const; + + PropertyKeyPath &operator=(const PropertyKeyPath &path); + + /** Appends an "any element" to the path instance.*/ + PropertyKeyPath &AddAnyElement(); + /** Appends an element with the passed name to the path instance.*/ + PropertyKeyPath &AddElement(const ElementNameType &name); + /** Appends an element with the passed name and any selection to the path instance.*/ + PropertyKeyPath &AddAnySelection(const ElementNameType &name); + /** Appends an element with the passed name and selection index to the path instance.*/ + PropertyKeyPath &AddSelection(const ElementNameType &name, ItemSelectionIndex index); + + PropertyKeyPath(); + PropertyKeyPath(const PropertyKeyPath &path); + + ~PropertyKeyPath(); + + void Reset(); + + protected: + NodeInfoVectorType m_NodeInfos; + + static bool PropertyKeyPathsMatch(const PropertyKeyPath &left, const PropertyKeyPath &right); + }; + + class MITKCORE_EXPORT InvalidPathNodeException : public mitk::Exception + { + public: + mitkExceptionClassMacro(InvalidPathNodeException, mitk::Exception); + }; + + MITKCORE_EXPORT std::ostream &operator<<(std::ostream &os, const PropertyKeyPath &path); + + /**Helper function that converts a path PropertyKeyPath into a regex string that can be used + to search for property keys (using std::regex) that are matched by the PropertyKeyPath. + This function is used in context of the property persistence service.*/ + MITKCORE_EXPORT std::string PropertyKeyPathToPropertyRegEx(const PropertyKeyPath &tagPath); + /**Helper function that converts a path PropertyKeyPath into a regex string that can be used + to search for property persistence keys (using std::regex) that are matched by the PropertyKeyPath. + This function is used in context of the property persistence service.*/ + MITKCORE_EXPORT std::string PropertyKeyPathToPersistenceKeyRegEx(const PropertyKeyPath &tagPath); + /**Helper function that converts a path PropertyKeyPath into a regex that can be used as key template + in a PropertyPersistanceInfo. + This function is used in context of the property persistence service.*/ + MITKCORE_EXPORT std::string PropertyKeyPathToPersistenceKeyTemplate(const PropertyKeyPath &tagPath); + /**Helper function that converts a path PropertyKeyPath into a regex that can be used as name template + in a PropertyPersistanceInfo. + This function is used in context of the property persistence service.*/ + MITKCORE_EXPORT std::string PropertyKeyPathToPersistenceNameTemplate(const PropertyKeyPath &tagPath); + + /** Converts the passed property name into a tag path. If the property name cannot be converted + into a valid path, the returned path is empty.*/ + MITKCORE_EXPORT PropertyKeyPath PropertyNameToPropertyKeyPath(const std::string &propertyName); + /** returns the correct property name for a given PropertyKeyPath instance. */ + MITKCORE_EXPORT std::string PropertyKeyPathToPropertyName(const PropertyKeyPath &tagPath); +} // namespace mitk + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#endif diff --git a/Modules/Core/src/DataManagement/mitkPropertyKeyPath.cpp b/Modules/Core/src/DataManagement/mitkPropertyKeyPath.cpp new file mode 100644 index 0000000000..0b42ed1b0e --- /dev/null +++ b/Modules/Core/src/DataManagement/mitkPropertyKeyPath.cpp @@ -0,0 +1,600 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include +#include + +#include +#include + +#include + +namespace mitk +{ + PropertyKeyPath::NodeInfo::NodeInfo() : type(NodeType::Invalid), selection(0){}; + + PropertyKeyPath::NodeInfo::NodeInfo(const ElementNameType &name, NodeType type, ItemSelectionIndex index) + : type(type), name(name), selection(index){}; + + bool PropertyKeyPath::NodeInfo::operator==(const NodeInfo &right) const + { + if (this->name != right.name) + return false; + if (this->type != right.type) + return false; + if (this->selection != right.selection) + return false; + + return true; + }; + + bool PropertyKeyPath::NodeInfo::Matches(const NodeInfo &right) const + { + if (type == NodeType::Invalid || right.type == NodeType::Invalid) + { + return false; + } + else if (type == NodeType::AnyElement || right.type == NodeType::AnyElement) + { + return true; + } + else if (name == right.name) + { + if (type == NodeType::Element && right.type == NodeType::Element) + { + return true; + } + else if (selection == right.selection || type == NodeType::AnySelection || right.type == NodeType::AnySelection) + { + return true; + } + } + return false; + }; + + bool PropertyKeyPath::IsEmpty() const { return m_NodeInfos.empty(); }; + + bool PropertyKeyPath::IsExplicit() const + { + for (const auto &pos : m_NodeInfos) + { + if ((pos.type == NodeInfo::NodeType::AnySelection) || (pos.type == NodeInfo::NodeType::AnyElement)) + { + return false; + } + } + + return true; + }; + + bool PropertyKeyPath::HasItemSelectionWildcardsOnly() const + { + bool result = false; + for (const auto &pos : m_NodeInfos) + { + if (pos.type == NodeInfo::NodeType::AnyElement) + { + return false; + } + result = result || pos.type == NodeInfo::NodeType::AnySelection; + } + + return result; + }; + + PropertyKeyPath::PathIndexType PropertyKeyPath::GetSize() const { return m_NodeInfos.size(); } + + PropertyKeyPath::PathIndexType PropertyKeyPath::AddNode(const NodeInfo &newNode) + { + m_NodeInfos.push_back(newNode); + return m_NodeInfos.size() - 1; + }; + + const PropertyKeyPath::NodeInfo &PropertyKeyPath::GetNode(const PathIndexType &index) const + { + if (index >= GetSize()) + { + mitkThrowException(InvalidPathNodeException) + << "Error. Cannot return info of path node. Node index is out of bounds. Index: " << index + << "; Path: " << PropertyKeyPathToPropertyName(*this); + } + + return m_NodeInfos[index]; + }; + + PropertyKeyPath::NodeInfo &PropertyKeyPath::GetNode(const PathIndexType &index) + { + if (index >= this->GetSize()) + { + mitkThrowException(InvalidPathNodeException) + << "Error. Cannot return info of path node. Node index is out of bounds. Index: " << index + << "; Path: " << PropertyKeyPathToPropertyName(*this); + } + + return m_NodeInfos[index]; + }; + + const PropertyKeyPath::NodeInfo &PropertyKeyPath::GetFirstNode() const + { + if (m_NodeInfos.empty()) + { + mitkThrowException(InvalidPathNodeException) << "Error. Cannot return first path node. Path is empty."; + } + return this->GetNode(0); + }; + + PropertyKeyPath::NodeInfo &PropertyKeyPath::GetFirstNode() + { + if (m_NodeInfos.empty()) + { + mitkThrowException(InvalidPathNodeException) << "Error. Cannot return first path node. Path is empty."; + } + return this->GetNode(0); + }; + + const PropertyKeyPath::NodeInfo &PropertyKeyPath::GetLastNode() const + { + if (m_NodeInfos.empty()) + { + mitkThrowException(InvalidPathNodeException) << "Error. Cannot return last path node. Path is empty."; + } + return this->GetNode(GetSize() - 1); + }; + + PropertyKeyPath::NodeInfo &PropertyKeyPath::GetLastNode() + { + if (m_NodeInfos.empty()) + { + mitkThrowException(InvalidPathNodeException) << "Error. Cannot return last path node. Path is empty."; + } + return this->GetNode(GetSize() - 1); + }; + + const PropertyKeyPath::NodeInfoVectorType &PropertyKeyPath::GetNodes() const { return m_NodeInfos; }; + + bool PropertyKeyPath::operator==(const PropertyKeyPath &path) const { return m_NodeInfos == path.m_NodeInfos; }; + + bool PropertyKeyPath::operator<(const PropertyKeyPath &right) const + { + auto rightIter = right.m_NodeInfos.cbegin(); + const auto rightEnd = right.m_NodeInfos.cend(); + for (const auto &leftPos : m_NodeInfos) + { + if (rightIter == rightEnd) + { + return false; + } + + if (leftPos.name < rightIter->name) + { + return true; + } + if (rightIter->name < leftPos.name) + { + return false; + } + + if (leftPos.type < rightIter->type) + { + return true; + } + if (rightIter->type < leftPos.type) + { + return false; + } + + if (leftPos.selection < rightIter->selection) + { + return true; + } + if (rightIter->selection < leftPos.selection) + { + return false; + } + + ++rightIter; + } + return rightIter != rightEnd; + } + + bool PropertyKeyPath::operator>(const PropertyKeyPath &right) const + { + auto rightIter = right.m_NodeInfos.cbegin(); + const auto rightEnd = right.m_NodeInfos.cend(); + for (const auto &leftPos : m_NodeInfos) + { + if (rightIter == rightEnd) + return false; + + if (leftPos.name > rightIter->name) + return true; + if (rightIter->name > leftPos.name) + return false; + + if (leftPos.type > rightIter->type) + return true; + if (rightIter->type > leftPos.type) + return false; + + if (leftPos.selection > rightIter->selection) + return true; + if (rightIter->selection > leftPos.selection) + return false; + ++rightIter; + } + return rightIter != rightEnd; + } + + bool PropertyKeyPath::operator>=(const PropertyKeyPath &right) const { return !(*this < right); } + + bool PropertyKeyPath::operator<=(const PropertyKeyPath &right) const { return !(*this > right); } + + bool PropertyKeyPath::Equals(const PropertyKeyPath &path) const { return PropertyKeyPathsMatch(*this, path); }; + + PropertyKeyPath &PropertyKeyPath::operator=(const PropertyKeyPath &path) + { + if (this != &path) + { + m_NodeInfos = path.m_NodeInfos; + } + + return *this; + }; + + PropertyKeyPath &PropertyKeyPath::AddAnyElement() + { + m_NodeInfos.emplace_back("", NodeInfo::NodeType::AnyElement); + return *this; + }; + + PropertyKeyPath &PropertyKeyPath::AddElement(const ElementNameType &name) + { + m_NodeInfos.emplace_back(name, NodeInfo::NodeType::Element); + return *this; + }; + + PropertyKeyPath &PropertyKeyPath::AddAnySelection(const ElementNameType &name) + { + m_NodeInfos.emplace_back(name, NodeInfo::NodeType::AnySelection); + return *this; + }; + + PropertyKeyPath &PropertyKeyPath::AddSelection(const ElementNameType &name, ItemSelectionIndex index) + { + m_NodeInfos.emplace_back(name, NodeInfo::NodeType::ElementSelection, index); + return *this; + }; + + PropertyKeyPath::PropertyKeyPath() { this->Reset(); }; + + PropertyKeyPath::PropertyKeyPath(const PropertyKeyPath &path) { *this = path; }; + + PropertyKeyPath::~PropertyKeyPath(){}; + + void PropertyKeyPath::Reset() { m_NodeInfos.clear(); }; + + bool PropertyKeyPath::PropertyKeyPathsMatch(const PropertyKeyPath &left, const PropertyKeyPath &right) + { + auto leftPos = left.GetNodes().cbegin(); + auto rightPos = right.GetNodes().cbegin(); + auto leftEnd = left.GetNodes().cend(); + auto rightEnd = right.GetNodes().cend(); + + while (leftPos != leftEnd && rightPos != rightEnd) + { + if (!leftPos->Matches(*rightPos)) + { + break; + } + ++leftPos; + ++rightPos; + } + + if (leftPos == leftEnd && rightPos == rightEnd) + { + return true; + } + else + { + return false; + } + }; + + std::ostream &operator<<(std::ostream &os, const PropertyKeyPath &value) + { + os << PropertyKeyPathToPropertyName(value); + return os; + }; + + std::string PropertyKeyPathToPropertyRegEx(const PropertyKeyPath &tagPath) + { + std::ostringstream nameStream; + + PropertyKeyPath::PathIndexType i = 0; + + for (const auto &node : tagPath.GetNodes()) + { + if (i) + { + nameStream << "\\."; + } + ++i; + + if (node.type == PropertyKeyPath::NodeInfo::NodeType::AnyElement) + { + nameStream << "([a-zA-Z0-9- ]+)"; + } + else if (node.type != PropertyKeyPath::NodeInfo::NodeType::Invalid) + { + nameStream << node.name; + + if (node.type == PropertyKeyPath::NodeInfo::NodeType::ElementSelection) + { + nameStream << "\\.\\[" << node.selection << "\\]"; + } + else if (node.type == PropertyKeyPath::NodeInfo::NodeType::AnySelection) + { + nameStream << "\\.\\[(\\d*)\\]"; + } + } + else + { + nameStream << "INVALIDNODE"; + } + } + + return nameStream.str(); + }; + + std::string PropertyKeyPathToPersistenceKeyRegEx(const PropertyKeyPath &tagPath) + { + std::ostringstream nameStream; + + PropertyKeyPath::PathIndexType i = 0; + + for (const auto &node : tagPath.GetNodes()) + { + if (i) + { + nameStream << "_"; + } + ++i; + + if (node.type == PropertyKeyPath::NodeInfo::NodeType::AnyElement) + { + nameStream << "([a-zA-Z0-9- ]+)"; + } + else if (node.type != PropertyKeyPath::NodeInfo::NodeType::Invalid) + { + nameStream << node.name; + + if (node.type == PropertyKeyPath::NodeInfo::NodeType::ElementSelection) + { + nameStream << "_\\[" << node.selection << "\\]"; + } + else if (node.type == PropertyKeyPath::NodeInfo::NodeType::AnySelection) + { + nameStream << "_\\[(\\d*)\\]"; + } + } + else + { + nameStream << "INVALIDNODE"; + } + } + + return nameStream.str(); + }; + + std::string PropertyKeyPathToPersistenceKeyTemplate(const PropertyKeyPath &tagPath) + { + std::ostringstream nameStream; + + int captureGroup = 1; + + PropertyKeyPath::PathIndexType i = 0; + + for (const auto &node : tagPath.GetNodes()) + { + if (i) + { + nameStream << "_"; + } + ++i; + + if (node.type == PropertyKeyPath::NodeInfo::NodeType::AnyElement) + { + nameStream << "$" << captureGroup++; + } + else if (node.type != PropertyKeyPath::NodeInfo::NodeType::Invalid) + { + nameStream << node.name; + + if (node.type == PropertyKeyPath::NodeInfo::NodeType::ElementSelection) + { + nameStream << "_[" << node.selection << "]"; + } + else if (node.type == PropertyKeyPath::NodeInfo::NodeType::AnySelection) + { + nameStream << "_[$" << captureGroup++ << "]"; + } + } + else + { + nameStream << "INVALID_NODE"; + } + } + + return nameStream.str(); + }; + + std::string PropertyKeyPathToPersistenceNameTemplate(const PropertyKeyPath &tagPath) + { + std::ostringstream nameStream; + + int captureGroup = 1; + + PropertyKeyPath::PathIndexType i = 0; + + for (const auto &node : tagPath.GetNodes()) + { + if (i) + { + nameStream << "."; + } + ++i; + + if (node.type == PropertyKeyPath::NodeInfo::NodeType::AnyElement) + { + nameStream << "$" << captureGroup++; + } + else if (node.type != PropertyKeyPath::NodeInfo::NodeType::Invalid) + { + nameStream << node.name; + + if (node.type == PropertyKeyPath::NodeInfo::NodeType::ElementSelection) + { + nameStream << ".[" << node.selection << "]"; + } + else if (node.type == PropertyKeyPath::NodeInfo::NodeType::AnySelection) + { + nameStream << ".[$" << captureGroup++ << "]"; + } + } + else + { + nameStream << "INVALID_NODE"; + } + } + + return nameStream.str(); + }; + + PropertyKeyPath PropertyNameToPropertyKeyPath(const std::string &propertyName) + { + PropertyKeyPath result; + + std::regex reg_element("([a-zA-Z0-9- ]+)"); + std::regex reg_anySelection("\\[\\*\\]"); + std::regex reg_Selection("\\[(\\d+)\\]"); + + std::istringstream f(propertyName); + std::string subStr; + + PropertyKeyPath::ElementNameType name = ""; + + while (getline(f, subStr, '.')) + { + if (subStr == "*") + { + if (!name.empty()) + { + result.AddElement(name); + name.clear(); + } + + result.AddAnyElement(); + } + else + { + std::smatch sm; + if (std::regex_match(subStr, sm, reg_anySelection)) + { + if (!name.empty()) + { + result.AddAnySelection(name); + name.clear(); + } + else + { // invalid path + return PropertyKeyPath(); + } + } + else if (std::regex_match(subStr, sm, reg_Selection)) + { + if (!name.empty()) + { + result.AddSelection(name, std::stoi(sm[1])); + name.clear(); + } + else + { // invalid path + return PropertyKeyPath(); + } + } + else if (std::regex_match(subStr, sm, reg_element)) + { + if (!name.empty()) + { // store the last element and start the next + result.AddElement(name); + } + name = sm[1]; + } + else + { + return PropertyKeyPath(); + } + } + } + + if (!name.empty()) + { // add last element + result.AddElement(name); + } + + return result; + }; + + std::string PropertyKeyPathToPropertyName(const mitk::PropertyKeyPath &tagPath) + { + std::ostringstream nameStream; + + PropertyKeyPath::PathIndexType i = 0; + + for (const auto &node : tagPath.GetNodes()) + { + if (i) + { + nameStream << "."; + } + ++i; + + if (node.type == PropertyKeyPath::NodeInfo::NodeType::AnyElement) + { + nameStream << "*"; + } + else if (node.type != PropertyKeyPath::NodeInfo::NodeType::Invalid) + { + nameStream << node.name; + + if (node.type == PropertyKeyPath::NodeInfo::NodeType::ElementSelection) + { + nameStream << ".[" << node.selection << "]"; + } + else if (node.type == PropertyKeyPath::NodeInfo::NodeType::AnySelection) + { + nameStream << ".[*]"; + } + } + else + { + nameStream << "INVALID_NODE"; + } + } + + return nameStream.str(); + }; +} // namespace mitk diff --git a/Modules/Core/test/files.cmake b/Modules/Core/test/files.cmake index 3bf1faa89f..6630393e3f 100644 --- a/Modules/Core/test/files.cmake +++ b/Modules/Core/test/files.cmake @@ -1,200 +1,201 @@ # 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 mitkNodePredicateFunctionTest.cpp mitkVectorTest.cpp mitkClippedSurfaceBoundsCalculatorTest.cpp mitkExceptionTest.cpp mitkExtractSliceFilterTest.cpp mitkLogTest.cpp mitkImageDimensionConverterTest.cpp mitkLoggingAdapterTest.cpp mitkUIDGeneratorTest.cpp mitkPlanePositionManagerTest.cpp mitkAffineTransformBaseTest.cpp mitkPropertyAliasesTest.cpp mitkPropertyDescriptionsTest.cpp mitkPropertyExtensionsTest.cpp mitkPropertyFiltersTest.cpp + mitkPropertyKeyPathTest.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/mitkPropertyKeyPathTest.cpp b/Modules/Core/test/mitkPropertyKeyPathTest.cpp new file mode 100644 index 0000000000..d736da9ea0 --- /dev/null +++ b/Modules/Core/test/mitkPropertyKeyPathTest.cpp @@ -0,0 +1,318 @@ +/*=================================================================== + +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 "mitkPropertyKeyPath.h" + +#include "mitkTestFixture.h" +#include "mitkTestingMacros.h" + +#include + +class mitkPropertyKeyPathTestSuite : public mitk::TestFixture +{ + CPPUNIT_TEST_SUITE(mitkPropertyKeyPathTestSuite); + + MITK_TEST(AccessFunctions); + MITK_TEST(PropertyKeyPathToPropertyRegEx); + MITK_TEST(PropertyKeyPathToPersistenceKeyRegEx); + MITK_TEST(PropertyKeyPathToPersistenceKeyTemplate); + MITK_TEST(PropertyKeyPathToPersistenceNameTemplate); + MITK_TEST(PropertyNameToPropertyKeyPath); + MITK_TEST(PropertyKeyPathToPropertyName); + MITK_TEST(ExecutePropertyRegEx); + MITK_TEST(Comparison); + + CPPUNIT_TEST_SUITE_END(); + +private: + mitk::PropertyKeyPath simplePath; + mitk::PropertyKeyPath simplePath2; + mitk::PropertyKeyPath deepPath; + mitk::PropertyKeyPath deepPath_withAnyElement; + mitk::PropertyKeyPath deepPath_withAnySelection; + mitk::PropertyKeyPath deepPath_withSelection; + mitk::PropertyKeyPath verydeepPath; + + mitk::PropertyKeyPath emptyPath; + +public: + void setUp() override + { + simplePath.AddElement("simple"); + + simplePath2.AddElement("AA-11"); + + deepPath.AddElement("a").AddElement("b2").AddElement("c3"); + + deepPath_withAnyElement.AddElement("a"); + deepPath_withAnyElement.AddAnyElement(); + deepPath_withAnyElement.AddElement("c3"); + + deepPath_withAnySelection.AddElement("a"); + deepPath_withAnySelection.AddAnySelection("b"); + deepPath_withAnySelection.AddElement("c"); + + deepPath_withSelection.AddElement("a"); + deepPath_withSelection.AddSelection("b", 6); + deepPath_withSelection.AddElement("c"); + + verydeepPath.AddAnySelection("a"); + verydeepPath.AddAnyElement(); + verydeepPath.AddElement("c"); + verydeepPath.AddSelection("d", 4); + verydeepPath.AddElement("e"); + } + + void tearDown() override {} + + void AccessFunctions() + { + const auto constEmptyPath = emptyPath; + const auto constVerydeepPath = verydeepPath; + + CPPUNIT_ASSERT_THROW(emptyPath.GetFirstNode(), mitk::InvalidPathNodeException); + CPPUNIT_ASSERT_THROW(emptyPath.GetLastNode(), mitk::InvalidPathNodeException); + CPPUNIT_ASSERT_THROW(emptyPath.GetNode(0), mitk::InvalidPathNodeException); + CPPUNIT_ASSERT_THROW(constEmptyPath.GetFirstNode(), mitk::InvalidPathNodeException); + CPPUNIT_ASSERT_THROW(constEmptyPath.GetLastNode(), mitk::InvalidPathNodeException); + CPPUNIT_ASSERT_THROW(constEmptyPath.GetNode(0), mitk::InvalidPathNodeException); + + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing GetFirstNode with 'a.[*].*.c.d.[4].e'", std::string("a"), verydeepPath.GetFirstNode().name); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing const GetFirstNode with 'a.[*].*.c.d.[4].e'", std::string("a"), constVerydeepPath.GetFirstNode().name); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing GetLastNode with 'a.[*].*.c.d.[4].e'", std::string("e"), verydeepPath.GetLastNode().name); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing GetLastNode with 'a.[*].*.c.d.[4].e'", std::string("e"), constVerydeepPath.GetLastNode().name); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing GetNode(3) with 'a.[*].*.c.d.[4].e'", std::string("d"), verydeepPath.GetNode(3).name); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing GetNode(3) with 'a.[*].*.c.d.[4].e'", std::string("d"), constVerydeepPath.GetNode(3).name); + + CPPUNIT_ASSERT(5 == constVerydeepPath.GetSize()); + CPPUNIT_ASSERT(0 == emptyPath.GetSize()); + } + + void PropertyKeyPathToPropertyRegEx() + { + std::string result = mitk::PropertyKeyPathToPropertyRegEx(simplePath); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing PropertyKeyPathToPropertyRegEx() with 'simple'", std::string("simple"), result); + result = mitk::PropertyKeyPathToPropertyRegEx(deepPath); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing PropertyKeyPathToPropertyRegEx() with 'a.b2.c3'", std::string("a\\.b2\\.c3"), result); + result = mitk::PropertyKeyPathToPropertyRegEx(deepPath_withAnyElement); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing PropertyKeyPathToPropertyRegEx() with 'a.*.c3'", std::string("a\\.([a-zA-Z0-9- ]+)\\.c3"), result); + result = mitk::PropertyKeyPathToPropertyRegEx(deepPath_withAnySelection); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing PropertyKeyPathToPropertyRegEx() with 'a.b.[*].c'", std::string("a\\.b\\.\\[(\\d*)\\]\\.c"), result); + result = mitk::PropertyKeyPathToPropertyRegEx(deepPath_withSelection); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing PropertyKeyPathToPropertyRegEx() with 'a.b.[6].c'", std::string("a\\.b\\.\\[6\\]\\.c"), result); + result = mitk::PropertyKeyPathToPropertyRegEx(verydeepPath); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing PropertyKeyPathToPropertyRegEx() with 'a.[*].*.c.d.[4].e'", + std::string("a\\.\\[(\\d*)\\]\\.([a-zA-Z0-9- ]+)\\.c\\.d\\.\\[4\\]\\.e"), + result); + } + + void PropertyKeyPathToPersistenceKeyRegEx() + { + std::string result = mitk::PropertyKeyPathToPersistenceKeyRegEx(simplePath); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing PropertyKeyPathToPersistenceKeyRegEx() with 'simple'", std::string("simple"), result); + result = mitk::PropertyKeyPathToPersistenceKeyRegEx(deepPath); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing PropertyKeyPathToPersistenceKeyRegEx() with 'a.b2.c3'", std::string("a_b2_c3"), result); + result = mitk::PropertyKeyPathToPersistenceKeyRegEx(deepPath_withAnyElement); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing PropertyKeyPathToPersistenceKeyRegEx() with 'a.*.c3'", std::string("a_([a-zA-Z0-9- ]+)_c3"), result); + result = mitk::PropertyKeyPathToPersistenceKeyRegEx(deepPath_withAnySelection); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing PropertyKeyPathToPersistenceKeyRegEx() with 'a.b.[*].c'", std::string("a_b_\\[(\\d*)\\]_c"), result); + result = mitk::PropertyKeyPathToPersistenceKeyRegEx(deepPath_withSelection); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing PropertyKeyPathToPersistenceKeyRegEx() with 'a.b.[6].c'", std::string("a_b_\\[6\\]_c"), result); + result = mitk::PropertyKeyPathToPersistenceKeyRegEx(verydeepPath); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing PropertyKeyPathToPersistenceKeyRegEx() with 'a.[*].*.c.d.[4].e'", + std::string("a_\\[(\\d*)\\]_([a-zA-Z0-9- ]+)_c_d_\\[4\\]_e"), + result); + } + + void PropertyKeyPathToPersistenceKeyTemplate() + { + std::string result = mitk::PropertyKeyPathToPersistenceKeyTemplate(simplePath); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing PropertyKeyPathToPersistenceKeyTemplate() with 'simple'", std::string("simple"), result); + result = mitk::PropertyKeyPathToPersistenceKeyTemplate(deepPath); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing PropertyKeyPathToPersistenceKeyTemplate() with 'a.b2.c3'", std::string("a_b2_c3"), result); + result = mitk::PropertyKeyPathToPersistenceKeyTemplate(deepPath_withAnyElement); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing PropertyKeyPathToPersistenceKeyTemplate() with 'a.*.c3'", std::string("a_$1_c3"), result); + result = mitk::PropertyKeyPathToPersistenceKeyTemplate(deepPath_withAnySelection); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing PropertyKeyPathToPersistenceKeyTemplate() with 'a.b.[*].c'", std::string("a_b_[$1]_c"), result); + result = mitk::PropertyKeyPathToPersistenceKeyTemplate(deepPath_withSelection); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing PropertyKeyPathToPersistenceKeyTemplate() with 'a.b.[6].c'", std::string("a_b_[6]_c"), result); + result = mitk::PropertyKeyPathToPersistenceKeyTemplate(verydeepPath); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing PropertyKeyPathToPersistenceKeyTemplate() with 'a.[*].*.c.d.[4].e'", + std::string("a_[$1]_$2_c_d_[4]_e"), + result); + } + + void PropertyKeyPathToPersistenceNameTemplate() + { + std::string result = mitk::PropertyKeyPathToPersistenceNameTemplate(simplePath); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing PropertyKeyPathToPersistenceNameTemplate() with 'simple'", std::string("simple"), result); + result = mitk::PropertyKeyPathToPersistenceNameTemplate(deepPath); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing PropertyKeyPathToPersistenceNameTemplate() with 'a.b2.c3'", std::string("a.b2.c3"), result); + result = mitk::PropertyKeyPathToPersistenceNameTemplate(deepPath_withAnyElement); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing PropertyKeyPathToPersistenceNameTemplate() with 'a.*.c3'", std::string("a.$1.c3"), result); + result = mitk::PropertyKeyPathToPersistenceNameTemplate(deepPath_withAnySelection); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing PropertyKeyPathToPersistenceNameTemplate() with 'a.b.[*].c'", std::string("a.b.[$1].c"), result); + result = mitk::PropertyKeyPathToPersistenceNameTemplate(deepPath_withSelection); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing PropertyKeyPathToPersistenceNameTemplate() with 'a.b.[6].c'", std::string("a.b.[6].c"), result); + result = mitk::PropertyKeyPathToPersistenceNameTemplate(verydeepPath); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing PropertyKeyPathToPersistenceNameTemplate() with 'a.[*].*.c.d.[4].e'", + std::string("a.[$1].$2.c.d.[4].e"), + result); + } + + void PropertyNameToPropertyKeyPath() + { + mitk::PropertyKeyPath result = mitk::PropertyNameToPropertyKeyPath("simple"); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing PropertyNameToPropertyKeyPath() with 'simple'", simplePath, result); + result = mitk::PropertyNameToPropertyKeyPath("a.b2.c3"); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing PropertyNameToPropertyKeyPath() with 'a.b2.c3'", deepPath, result); + result = mitk::PropertyNameToPropertyKeyPath("a.*.c3"); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing PropertyNameToPropertyKeyPath() with 'a.*.c3'", deepPath_withAnyElement, result); + result = mitk::PropertyNameToPropertyKeyPath("a.b.[*].c"); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing PropertyNameToPropertyKeyPath() with 'a.b.[*].c'", deepPath_withAnySelection, result); + result = mitk::PropertyNameToPropertyKeyPath("a.b.[6].c"); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing PropertyNameToPropertyKeyPath() with 'a.b.[6].c'", deepPath_withSelection, result); + result = mitk::PropertyNameToPropertyKeyPath("a.[*].*.c.d.[4].e"); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing PropertyNameToPropertyKeyPath() with 'a.[*].*.c.d.[4].e'", verydeepPath, result); + + result = mitk::PropertyNameToPropertyKeyPath("AA-11"); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing PropertyNameToPropertyKeyPath() with 'AA-11'", simplePath2, result); + + result = mitk::PropertyNameToPropertyKeyPath("$$$IlligalNameChar.sub"); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing PropertyNameToPropertyKeyPath() with wrong path", emptyPath, result); + result = mitk::PropertyNameToPropertyKeyPath("emptyNode..sub"); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing PropertyNameToPropertyKeyPath() with wrong path", emptyPath, result); + result = mitk::PropertyNameToPropertyKeyPath("wrongIndex.[d]"); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing PropertyNameToPropertyKeyPath() with wrong path", emptyPath, result); + } + + void PropertyKeyPathToPropertyName() + { + std::string result = mitk::PropertyKeyPathToPropertyName(simplePath); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing PropertyKeyPathToPropertyName() with 'simple'", result, std::string("simple")); + result = mitk::PropertyKeyPathToPropertyName(deepPath); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing PropertyKeyPathToPropertyName() with 'a.b2.c3'", result, std::string("a.b2.c3")); + result = mitk::PropertyKeyPathToPropertyName(deepPath_withAnyElement); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing PropertyKeyPathToPropertyName() with 'a.*.c3'", result, std::string("a.*.c3")); + result = mitk::PropertyKeyPathToPropertyName(deepPath_withAnySelection); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing PropertyKeyPathToPropertyName() with 'a.b.[*].c'", result, std::string("a.b.[*].c")); + result = mitk::PropertyKeyPathToPropertyName(deepPath_withSelection); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing PropertyKeyPathToPropertyName() with 'a.b.[6].c'", result, std::string("a.b.[6].c")); + result = mitk::PropertyKeyPathToPropertyName(verydeepPath); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing PropertyKeyPathToPropertyName() with 'a.[*].*.c.d.[4].e'", result, std::string("a.[*].*.c.d.[4].e")); + } + + void Comparison() + { + mitk::PropertyKeyPath deepPath_noSelection = + mitk::PropertyKeyPath().AddElement("a").AddElement("b").AddElement("c"); + + CPPUNIT_ASSERT(deepPath_noSelection < deepPath); + CPPUNIT_ASSERT(deepPath_noSelection < deepPath_withSelection); + CPPUNIT_ASSERT(deepPath_withSelection < deepPath); + CPPUNIT_ASSERT(deepPath_withSelection < deepPath_withAnySelection); + CPPUNIT_ASSERT(deepPath_withAnyElement < deepPath_noSelection); + + CPPUNIT_ASSERT(!(deepPath_noSelection < deepPath_noSelection)); + CPPUNIT_ASSERT(!(deepPath_noSelection > deepPath_noSelection)); + CPPUNIT_ASSERT(deepPath_noSelection <= deepPath_noSelection); + CPPUNIT_ASSERT(deepPath_noSelection >= deepPath_noSelection); + } + + void ExecutePropertyRegEx() + { + std::regex regEx(mitk::PropertyKeyPathToPropertyRegEx(simplePath)); + std::string result = mitk::PropertyKeyPathToPropertyName(simplePath); + CPPUNIT_ASSERT(std::regex_match(result, regEx)); + regEx = std::regex(mitk::PropertyKeyPathToPropertyRegEx(deepPath)); + result = mitk::PropertyKeyPathToPropertyName(deepPath); + CPPUNIT_ASSERT(std::regex_match(result, regEx)); + + regEx = std::regex(mitk::PropertyKeyPathToPropertyRegEx(deepPath_withAnyElement)); + result = mitk::PropertyKeyPathToPropertyName(deepPath_withAnyElement); + auto position = result.find("*"); + if (std::string::npos != position) + { + result.replace(position, 1, "ConcreteNode1"); + CPPUNIT_ASSERT(std::regex_match(result, regEx)); + } + + regEx = std::regex(mitk::PropertyKeyPathToPropertyRegEx(deepPath_withAnySelection)); + result = mitk::PropertyKeyPathToPropertyName(deepPath_withAnySelection); + position = result.find("[*]"); + if (std::string::npos != position) + { + result.replace(position, 3, "[10]"); + CPPUNIT_ASSERT(std::regex_match(result, regEx)); + } + + regEx = std::regex(mitk::PropertyKeyPathToPropertyRegEx(deepPath_withSelection)); + result = mitk::PropertyKeyPathToPropertyName(deepPath_withSelection); + CPPUNIT_ASSERT(std::regex_match(result, regEx)); + + regEx = std::regex(mitk::PropertyKeyPathToPropertyRegEx(verydeepPath)); + result = mitk::PropertyKeyPathToPropertyName(verydeepPath); + position = result.find("[*]"); + if (std::string::npos != position) + { + result.replace(position, 3, "[1]"); + position = result.find("*"); + if (std::string::npos != position) + { + result.replace(position, 1, "ConcreteNode2"); + CPPUNIT_ASSERT(std::regex_match(result, regEx)); + } + } + } +}; + +MITK_TEST_SUITE_REGISTRATION(mitkPropertyKeyPath) diff --git a/Modules/DICOMReader/include/mitkDICOMTag.h b/Modules/DICOMReader/include/mitkDICOMTag.h index 85ed4bb773..0f0ad330ae 100644 --- a/Modules/DICOMReader/include/mitkDICOMTag.h +++ b/Modules/DICOMReader/include/mitkDICOMTag.h @@ -1,91 +1,90 @@ /*=================================================================== 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 mitkTag_h #define mitkTag_h #include "mitkPoint.h" #include "mitkVector.h" -#include "mitkPoint.h" #include "MitkDICOMReaderExports.h" namespace mitk { /** \ingroup DICOMReaderModule \brief Representation of a DICOM tag. This class is just meant to combine group and element numbers for better readability and make handling tags more easy by offering comparison methods. */ class MITKDICOMREADER_EXPORT DICOMTag { public: DICOMTag(unsigned int group, unsigned int element); DICOMTag(const DICOMTag& other); DICOMTag& operator=(const DICOMTag& other); bool operator==(const DICOMTag& other) const; bool operator<(const DICOMTag& other) const; unsigned int GetGroup() const; unsigned int GetElement() const; /// Return the name of this tag (e.g. "SeriesDescription" instead of "(0008,103e)") std::string GetName() const; /// add "(group-id,element-id) name" to given stream void Print(std::ostream& os) const; private: std::string toHexString(unsigned int i) const; unsigned int m_Group; unsigned int m_Element; }; typedef std::vector DICOMTagList; /** \brief Convert DICOM string describing a point two Vector3D. DICOM tags like ImageOrientationPatient contain two vectors as float numbers separated by backslashes: \verbatim 42.7131\13.77\0.7\137.76\0.3 \endverbatim */ void DICOMStringToOrientationVectors(const std::string& s, Vector3D& right, Vector3D& up, bool& successful); bool DICOMStringToSpacing(const std::string& s, ScalarType& spacingX, ScalarType& spacingY); /** \brief Convert DICOM string describing a point to Point3D. DICOM tags like ImagePositionPatient contain a position as float numbers separated by backslashes: \verbatim 42.7131\13.77\0.7 \endverbatim */ Point3D DICOMStringToPoint3D(const std::string& s, bool& successful); } #endif