#include "htmlprint.h" #include #include using namespace example_novel; using namespace printer; using namespace lib_parse; Access::Access(std::shared_ptr handle) :access_handle(handle) {} std::shared_ptr Access::accessPeers() const { return access_handle; } void Access::setPageRefers(const QString& href) { this->summary_refer_store = href; } QString Access::pageRefers() const { return this->summary_refer_store; } Element::Element(std::shared_ptr handle) :Access(handle) {} void printer::Element::setSliceRefer(const QString& href) { this->refer_store = href; } QString printer::Element::sliceRefers() const { return refer_store; } Group::Group(std::shared_ptr handle) : Access(handle) {} void Group::append(std::shared_ptr elm) { element_store.append(elm); } QList> Group::elements() const { return this->element_store; } std::shared_ptr printer::Group::getElement(const QString& signature) const { for (auto& it : elements()) { if (it->accessPeers()->element()->signature() == signature) return it; } return nullptr; } StoryLine::StoryLine(std::shared_ptr handle) :Group(handle) {} void StoryLine::buildPageHTML(QDomElement& parent) const { auto syntax_access = this->accessPeers(); auto storyline_inst = std::dynamic_pointer_cast(syntax_access->element()); auto doc = parent.ownerDocument(); auto dom_storyline = doc.createElement("div"); parent.appendChild(dom_storyline); auto dom_title = doc.createElement("h1"); dom_title.appendChild(doc.createTextNode(storyline_inst->name())); dom_storyline.appendChild(dom_title); for (auto& inst_c : syntax_access->children()) { switch ((NovelNode)inst_c->element()->typeMark()) { case NovelNode::TextSection: { auto text_inst = std::dynamic_pointer_cast(inst_c->element()); auto dom_p = doc.createElement("p"); dom_p.appendChild(doc.createTextNode(text_inst->content())); dom_storyline.appendChild(dom_p); }break; case NovelNode::FragmentRefer: case NovelNode::FragmentDefine: { auto element_inst = this->getElement(inst_c->element()->signature()); element_inst->buildSliceHTML(dom_storyline); }break; default: break; } } } StoryVolume::StoryVolume(std::shared_ptr handle) : Group(handle) {} void StoryVolume::buildPageHTML(QDomElement& parent) const { auto syntax_access = this->accessPeers(); auto volume_inst = std::dynamic_pointer_cast(syntax_access->element()); auto doc_inst = parent.ownerDocument(); auto dom_volume = doc_inst.createElement("div"); parent.appendChild(dom_volume); auto dom_title = doc_inst.createElement("h1"); dom_title.appendChild(doc_inst.createTextNode(volume_inst->name())); dom_volume.appendChild(dom_title); std::function>&)> rich_refer_build = [&](QDomElement& parent_element, const QList> children) { for (auto& child : children) { auto doc_ins = parent_element.ownerDocument(); switch ((NovelNode)child->element()->typeMark()) { case NovelNode::TextSection: { auto text_inst = std::dynamic_pointer_cast(child->element()); auto dom_p = doc_ins.createElement("p"); dom_p.appendChild(doc_ins.createTextNode(text_inst->content())); parent_element.appendChild(dom_p); }break; case NovelNode::ArticleDefine: { auto article_inst = std::dynamic_pointer_cast(child->element()); auto article_group = doc_ins.createElement("div"); auto article_head = doc_ins.createElement("h2"); article_head.appendChild(doc_ins.createTextNode(article_inst->name() + u8"{")); article_group.appendChild(article_head); rich_refer_build(article_group, child->children()); article_group.appendChild(doc_ins.createTextNode(u8"}")); parent_element.appendChild(article_group); }break; case NovelNode::FragmentRefer:{ auto fragment_inst = std::dynamic_pointer_cast(child->element()); auto refer_inst = this->getElement(fragment_inst->signature()); refer_inst->buildSliceHTML(parent_element); }break; default: break; } } }; rich_refer_build(dom_volume, syntax_access->children()); } FragmentRef::FragmentRef(std::shared_ptr handle) : Element(handle) {} void printer::FragmentRef::setHost(std::shared_ptr frag_inst) { this->host_inst = frag_inst; } std::shared_ptr printer::FragmentRef::hostFragment() const { return this->host_inst.lock(); } void FragmentRef::buildSliceHTML(QDomElement& dom_parent) const { auto syntax_access = this->accessPeers(); auto refer_element = std::dynamic_pointer_cast(syntax_access->element()); auto jump_to_host = this->hostFragment()->pageRefers(); auto doc = dom_parent.ownerDocument(); auto dom_reference = doc.createElement(u8"div"); dom_reference.setAttribute("id", QString::number((qulonglong)refer_element.get())); dom_parent.appendChild(dom_reference); auto dom_title = doc.createElement(u8"h2"); dom_reference.appendChild(dom_title); auto dom_href = doc.createElement(u8"a"); dom_href.appendChild(doc.createTextNode(refer_element->referSignature())); dom_href.setAttribute("href", u8"file:///"+jump_to_host); dom_title.appendChild(dom_href); std::function>&)> rich_refer_build = [&](QDomElement& parent_element, const QList> children) { for (auto& child : children) { auto doc_ins = parent_element.ownerDocument(); switch ((NovelNode)child->element()->typeMark()) { case NovelNode::TextSection: { auto text_inst = std::dynamic_pointer_cast(child->element()); auto dom_p = doc_ins.createElement("p"); dom_p.appendChild(doc_ins.createTextNode(text_inst->content())); parent_element.appendChild(dom_p); }break; case NovelNode::ArticleDefine: { auto article_inst = std::dynamic_pointer_cast(child->element()); auto article_group = doc_ins.createElement("div"); auto article_head = doc_ins.createElement("h2"); article_head.appendChild(doc_ins.createTextNode(article_inst->name() + u8"{")); article_group.appendChild(article_head); rich_refer_build(article_group, child->children()); article_group.appendChild(doc_ins.createTextNode(u8"}")); parent_element.appendChild(article_group); }break; default: break; } } }; rich_refer_build(dom_reference, syntax_access->children()); } void FragmentRef::buildPageHTML(QDomElement& parent) const { auto syntax_access = this->accessPeers(); auto refer_element = std::dynamic_pointer_cast(syntax_access->element()); auto doc = parent.ownerDocument(); auto refers_dom = doc.createElement(u8"div"); parent.appendChild(refers_dom); auto title_block = doc.createElement(u8"h2"); refers_dom.appendChild(title_block); auto title_refer = doc.createElement(u8"a"); title_refer.appendChild(doc.createTextNode(refer_element->signature())); title_refer.setAttribute("href", u8"file:///"+this->sliceRefers()); title_block.appendChild(title_refer); std::function>)> build_cascade = [&](QList> children_items) { for (auto child : children_items) { if (child->element()->typeMark() == (int)NovelNode::TextSection) { auto text_inst = std::dynamic_pointer_cast(child->element()); auto p = doc.createElement("p"); p.appendChild(doc.createTextNode(text_inst->content())); refers_dom.appendChild(p); } else { build_cascade(child->children()); } } }; build_cascade(syntax_access->children()); } Fragment::Fragment(std::shared_ptr handle) : Element(handle) {} void Fragment::appendRefers(std::shared_ptr inst) { this->additionals_store.append(inst); inst->setHost(std::static_pointer_cast(this->shared_from_this())); } QList> Fragment::additionals() const { return this->additionals_store; } void Fragment::buildSliceHTML(QDomElement& parent) const { auto syntax_access = this->accessPeers(); auto fragment_inst = std::dynamic_pointer_cast(syntax_access->element()); auto doc = parent.ownerDocument(); auto dom_fragment = doc.createElement("div"); dom_fragment.setAttribute("id", QString::number((qulonglong)fragment_inst.get())); parent.appendChild(dom_fragment); auto dom_title = doc.createElement("h2"); dom_fragment.appendChild(dom_title); auto dom_href = doc.createElement("a"); dom_href.appendChild(doc.createTextNode(fragment_inst->name())); dom_href.setAttribute("href", u8"file:///"+this->pageRefers()); dom_title.appendChild(dom_href); for (auto& inst_c : syntax_access->children()) { if (NovelNode::TextSection == (NovelNode)inst_c->element()->typeMark()) { auto text_inst = std::dynamic_pointer_cast(inst_c->element()); auto dom_p = doc.createElement("p"); dom_p.appendChild(doc.createTextNode(text_inst->content())); dom_fragment.appendChild(dom_p); } } } void Fragment::buildPageHTML(QDomElement& parent) const { auto syntax_access = this->accessPeers(); auto fragment_inst = std::dynamic_pointer_cast(syntax_access->element()); auto doc = parent.ownerDocument(); auto dom_fragment = doc.createElement("div"); parent.appendChild(dom_fragment); auto dom_title = doc.createElement("h1"); dom_fragment.appendChild(dom_title); auto dom_href = doc.createElement("a"); dom_href.appendChild(doc.createTextNode(fragment_inst->signature())); dom_href.setAttribute("href", u8"file:///" + this->sliceRefers()); dom_title.appendChild(dom_href); for (auto& inst_c : syntax_access->children()) { if (NovelNode::TextSection == (NovelNode)inst_c->element()->typeMark()) { auto text_inst = std::dynamic_pointer_cast(inst_c->element()); auto dom_p = doc.createElement("p"); dom_p.appendChild(doc.createTextNode(text_inst->content())); dom_fragment.appendChild(dom_p); } } for (auto& it : this->additionals()) { it->buildPageHTML(dom_fragment); } } #include void tools_printer::build_fragments(std::shared_ptr novel_root) { if (novel_root->element()->typeMark() == (int)NovelNode::FragmentDefine) { auto inst = std::make_shared(novel_root); auto name = novel_root->element()->signature(); this->fragment_defines[name] = inst; } for (auto& inst_c : novel_root->children()) { build_fragments(inst_c); } } void tools_printer::build_refers_network(std::shared_ptr novel_node) { switch ((NovelNode)novel_node->element()->typeMark()) { case NovelNode::StoryDefine: { auto storyinst = std::make_shared(novel_node); this->storyline_defines[novel_node->element()->signature()] = storyinst; build_storyline(storyinst); }return; case NovelNode::VolumeDefine: { auto volumeinst = std::make_shared(novel_node); this->volume_defines[novel_node->element()->signature()] = volumeinst; build_volumeline(volumeinst); }return; } for (auto& inst_c : novel_node->children()) build_refers_network(inst_c); } void tools_printer::build_storyline(std::shared_ptr line, std::shared_ptr novel_node) { if (!novel_node) { for (auto& inst_c : line->accessPeers()->children()) { build_storyline(line, inst_c); } } else { switch ((NovelNode)novel_node->element()->typeMark()) { case NovelNode::FragmentDefine: { auto inst = this->fragment_defines[novel_node->element()->signature()]; line->append(inst); }return; case NovelNode::FragmentRefer: { auto refer_node = std::dynamic_pointer_cast(novel_node->element()); auto refer_fragment = this->fragment_defines[refer_node->referSignature()]; auto inst = std::make_shared(novel_node); refer_fragment->appendRefers(inst); line->append(inst); }return; } for (auto& inst_c : novel_node->children()) build_storyline(line, inst_c); } } void tools_printer::build_volumeline(std::shared_ptr volume, std::shared_ptr novel_node) { if (!novel_node) { for (auto& inst_c : volume->accessPeers()->children()) build_volumeline(volume, inst_c); } else { if (NovelNode::FragmentRefer == (NovelNode)novel_node->element()->typeMark()) { auto refer_node = std::dynamic_pointer_cast(novel_node->element()); auto refer_fragment = this->fragment_defines[refer_node->referSignature()]; auto inst = std::make_shared(novel_node); refer_fragment->appendRefers(inst); volume->append(inst); return; } for (auto& inst_c : novel_node->children()) build_volumeline(volume, inst_c); } } void tools_printer::fragments_anchors_define(const QList>& list, const QDir& root_dir) { auto path = root_dir.filePath("fragments"); if (!QDir(path).exists()) root_dir.mkdir("fragments"); QDir target_dir(path); for (auto& it : list) { auto address_x = QString::number((qulonglong)it->accessPeers()->element().get()); it->setPageRefers(target_dir.absoluteFilePath(QString("%1.html").arg(address_x))); } } std::function>&, const QString&)> refers_refresh = [&](const QList>& items, const QString& summary_href) { for (auto& item : items) { auto element_addr = QString::number((qulonglong)item->accessPeers()->element().get()); item->setSliceRefer(summary_href + u8"#" + element_addr); } }; void tools_printer::storylines_anchors_define(const QList>& list, const QDir& root_dir) { auto path = root_dir.filePath("storylines"); if (!QDir(path).exists()) root_dir.mkdir("storylines"); QDir target_dir(path); for (auto& it : list) { auto address_x = QString::number((qulonglong)it->accessPeers()->element().get()); auto page_address = target_dir.absoluteFilePath(QString("%1.html").arg(address_x)); it->setPageRefers(page_address); refers_refresh(it->elements(), page_address); } } void tools_printer::volumes_anchors_define(const QList>& list, const QDir& root_dir) { auto path = root_dir.filePath("volumes"); if (!QDir(path).exists()) root_dir.mkdir("volumes"); QDir target_dir(path); for (auto& it : list) { auto address_x = QString::number((qulonglong)it->accessPeers()->element().get()); auto page_address = target_dir.absoluteFilePath(QString("%1.html").arg(address_x)); it->setPageRefers(page_address); refers_refresh(it->elements(), page_address); } } auto get_node_name = [](const std::shared_ptr item){ return u8"node_" + QString::number((qulonglong)item->accessPeers()->element().get()); }; QString printer::tools_printer::storylines_paint(const QList> &lines) { QHash> node_records; QString nodes_description; for (auto& story : lines) { auto story_elem = std::dynamic_pointer_cast(story->accessPeers()->element()); node_records[story_elem->signature()] = story; nodes_description += get_node_name(story) + QString(u8"[fillcolor=pink,label=\"%1{%2}\",shape=\"cds\"]\n").arg(story_elem->name()).arg(story_elem->sort()); for (auto &frag : story->elements()) { auto fragment_peers = frag->accessPeers()->element(); if (fragment_peers->typeMark() == (int)example_novel::NovelNode::FragmentDefine) { auto fragment_elem = std::dynamic_pointer_cast(fragment_peers); auto node_name = fragment_elem->signature(); node_records[node_name] = frag; nodes_description += get_node_name(frag) + QString(u8"[label=\"{%2}::%1\",shape=\"rect\"]\n") .arg(fragment_elem->name()).arg(story_elem->sort()); } } } QString arrows_link; for (auto &story : lines) { auto story_elem = std::dynamic_pointer_cast(story->accessPeers()->element()); QString previous_node = get_node_name(story); for (auto &frag : story->elements()) { if (example_novel::NovelNode::FragmentDefine == (example_novel::NovelNode) frag->accessPeers()->element()->typeMark()) { arrows_link += previous_node + u8"->" + get_node_name(frag) + QString(u8"[label=\"%1{%2}\"]\n") .arg(story_elem->name()).arg(story_elem->sort()); previous_node = get_node_name(frag); } else if (example_novel::NovelNode::FragmentRefer == (example_novel::NovelNode)frag->accessPeers()->element()->typeMark()) { auto frag_refer = std::dynamic_pointer_cast(frag->accessPeers()->element()); auto frag_src = node_records[frag_refer->referSignature()]; arrows_link += previous_node + u8"->" + get_node_name(frag_src) + QString(u8"[label=\"%1{%2}\"]\n") .arg(story_elem->name()).arg(story_elem->sort()); previous_node = get_node_name(frag_src); } } } return QString(u8"digraph{ rankdir = LR \n node[style=filled] \n %1\n %2 }").arg(nodes_description).arg(arrows_link); } QString printer::tools_printer::volumes_paint(const QList>& vols, const QList>& lines) { QHash> node_records; QString clusters_description; for (auto& story : lines) { QString nodes_description; for (auto &frag : story->elements()) { auto fragment_peers = frag->accessPeers()->element(); if (fragment_peers->typeMark() == (int)example_novel::NovelNode::FragmentDefine) { auto fragment_elem = std::dynamic_pointer_cast(fragment_peers); node_records[fragment_elem->signature()] = frag; nodes_description += get_node_name(frag) + QString(u8"[label=\"%1\",shape=\"ellipse\"]\n").arg(fragment_elem->name()); } } auto story_elem = std::dynamic_pointer_cast(story->accessPeers()->element()); clusters_description += QString(u8"subgraph cluster_%1 { label=%3 \n %2 }") .arg((qulonglong)story_elem.get()).arg(nodes_description).arg(story_elem->name()); } auto article_cluster = [&node_records]( const std::shared_ptr article_access, QList &arrows_out)->QString { QString nodes_description; for (auto& fragment_access : article_access->children()) { if (fragment_access->element()->typeMark() == (int)example_novel::NovelNode::FragmentRefer) { auto refer_fragment = std::dynamic_pointer_cast(fragment_access->element()); nodes_description += QString(u8"fragment_%1[label=\"%2\",shape=\"plaintext\"]\n") .arg((qulonglong)refer_fragment.get()).arg(refer_fragment->fragmentRefer()); auto symbo_refer = node_records[refer_fragment->referSignature()]; arrows_out << QString(u8"fragment_%1 -- %2[color=\"red\"]\n").arg((qulonglong)refer_fragment.get()).arg(get_node_name(symbo_refer)); } } auto article_define = std::dynamic_pointer_cast(article_access->element()); return QString(u8"subgraph cluster_%1{ label=%2 \n %3 }\n").arg((qulonglong)article_access->element().get()) .arg(article_define->name()).arg(nodes_description); }; QString arrows_link; for (auto &vol : vols) { QString members_description; for (auto& eref : vol->accessPeers()->children()) { QList arrows_temp; switch ((example_novel::NovelNode)eref->element()->typeMark()){ case example_novel::NovelNode::ArticleDefine: members_description += article_cluster(eref, arrows_temp); break; default: break; } for (auto& arrow : arrows_temp) { arrows_link += arrow; } } auto volume_elem = std::dynamic_pointer_cast(vol->accessPeers()->element()); clusters_description += QString(u8"subgraph cluster_%1 { label=%3 \n %2 }") .arg((qulonglong)volume_elem.get()).arg(members_description).arg(volume_elem->name()); } return QString("graph scale{ %1 \n %2}").arg(clusters_description).arg(arrows_link); } void printer::AstGenerate::append_tokens(QDomElement _elm, std::shared_ptr inst) { auto dom_tokens = doc.createElement(u8"tokens"); _elm.appendChild(dom_tokens); for (auto& token : inst->selfTokens()) { auto dom_token = doc.createElement(u8"token"); dom_tokens.appendChild(dom_token); dom_token.setAttribute(u8"text", token->token()->content()); dom_token.setAttribute(u8"row", token->token()->row()); dom_token.setAttribute(u8"col", token->token()->column()); } } printer::AstGenerate::AstGenerate() { auto procs = doc.createProcessingInstruction("xml", "version='1.0' encoding='utf-8'"); doc.appendChild(procs); } QString printer::AstGenerate::content() const { return doc.toString(2); } VisitMode printer::AstGenerate::mode() const { return VisitMode::FirstParent; } #include bool printer::AstGenerate::visit(std::shared_ptr syntax_element) { switch ((NovelNode)syntax_element->element()->typeMark()) { case NovelNode::GlobalElement:{ auto body = doc.createElement(u8"ast"); doc.appendChild(body); body.setAttribute(u8"time", QDateTime::currentDateTime().toString(u8"yyyyMMdd_hhmmss")); element_stack.append(body); }break; case NovelNode::Document: break; case NovelNode::StoryDefine:{ while (element_stack.last().tagName() != u8"ast") { element_stack.takeLast(); } auto current_ast = element_stack.last(); auto story_node = std::dynamic_pointer_cast(syntax_element->element()); auto dom_story = doc.createElement(u8"story"); current_ast.appendChild(dom_story); element_stack.append(dom_story); dom_story.setAttribute(u8"name", story_node->name()); dom_story.setAttribute(u8"address", (qulonglong)story_node.get()); dom_story.setAttribute(u8"file-path", story_node->filePath()); dom_story.setAttribute(u8"sort", story_node->sort()); append_tokens(dom_story, story_node); }break; case NovelNode::FragmentDefine: { while (element_stack.last().tagName() != u8"story") { element_stack.takeLast(); } auto current_story = element_stack.last(); auto fragment_node = std::dynamic_pointer_cast(syntax_element->element()); auto dom_fragment = doc.createElement(u8"fragment"); current_story.appendChild(dom_fragment); element_stack.append(dom_fragment); dom_fragment.setAttribute(u8"name", fragment_node->name()); dom_fragment.setAttribute(u8"address", (qulonglong)fragment_node.get()); dom_fragment.setAttribute(u8"file-path", fragment_node->filePath()); append_tokens(dom_fragment, fragment_node); }break; case NovelNode::TextSection:{ auto current_text = element_stack.last(); auto text_node = std::dynamic_pointer_cast(syntax_element->element()); auto dom_text = doc.createElement(u8"text-section"); current_text.appendChild(dom_text); dom_text.setAttribute(u8"text", text_node->content()); dom_text.setAttribute(u8"file-path", text_node->filePath()); append_tokens(dom_text, text_node); }break; case NovelNode::FragmentRefer:{ while (element_stack.last().tagName() != u8"article" && element_stack.last().tagName() != u8"story") { element_stack.takeLast(); } auto current_pnode = element_stack.last(); auto refer_node = std::dynamic_pointer_cast(syntax_element->element()); auto dom_refer = doc.createElement(u8"refer"); element_stack.append(dom_refer); current_pnode.appendChild(dom_refer); dom_refer.setAttribute(u8"story", refer_node->storyRefer()); dom_refer.setAttribute(u8"fragment", refer_node->fragmentRefer()); dom_refer.setAttribute(u8"file-path", refer_node->filePath()); append_tokens(dom_refer, refer_node); }break; case NovelNode::VolumeDefine:{ while (element_stack.last().tagName() != u8"ast") { element_stack.takeLast(); } auto current_ast = element_stack.last(); auto volume_node = std::dynamic_pointer_cast(syntax_element->element()); auto dom_volume = doc.createElement(u8"volume"); current_ast.appendChild(dom_volume); element_stack.append(dom_volume); dom_volume.setAttribute(u8"name", volume_node->name()); dom_volume.setAttribute(u8"address", (qulonglong)volume_node.get()); dom_volume.setAttribute(u8"file-path", volume_node->filePath()); append_tokens(dom_volume, volume_node); }break; case NovelNode::ArticleDefine:{ while (element_stack.last().tagName() != u8"volume") { element_stack.takeLast(); } auto current_volume = element_stack.last(); auto article_node = std::dynamic_pointer_cast(syntax_element->element()); auto dom_article = doc.createElement(u8"article"); current_volume.appendChild(dom_article); element_stack.append(dom_article); dom_article.setAttribute(u8"name", article_node->name()); dom_article.setAttribute(u8"address", (qulonglong)article_node.get()); dom_article.setAttribute(u8"file-path", article_node->filePath()); append_tokens(dom_article, article_node); }break; case NovelNode::RankDeclaration:{ auto ast_element = element_stack.first(); auto rank_node = std::dynamic_pointer_cast(syntax_element->element()); auto dom_rank = doc.createElement(u8"rank"); ast_element.appendChild(dom_rank); dom_rank.setAttribute(u8"rank", rank_node->rankNumber()); dom_rank.setAttribute(u8"doc-path", rank_node->filePath()); append_tokens(dom_rank, rank_node); }break; default: break; } return true; }