854 lines
32 KiB
C++
854 lines
32 KiB
C++
#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::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<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() + 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<const FragmentRefers>(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 FragmentRefers>(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<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() + 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<const FragmentRefers>(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<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 FragmentDefine>(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<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 FragmentDefine>(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<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::FragmentDefine) {
|
||
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::FragmentDefine: {
|
||
auto inst = this->fragment_defines[novel_node->element()->signature()];
|
||
line->append(inst);
|
||
}return;
|
||
case NovelNode::FragmentRefer: {
|
||
auto refer_node = std::dynamic_pointer_cast<const FragmentRefers>(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::FragmentRefer == (NovelNode)novel_node->element()->typeMark()) {
|
||
auto refer_node = std::dynamic_pointer_cast<const FragmentRefers>(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 + u8"#" + 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 u8"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(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<const example_novel::FragmentDefine>(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<const example_novel::StoryDefine>(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<const example_novel::FragmentRefers>(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<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::FragmentDefine) {
|
||
auto fragment_elem = std::dynamic_pointer_cast<const example_novel::FragmentDefine>(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<const example_novel::StoryDefine>(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<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::FragmentRefer) {
|
||
auto refer_fragment = std::dynamic_pointer_cast<const example_novel::FragmentRefers>(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<const example_novel::ArticleDefine>(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<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(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);
|
||
}
|
||
|
||
#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(u8"html", QString(), QString()));
|
||
auto html = doc_inst.createElement(u8"html");
|
||
doc_inst.appendChild(html);
|
||
|
||
auto body = doc_inst.createElement(u8"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(u8"relates.dot"));
|
||
if (dot_file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||
QTextStream txt(&dot_file);
|
||
txt.setCodec(u8"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(u8"volumes_group.dot"));
|
||
if (vols_file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||
QTextStream txt(&vols_file);
|
||
txt.setCodec(u8"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(u8"html", QString(), QString()));
|
||
auto html = doc_inst.createElement(u8"html");
|
||
doc_inst.appendChild(html);
|
||
|
||
auto body = doc_inst.createElement(u8"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(u8"<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"));
|
||
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(u8"href", u8"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(u8"%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(u8"<EFBFBD>־<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"));
|
||
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(u8"href", u8"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(u8"<EFBFBD><EFBFBD><EFBFBD>ڼ<EFBFBD><EFBFBD><EFBFBD>"));
|
||
dom_fragment.appendChild(dom_fragment_title);
|
||
body.appendChild(dom_fragment);
|
||
|
||
auto table_cube = doc_inst.createElement(u8"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(u8"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(u8"href", u8"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(u8"div");
|
||
auto dom_relate_title = doc_inst.createElement(u8"h2");
|
||
dom_relate_title.appendChild(doc_inst.createTextNode(u8"<EFBFBD><EFBFBD>ϵͼ"));
|
||
dom_relate.appendChild(dom_relate_title);
|
||
body.appendChild(dom_relate);
|
||
|
||
auto img = doc_inst.createElement(u8"img");
|
||
img.setAttribute(u8"src", u8"file:///" + QDir::current().filePath(u8"relates.svg"));
|
||
dom_relate.appendChild(img);
|
||
dom_relate.appendChild(doc_inst.createElement("br"));
|
||
img = doc_inst.createElement(u8"img");
|
||
img.setAttribute(u8"src", u8"file:///" + QDir::current().filePath(u8"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(u8"%html<6D><6C><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD>䣺%1 ms<6D><73>").arg(time_stamp.msecsTo(current_stamp));
|
||
qDebug().noquote() << u8"%<25><><EFBFBD><EFBFBD><EFBFBD>ɹ<EFBFBD><C9B9><EFBFBD>" << destination_dir.absoluteFilePath(u8"index.html");
|
||
}
|
||
|
||
void printer::AstGenerate::append_tokens(QDomElement _elm, std::shared_ptr<const ast_gen::SyntaxElement> 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 <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(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<const example_novel::StoryDefine>(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<const example_novel::FragmentDefine>(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<const example_novel::TextSection>(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<const example_novel::FragmentRefers>(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<const example_novel::VolumeDefine>(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<const example_novel::ArticleDefine>(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<const example_novel::RankDeclare>(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;
|
||
}
|