summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/model/Document.cpp54
-rw-r--r--src/core/model/Document.hpp58
-rw-r--r--src/core/model/Domain.hpp10
-rw-r--r--src/plugins/html/DemoOutput.cpp5
-rw-r--r--test/core/model/TestAdvanced.hpp117
-rw-r--r--test/plugins/html/DemoOutputTest.cpp2
6 files changed, 211 insertions, 35 deletions
diff --git a/src/core/model/Document.cpp b/src/core/model/Document.cpp
index 073f728..c653fe3 100644
--- a/src/core/model/Document.cpp
+++ b/src/core/model/Document.cpp
@@ -100,7 +100,7 @@ static Rooted<StructuredClass> resolveDescriptor(
}
// Otherwise take the first valid result.
for (auto &r : resolved) {
- if(r->isa(typeOf<StructuredClass>())){
+ if (r->isa(typeOf<StructuredClass>())) {
return r.cast<StructuredClass>();
}
}
@@ -155,6 +155,9 @@ Rooted<StructuredEntity> StructuredEntity::buildEntity(
return {nullptr};
}
// append the new entity to the right field.
+ if (!parent->hasField(fieldName)) {
+ return {nullptr};
+ }
NodeVector<StructuredEntity> &field = parent->getField(fieldName);
field.push_back(entity);
@@ -178,13 +181,60 @@ Rooted<DocumentPrimitive> DocumentPrimitive::buildEntity(
return {nullptr};
}
// append the new entity to the right field.
+ if (!parent->hasField(fieldName)) {
+ return {nullptr};
+ }
NodeVector<StructuredEntity> &field = parent->getField(fieldName);
field.push_back(entity);
-
// and return it.
return entity;
}
+Rooted<AnnotationEntity::Anchor> AnnotationEntity::buildAnchor(
+ Handle<DocumentEntity> parent, std::string id, const std::string &fieldName)
+{
+ // If the parent is not set, we can not build the anchor.
+ if (parent == nullptr) {
+ return {nullptr};
+ }
+ // Then construct the Anchor itself
+ Rooted<Anchor> anchor{
+ new AnnotationEntity::Anchor(parent->getManager(), parent, id)};
+ // append the new entity to the right field.
+ if (!parent->hasField(fieldName)) {
+ return {nullptr};
+ }
+ NodeVector<StructuredEntity> &field = parent->getField(fieldName);
+ field.push_back(anchor);
+ // and return it.
+ return anchor;
+}
+
+Rooted<AnnotationEntity> AnnotationEntity::buildEntity(
+ Handle<Document> parent, std::vector<Handle<Domain>> domains,
+ const std::string &className, Handle<AnnotationEntity::Anchor> start,
+ Handle<AnnotationEntity::Anchor> end, Variant attributes, std::string name)
+{
+ // If the parent is not set, we can not build the AnnotationEntity.
+ if (parent == nullptr) {
+ return {nullptr};
+ }
+ // If we can not find the correct descriptor, we can not build the entity
+ // either.
+ Rooted<StructuredClass> descriptor = resolveDescriptor(domains, className);
+ if (descriptor == nullptr) {
+ return {nullptr};
+ }
+ // Then construct the AnnotationEntity itself
+ Rooted<AnnotationEntity> anno{
+ new AnnotationEntity(parent->getManager(), parent, descriptor,
+ attributes, start, end, name)};
+ // append the new entity to the document
+ parent->getAnnotations().push_back(anno);
+ // and return it.
+ return anno;
+}
+
/* Type registrations */
}
diff --git a/src/core/model/Document.hpp b/src/core/model/Document.hpp
index 7523962..993df9e 100644
--- a/src/core/model/Document.hpp
+++ b/src/core/model/Document.hpp
@@ -207,21 +207,15 @@ public:
* information please refer to the header documentation above.
*/
class StructuredEntity : public DocumentEntity {
-private:
- NodeVector<AnnotationEntity> annotations;
-
public:
StructuredEntity(Manager &mgr, Handle<Node> parent,
Handle<StructuredClass> descriptor, Variant attributes,
std::string name = "")
: DocumentEntity(mgr, parent, descriptor, std::move(attributes),
- std::move(name)),
- annotations(this)
+ std::move(name))
{
}
- NodeVector<AnnotationEntity> &getAnnotations() { return annotations; }
-
/**
* This builds the root StructuredEntity for the given document. It
* automatically appends the newly build entity to the given document.
@@ -343,12 +337,11 @@ public:
public:
/**
* @param mgr is the Manager instance.
- * @param name is the Anchor id.
* @param parent is the parent of this Anchor in the Structure Tree (!),
* not the AnnotationEntity that references this Anchor.
+ * @param name is the Anchor id.
*/
- Anchor(Manager &mgr, Handle<StructuredEntity> parent,
- std::string name = "")
+ Anchor(Manager &mgr, Handle<DocumentEntity> parent, std::string name)
: StructuredEntity(mgr, parent, nullptr, Variant(), std::move(name))
{
}
@@ -372,6 +365,45 @@ public:
Rooted<Anchor> getStart() { return start; }
Rooted<Anchor> getEnd() { return end; }
+
+ /**
+ * This builds an Anchor as child of the given DocumentEntity. It
+ * automatically appends the newly build Anchor to its parent.
+ *
+ * @param parent is the parent DocumentEntity. The newly constructed
+ * Anchor will automatically be appended to it.
+ * @param id is the id of this Anchor.
+ * @param fieldName is the name of the field where the newly constructed
+ * Anchor shall be appended.
+ *
+ * @return the newly created Anchor or a nullptr if some
+ * input handle was empty.
+ */
+ static Rooted<Anchor> buildAnchor(Handle<DocumentEntity> parent,
+ std::string id,
+ const std::string &fieldName = "");
+ /**
+ * This builds an AnnotationEntity as child of the given DocumentEntity. It
+ * automatically appends the newly build entity to its parent.
+ *
+ * @param parent is the document the newly constructed AnnotationEntity
+ * will be appended to.
+ * @param domains are the domains that are used to find the
+ * AnnotationClass for the new node. The domains will be
+ * searched in the given order.
+ * @param className is the name of the AnnotationClass.
+ * @param attributes are the attributes of the new node in terms of a Struct
+ * variant (empty per default).
+ * @param name is the name of this AnnotationEntity (empty per
+ * default).
+ * @return the newly created AnnotationEntity or a nullptr if some
+ * input handle was empty or the given domains did not
+ * contain a AnnotationClass with the given name.
+ */
+ static Rooted<AnnotationEntity> buildEntity(Handle<Document> parent, std::vector<Handle<Domain>> domains,
+ const std::string &className,
+ Handle<Anchor> start, Handle<Anchor> end,
+ Variant attributes = Variant(), std::string name = "");
};
/**
@@ -382,17 +414,21 @@ class Document : public Node {
private:
// TODO: Might there be several roots? E.g. metadata?
Owned<StructuredEntity> root;
+ NodeVector<AnnotationEntity> annotations;
public:
Document(Manager &mgr, std::string name)
// TODO: Can a document have a parent?
- : Node(mgr, std::move(name), nullptr)
+ : Node(mgr, std::move(name), nullptr),
+ annotations(this)
{
}
void setRoot(Handle<StructuredEntity> root) { this->root = acquire(root); };
Rooted<StructuredEntity> getRoot() const { return root; }
+
+ NodeVector<AnnotationEntity> getAnnotations() { return annotations; }
};
}
diff --git a/src/core/model/Domain.hpp b/src/core/model/Domain.hpp
index 6a07b32..027cf88 100644
--- a/src/core/model/Domain.hpp
+++ b/src/core/model/Domain.hpp
@@ -306,8 +306,7 @@ public:
*/
FieldDescriptor(Manager &mgr, Handle<Descriptor> parent,
FieldType fieldType = FieldType::TREE,
- std::string name = "",
- bool optional = false)
+ std::string name = "", bool optional = false)
: Node(mgr, std::move(name), parent),
children(this),
fieldType(fieldType),
@@ -532,6 +531,13 @@ public:
* This class has no special properties and is in essence just a Descriptor.
*/
class AnnotationClass : public Descriptor {
+public:
+ AnnotationClass(Manager &mgr, std::string name, Handle<Domain> domain,
+ // TODO: What would be a wise default value for attributes?
+ Handle<StructType> attributesDescriptor)
+ : Descriptor(mgr, std::move(name), domain, attributesDescriptor)
+ {
+ }
};
/**
diff --git a/src/plugins/html/DemoOutput.cpp b/src/plugins/html/DemoOutput.cpp
index 307d37a..c858695 100644
--- a/src/plugins/html/DemoOutput.cpp
+++ b/src/plugins/html/DemoOutput.cpp
@@ -183,6 +183,10 @@ Rooted<xml::Element> DemoHTMLTransformer::transformParagraph(
// transform paragraph children to XML as well
for (auto &n : par->getField()) {
+ if (n->isa(typeOf<model::AnnotationEntity::Anchor>())) {
+ // TODO: Handle Anchors!
+ continue;
+ }
std::string childDescriptorName = n->getDescriptor()->getName();
if (childDescriptorName == "text") {
Handle<model::DocumentPrimitive> primitive =
@@ -193,7 +197,6 @@ Rooted<xml::Element> DemoHTMLTransformer::transformParagraph(
p->children.push_back(
new xml::Text(mgr, primitive->getContent().asString()));
}
- // TODO: Handle non-text content
}
return p;
}
diff --git a/test/core/model/TestAdvanced.hpp b/test/core/model/TestAdvanced.hpp
index bec00f9..5af6003 100644
--- a/test/core/model/TestAdvanced.hpp
+++ b/test/core/model/TestAdvanced.hpp
@@ -109,6 +109,25 @@ static Rooted<Domain> constructListDomain(Manager &mgr,
return domain;
}
+/**
+ * This constructs the "emphasis" domain.
+ */
+static Rooted<Domain> constructEmphasisDomain(Manager &mgr,
+ Handle<SystemTypesystem> sys,
+ Logger &logger)
+{
+ // set up domain node.
+ Rooted<Domain> domain{new Domain(mgr, sys, "emphasis")};
+ // create AnnotationClasses
+ Rooted<AnnotationClass> em{
+ new AnnotationClass(mgr, "emphasized", domain, {nullptr})};
+ domain->getAnnotationClasses().push_back(em);
+ Rooted<AnnotationClass> strong{
+ new AnnotationClass(mgr, "strong", domain, {nullptr})};
+ domain->getAnnotationClasses().push_back(strong);
+ return domain;
+}
+
static bool addText(Handle<StructuredEntity> parent,
std::vector<Handle<Domain>> &doms,
const std::string &content)
@@ -147,6 +166,34 @@ static bool addHeading(Handle<StructuredEntity> parent,
return true;
}
+static int annoIdx = 1;
+
+// Only works for non-overlapping annotations!
+static bool addAnnotation(Handle<Document> doc, Handle<StructuredEntity> parent,
+ std::vector<Handle<Domain>> &doms,
+ const std::string &text, const std::string &annoClass)
+{
+ Rooted<AnnotationEntity::Anchor> start =
+ AnnotationEntity::buildAnchor(parent, std::to_string(annoIdx++));
+ if (start.isNull()) {
+ return false;
+ }
+ if (!addText(parent, doms, text)) {
+ return false;
+ }
+ Rooted<AnnotationEntity::Anchor> end =
+ AnnotationEntity::buildAnchor(parent, std::to_string(annoIdx++));
+ if (end.isNull()) {
+ return false;
+ }
+ Rooted<AnnotationEntity> anno =
+ AnnotationEntity::buildEntity(doc, doms, annoClass, start, end);
+ if (anno.isNull()) {
+ return false;
+ }
+ return true;
+}
+
/**
* This constructs a more advanced book document using not only the book
* domain but also headings, emphasis and lists.
@@ -170,10 +217,19 @@ static Rooted<Document> constructAdvancedDocument(Manager &mgr,
}
// Add the heading.
- // TODO: use em here.
- if (!addHeading(book, doms,
- "Beantwortung der Frage: <em>Was ist Aufklärung?</em>")) {
- return {nullptr};
+ {
+ Rooted<StructuredEntity> heading = StructuredEntity::buildEntity(
+ book, doms, "heading", "heading", {}, "");
+ if (heading.isNull()) {
+ return {nullptr};
+ }
+ if (!addText(heading, doms, "Beantwortung der Frage: ")) {
+ return {nullptr};
+ }
+ if (!addAnnotation(doc, heading, doms, "Was ist Aufklärung?",
+ "emphasized")) {
+ return {nullptr};
+ }
}
// Add the main section.
@@ -196,20 +252,43 @@ static Rooted<Document> constructAdvancedDocument(Manager &mgr,
return {nullptr};
}
// Add its text.
- // TODO: Use em and strong here
- if (!addText(p, doms,
- " <strong>Aufklärung ist der Ausgang des Menschen aus "
- "seiner selbstverschuldeten Unmündigkeit</strong>. "
- "<em>Unmündigkeit</em> ist das Unvermögen, sich seines "
- "Verstandes ohne Leitung eines anderen zu bedienen. "
- "<em>Selbstverschuldet</em> ist diese Unmündigkeit, wenn "
- "die Ursache derselben nicht am Mangel des Verstandes, "
- "sondern der Entschließung und des Mutes liegt, sich "
- "seiner ohne Leitung eines andern zu bedienen. <em>Sapere "
- "aude! Habe Mut, dich deines eigenen Verstandes zu "
- "bedienen!</em> ist also der Wahlspruch der "
- "Aufklärung.")) {
- return {nullptr};
+ {
+ if (!addAnnotation(doc, p, doms,
+ "Aufklärung ist der Ausgang des Menschen aus "
+ "seiner selbstverschuldeten Unmündigkeit",
+ "strong")) {
+ return {nullptr};
+ }
+ if (!addAnnotation(doc, p, doms, "Unmündigkeit",
+ "emphasized")) {
+ return {nullptr};
+ }
+ if (!addText(p, doms,
+ "ist das Unvermögen, sich seines Verstandes ohne "
+ "Leitung eines anderen zu bedienen. ")) {
+ return {nullptr};
+ }
+ if (!addAnnotation(doc, p, doms, "Selbstverschuldet",
+ "emphasized")) {
+ return {nullptr};
+ }
+ if (!addText(p, doms,
+ " ist diese Unmündigkeit, wenn die Ursache derselben "
+ "nicht am Mangel des Verstandes, sondern der "
+ "Entschließung und des Mutes liegt, sich seiner ohne "
+ "Leitung eines andern zu bedienen.")) {
+ return {nullptr};
+ }
+ if (!addAnnotation(doc, p, doms,
+ "Sapere aude! Habe Mut, dich deines eigenen "
+ "Verstandes zu bedienen!",
+ "emphasized")) {
+ return {nullptr};
+ }
+ if (!addText(p, doms,
+ " ist also der Wahlspruch der Aufklärung.")) {
+ return {nullptr};
+ }
}
}
@@ -225,7 +304,7 @@ static Rooted<Document> constructAdvancedDocument(Manager &mgr,
}
// Add list with citations
{
- //TODO: We need to restrict this to the list domain. Otherwise
+ // TODO: We need to restrict this to the list domain. Otherwise
// this leads to resolve errors for some reason.
Rooted<StructuredEntity> ul =
StructuredEntity::buildEntity(lesarten, {listDom}, "ul");
diff --git a/test/plugins/html/DemoOutputTest.cpp b/test/plugins/html/DemoOutputTest.cpp
index 471ccc3..36b53b4 100644
--- a/test/plugins/html/DemoOutputTest.cpp
+++ b/test/plugins/html/DemoOutputTest.cpp
@@ -45,6 +45,8 @@ TEST(DemoHTMLTransformer, writeHTML)
model::constructHeadingDomain(mgr, sys, bookDom, logger);
Rooted<model::Domain> listDom =
model::constructListDomain(mgr, sys, bookDom, logger);
+ Rooted<model::Domain> emDom =
+ model::constructEmphasisDomain(mgr, sys, logger);
// Construct the document.
Rooted<model::Document> doc =
model::constructAdvancedDocument(mgr, bookDom, headingDom, listDom);