diff options
-rw-r--r-- | src/core/model/Document.cpp | 53 | ||||
-rw-r--r-- | src/core/model/Document.hpp | 208 | ||||
-rw-r--r-- | src/core/model/Node.cpp | 5 | ||||
-rw-r--r-- | src/core/model/Node.hpp | 4 | ||||
-rw-r--r-- | test/core/model/DocumentTest.cpp | 36 |
5 files changed, 179 insertions, 127 deletions
diff --git a/src/core/model/Document.cpp b/src/core/model/Document.cpp index a6bcb15..a329392 100644 --- a/src/core/model/Document.cpp +++ b/src/core/model/Document.cpp @@ -92,25 +92,19 @@ int DocumentEntity::getFieldDescriptorIndex( } } -void DocumentEntity::addStructureNode(Handle<StructureNode> s, - const std::string &fieldName) +void DocumentEntity::invalidateSubInstance() { if (subInst->isa(RttiTypes::StructuredEntity)) { - const StructuredEntity *s = - static_cast<const StructuredEntity *>(subInst); - s->invalidate(); + subInst.cast<StructuredEntity>()->invalidate(); } else { - const AnnotationEntity *a = - static_cast<const AnnotationEntity *>(subInst); - a->invalidate(); + subInst.cast<AnnotationEntity>()->invalidate(); } - fields[getFieldDescriptorIndex(fieldName, true)].push_back(s); } DocumentEntity::DocumentEntity(Handle<Node> subInst, Handle<Descriptor> descriptor, Variant attributes) - : subInst(subInst.get()), + : subInst(subInst), descriptor(subInst->acquire(descriptor)), attributes(std::move(attributes)) { @@ -296,6 +290,45 @@ bool DocumentEntity::doValidate(Logger &logger) const return valid; } +void DocumentEntity::setAttributes(const Variant &a) +{ + invalidateSubInstance(); + attributes = a; +} + +void DocumentEntity::addStructureNode(Handle<StructureNode> s, + const std::string &fieldName) +{ + invalidateSubInstance(); + fields[getFieldDescriptorIndex(fieldName, true)].push_back(s); +} + +void DocumentEntity::addStructureNodes( + const std::vector<Handle<StructureNode>> &ss, const std::string &fieldName) +{ + invalidateSubInstance(); + NodeVector<StructureNode> &field = + fields[getFieldDescriptorIndex(fieldName, true)]; + field.insert(field.end(), ss.begin(), ss.end()); +} + +void DocumentEntity::addStructureNode(Handle<StructureNode> s, + Handle<FieldDescriptor> fieldDescriptor) +{ + invalidateSubInstance(); + fields[getFieldDescriptorIndex(fieldDescriptor, true)].push_back(s); +} + +void DocumentEntity::addStructureNodes( + const std::vector<Handle<StructureNode>> &ss, + Handle<FieldDescriptor> fieldDescriptor) +{ + invalidateSubInstance(); + NodeVector<StructureNode> &field = + fields[getFieldDescriptorIndex(fieldDescriptor, true)]; + field.insert(field.end(), ss.begin(), ss.end()); +} + /* Class StructureNode */ StructureNode::StructureNode(Manager &mgr, std::string name, diff --git a/src/core/model/Document.hpp b/src/core/model/Document.hpp index 62109fc..d89ade8 100644 --- a/src/core/model/Document.hpp +++ b/src/core/model/Document.hpp @@ -144,12 +144,14 @@ class DocumentEntity { private: /* * this is a rather dirty method that should not be used in other cases: - * We store a pointer to the Node instance that inherits from - * DocumentEntity. + * We store a handle to the Node instance that inherits from + * DocumentEntity. This Handle is not registered and would lead to Segfaults + * if we could not garantuee that it lives exactly as long as this + * DocumentEntity because the handle is for the subclass instance. */ - const Node *subInst; + Handle<Node> subInst; Owned<Descriptor> descriptor; - const Variant attributes; + Variant attributes; std::vector<NodeVector<StructureNode>> fields; int getFieldDescriptorIndex(const std::string &fieldName, @@ -158,10 +160,9 @@ private: int getFieldDescriptorIndex(Handle<FieldDescriptor> fieldDescriptor, bool enforce) const; -protected: - void addStructureNode(Handle<StructureNode> s, - const std::string &fieldName = ""); + void invalidateSubInstance(); +protected: bool doValidate(Logger &logger) const; public: @@ -198,6 +199,15 @@ public: Variant getAttributes() const { return attributes; } /** + * Sets the attributes for this DocumentEntity. Attributes are set as a Map + * variant. + * + * @param a is a Map variant containing the attributes for this + * DocumentEntity. + */ + void setAttributes(const Variant &a); + + /** * This returns true if there is a FieldDescriptor in the Descriptor for * this DocumentEntity which has the given name. If an empty name is * given it is assumed that the 'default' FieldDescriptor is referenced, @@ -207,7 +217,7 @@ public: * * @param fieldName is the name of a field as specified in the * FieldDescriptor in the Domain description. - * @return true if this FieldDescriptor exists. + * @return true if this FieldDescriptor exists. */ bool hasField(const std::string &fieldName = "") const { @@ -225,7 +235,7 @@ public: * * @param fieldName is the name of a field as specified in the * FieldDescriptor in the Domain description. - * @return a NodeVector of all StructuredEntities in that field. + * @return a NodeVector of all StructuredEntities in that field. */ const NodeVector<StructureNode> &getField( const std::string &fieldName = "") const @@ -242,7 +252,8 @@ public: * * @param fieldDescriptor is a FieldDescriptor defined in the Descriptor for * this DocumentEntity. - * @return a NodeVector of all StructuredEntities in that field. + * @return a NodeVector of all StructuredEntities in that + * field. */ const NodeVector<StructureNode> &getField( Handle<FieldDescriptor> fieldDescriptor) const @@ -250,84 +261,63 @@ public: return fields[getFieldDescriptorIndex(fieldDescriptor, true)]; } - // TODO: Change this to move methods. - // /** - // * This adds a StructureNode to the field with the given name. If an - // * empty name is given it is assumed that the 'default' FieldDescriptor - // is - // * referenced, where 'default' means either: - // * 1.) The only TREE typed FieldDescriptor (if present) or - // * 2.) the only FieldDescriptor (if only one is specified). - // * - // * If the name is unknown an exception is thrown. - // * - // * @param s is the StructureNode that shall be added. - // * @param fieldName is the name of a field as specified in the - // * FieldDescriptor in the Domain description. - // */ - // void addStructureNode(Handle<StructureNode> s, - // const std::string &fieldName = "") - // { - // fields[getFieldDescriptorIndex(fieldName, true)].push_back(s); - // } - // /** - // * This adds multiple StructureNodes to the field with the given name. - // * If an empty name is given it is assumed that the 'default' - // * FieldDescriptor is referenced, where 'default' means either: - // * 1.) The only TREE typed FieldDescriptor (if present) or - // * 2.) the only FieldDescriptor (if only one is specified). - // * - // * If the name is unknown an exception is thrown. - // * - // * @param ss are the StructureNodes that shall be added. - // * @param fieldName is the name of a field as specified in the - // * FieldDescriptor in the Domain description. - // */ - // void addStructureNodes(const std::vector<Handle<StructureNode>> &ss, - // const std::string &fieldName = "") - // { - // NodeVector<StructureNode> &field = - // fields[getFieldDescriptorIndex(fieldName, true)]; - // field.insert(field.end(), ss.begin(), ss.end()); - // } - - // /** - // * This adds a StructureNode to the field with the given - // FieldDescriptor. - // * - // * If the FieldDescriptor does not belong to the Descriptor of this node - // * an exception is thrown. - // * - // * @param s is the StructureNode that shall be added. - // * @param fieldDescriptor is a FieldDescriptor defined in the Descriptor - // for - // * this DocumentEntity. - // */ - // void addStructureNode(Handle<StructureNode> s, - // Handle<FieldDescriptor> fieldDescriptor) - // { - // fields[getFieldDescriptorIndex(fieldDescriptor, true)].push_back(s); - // } - - // /** - // * This adds multiple StructureNodes to the field with the given - // * FieldDescriptor. - // * - // * If the FieldDescriptor does not belong to the Descriptor of this node - // * an exception is thrown. - // * - // * @param ss are the StructureNodes that shall be added. - // * @param fieldDescriptor is a FieldDescriptor defined in the Descriptor - // for - // * this DocumentEntity. - // */ - // void addStructureNodes(const std::vector<Handle<StructureNode>> &ss, - // Handle<FieldDescriptor> fieldDescriptor) - // { - // NodeVector<StructureNode> &field = - // fields[getFieldDescriptorIndex(fieldDescriptor, true)]; - // field.insert(field.end(), ss.begin(), ss.end()); - // } + /** + * This adds a StructureNode to the field with the given name. If an + * empty name is given it is assumed that the 'default' FieldDescriptor is + * referenced, where 'default' means either: + * 1.) The only TREE typed FieldDescriptor (if present) or + * 2.) the only FieldDescriptor (if only one is specified). + * + * If the name is unknown an exception is thrown. + * + * @param s is the StructureNode that shall be added. + * @param fieldName is the name of a field as specified in the + * FieldDescriptor in the Domain description. + */ + void addStructureNode(Handle<StructureNode> s, + const std::string &fieldName = ""); + /** + * This adds multiple StructureNodes to the field with the given name. + * If an empty name is given it is assumed that the 'default' + * FieldDescriptor is referenced, where 'default' means either: + * 1.) The only TREE typed FieldDescriptor (if present) or + * 2.) the only FieldDescriptor (if only one is specified). + * + * If the name is unknown an exception is thrown. + * + * @param ss are the StructureNodes that shall be added. + * @param fieldName is the name of a field as specified in the + * FieldDescriptor in the Domain description. + */ + void addStructureNodes(const std::vector<Handle<StructureNode>> &ss, + const std::string &fieldName = ""); + + /** + * This adds a StructureNode to the field with the given FieldDescriptor. + * + * If the FieldDescriptor does not belong to the Descriptor of this node + * an exception is thrown. + * + * @param s is the StructureNode that shall be added. + * @param fieldDescriptor is a FieldDescriptor defined in the Descriptor for + * this DocumentEntity. + */ + void addStructureNode(Handle<StructureNode> s, + Handle<FieldDescriptor> fieldDescriptor); + + /** + * This adds multiple StructureNodes to the field with the given + * FieldDescriptor. + * + * If the FieldDescriptor does not belong to the Descriptor of this node + * an exception is thrown. + * + * @param ss are the StructureNodes that shall be added. + * @param fieldDescriptor is a FieldDescriptor defined in the Descriptor for + * this DocumentEntity. + */ + void addStructureNodes(const std::vector<Handle<StructureNode>> &ss, + Handle<FieldDescriptor> fieldDescriptor); }; /** @@ -432,7 +422,7 @@ public: * where this DocumentPrimitive shall be added. It is empty * per default, referring to the default field. */ - DocumentPrimitive(Manager &mgr, Handle<Node> parent, Variant content, + DocumentPrimitive(Manager &mgr, Handle<Node> parent, Variant content = {}, const std::string &fieldName = "") : StructureNode(mgr, "", parent, fieldName), content(content) { @@ -444,6 +434,17 @@ public: * @return the content of this DocumentPrimitive. */ Variant getContent() const { return content; } + + /** + * Sets the content of this DocumentPrimitive to the given Variant. + * + * @param c is the new content of this DocumentPrimitive. + */ + void setContent(const Variant &c) + { + invalidate(); + content = c; + } }; /** @@ -527,8 +528,9 @@ public: * used for references later on. It is empty per default. */ AnnotationEntity(Manager &mgr, Handle<Document> parent, - Handle<AnnotationClass> descriptor, Handle<Anchor> start, - Handle<Anchor> end, Variant attributes = {}, + Handle<AnnotationClass> descriptor, + Handle<Anchor> start = nullptr, + Handle<Anchor> end = nullptr, Variant attributes = {}, std::string name = ""); /** @@ -544,6 +546,27 @@ public: * @return the end Anchor of this AnnotationEntity. */ Rooted<Anchor> getEnd() const { return end; } + + /** + * Sets the start Anchor of this AnnotationEntity. + * + * @param s is the new start Anchor for this AnnotationEntity. + */ + void setStart(Handle<Anchor> s) + { + invalidate(); + start = acquire(s); + } + + /** + * Sets the end Anchor of this AnnotationEntity. + * + * @param e is the new end Anchor for this AnnotationEntity. + */ + void setEnd(Handle<Anchor> e) + { + end = acquire(e); + } }; /** @@ -567,8 +590,7 @@ protected: public: Document(Manager &mgr, std::string name) - : Node(mgr, std::move(name), nullptr), - annotations(this) + : Node(mgr, std::move(name), nullptr), annotations(this) { } diff --git a/src/core/model/Node.cpp b/src/core/model/Node.cpp index c4892af..5867fa3 100644 --- a/src/core/model/Node.cpp +++ b/src/core/model/Node.cpp @@ -227,6 +227,7 @@ std::vector<std::string> ResolutionResult::path() const void Node::setName(std::string name) { + invalidate(); // Call the name change event and (afterwards!) set the new name NameChangeEvent ev{this->name, name}; triggerEvent(ev); @@ -380,7 +381,7 @@ bool Node::validateName(Logger &logger) const return true; } -void Node::invalidate() const +void Node::invalidate() { // Only perform the invalidation if necessary if (validationState != ValidationState::UNKNOWN) { @@ -391,7 +392,7 @@ void Node::invalidate() const } } -void Node::markInvalid() const +void Node::markInvalid() { // Do not override the validationState if we're currently in the validation // procedure, try to mark the parent node as invalid diff --git a/src/core/model/Node.hpp b/src/core/model/Node.hpp index 190e8de..3e778a6 100644 --- a/src/core/model/Node.hpp +++ b/src/core/model/Node.hpp @@ -319,12 +319,12 @@ protected: * changed such that a new validation run has to be made. Also informs the * parent node about the invalidation. */ - void invalidate() const; + void invalidate(); /** * This method should be called if a Node finds itself in an invalid state. */ - void markInvalid() const; + void markInvalid(); /** * The convention for this function is as follows: diff --git a/test/core/model/DocumentTest.cpp b/test/core/model/DocumentTest.cpp index fea5296..874fba7 100644 --- a/test/core/model/DocumentTest.cpp +++ b/test/core/model/DocumentTest.cpp @@ -229,10 +229,18 @@ TEST(Document, validate) doc->addDomain(domain); Rooted<StructuredEntity> root = buildRootStructuredEntity(doc, logger, {"root"}); - buildStructuredEntity(doc, logger, root, {"childSub"}); + Rooted<StructuredEntity> child = + buildStructuredEntity(doc, logger, root, {"childSub"}); ASSERT_FALSE(doc->validate(logger)); + // if we add a DocumentPrimitive with the wrong content it should not + // work either. + Rooted<DocumentPrimitive> primitive{ + new DocumentPrimitive(mgr, child, {"ololol"}, "int")}; + //TODO: ASSERT_FALSE(doc->validate(logger)); + // but if we set the content right, it should work. + primitive->setContent({2}); + ASSERT_TRUE(doc->validate(logger)); } - // TODO: Check wrongly typed primitive content. // Now add an Annotation class to the domain. Rooted<AnnotationClass> annoClass{new AnnotationClass(mgr, "anno", domain)}; @@ -244,23 +252,6 @@ TEST(Document, validate) doc->addDomain(domain); Rooted<StructuredEntity> root = buildRootStructuredEntity(doc, logger, {"root"}); - Rooted<StructuredEntity> child = - buildStructuredEntity(doc, logger, root, {"childSub"}); - Rooted<DocumentPrimitive> primitive{ - new DocumentPrimitive(mgr, child, {2}, "int")}; - ASSERT_TRUE(doc->validate(logger)); - // then add an AnnotationEntity without Anchors. - buildAnnotationEntity(doc, logger, {"anno"}, nullptr, nullptr); - ASSERT_FALSE(doc->validate(logger)); - } - { - /* - * Do the same again, but with a valid AnnotationEntity now. - */ - Rooted<Document> doc{new Document(mgr, "myDoc.oxd")}; - doc->addDomain(domain); - Rooted<StructuredEntity> root = - buildRootStructuredEntity(doc, logger, {"root"}); Rooted<Anchor> start{new Anchor(mgr, "start", root)}; Rooted<StructuredEntity> child = buildStructuredEntity(doc, logger, root, {"childSub"}); @@ -269,7 +260,12 @@ TEST(Document, validate) Rooted<Anchor> end{new Anchor(mgr, "end", root)}; ASSERT_TRUE(doc->validate(logger)); // then add an AnnotationEntity without Anchors. - buildAnnotationEntity(doc, logger, {"anno"}, start, end); + Rooted<AnnotationEntity> anno = + buildAnnotationEntity(doc, logger, {"anno"}, nullptr, nullptr); + ASSERT_FALSE(doc->validate(logger)); + // but it should be valid again if we set the start end and Anchor. + anno->setStart(start); + anno->setEnd(end); ASSERT_TRUE(doc->validate(logger)); } } |