WsParser_VS/WsNovelParser/htmlprint.cpp

893 lines
33 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "htmlprint.h"
#include <QDir>
#include <QDomElement>
using namespace example_novel;
using namespace printer;
using namespace lib_parse;
Access::Access(std::shared_ptr<const ast_gen::ElementAccess> handle)
:access_handle(handle) {
}
std::shared_ptr<const ast_gen::ElementAccess> 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<const ast_gen::ElementAccess> 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<const ast_gen::ElementAccess> handle) : Access(handle) {
}
void Group::append(std::shared_ptr<Element> elm) {
element_store.append(elm);
}
QList<std::shared_ptr<Element>> Group::elements() const {
return this->element_store;
}
std::shared_ptr<Element> 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<const ast_gen::ElementAccess> handle) :Group(handle) {
}
void StoryLine::buildPageHTML(QDomElement& parent) const {
auto syntax_access = this->accessPeers();
auto storyline_inst = std::dynamic_pointer_cast<const StoryDefine>(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<const TextSection>(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::PointRefers:
case NovelNode::PointDefines:
{
auto element_inst = this->getElement(inst_c->element()->signature());
element_inst->buildSliceHTML(dom_storyline);
}break;
default:
break;
}
}
}
StoryVolume::StoryVolume(std::shared_ptr<const ast_gen::ElementAccess> handle) : Group(handle) {
}
void StoryVolume::buildPageHTML(QDomElement& parent) const {
auto syntax_access = this->accessPeers();
auto volume_inst = std::dynamic_pointer_cast<const VolumeDefine>(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<void(QDomElement&, const QList<std::shared_ptr<const ast_gen::ElementAccess>>&)> rich_refer_build =
[&](QDomElement& parent_element, const QList<std::shared_ptr<const ast_gen::ElementAccess>> 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<const TextSection>(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<const ArticleDefine>(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() + "{"));
article_group.appendChild(article_head);
rich_refer_build(article_group, child->children());
article_group.appendChild(doc_ins.createTextNode("}"));
parent_element.appendChild(article_group);
}break;
case NovelNode::PointRefers:
{
auto fragment_inst = std::dynamic_pointer_cast<const PointRefers>(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<const ast_gen::ElementAccess> handle) : Element(handle) {
}
void printer::FragmentRef::setHost(std::shared_ptr<Fragment> frag_inst) {
this->host_inst = frag_inst;
}
std::shared_ptr<Fragment> 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<const PointRefers>(syntax_access->element());
auto jump_to_host = this->hostFragment()->pageRefers();
auto doc = dom_parent.ownerDocument();
auto dom_reference = doc.createElement("div");
dom_reference.setAttribute("id", QString::number((qulonglong) refer_element.get()));
dom_parent.appendChild(dom_reference);
auto dom_title = doc.createElement("h2");
dom_reference.appendChild(dom_title);
auto dom_href = doc.createElement("a");
dom_href.appendChild(doc.createTextNode(refer_element->referSignature()));
dom_href.setAttribute("href", "file:///" + jump_to_host);
dom_title.appendChild(dom_href);
std::function<void(QDomElement&, const QList<std::shared_ptr<const ast_gen::ElementAccess>>&)> rich_refer_build =
[&](QDomElement& parent_element, const QList<std::shared_ptr<const ast_gen::ElementAccess>> 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<const TextSection>(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<const ArticleDefine>(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() + "{"));
article_group.appendChild(article_head);
rich_refer_build(article_group, child->children());
article_group.appendChild(doc_ins.createTextNode("}"));
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<const PointRefers>(syntax_access->element());
auto doc = parent.ownerDocument();
auto refers_dom = doc.createElement("div");
parent.appendChild(refers_dom);
auto title_block = doc.createElement("h2");
refers_dom.appendChild(title_block);
auto title_refer = doc.createElement("a");
title_refer.appendChild(doc.createTextNode(refer_element->signature()));
title_refer.setAttribute("href", "file:///" + this->sliceRefers());
title_block.appendChild(title_refer);
std::function<void(QList<std::shared_ptr<const ast_gen::ElementAccess>>)> build_cascade =
[&](QList<std::shared_ptr<const ast_gen::ElementAccess>> children_items) {
for (auto child : children_items) {
if (child->element()->typeMark() == (int) NovelNode::TextSection) {
auto text_inst = std::dynamic_pointer_cast<const TextSection>(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<const ast_gen::ElementAccess> handle) : Element(handle) {
}
void Fragment::appendRefers(std::shared_ptr<FragmentRef> inst) {
this->additionals_store.append(inst);
inst->setHost(std::static_pointer_cast<Fragment>(this->shared_from_this()));
}
QList<std::shared_ptr<FragmentRef>> 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<const PointDefines>(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", "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<const TextSection>(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<const PointDefines>(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", "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<const TextSection>(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 <ast_novel.h>
void tools_printer::build_fragments(std::shared_ptr<const ast_gen::ElementAccess> novel_root) {
if (novel_root->element()->typeMark() == (int) NovelNode::PointDefines) {
auto inst = std::make_shared<Fragment>(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<const ast_gen::ElementAccess> novel_node) {
switch ((NovelNode) novel_node->element()->typeMark()) {
case NovelNode::StoryDefine:
{
auto storyinst = std::make_shared<StoryLine>(novel_node);
this->storyline_defines[novel_node->element()->signature()] = storyinst;
build_storyline(storyinst);
}return;
case NovelNode::VolumeDefine:
{
auto volumeinst = std::make_shared<StoryVolume>(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<StoryLine> line, std::shared_ptr<const ast_gen::ElementAccess> 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::PointDefines:
{
auto inst = this->fragment_defines[novel_node->element()->signature()];
line->append(inst);
}return;
case NovelNode::PointRefers:
{
auto refer_node = std::dynamic_pointer_cast<const PointRefers>(novel_node->element());
auto refer_fragment = this->fragment_defines[refer_node->referSignature()];
auto inst = std::make_shared<FragmentRef>(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<StoryVolume> volume, std::shared_ptr<const ast_gen::ElementAccess> novel_node) {
if (!novel_node) {
for (auto& inst_c : volume->accessPeers()->children())
build_volumeline(volume, inst_c);
}
else {
if (NovelNode::PointRefers == (NovelNode) novel_node->element()->typeMark()) {
auto refer_node = std::dynamic_pointer_cast<const PointRefers>(novel_node->element());
auto refer_fragment = this->fragment_defines[refer_node->referSignature()];
auto inst = std::make_shared<FragmentRef>(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<std::shared_ptr<Fragment>>& 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<void(const QList<std::shared_ptr<Element>>&, const QString&)> refers_refresh =
[&](const QList<std::shared_ptr<Element>>& items, const QString& summary_href) {
for (auto& item : items) {
auto element_addr = QString::number((qulonglong) item->accessPeers()->element().get());
item->setSliceRefer(summary_href + "#" + element_addr);
}
};
void tools_printer::storylines_anchors_define(const QList<std::shared_ptr<StoryLine>>& 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<std::shared_ptr<StoryVolume>>& 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<Access> item) {
return "node_" + QString::number((qulonglong) item->accessPeers()->element().get());
};
QString printer::tools_printer::storylines_paint(const QList<std::shared_ptr<StoryLine>>& lines) {
QHash<QString, std::shared_ptr<Access>> node_records;
QString nodes_description;
for (auto& story : lines) {
auto story_elem = std::dynamic_pointer_cast<const example_novel::StoryDefine>(story->accessPeers()->element());
node_records[story_elem->signature()] = story;
nodes_description += get_node_name(story) + QString("[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::PointDefines) {
auto fragment_elem = std::dynamic_pointer_cast<const example_novel::PointDefines>(fragment_peers);
auto node_name = fragment_elem->signature();
node_records[node_name] = frag;
nodes_description += get_node_name(frag) + QString("[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<const example_novel::StoryDefine>(story->accessPeers()->element());
QString previous_node = get_node_name(story);
for (auto& frag : story->elements()) {
if (example_novel::NovelNode::PointDefines == (example_novel::NovelNode) frag->accessPeers()->element()->typeMark()) {
arrows_link += previous_node + "->" + get_node_name(frag) + QString("[label=\"%1{%2}\"]\n")
.arg(story_elem->name()).arg(story_elem->sort());
previous_node = get_node_name(frag);
}
else if (example_novel::NovelNode::PointRefers == (example_novel::NovelNode) frag->accessPeers()->element()->typeMark()) {
auto frag_refer = std::dynamic_pointer_cast<const example_novel::PointRefers>(frag->accessPeers()->element());
auto frag_src = node_records[frag_refer->referSignature()];
arrows_link += previous_node + "->" + get_node_name(frag_src) + QString("[label=\"%1{%2}\"]\n")
.arg(story_elem->name()).arg(story_elem->sort());
previous_node = get_node_name(frag_src);
}
}
}
return QString("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<std::shared_ptr<StoryVolume>>& vols, const QList<std::shared_ptr<StoryLine>>& lines) {
QHash<QString, std::shared_ptr<Element>> 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::PointDefines) {
auto fragment_elem = std::dynamic_pointer_cast<const example_novel::PointDefines>(fragment_peers);
node_records[fragment_elem->signature()] = frag;
nodes_description += get_node_name(frag) + QString("[label=\"%1\",shape=\"ellipse\"]\n").arg(fragment_elem->name());
}
}
auto story_elem = std::dynamic_pointer_cast<const example_novel::StoryDefine>(story->accessPeers()->element());
clusters_description += QString("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<const ast_gen::ElementAccess> article_access, QList<QString>& arrows_out)->QString {
QString nodes_description;
for (auto& fragment_access : article_access->children()) {
if (fragment_access->element()->typeMark() == (int) example_novel::NovelNode::PointRefers) {
auto refer_fragment = std::dynamic_pointer_cast<const example_novel::PointRefers>(fragment_access->element());
nodes_description += QString("fragment_%1[label=\"%2\",shape=\"plaintext\"]\n")
.arg((qulonglong) refer_fragment.get()).arg(refer_fragment->sliceRefer());
auto symbo_refer = node_records[refer_fragment->referSignature()];
arrows_out << QString("fragment_%1 -- %2[color=\"red\"]\n").arg((qulonglong) refer_fragment.get()).arg(get_node_name(symbo_refer));
}
}
auto article_define = std::dynamic_pointer_cast<const example_novel::ArticleDefine>(article_access->element());
return QString("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<QString> 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<const example_novel::VolumeDefine>(vol->accessPeers()->element());
clusters_description += QString("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);
}
#include <QTextStream>
#include <QTime>
#include <QDebug>
void printer::tools_printer::plain_html_output(const std::shared_ptr<const ast_gen::ElementAccess> access_ptr, const QDir& destination_dir) const {
QTime time_stamp = QTime::currentTime();
auto tool = *this;
tool.build_fragments(access_ptr);
tool.build_refers_network(access_ptr);
tool.fragments_anchors_define(tool.fragment_defines.values(), destination_dir);
tool.storylines_anchors_define(tool.storyline_defines.values(), destination_dir);
tool.volumes_anchors_define(tool.volume_defines.values(), destination_dir);
std::function<void(std::shared_ptr<const printer::Access>)> html_output =
[](std::shared_ptr<const printer::Access> inst) {
auto target_path = inst->pageRefers();
QFile tfile(target_path);
if (tfile.open(QIODevice::WriteOnly | QIODevice::Text)) {
QDomDocument doc_inst(QDomImplementation().createDocumentType("html", QString(), QString()));
auto html = doc_inst.createElement("html");
doc_inst.appendChild(html);
auto body = doc_inst.createElement("body");
html.appendChild(body);
inst->buildPageHTML(body);
QTextStream tout(&tfile);
doc_inst.save(tout, 2);
tout.flush();
}
};
for (auto& node : tool.fragment_defines)
html_output(node);
for (auto& node : tool.storyline_defines)
html_output(node);
for (auto& node : tool.volume_defines)
html_output(node);
QDir::setCurrent(destination_dir.canonicalPath());
auto dot_src = tool.storylines_paint(tool.storyline_defines.values());
QFile dot_file(QDir::current().filePath("relates.dot"));
if (dot_file.open(QIODevice::WriteOnly | QIODevice::Text)) {
QTextStream txt(&dot_file);
txt.setCodec("UTF-8");
txt << dot_src;
txt.flush();
}
system("dot -Tsvg relates.dot -o relates.svg");
auto vols_src = tool.volumes_paint(tool.volume_defines.values(), tool.storyline_defines.values());
QFile vols_file(QDir::current().filePath("volumes_group.dot"));
if (vols_file.open(QIODevice::WriteOnly | QIODevice::Text)) {
QTextStream txt(&vols_file);
txt.setCodec("UTF-8");
txt << vols_src;
txt.flush();
}
system("fdp -Tsvg volumes_group.dot -o volumes_group.svg");
{
QFile tfile("./index.html");
if (tfile.open(QIODevice::WriteOnly | QIODevice::Text)) {
QDomDocument doc_inst(QDomImplementation().createDocumentType("html", QString(), QString()));
auto html = doc_inst.createElement("html");
doc_inst.appendChild(html);
auto body = doc_inst.createElement("body");
html.appendChild(body);
auto dom_storyline = doc_inst.createElement("div");
auto dom_storyline_title = doc_inst.createElement("h2");
dom_storyline_title.appendChild(doc_inst.createTextNode("故事脉络"));
dom_storyline.appendChild(dom_storyline_title);
body.appendChild(dom_storyline);
auto lines = tool.storyline_defines.values();
std::sort(lines.begin(), lines.end(), [](std::shared_ptr<printer::StoryLine> a, std::shared_ptr<printer::StoryLine> b)->bool {
auto a_elm = std::dynamic_pointer_cast<const example_novel::StoryDefine>(a->accessPeers()->element());
auto b_elm = std::dynamic_pointer_cast<const example_novel::StoryDefine>(b->accessPeers()->element());
return a_elm->sort() < b_elm->sort();
});
for (auto& inst_line : lines) {
auto dom_line = doc_inst.createElement("p");
dom_storyline.appendChild(dom_line);
auto line_href = doc_inst.createElement("a");
line_href.setAttribute("href", "file:///" + inst_line->pageRefers());
auto a_elm = std::dynamic_pointer_cast<const example_novel::StoryDefine>(inst_line->accessPeers()->element());
line_href.appendChild(doc_inst.createTextNode(QString("%1.%2").arg(a_elm->sort()).arg(a_elm->signature())));
dom_line.appendChild(line_href);
}
auto dom_volume = doc_inst.createElement("div");
auto dom_volume_title = doc_inst.createElement("h2");
dom_volume_title.appendChild(doc_inst.createTextNode("分卷内容"));
dom_volume.appendChild(dom_volume_title);
body.appendChild(dom_volume);
for (auto& inst_volume : tool.volume_defines) {
auto dom_volume_ref = doc_inst.createElement("p");
dom_volume.appendChild(dom_volume_ref);
auto volume_href = doc_inst.createElement("a");
volume_href.setAttribute("href", "file:///" + inst_volume->pageRefers());
volume_href.appendChild(doc_inst.createTextNode(inst_volume->accessPeers()->element()->signature()));
dom_volume_ref.appendChild(volume_href);
}
auto dom_fragment = doc_inst.createElement("div");
auto dom_fragment_title = doc_inst.createElement("h2");
dom_fragment_title.appendChild(doc_inst.createTextNode("情节集合"));
dom_fragment.appendChild(dom_fragment_title);
body.appendChild(dom_fragment);
auto table_cube = doc_inst.createElement("table");
dom_fragment.appendChild(table_cube);
int row_ctrl = 0;
QDomElement elm_row;
for (auto& inst_frag : tool.fragment_defines) {
if (row_ctrl++ % 4 == 0) {
elm_row = doc_inst.createElement("tr");
table_cube.appendChild(elm_row);
}
auto dom_fragment_ref = doc_inst.createElement("td");
elm_row.appendChild(dom_fragment_ref);
auto frag_href = doc_inst.createElement("a");
frag_href.setAttribute("href", "file:///" + inst_frag->pageRefers());
frag_href.appendChild(doc_inst.createTextNode(inst_frag->accessPeers()->element()->signature()));
dom_fragment_ref.appendChild(frag_href);
}
auto dom_relate = doc_inst.createElement("div");
auto dom_relate_title = doc_inst.createElement("h2");
dom_relate_title.appendChild(doc_inst.createTextNode("联系图"));
dom_relate.appendChild(dom_relate_title);
body.appendChild(dom_relate);
auto img = doc_inst.createElement("img");
img.setAttribute("src", "file:///" + QDir::current().filePath("relates.svg"));
dom_relate.appendChild(img);
dom_relate.appendChild(doc_inst.createElement("br"));
img = doc_inst.createElement("img");
img.setAttribute("src", "file:///" + QDir::current().filePath("volumes_group.svg"));
dom_relate.appendChild(img);
QTextStream tout(&tfile);
doc_inst.save(tout, 2);
tout.flush();
}
}
auto current_stamp = QTime::currentTime();
qDebug().noquote() << QString("%html构建消耗时间%1 ms。").arg(time_stamp.msecsTo(current_stamp));
qDebug().noquote() << "%编译成功:" << destination_dir.absoluteFilePath("index.html");
}
void printer::AstGenerate::append_tokens(QDomElement _elm, std::shared_ptr<const ast_gen::SyntaxElement> inst) {
auto dom_tokens = doc.createElement("tokens");
_elm.appendChild(dom_tokens);
for (auto& token : inst->selfTokens()) {
auto dom_token = doc.createElement("token");
dom_tokens.appendChild(dom_token);
dom_token.setAttribute("text", token->token()->content());
dom_token.setAttribute("row", token->token()->row());
dom_token.setAttribute("col", token->token()->column());
}
}
printer::AstGenerate::AstGenerate(const QDir& src_rt)
: src_root(src_rt) {
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 <QDateTime>
bool printer::AstGenerate::visit(std::shared_ptr<const ast_gen::ElementAccess> syntax_element) {
switch ((NovelNode) syntax_element->element()->typeMark()) {
case NovelNode::GlobalElement:
{
auto body = doc.createElement("ast");
doc.appendChild(body);
body.setAttribute("time", QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss"));
body.setAttribute("dir_src", src_root.absolutePath());
element_stack.append(body);
}break;
case NovelNode::Document: break;
case NovelNode::StoryDefine:
{
while (element_stack.last().tagName() != "ast") {
element_stack.takeLast();
}
auto current_ast = element_stack.last();
auto story_node = std::dynamic_pointer_cast<const example_novel::StoryDefine>(syntax_element->element());
auto dom_story = doc.createElement("story");
current_ast.appendChild(dom_story);
element_stack.append(dom_story);
dom_story.setAttribute("name", story_node->name());
dom_story.setAttribute("address", (qulonglong) story_node.get());
dom_story.setAttribute("file-path", src_root.relativeFilePath(story_node->filePath()));
dom_story.setAttribute("sort", story_node->sort());
append_tokens(dom_story, story_node);
}break;
case NovelNode::FragmentSlice:
{
while (element_stack.last().tagName() != "story") {
element_stack.takeLast();
}
auto current_story = element_stack.last();
auto slice_node = std::dynamic_pointer_cast<const example_novel::FragmentSlice>(syntax_element->element());
auto dom_slice = doc.createElement("slice");
current_story.appendChild(dom_slice);
element_stack.append(dom_slice);
dom_slice.setAttribute("name", slice_node->name());
dom_slice.setAttribute("address", (qulonglong) slice_node.get());
}break;
case NovelNode::PointDefines:
{
while (element_stack.last().tagName() != "slice") {
element_stack.takeLast();
}
auto current_slice = element_stack.last();
auto point_node = std::dynamic_pointer_cast<const example_novel::PointDefines>(syntax_element->element());
auto dom_point = doc.createElement("point");
current_slice.appendChild(dom_point);
element_stack.append(dom_point);
dom_point.setAttribute("name", point_node->name());
dom_point.setAttribute("address", (qulonglong) point_node.get());
dom_point.setAttribute("file-path", src_root.relativeFilePath(point_node->filePath()));
append_tokens(dom_point, point_node);
}break;
case NovelNode::TextSection:
{
while (element_stack.last().tagName() == "text") {
element_stack.takeLast();
}
auto current_pnode = element_stack.last();
auto text_node = std::dynamic_pointer_cast<const example_novel::TextSection>(syntax_element->element());
auto dom_text = doc.createElement("text-section");
current_pnode.appendChild(dom_text);
dom_text.setAttribute("text", text_node->content());
dom_text.setAttribute("file-path", src_root.relativeFilePath(text_node->filePath()));
append_tokens(dom_text, text_node);
}break;
case NovelNode::PointRefers:
{
while (element_stack.last().tagName() != "article" && element_stack.last().tagName() != "slice") {
element_stack.takeLast();
}
auto current_pnode = element_stack.last();
auto refer_node = std::dynamic_pointer_cast<const example_novel::PointRefers>(syntax_element->element());
auto dom_refer = doc.createElement("refer");
element_stack.append(dom_refer);
current_pnode.appendChild(dom_refer);
dom_refer.setAttribute("story", refer_node->storyRefer());
dom_refer.setAttribute("slice", refer_node->sliceRefer());
dom_refer.setAttribute("point", refer_node->pointRefer());
dom_refer.setAttribute("file-path", src_root.relativeFilePath(refer_node->filePath()));
append_tokens(dom_refer, refer_node);
}break;
case NovelNode::VolumeDefine:
{
while (element_stack.last().tagName() != "ast") {
element_stack.takeLast();
}
auto current_ast = element_stack.last();
auto volume_node = std::dynamic_pointer_cast<const example_novel::VolumeDefine>(syntax_element->element());
auto dom_volume = doc.createElement("volume");
current_ast.appendChild(dom_volume);
element_stack.append(dom_volume);
dom_volume.setAttribute("name", volume_node->name());
dom_volume.setAttribute("address", (qulonglong) volume_node.get());
dom_volume.setAttribute("file-path", src_root.relativeFilePath(volume_node->filePath()));
append_tokens(dom_volume, volume_node);
}break;
case NovelNode::ArticleDefine:
{
while (element_stack.last().tagName() != "volume") {
element_stack.takeLast();
}
auto current_volume = element_stack.last();
auto article_node = std::dynamic_pointer_cast<const example_novel::ArticleDefine>(syntax_element->element());
auto dom_article = doc.createElement("article");
current_volume.appendChild(dom_article);
element_stack.append(dom_article);
dom_article.setAttribute("name", article_node->name());
dom_article.setAttribute("address", (qulonglong) article_node.get());
dom_article.setAttribute("file-path", src_root.relativeFilePath(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<const example_novel::RankDeclare>(syntax_element->element());
auto dom_rank = doc.createElement("rank");
ast_element.appendChild(dom_rank);
dom_rank.setAttribute("rank", rank_node->rankNumber());
dom_rank.setAttribute("doc-path", src_root.relativeFilePath(rank_node->filePath()));
append_tokens(dom_rank, rank_node);
}break;
default:
break;
}
return true;
}