/* * * Copyright (C) 2000-2016, OFFIS e.V. * All rights reserved. See COPYRIGHT file for details. * * This software and supporting documentation were developed by * * OFFIS e.V. * R&D Division Health * Escherweg 2 * D-26121 Oldenburg, Germany * * * Module: dcmsr * * Author: Joerg Riesmeier * * Purpose: * classes: DSRDocumentSubTree * */ #ifndef DSRDOCST_H #define DSRDOCST_H #include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */ #include "dcmtk/dcmsr/dsrtree.h" #include "dcmtk/dcmsr/dsrdoctn.h" #include "dcmtk/dcmsr/dsrdncsr.h" #include "dcmtk/dcmsr/dsrcitem.h" #include "dcmtk/ofstd/ofmem.h" /*------------------------* * forward declarations * *------------------------*/ class DSRIODConstraintChecker; class DSRSubTemplate; /*-------------------* * type definition * *-------------------*/ typedef OFshared_ptr DSRSharedSubTemplate; /*--------------------------* * template instantiation * *--------------------------*/ // the following is required in order to help older Clang compilers, // e.g. Clang 3.0 and 3.1 on Mac OS X when building with shared libs #if defined(__clang__) template class DSRTree; #endif /*---------------------* * class declaration * *---------------------*/ /** Class managing a SR document subtree. * A subtree represents an extract of an SR document tree. Compared to the "SR Document * Content Tree" that is defined in the DICOM standard, there are almost no restrictions * regarding the value and relationship types. It is also possible to have multiple nodes * on the top-level, i.e. no dedicated root, or to use "unknown" relationship types. */ class DCMTK_DCMSR_EXPORT DSRDocumentSubTree : public DSRTree { public: /** default constructor */ DSRDocumentSubTree(); /** copy constructor. * Please note that the internal cursor is not copied but reset, i.e. set to the root * node. Also the IOD constraint checker is not copied by this class but recreated * by the derived class DSRDocumentTree (based on the corresponding document type). * This constructor also updates any by-reference relationships, i.e. translates the * references from the source 'tree' (based on the position string) to the IDs of the * newly created nodes. ** @param tree subtree to be copied */ DSRDocumentSubTree(const DSRDocumentSubTree &tree); /** destructor */ virtual ~DSRDocumentSubTree(); /** assignment operator. * Please note that internally the copy constructor is used, so the same comments apply. ** @param tree subtree to be copied ** @return reference to this subtree after copying */ DSRDocumentSubTree &operator=(DSRDocumentSubTree tree); /** clone this subtree. * Internally, the copy constructor is used, so the corresponding comments apply. ** @return copy of this subtree */ virtual DSRDocumentSubTree *clone() const; /** clear internal member variables */ virtual void clear(); /** check whether the current internal state is valid. * A subtree is valid if it is not empty. ** @return OFTrue if valid, OFFalse otherwise */ virtual OFBool isValid() const; /** check whether the internal cursor, which points to the current content item, is valid ** @return OFTrue if cursor is valid, OFFalse otherwise */ virtual OFBool isCursorValid() const; /** check whether this subtree is a valid document tree. * In order to be a valid document tree, there should be a single root node only, with * the value type "CONTAINER", and the internal relationship type of this node should be * DSRTypes::RT_isRoot. ** @param defaultRelType default relationship type that is used if the one of the * top-level node (root node) is "unknown" ** @return OFTrue if subtree is a valid document tree, OFFalse otherwise */ virtual OFBool isValidDocumentTree(const E_RelationshipType defaultRelType = RT_unknown) const; /** check whether this subtree is an expanded document tree. * Expanded means that no instances of DSRIncludedTemplateTreeNode exist in the document * tree, i.e. no templates were included or all of them were replaced by their content * (subtree). ** @return OFTrue if subtree is an expanded document tree, OFFalse otherwise */ virtual OFBool isExpandedDocumentTree() const; /** check whether template identification is set ** @return OFTrue if template identification is set, OFFalse otherwise */ virtual OFBool hasTemplateIdentification() const; /** check whether template identification is possible at all. * According to the DICOM standard, it can be used if "the template consists of a single * CONTAINER with nested content, and it is the outermost invocation of a set of nested * templates that start with the same CONTAINER." * With other words, the tree should have a single root node with value type "CONTAINER". ** @return OFTrue if template identification is possible, OFFalse otherwise */ virtual OFBool canUseTemplateIdentification() const; /** print current SR document tree to specified output stream ** @param stream output stream * @param flags optional flag used to customize the output (see DSRTypes::PF_xxx) * @param posCounter optional pointer to position counter that should be used to * initialize the counter for line indentation or numbering of * nested content items ** @return status, EC_Normal if successful, an error code otherwise */ virtual OFCondition print(STD_NAMESPACE ostream &stream, const size_t flags = 0, const DSRPositionCounter *posCounter = NULL); /** write current SR document tree in XML format ** @param stream output stream to which the XML document is written * @param flags optional flag used to customize the output (see DSRTypes::XF_xxx) ** @return status, EC_Normal if successful, an error code otherwise */ virtual OFCondition writeXML(STD_NAMESPACE ostream &stream, const size_t flags = 0); /** get reference to current content item. * This mechanism allows to access all content items without using pointers. ** @return reference to current content item (might be invalid) */ virtual DSRContentItem &getCurrentContentItem(); /** get read-only access to current node (content item) ** @return pointer to current node (might be NULL) */ virtual const DSRDocumentTreeNode *getCurrentNode() const; /** get a cursor to the root node of this document tree. * This cursor can be used to iterate over the nodes of the document tree without * changing the internal cursor. Please note that the cursor might become invalid, * e.g. by pointing to a non-existing node if the content of the document tree is * modified after the cursor has been retrieved. * Included sub-templates are not supported by this type of cursor, i.e. the subtree * that is managed by an instance of DSRIncludedTemplateTreeNode is not iterated. ** @param cursor reference to variable where the cursor is stored ** @return OFTrue is the returned 'cursor' is valid, OFFalse otherwise */ virtual OFBool getCursorToRootNode(DSRDocumentTreeNodeCursor &cursor) const; /** get a cursor to the root node of this document tree. * This cursor can be used to iterate over the nodes of the document tree without * changing the internal cursor. Please note that the cursor might become invalid, * e.g. by pointing to a non-existing node if the content of the document tree is * modified after the cursor has been retrieved. * This type of cursor also supports included sub-templates, i.e. the subtree that * is managed by an instance of DSRIncludedTemplateTreeNode is also iterated. ** @param cursor reference to variable where the cursor is stored ** @return OFTrue is the returned 'cursor' is valid, OFFalse otherwise */ virtual OFBool getCursorToRootNode(DSRIncludedTemplateNodeCursor &cursor) const; /** count number of content items (nodes) in the document tree. * This method iterates over all nodes that are stored in the document tree. * By default, included sub-templates are counted as a single node (see options). ** @param searchIntoSubTemplates optional flag indicating whether to also * count the content of included sub-templates * (i.e.\ the nodes of the managed subtrees) * @param countIncludedTemplateNodes optional flag indicating whether to count * the DSRIncludedTemplateTreeNode instances * as nodes. See includeTemplate() for details. ** @return number of nodes, 0 if document tree is empty */ size_t countNodes(const OFBool searchIntoSubTemplates = OFFalse, const OFBool countIncludedTemplateNodes = OFTrue) const; /** set internal cursor to a named node. * If more than one node exists with the given concept name, the first one will * be selected. Use gotoNextNamedNode() in order to go to the next matching node. ** @param conceptName concept name of the node to be searched for * @param startFromRoot flag indicating whether to start from the root node * or the current one * @param searchIntoSub flag indicating whether to search into sub-trees * ("deep search") or on the current level only ** @return ID of the new current node if successful, 0 otherwise */ virtual size_t gotoNamedNode(const DSRCodedEntryValue &conceptName, const OFBool startFromRoot = OFTrue, const OFBool searchIntoSub = OFTrue); /** set internal cursor to a named node (starting from the first children of the * current node). * If more than one node exists with the given concept name, the first one will * be selected. Use gotoNextNamedNode() in order to go to the next matching node. ** @param conceptName concept name of the node to be searched for * @param searchIntoSub flag indicating whether to search into sub-trees * ("deep search") or on the current level only ** @return ID of the new current node if successful, 0 otherwise */ virtual size_t gotoNamedChildNode(const DSRCodedEntryValue &conceptName, const OFBool searchIntoSub = OFTrue); /** set internal cursor to the next named node. * Starts from "next" node, i.e. either the first children of the current node * or the first sibling following the current node. ** @param conceptName concept name of the node to be searched for * @param searchIntoSub flag indicating whether to search into sub-trees * ("deep search") or on the current level only ** @return ID of the new current node if successful, 0 otherwise */ virtual size_t gotoNextNamedNode(const DSRCodedEntryValue &conceptName, const OFBool searchIntoSub = OFTrue); /** set internal cursor to an annotated node. * If more than one node exists with the given annotation text, the first one will * be selected. Use gotoNextAnnotatedNode() in order to go to the next matching * node. In contrast to gotoNamedNode(), a "deep search" is always performed. ** @param annotationText annotation text of the node to be searched for * @param startFromRoot flag indicating whether to start from the root node * or the current one ** @return ID of the new current node if successful, 0 otherwise */ virtual size_t gotoAnnotatedNode(const OFString &annotationText, const OFBool startFromRoot = OFTrue); /** set internal cursor to the next annotated node. * Starts from "next" node, i.e. either the first children of the current node * or the first sibling following the current node. ** @param annotationText annotation text of the node to be searched for ** @return ID of the new current node if successful, 0 otherwise */ virtual size_t gotoNextAnnotatedNode(const OFString &annotationText); /** check whether specified content item can be added to the current one. * This method can be used to decide which type of content items can be added prior * to really doing so. Please note that only by-value relationships are supported. * Always returns true if no constraint checker is available but 'relationshipType' * and 'valueType' have valid values. ** @param relationshipType relationship type of node to be checked with regard to * the current one * @param valueType value type of node to be checked * @param addMode flag specifying at which position the new node would * be added (e.g. after or below the current node) ** @return OFTrue if specified node can be added, OFFalse otherwise */ virtual OFBool canAddContentItem(const E_RelationshipType relationshipType, const E_ValueType valueType, const E_AddMode addMode = AM_afterCurrent) const; /** check whether specified by-reference relationship can be added to the current * content item. * Always returns true if no constraint checker is available but 'relationshipType' and * 'targetValueType' have valid values. The value type DSRTypes::VT_includedTemplate is * never allowed for the target content item. ** @param relationshipType type of relationship between current and target node * @param targetValueType value type of the referenced node (target content item) ** @return OFTrue if specified by-reference relationship can be added, OFFalse otherwise */ virtual OFBool canAddByReferenceRelationship(const E_RelationshipType relationshipType, const E_ValueType targetValueType) const; /** add specified content item to the current one. * If possible, this method creates a new node as specified and adds it to the current * one. The method canAddContentItem() is called internally to check parameters first. * If the node could be added successfully, the cursor is set to it automatically. ** @param relationshipType relationship type of node to be added with regard to * the current one * @param valueType value type of node to be added * @param addMode flag specifying at which position to add the new node * (e.g. after or below the current node) ** @return ID of new node if successful, 0 otherwise */ virtual size_t addContentItem(const E_RelationshipType relationshipType, const E_ValueType valueType, const E_AddMode addMode = AM_afterCurrent); /** add specified content item to the current one. * If possible, this method adds a given new node to the current one. The method * canAddContentItem() is called internally to check parameters first. If the * node could be added successfully, the cursor is set to it automatically. * Please note that no copy of the given node is created. Therefore, the node * has to be created with new() or with DSRTypes::createDocumentTreeNode() - do * not use a reference to a local variable and do not delete it a second time. ** @param node pointer to the new node to be added (should not be empty). * Reference remains valid after successful insertion. * @param addMode flag specifying at which position to add the new node * (e.g. after or below the current node) * @param deleteIfFail flag specifying whether to delete the given 'node' if * adding fails. By default, the item is not deleted, i.e. * in case of error it has to be deleted by the caller. ** @return status, EC_Normal if successful, an error code otherwise */ virtual OFCondition addContentItem(DSRDocumentTreeNode *node, const E_AddMode addMode = AM_afterCurrent, const OFBool deleteIfFail = OFFalse); /** add specified content item after the current one. * If possible, this method creates a new node as specified and adds it after the current * one, i.e. on the same level. Internally, the first variant of the addContentItem() * method is called with the third parameter being DSRTypes::AM_afterCurrent. If * successful, the given concept name is set for the new node, and the cursor is updated. * @note This is a convenience function that avoids calling several other functions. ** @param relationshipType relationship type of node to be added with regard * to the current one * @param valueType value type of node to be added * @param conceptName concept name of the node to be added * @param check if enabled, check 'conceptName for validity before setting it ** @return status, EC_Normal if successful, an error code otherwise */ virtual OFCondition addContentItem(const E_RelationshipType relationshipType, const E_ValueType valueType, const DSRCodedEntryValue &conceptName, const OFBool check = OFTrue); /** add specified content item below the current one. * If possible, this method creates a new node as specified and adds it below the current * one, i.e. as a child. Internally, the first variant of the addContentItem() method * is called with the third parameter being DSRTypes::AM_belowCurrent. If successful, * the given concept name is set for the new node, and the cursor is updated. * @note This is a convenience function that avoids calling several other functions. ** @param relationshipType relationship type of node to be added with regard * to the current one * @param valueType value type of node to be added * @param conceptName concept name of the node to be added * @param check if enabled, check 'conceptName for validity before setting it ** @return status, EC_Normal if successful, an error code otherwise */ virtual OFCondition addChildContentItem(const E_RelationshipType relationshipType, const E_ValueType valueType, const DSRCodedEntryValue &conceptName, const OFBool check = OFTrue); /** add specified by-reference relationship to the current content item. * If possible, this method creates a new pseudo-node (relationship) and adds it to the * current one. The method canAddByReferenceRelationship() is called internally to check * parameters first. The internal cursor is automatically re-set to the current node. ** @param relationshipType relationship type between current and referenced node * @param referencedNodeID ID of the referenced node (target content item) ** @return ID of new pseudo-node if successful, 0 otherwise */ virtual size_t addByReferenceRelationship(const E_RelationshipType relationshipType, const size_t referencedNodeID); /** update the position strings used to encode by-reference relationships (if any). * Internally, this method calls checkByReferenceRelationships() with the 'mode' * parameter being DSRTypes::CM_updatePositionString. It should be called before * this subtree is cloned in order to make sure that the by-reference relationships * (if any) still work on the cloned subtree. This method should also be called * before accessing the position string of a referenced content item, see * DSRByReferenceTreeNode::getReferencedContentItem(). ** @param updateIncludedTemplates optional flag indicating whether to also update * the subtrees managed by included sub-templates ** @return status, EC_Normal if successful, an error code otherwise */ virtual OFCondition updateByReferenceRelationships(const OFBool updateIncludedTemplates = OFFalse); /** check whether specified subtree can be inserted at the current position, i.e.\ added * to the current content item. Internally, the method canAddContentItem() is used for * all top-level nodes of the document subtree. In addition, if a constraint checker * is available, the remaining nodes of the given subtree are also checked for their * compliance with the relationship content constraints of the underlying SR IOD. ** @param tree pointer to new subtree to be inserted (should not be empty) * @param addMode flag specifying at which position the new subtree would * be added (e.g. after or below the current node) * @param defaultRelType default relationship type between the top-level nodes of * the given subtree and the current node. This relationship * type is used if the one of a top-level node is "unknown". ** @return OFTrue if specified subtree can be inserted, OFFalse otherwise */ virtual OFBool canInsertSubTree(const DSRDocumentSubTree *tree, const E_AddMode addMode = AM_belowCurrent, const E_RelationshipType defaultRelType = RT_unknown) const; /** insert specified subtree to this tree, i.e.\ add it to the current content item. * If possible, this method adds a given new subtree to the current content item. * The method canInsertSubTree() is called internally to check the parameters first. * Please note that no copy of the given subtree is created. Therefore, the subtree * has to be created with new() or with cloneSubTree() - do not use a reference to a * local variable and do not delete it a second time. ** @param tree pointer to new subtree to be inserted (should not be empty). * Reference becomes invalid after successful insertion! * @param addMode flag specifying at which position to add the new subtree * (e.g. after or below the current node) * @param defaultRelType default relationship type between the top-level nodes of * the given subtree and the current node. This relationship * type is used if the one of a top-level node is "unknown". * @param deleteIfFail flag specifying whether to delete the given 'tree' if * adding fails. By default, the tree is not deleted, i.e. * in case of error it has to be deleted by the caller. ** @return status, EC_Normal if successful, an error code otherwise */ virtual OFCondition insertSubTree(DSRDocumentSubTree *tree, const E_AddMode addMode = AM_belowCurrent, const E_RelationshipType defaultRelType = RT_unknown, const OFBool deleteIfFail = OFFalse); /** extract a subtree i.e.\ a fragment from this tree. * The subtree is specified by the current node, which becomes the root of the subtree. * In contrast to cloneSubTree(), this method also makes sure that the by-reference * relationships are preserved (as long as both source and target node are contained * in the same tree). Please note that the returned subtree has to be deleted by the * caller if it is not inserted into the document tree using insertSubTree(). ** @return pointer to the extracted subtree, NULL in case of error */ virtual DSRDocumentSubTree *extractSubTree(); /** remove current content item from tree. * Please note that not only the specified node but also all of its child nodes are * removed from the tree and then deleted. The internal cursor is set automatically * to a new valid position. ** @return ID of the node which became the current one after deletion, 0 if an error * occurred or the tree is now empty. */ virtual size_t removeCurrentContentItem(); /** remove a subtree from this tree. * The subtree to be removed (and deleted) is either specified by the current node or by * the node with the given ID. Afterwards, the internal cursor is set automatically to * a new valid position. It would be an error to remove a subtree from an empty tree. ** @param searchID ID of the root node specifying the subtree to be removed. * By default (0), the current node is used. ** @return status, EC_Normal if successful, an error code otherwise */ virtual OFCondition removeSubTree(const size_t searchID = 0); /** clone the current tree node. * Internally, the copy constructor of the respective tree node class is used, so the * corresponding comments apply. Please note that the returned tree node has to be * deleted by the caller if it is not added to the document tree using addContentItem(). ** @return pointer to a copy of the current tree node, NULL in case of error */ virtual DSRDocumentTreeNode *cloneCurrentTreeNode() const; /** clone a subtree i.e.\ a fragment of this tree. * The cloning starts with the current node and ends with the given node. * Please note that the returned subtree has to be deleted by the caller if it is not * inserted into the document tree using insertSubTree(). ** @param stopAfterNodeID ID of the node after which the cloning should stop. * By default (0), the process ends after cloning the * current node with all of its child nodes (if any). ** @return pointer to a copy of the specified subtree, NULL in case of error */ virtual DSRDocumentSubTree *cloneSubTree(const size_t stopAfterNodeID = 0) const; /** created an expanded version of this (sub)tree. * Expanded means that no instance of DSRIncludedTemplateTreeNode will exist in the new * document tree, i.e. all of them are replaced by their content (subtree). Please note * that the returned subtree has to be deleted by the caller if it is not inserted into * the document tree using insertSubTree(). ** @param tree variable that will store the pointer to the new subtree ** @return status, EC_Normal if successful, an error code otherwise */ virtual OFCondition createExpandedSubTree(DSRDocumentSubTree *&tree) const; /** compare template identification of the root node with given values. * Please note that the comparison only takes place if there is a single node at the * root of the tree and its value type is CONTAINER. ** @param templateIdentifier template identifier to compare with * @param mappingResource mapping resource that defines the template * @param mappingResourceUID uniquely identifies the mapping resource (optional). * Not used for comparison if the value is empty. ** @result OFTrue if template identification can be compared and the values are * identical, OFFalse otherwise */ virtual OFBool compareTemplateIdentification(const OFString &templateIdentifier, const OFString &mappingResource, const OFString &mappingResourceUID = "") const; /** get template identifier and mapping resource from the root node of this tree. See * DSRDocumentTreeNode::getTemplateIdentification() for details on template identification. * Please note that the template identification is only retrieved if there is a single node * at the root of the tree and its value type is CONTAINER. ** @param templateIdentifier identifier of the template (might be empty) * @param mappingResource mapping resource that defines the template (might be empty) ** @return status, EC_Normal if successful, an error code otherwise */ virtual OFCondition getTemplateIdentification(OFString &templateIdentifier, OFString &mappingResource) const; /** get template identifier, mapping resource and optional mapping resource UID from the * root node of this tree. See DSRDocumentTreeNode::getTemplateIdentification() for * details on template identification. * Please note that the template identification is only retrieved if there is a single node * at the root of the tree and its value type is CONTAINER. ** @param templateIdentifier identifier of the template (might be empty) * @param mappingResource mapping resource that defines the template (might be empty) * @param mappingResourceUID uniquely identifies the mapping resource (might be empty) ** @return status, EC_Normal if successful, an error code otherwise */ virtual OFCondition getTemplateIdentification(OFString &templateIdentifier, OFString &mappingResource, OFString &mappingResourceUID) const; /** set template identifier and mapping resource to the root node of this tree. * The identification is valid if the first two values are either present (non-empty) or * all three values are absent (empty). See DSRDocumentTreeNode::getTemplateIdentification() * for details. * Please note that the template identification is only set if there is a single node at * the root of the tree and its value type is CONTAINER. ** @param templateIdentifier identifier of the template to be set * @param mappingResource mapping resource that defines the template * @param mappingResourceUID uniquely identifies the mapping resource (optional) * @param check check 'templateIdentifier', 'mappingResource' and * 'mappingResourceUID' for conformance with VR (CS,UI) and * VM (1) if enabled ** @return status, EC_Normal if successful, an error code otherwise */ virtual OFCondition setTemplateIdentification(const OFString &templateIdentifier, const OFString &mappingResource, const OFString &mappingResourceUID = "", const OFBool check = OFTrue); protected: /** special constructor that receives a pointer to the root node. * Please note that the 'rootNode' and the associated tree is not copied! ** @param rootNode pointer to the root node of the "new" tree */ DSRDocumentSubTree(DSRDocumentTreeNode *rootNode); /** special copy constructor that clones a particular subtree only ** @param startCursor first node of the subtree to be copied * @param stopAfterNodeID ID of the node after which the cloning should stop */ DSRDocumentSubTree(const DSRDocumentTreeNodeCursor &startCursor, size_t stopAfterNodeID); /** fast, non-throwing swap function. * The time complexity of this function is constant. ** @param tree subtree to swap with */ void swap(DSRDocumentSubTree &tree); /** get pointer to current node. * Hide this inherited method from the public interface. ** @return pointer to current node (might be NULL) */ virtual DSRDocumentTreeNode *getNode() const; /** add new node to the current one. * Please note that no copy of the given node is created. Therefore, the node * has to be created with new() - do not use a reference to a local variable. * If the node could be added successfully, the cursor is set to it automatically. ** @param node pointer to the new node to be added * @param addMode flag specifying at which position to add the new node * (e.g. after or below the current node) ** @return ID of the new node if successful, 0 otherwise */ virtual size_t addNode(DSRDocumentTreeNode *node, const E_AddMode addMode = AM_afterCurrent); /** replace current node by the given one. * Please note that no copy of the given node is created. Therefore, the node * should be created with new() - do not use a reference to a local variable. If * the node could be replaced successfully, the "old" node (and all of its child * nodes) are deleted, and the cursor is set to the new one. ** @param node pointer to the new node to replace the current one ** @return ID of the new node if successful, 0 otherwise */ virtual size_t replaceNode(DSRDocumentTreeNode *node); /** extract current node from tree. * Please note that not only the specified node but also all of its child nodes are * extracted from the tree. The cursor is set automatically to a new valid position. ** @return pointer to extracted node, NULL in case of error (or the tree was empty) */ virtual DSRDocumentTreeNode *extractNode(); /** get pointer to root node and "forget" the internal reference to this node. * In other words: after calling this method, the stored tree will be empty. * This also means that the caller is responsible for deleting the allocated memory. ** @return pointer to root node, might be NULL (empty tree) */ virtual DSRDocumentTreeNode *getAndRemoveRootNode(); /** remove current node from tree. * Please note that not only the specified node but also all of his child nodes are * removed from the tree and deleted afterwards. The cursor is set automatically to * a new valid position. ** @return ID of the node which became the current one after deletion, 0 if an error * occurred or the tree is now empty. */ virtual size_t removeNode(); /** include specified sub-template, i.e.\ add a new DSRIncludedTemplateTreeNode, which * references this template, to the current content item. * Please note that no checks are performed that would make sure that the template * with its top-level nodes can actually be added, e.g. by using an IOD constraint * checker. This is also the reason why this method is "protected" and not "public", * i.e. it can only be used by derived classes, e.g. DSRSubTemplate and its children. ** @param subTemplate shared pointer to a sub-template that should be included * into this tree (at the current position) * @param addMode flag specifying at which position to add the 'subTemplate' * (e.g. after or below the current node) * @param defaultRelType default relationship type that will be used when the * subtree that is managed by the 'subTemplate' is inserted * into this tree and the relationship type of one of the * top-level nodes is "unknown". Also see documentation of * createExpandedSubTree(). ** @return status, EC_Normal if successful, an error code otherwise */ virtual OFCondition includeTemplate(const DSRSharedSubTemplate &subTemplate, const E_AddMode addMode = AM_belowCurrent, const E_RelationshipType defaultRelType = RT_unknown); /** expand all "included template" content items in a given (sub)tree. * Expanding means that all instances of DSRIncludedTemplateTreeNode are replaced by * their content (subtree). * Please note that the internal cursor of the given 'tree' is set to the root node * if no error occurred. Otherwise, the cursor points to the content item that * caused the problem. ** @param tree pointer to the subtree that should be expanded ** @return status, EC_Normal if successful, an error code otherwise */ virtual OFCondition expandIncludedTemplates(DSRDocumentSubTree *tree) const; /** check the by-reference relationships (if any) for validity. * This function checks whether all by-reference relationships possibly contained * in the document tree are valid according to the following restrictions: source * and target node are not identical and the target node is not an ancestor of the * source node (requirement from the DICOM standard to prevent loops -> directed * acyclic graph, though this is not 100% true - see "reportlp.dcm" example). * In addition, the position strings (used to encode by-reference relationships * according to the DICOM standard) OR the node IDs (used internally to uniquely * identify nodes) can be updated. * Please note that the checking modes DSRTypes::CM_updatePositionString and * DSRTypes::CM_updateNodeID are mutually exclusive. ** @tparam T_Cursor template type used for the cursor iterating the document (sub)tree ** @param mode mode used to customize the checking process (see DSRTypes::CM_xxx) * @param flags flag used to customize the reading (see DSRTypes::RF_xxx) and/or * printing process (see DSRTypes::PF_xxx). Conflicting definitions * are avoided using the appropriate bit mask (see DSRTypes::CB_xxx). ** @return status, EC_Normal if successful, an error code otherwise */ template OFCondition checkByReferenceRelationships(const size_t mode = 0, const size_t flags = 0); /** reset flag for all content items whether they are target of a by-reference relationship. * This function calls 'setReferenceTarget(OFFalse)' for all content items in the tree. */ virtual void resetReferenceTargetFlag(); /** update the tree for subsequent output, e.g.\ for being printed or added to an SR * document. By default, this virtual function does nothing but is called automatically * by the affected output methods and should be overwritten in derived classes. */ virtual void updateTreeForOutput(); /** check whether the given subtree complies with the constraints of the given checker ** @param tree pointer to subtree that should be checked * @param checker pointer to relationship content constraints checker to be used. * If NULL, no checks are performed by this method. ** @return status, EC_Normal if successful, an error code otherwise */ virtual OFCondition checkSubTreeConstraints(const DSRDocumentSubTree *tree, const DSRIODConstraintChecker *checker) const; /// check relationship content constraints of the associated IOD DSRIODConstraintChecker *ConstraintChecker; private: /// current content item. Introduced to avoid the external use of pointers. DSRContentItem CurrentContentItem; }; #endif