From 51de9238ddbd6b7f4cdaa5e9a5918cae952891b2 Mon Sep 17 00:00:00 2001 From: Benjamin Paassen Date: Mon, 12 Jan 2015 15:50:10 +0100 Subject: Tried to introduce another StructureNode class as common superclass for StructuredEntity, Anchor and DocumentPrimitive. Nearly seems to work, but not entirely so. There are still issues with the Manager it seems. --- src/core/managed/Managed.hpp | 2 +- src/core/model/Document.cpp | 8 ++-- src/core/model/Document.hpp | 73 ++++++++++++++++++++++----------- src/plugins/html/DemoOutput.cpp | 38 ++++++++++------- test/core/model/DocumentTest.cpp | 20 +++++---- test/core/model/TestDocumentBuilder.hpp | 2 +- test/plugins/html/DemoOutputTest.cpp | 2 +- 7 files changed, 93 insertions(+), 52 deletions(-) diff --git a/src/core/managed/Managed.hpp b/src/core/managed/Managed.hpp index 8ad609f..dd1a23a 100644 --- a/src/core/managed/Managed.hpp +++ b/src/core/managed/Managed.hpp @@ -357,7 +357,7 @@ public: * Statically casts the handle to a handle of the given type. */ template - Handle cast() + Handle cast() const { return Handle(static_cast(ptr)); } diff --git a/src/core/model/Document.cpp b/src/core/model/Document.cpp index f591095..723aafd 100644 --- a/src/core/model/Document.cpp +++ b/src/core/model/Document.cpp @@ -111,13 +111,15 @@ const Rtti Document = const Rtti AnnotationEntity = RttiBuilder("AnnotationEntity").parent(&DocumentEntity).composedOf( &StructuredEntity); +const Rtti StructureNode = + RttiBuilder("StructureNode").parent(&Node); const Rtti StructuredEntity = - RttiBuilder("StructuredEntity").parent(&DocumentEntity).composedOf( + RttiBuilder("StructuredEntity").parent(&DocumentEntity).parent(&StructureNode).composedOf( {&StructuredEntity, &Anchor, &DocumentPrimitive}); const Rtti DocumentPrimitive = - RttiBuilder("DocumentPrimitive").parent(&StructuredEntity); + RttiBuilder("DocumentPrimitive").parent(&StructureNode); const Rtti Anchor = - RttiBuilder("Anchor").parent(&StructuredEntity); + RttiBuilder("Anchor").parent(&StructureNode); } } diff --git a/src/core/model/Document.hpp b/src/core/model/Document.hpp index 6e3b320..9bf8f07 100644 --- a/src/core/model/Document.hpp +++ b/src/core/model/Document.hpp @@ -124,9 +124,8 @@ class Rtti; namespace model { -class StructuredEntity; -class AnnotationEntity; class Document; +class StructureNode; /** * A DocumentEntity is the common superclass for StructuredEntities and @@ -139,11 +138,11 @@ class Document; * name. * */ -class DocumentEntity : public Node { +class DocumentEntity : public virtual Node { private: Owned descriptor; const Variant attributes; - std::vector> fields; + std::vector> fields; int getFieldDescriptorIndex(const std::string &fieldName, bool enforce) const; @@ -164,10 +163,12 @@ public: if (!descriptor.isNull()) { for (size_t f = 0; f < descriptor->getFieldDescriptors().size(); f++) { - fields.push_back(NodeVector(this)); + fields.push_back(NodeVector(this)); } } } + //TODO: Is this necessary? + virtual ~DocumentEntity() {}; Rooted getDescriptor() const { return descriptor; } @@ -203,7 +204,7 @@ public: * FieldDescriptor in the Domain description. * @return a NodeVector of all StructuredEntities in that field. */ - const NodeVector &getField( + const NodeVector &getField( const std::string &fieldName = "") const { return fields[getFieldDescriptorIndex(fieldName, true)]; @@ -220,7 +221,7 @@ public: * this DocumentEntity. * @return a NodeVector of all StructuredEntities in that field. */ - const NodeVector &getField( + const NodeVector &getField( Handle fieldDescriptor) const { return fields[getFieldDescriptorIndex(fieldDescriptor, true)]; @@ -238,7 +239,7 @@ public: * @param fieldName is the name of a field as specified in the * FieldDescriptor in the Domain description. */ - void addStructuredEntity(Handle s, + void addStructuredEntity(Handle s, const std::string &fieldName = "") { fields[getFieldDescriptorIndex(fieldName, true)].push_back(s); @@ -256,10 +257,10 @@ public: * @param fieldName is the name of a field as specified in the * FieldDescriptor in the Domain description. */ - void addStructuredEntities(const std::vector> &ss, + void addStructuredEntities(const std::vector> &ss, const std::string &fieldName = "") { - NodeVector &field = + NodeVector &field = fields[getFieldDescriptorIndex(fieldName, true)]; field.insert(field.end(), ss.begin(), ss.end()); } @@ -274,7 +275,7 @@ public: * @param fieldDescriptor is a FieldDescriptor defined in the Descriptor for * this DocumentEntity. */ - void addStructuredEntity(Handle s, + void addStructuredEntity(Handle s, Handle fieldDescriptor) { fields[getFieldDescriptorIndex(fieldDescriptor, true)].push_back(s); @@ -291,26 +292,42 @@ public: * @param fieldDescriptor is a FieldDescriptor defined in the Descriptor for * this DocumentEntity. */ - void addStructuredEntities(const std::vector> &ss, + void addStructuredEntities(const std::vector> &ss, Handle fieldDescriptor) { - NodeVector &field = + NodeVector &field = fields[getFieldDescriptorIndex(fieldDescriptor, true)]; field.insert(field.end(), ss.begin(), ss.end()); } }; /** - * A StructuredEntity is a node in the Structure Tree of a document. For more + * A StructureNode is a Node of the StructureTree of the document. This is a + * common superclass for StructuredEntity, Anchor and DocumentPrimitive. + */ +class StructureNode : public virtual Node { +public: + StructureNode(Manager &mgr, std::string name, Handle parent) + : Node(mgr, std::move(name), parent) + { + } + //TODO: Is this necessary? + virtual ~StructureNode(){}; +}; + +/** + * A StructuredEntity is an instance of a StructuredClass. For more * information please refer to the header documentation above. */ -class StructuredEntity : public DocumentEntity { +class StructuredEntity : public DocumentEntity, public StructureNode { public: StructuredEntity(Manager &mgr, Handle parent, Handle descriptor, Variant attributes, std::string name = "") - : DocumentEntity(mgr, parent, descriptor, std::move(attributes), - std::move(name)) + : Node(mgr, std::move(name), parent), + DocumentEntity(mgr, parent, descriptor, std::move(attributes), + std::move(name)), + StructureNode(mgr, std::move(name), parent) { } }; @@ -320,15 +337,20 @@ public: * The most straightforward example for this is the actual document text, e.g. * inside a paragraph. In that case this would represent a mere string. */ -class DocumentPrimitive : public StructuredEntity { +class DocumentPrimitive : public StructureNode { +private: + Variant content; + public: DocumentPrimitive(Manager &mgr, Handle parent, Variant content = {}) - : StructuredEntity(mgr, parent, nullptr, std::move(content)) + : Node(mgr, parent), + StructureNode(mgr, "", parent), + content(content) { } - Variant getContent() const { return getAttributes(); } + Variant getContent() const { return content; } // TODO: Override such methods like "getField" to disable them? }; @@ -361,7 +383,7 @@ public: * referenced by an AnnotationEntity as it start and end point. * Please refer to the AnnotationEntity documentation for more information. */ - class Anchor : public StructuredEntity { + class Anchor : public StructureNode { public: /** * @param mgr is the Manager instance. @@ -369,8 +391,9 @@ public: * not the AnnotationEntity that references this Anchor. * @param name is the Anchor id. */ - Anchor(Manager &mgr, Handle parent, std::string name) - : StructuredEntity(mgr, parent, nullptr, Variant(), std::move(name)) + Anchor(Manager &mgr, std::string name, Handle parent) + : Node(mgr, std::move(name), parent), + StructureNode(mgr, std::move(name), parent) { } }; @@ -399,7 +422,8 @@ public: Handle descriptor, Handle start, Handle end, Variant attributes = {}, std::string name = "") - : DocumentEntity(mgr, parent, descriptor, attributes, std::move(name)), + : Node(mgr, std::move(name), parent), + DocumentEntity(mgr, parent, descriptor, attributes, std::move(name)), start(acquire(start)), end(acquire(end)) { @@ -509,6 +533,7 @@ namespace RttiTypes { extern const Rtti Document; extern const Rtti DocumentEntity; extern const Rtti AnnotationEntity; +extern const Rtti StructureNode; extern const Rtti StructuredEntity; extern const Rtti DocumentPrimitive; extern const Rtti Anchor; diff --git a/src/plugins/html/DemoOutput.cpp b/src/plugins/html/DemoOutput.cpp index 4cadf12..7dc1660 100644 --- a/src/plugins/html/DemoOutput.cpp +++ b/src/plugins/html/DemoOutput.cpp @@ -33,8 +33,7 @@ void DemoHTMLTransformer::writeHTML(Handle doc, { Manager &mgr = doc->getManager(); // Create an XML object tree for the document first. - Rooted html{new xml::Element{ - mgr, {nullptr}, "html"}}; + Rooted html{new xml::Element{mgr, {nullptr}, "html"}}; // add the head Element Rooted head{new xml::Element{mgr, html, "head"}}; html->addChild(head); @@ -117,8 +116,8 @@ Rooted DemoHTMLTransformer::transformSection( // check if we have a heading. if (section->hasField("heading") && section->getField("heading").size() > 0) { - Rooted heading = - section->getField("heading")[0]; + Handle heading = + section->getField("heading")[0].cast(); std::string headingclass; switch (type) { case SectionType::BOOK: @@ -147,8 +146,11 @@ Rooted DemoHTMLTransformer::transformSection( } // Then we get all the children. - NodeVector mainField = section->getField(); - for (auto &n : mainField) { + for (auto &n : section->getField()) { + if (!n->isa(RttiTypes::StructuredEntity)) { + continue; + } + Handle s = n.cast(); /* * Strictly speaking this is the wrong mechanism, because we would have * to make an "isa" call here because we can not rely on our knowledge @@ -156,14 +158,14 @@ Rooted DemoHTMLTransformer::transformSection( * to be a listener structure of transformations that check if they can * transform this specific node. */ - const std::string childDescriptorName = n->getDescriptor()->getName(); + const std::string childDescriptorName = s->getDescriptor()->getName(); Rooted child; if (childDescriptorName == "paragraph") { - child = transformParagraph(sec, n, startMap, endMap); + child = transformParagraph(sec, s, startMap, endMap); } else if (childDescriptorName == "ul" || childDescriptorName == "ol") { - child = transformList(sec, n, startMap, endMap); + child = transformList(sec, s, startMap, endMap); } else { - child = transformSection(sec, n, startMap, endMap); + child = transformSection(sec, s, startMap, endMap); } if (!child.isNull()) { sec->addChild(child); @@ -181,7 +183,9 @@ Rooted DemoHTMLTransformer::transformList( std::string listclass = list->getDescriptor()->getName(); Rooted l{new xml::Element{mgr, parent, listclass}}; // iterate through list items. - for (auto &item : list->getField()) { + for (auto &it : list->getField()) { + Handle item = + it.cast(); std::string itDescrName = item->getDescriptor()->getName(); if (itDescrName == "item") { // create the list item. @@ -259,7 +263,8 @@ Rooted DemoHTMLTransformer::transformParagraph( // check if we have a heading. if (par->hasField("heading") && par->getField("heading").size() > 0) { - Rooted heading = par->getField("heading")[0]; + Handle heading = + par->getField("heading")[0].cast(); // put the heading in a strong xml::Element. Rooted strong{new xml::Element{mgr, p, "strong"}}; p->addChild(strong); @@ -334,10 +339,15 @@ Rooted DemoHTMLTransformer::transformParagraph( continue; } // if this is not an anchor, we can only handle text. - std::string childDescriptorName = n->getDescriptor()->getName(); + if(!n->isa(RttiTypes::StructuredEntity)){ + continue; + } + Handle t = n.cast(); + + std::string childDescriptorName = t->getDescriptor()->getName(); if (childDescriptorName == "text") { Handle primitive = - n->getField()[0].cast(); + t->getField()[0].cast(); if (primitive.isNull()) { throw OusiaException("Text field is not primitive!"); } diff --git a/test/core/model/DocumentTest.cpp b/test/core/model/DocumentTest.cpp index d11bb78..4b0447d 100644 --- a/test/core/model/DocumentTest.cpp +++ b/test/core/model/DocumentTest.cpp @@ -34,7 +34,7 @@ namespace model { TEST(Document, testDocumentConstruction) { // Construct Manager - TerminalLogger logger {std::cerr, true}; + TerminalLogger logger{std::cerr, true}; Manager mgr{1}; Rooted sys{new SystemTypesystem(mgr)}; // Get the domain. @@ -52,7 +52,8 @@ TEST(Document, testDocumentConstruction) ASSERT_EQ(2U, root->getField().size()); // get foreword (paragraph) { - Rooted foreword = root->getField()[0]; + Rooted foreword = + root->getField()[0].cast(); ASSERT_FALSE(foreword.isNull()); ASSERT_EQ("paragraph", foreword->getDescriptor()->getName()); // it should contain one text node @@ -61,7 +62,8 @@ TEST(Document, testDocumentConstruction) // which in turn should have a primitive content field containing the // right text. { - Rooted text = foreword->getField()[0]; + Rooted text = + foreword->getField()[0].cast(); ASSERT_FALSE(text.isNull()); ASSERT_EQ("text", text->getDescriptor()->getName()); ASSERT_TRUE(text->hasField()); @@ -74,24 +76,26 @@ TEST(Document, testDocumentConstruction) } // get section { - Rooted section = root->getField()[1]; + Rooted section = + root->getField()[1].cast(); ASSERT_FALSE(section.isNull()); ASSERT_EQ("section", section->getDescriptor()->getName()); // it should contain one paragraph ASSERT_TRUE(section->hasField()); ASSERT_EQ(1U, section->getField().size()); { - Rooted par = section->getField()[0]; + Rooted par = + section->getField()[0].cast(); ASSERT_FALSE(par.isNull()); ASSERT_EQ("paragraph", par->getDescriptor()->getName()); // it should contain one text node ASSERT_TRUE(par->hasField()); ASSERT_EQ(1U, par->getField().size()); // which in turn should have a primitive content field containing - // the - // right text. + // the right text. { - Rooted text = par->getField()[0]; + Rooted text = + par->getField()[0].cast(); ASSERT_FALSE(text.isNull()); ASSERT_EQ("text", text->getDescriptor()->getName()); ASSERT_TRUE(text->hasField()); diff --git a/test/core/model/TestDocumentBuilder.hpp b/test/core/model/TestDocumentBuilder.hpp index 4662a28..a1c8dde 100644 --- a/test/core/model/TestDocumentBuilder.hpp +++ b/test/core/model/TestDocumentBuilder.hpp @@ -235,7 +235,7 @@ Rooted buildAnchor(Logger &logger, } // Then construct the Anchor itself Rooted anchor{ - new AnnotationEntity::Anchor(parent->getManager(), parent, id)}; + new AnnotationEntity::Anchor(parent->getManager(), id, parent)}; // append the new entity to the right field. if (!parent->hasField(fieldName)) { logger.error(std::string("The parent has no field of the name ") + diff --git a/test/plugins/html/DemoOutputTest.cpp b/test/plugins/html/DemoOutputTest.cpp index ddd8f1c..9d1949e 100644 --- a/test/plugins/html/DemoOutputTest.cpp +++ b/test/plugins/html/DemoOutputTest.cpp @@ -56,7 +56,7 @@ TEST(DemoHTMLTransformer, writeHTML) #ifdef MANAGER_GRAPHVIZ_EXPORT // dump the manager state - mgr.exportGraphviz("bookDocument.dot"); + mgr.exportGraphviz("build/bookDocument.dot"); #endif // we can only do a rough check here. -- cgit v1.2.3