diff --git a/QtNovelDesc.pro b/QtNovelDesc.pro index 8ea782c..016a827 100644 --- a/QtNovelDesc.pro +++ b/QtNovelDesc.pro @@ -4,4 +4,5 @@ SUBDIRS += \ GenericConsole \ WordsIDE \ libConfig \ - libProjectManager + libProjectManager \ + u_test diff --git a/QtNovelDesc.pro.user b/QtNovelDesc.pro.user index 12c2b92..1b9c4c1 100644 --- a/QtNovelDesc.pro.user +++ b/QtNovelDesc.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId @@ -99,7 +99,7 @@ qt.qt5.51211.win64_msvc2017_64_kit 0 0 - 3 + 0 0 D:\Projects\Cpp\build-QtNovelDesc-Desktop_Qt_5_12_11_MSVC2017_64bit-Debug @@ -337,235 +337,16 @@ 2 - Qt4ProjectManager.Qt4RunConfiguration:D:/Projects/Cpp/QtNovelDesc/DesParser/DesParser.pro - D:/Projects/Cpp/QtNovelDesc/DesParser/DesParser.pro + Qt4ProjectManager.Qt4RunConfiguration:D:/Projects/Cpp/QtNovelDesc/u_test/u_test.pro + D:/Projects/Cpp/QtNovelDesc/u_test/u_test.pro false true true false true - D:/Projects/Cpp/build-QtNovelDesc-Desktop_Qt_5_12_11_MSVC2017_64bit-Debug/DesParser + D:/Projects/Cpp/build-QtNovelDesc-Desktop_Qt_5_12_11_MSVC2017_64bit-Debug/u_test - - dwarf - - cpu-cycles - - - 250 - - -e - cpu-cycles - --call-graph - dwarf,4096 - -F - 250 - - -F - true - 4096 - false - false - 1000 - - true - - - false - false - false - false - true - 0.01 - 10 - true - kcachegrind - 1 - - 25 - - 1 - true - false - true - - valgrind - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - - - 2 - - Qt4ProjectManager.Qt4RunConfiguration:D:/Projects/Cpp/QtNovelDesc/Testpad/Testpad.pro - D:/Projects/Cpp/QtNovelDesc/Testpad/Testpad.pro - false - true - true - false - true - D:/Projects/Cpp/build-QtNovelDesc-Desktop_Qt_5_12_11_MSVC2017_64bit-Debug/Testpad - - - dwarf - - cpu-cycles - - - 250 - - -e - cpu-cycles - --call-graph - dwarf,4096 - -F - 250 - - -F - true - 4096 - false - false - 1000 - - true - - - false - false - false - false - true - 0.01 - 10 - true - kcachegrind - 1 - - 25 - - 1 - true - false - true - - valgrind - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - - - 2 - - Qt4ProjectManager.Qt4RunConfiguration:D:/Projects/Cpp/QtNovelDesc/CoreTest/CoreTest.pro - D:/Projects/Cpp/QtNovelDesc/CoreTest/CoreTest.pro - false - true - true - false - true - D:/Projects/Cpp/build-QtNovelDesc-Desktop_Qt_5_12_11_MSVC2017_64bit-Debug/CoreTest - - - dwarf - - cpu-cycles - - - 250 - - -e - cpu-cycles - --call-graph - dwarf,4096 - -F - 250 - - -F - true - 4096 - false - false - 1000 - - true - - - false - false - false - false - true - 0.01 - 10 - true - kcachegrind - 1 - - 25 - - 1 - true - false - true - - valgrind - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - - - 2 - - Qt4ProjectManager.Qt4RunConfiguration:D:/Projects/Cpp/QtNovelDesc/WordsIDE/WordsIDE.pro - D:/Projects/Cpp/QtNovelDesc/WordsIDE/WordsIDE.pro - false - true - true - false - true - D:/Projects/Cpp/build-QtNovelDesc-Desktop_Qt_5_12_11_MSVC2017_64bit-Debug/WordsIDE - - 4 + 1 diff --git a/WordsIDE/WordsIDE.pro b/WordsIDE/WordsIDE.pro index 966cf8a..aa07b07 100644 --- a/WordsIDE/WordsIDE.pro +++ b/WordsIDE/WordsIDE.pro @@ -29,6 +29,7 @@ SOURCES += \ mainwindow.cpp \ manager_docs.cpp \ messagespresent.cpp \ + parsebridge.cpp \ presentcontainer.cpp \ projectpresent.cpp \ route.cpp \ @@ -58,6 +59,7 @@ HEADERS += \ manager_docs.h \ messagespresent.h \ opstream.h \ + parsebridge.h \ presentcontainer.h \ projectpresent.h \ route.h \ diff --git a/WordsIDE/appcore.cpp b/WordsIDE/appcore.cpp index d654dcb..03e6b0b 100644 --- a/WordsIDE/appcore.cpp +++ b/WordsIDE/appcore.cpp @@ -80,7 +80,7 @@ QList AppCore::getConfigs(QList types) const for(auto &x : types){ if(x == Scale::Global) rets << global_config; - if(x == Scale::Project && current_project->isOpen()) + if(x == Scale::Project && current_project->isOpenning()) rets << current_project->configraions(); } diff --git a/WordsIDE/appcore.h b/WordsIDE/appcore.h index 7ab4078..ea397d6 100644 --- a/WordsIDE/appcore.h +++ b/WordsIDE/appcore.h @@ -5,7 +5,6 @@ #include #include #include -#include #include class MainWindow; @@ -71,8 +70,7 @@ namespace Core { void setCurrentProject(Project::ProjectManager *project); Project::ProjectManager* currentProject() const; - QList getConfigs(QList types) const; - Parse::Result::ParseCore * parseCore() const; + QList getConfigs(QList types) const; QList extensions(const QString &suffix = QString()) const; diff --git a/WordsIDE/fragmentsorderpresent.h b/WordsIDE/fragmentsorderpresent.h index 70abb98..0213345 100644 --- a/WordsIDE/fragmentsorderpresent.h +++ b/WordsIDE/fragmentsorderpresent.h @@ -7,7 +7,6 @@ #include #include #include -#include namespace DataModel { class FragmentsOrderviewModel : public Schedule::AccessibleObject { diff --git a/WordsIDE/mainwindow.cpp b/WordsIDE/mainwindow.cpp index ab4385a..804b49f 100644 --- a/WordsIDE/mainwindow.cpp +++ b/WordsIDE/mainwindow.cpp @@ -116,7 +116,7 @@ void MainWindow::initial_menubar(QMenuBar *mbar) { XApp::disp_core->postCommand(OpenProject(file)); build_internal(true); }); - sync_kernel->actionEnableSync(opnp, [this]() -> bool { return !project_manager->isOpen(); }); + sync_kernel->actionEnableSync(opnp, [this]() -> bool { return !project_manager->isOpenning(); }); auto newp = project->addAction("新建项目", [this]() { auto name = QInputDialog::getText(this, "输入项目名称", "项目名称"); @@ -128,13 +128,13 @@ void MainWindow::initial_menubar(QMenuBar *mbar) { XApp::disp_core->postCommand(NewProject(QDir(dir_path), name)); }); - sync_kernel->actionEnableSync(newp, [this]() -> bool { return !project_manager->isOpen(); }); + sync_kernel->actionEnableSync(newp, [this]() -> bool { return !project_manager->isOpenning(); }); auto clsp = project->addAction("关闭项目", [this]() { XApp::disp_core->postCommand(CloseProject()); this->refresh_views(); }); - sync_kernel->actionEnableSync(clsp, [this]() -> bool { return project_manager->isOpen(); }); + sync_kernel->actionEnableSync(clsp, [this]() -> bool { return project_manager->isOpenning(); }); project->addSeparator(); auto pnew = project->addAction("新建路径", [this]() { @@ -142,10 +142,10 @@ void MainWindow::initial_menubar(QMenuBar *mbar) { if (packages != "") XApp::disp_core->postCommand(NewPackage(packages)); }); - sync_kernel->actionEnableSync(pnew, [this]() -> bool { return project_manager->isOpen(); }); + sync_kernel->actionEnableSync(pnew, [this]() -> bool { return project_manager->isOpenning(); }); auto _xnew = project->addMenu("新建文件"); - _xnew->setEnabled(project_manager->isOpen()); + _xnew->setEnabled(project_manager->isOpenning()); auto types = docs_container->fileTypes(); for (auto &t : types) { _xnew->addAction(t, [this, &t]() { @@ -161,12 +161,12 @@ void MainWindow::initial_menubar(QMenuBar *mbar) { XApp::disp_core->postCommand(NewFile(group_path, name, t)); }); } - sync_kernel->widgetEnableSync(_xnew, [this]() -> bool { return project_manager->isOpen(); }); + sync_kernel->widgetEnableSync(_xnew, [this]() -> bool { return project_manager->isOpenning(); }); project->addSeparator(); auto sav = project->addAction("保存全部", [this]() { XApp::disp_core->postCommand(SaveAll()); }); sav->setShortcut(QKeySequence::StandardKey::Save); - sync_kernel->actionEnableSync(sav, [this]() -> bool { return project_manager->isOpen(); }); + sync_kernel->actionEnableSync(sav, [this]() -> bool { return project_manager->isOpenning(); }); project->addSeparator(); project->addAction("退出", [this]() { @@ -218,7 +218,7 @@ void MainWindow::initial_menubar(QMenuBar *mbar) { change->addAction("编辑视图"); view->addSeparator(); auto func = view->addMenu("功能视图"); - sync_kernel->widgetEnableSync(func, [this]() { return this->project_manager->isOpen(); }); + sync_kernel->widgetEnableSync(func, [this]() { return this->project_manager->isOpenning(); }); // 项目管理 { auto project_v = func->addAction("项目管理", [this](bool v) { XApp::disp_core->postCommand(CompVisible(this, project_present, v)); }); @@ -302,7 +302,7 @@ void MainWindow::initial_menubar(QMenuBar *mbar) { exp->addSeparator(); exp->addAction("导出TXT内容"); auto build = tool->addAction("编译", [this]() { this->build_internal(); }); - sync_kernel->actionEnableSync(build, [this]() -> bool { return project_manager->isOpen(); }); + sync_kernel->actionEnableSync(build, [this]() -> bool { return project_manager->isOpenning(); }); // 窗口菜单 auto window = mbar->addMenu("窗口"); @@ -483,7 +483,7 @@ void MainWindow::hasBeenClosed(const Core::Route &key) { docs_container->hasBeen void MainWindow::closeEvent(QCloseEvent *event) { // 关闭事件 - if (project_manager->isOpen()) { + if (project_manager->isOpenning()) { XApp::disp_core->postCommand(CloseProject()); } diff --git a/WordsIDE/manager_docs.cpp b/WordsIDE/manager_docs.cpp index e5f6680..af95383 100644 --- a/WordsIDE/manager_docs.cpp +++ b/WordsIDE/manager_docs.cpp @@ -39,12 +39,12 @@ QList DocumentsManager::fileTypes() const void DocumentsManager::newFile(const Route &group_path, const QString &name, const QString &suffix) { auto list = rtcore->extensions(suffix); - QDir root = pjtins->projectDir(); + QDir root = pjtins->directory(); auto rst = list.first()->create(root, name, suffix); if(std::get<0>(rst)){ auto rpath = root.relativeFilePath(std::get<1>(rst)); - auto idx = pjtins->signFile(converter(group_path), name, rpath); + auto idx = pjtins->appendFile(converter(group_path), name, rpath); openFile(converter(idx)); } else{ @@ -99,7 +99,7 @@ void DocumentsManager::removeNode(const Route &node_path) } close(path_buff); - pjtins->deleteTarget(node_mindex); + pjtins->delete(node_mindex); } void DocumentsManager::renameNode(const Route &node_path, const QString &name) diff --git a/WordsIDE/parsebridge.cpp b/WordsIDE/parsebridge.cpp new file mode 100644 index 0000000..fd23f42 --- /dev/null +++ b/WordsIDE/parsebridge.cpp @@ -0,0 +1,416 @@ +#include "parsebridge.h" + +#include +#include +#include + +using namespace bridge; + +class Impl_NovelParseException : public Config::ParseException { +private: + QString title_s, reason_s; + +public: + Impl_NovelParseException(const QString &t, const QString &r) { + this->title_s = t; + this->reason_s = r; + } + + // ParseException interface +public: + virtual QString reason() const override { return reason_s; } + virtual QString title() const override { return reason_s; } +}; + +ParseBridge::ParseBridge() : chains_model(new QStandardItemModel), volumes_model(new QStandardItemModel), errors_model(new QStandardItemModel) {} + +ParseBridge::~ParseBridge() { + delete chains_model; + delete volumes_model; + delete errors_model; + + for (auto it : docs_store) + delete it; + docs_store.clear(); +} + +QString ParseBridge::novelName() const { return name_store; } + +QStandardItemModel *ParseBridge::volumesPresentModel() const { return volumes_model; } + +void bridge::ParseBridge::load(const QString &data_path) { + // clear cache + this->doc_ins.clear(); + chains_model->clear(); + volumes_model->clear(); + errors_model->clear(); + + for (auto it : docs_store) + delete it; + docs_store.clear(); + + // 重新载入小说编译结果 + QFileInfo target_xml(data_path); + if (!target_xml.exists()) + throw new Impl_NovelParseException("小说解析过程错", "指定路径数据文件不存在:" + data_path); + + QFile data_in(target_xml.canonicalFilePath()); + if (!data_in.open(QIODevice::ReadOnly | QIODevice::Text)) + throw new Impl_NovelParseException("小说解析过程错", "指定数据文件无法打开:" + target_xml.canonicalFilePath()); + + QString err_msg; + int col, row; + if (!this->doc_ins.setContent(&data_in, &err_msg, &row, &col)) { + throw new Impl_NovelParseException("小说解析过程我", QString("数据文件格式错:%3").arg(row).arg(col).arg(err_msg)); + } + + // 载入语法节点 + auto root = doc_ins.documentElement(); + name_store = root.attribute("name", "空白小说名称"); + auto childnodes = root.childNodes(); + for (auto idx = 0; idx < childnodes.size(); ++idx) { + auto child = childnodes.at(idx); + if (child.isElement()) { + auto elm_inst = child.toElement(); + if (elm_inst.tagName() == "doc") { + load_document(elm_inst, this->docs_store); + } + } + } +} + +void ParseBridge::load_document(const QDomElement &pdoc, std::vector node_sets) { + auto doc_name = pdoc.attribute("name", "未命名文档名"); + auto file_path = pdoc.attribute("file"); + auto doc_ins = new DocumentInst(doc_name, file_path); + node_sets.push_back(doc_ins); + + // 载入解析错误 + auto errors = pdoc.elementsByTagName("error"); + for (auto idx = 0; idx < errors.size(); ++idx) { + auto e_elm = errors.at(idx).toElement(); + load_errors(errorsPresentModel(), e_elm, doc_ins); + } + + auto children = pdoc.childNodes(); + for (auto idx = 0; idx < children.size(); ++idx) { + auto node = children.at(idx); + if (node.isElement()) { + load_element(node.toElement(), doc_ins); + } + } +} + +void ParseBridge::load_element(const QDomElement &telm, DocumentInst *pinst, QStandardItem *pitem) { + if (telm.tagName() == "story") + load_story(chainsPresentModel(), telm, pinst); + else if (telm.tagName() == "text") + load_desc(telm, static_cast(pitem)); + else if (telm.tagName() == "fragment") + load_fragment(telm, pitem); + else if (telm.tagName() == "frag-refer") + load_frag_refer(telm, pitem); + else if (telm.tagName() == "volume") + load_volumes(volumesPresentModel(), telm, pinst); + else if (telm.tagName() == "article") + load_article(telm, pitem); + else + throw new Impl_NovelParseException("小说解析结果载入错", "位置tagName:" + telm.tagName()); +} + +void ParseBridge::load_errors(QStandardItemModel *anchor, const QDomElement &error_elm, DocumentInst *pinst) { + auto pos_value = error_elm.attribute("pos"); + auto message = error_elm.attribute("message"); + + QRegExp exp0("(\\d+)"); + auto index = exp0.indexIn(pos_value); + auto row = exp0.cap(1).toInt(); + exp0.indexIn(pos_value, index + exp0.cap(1).length()); + auto col = exp0.cap(1).toInt(); + + auto perror = new ParseException(pinst); + perror->load(message, row, col); + + QList inst_row; + inst_row << perror; + inst_row << new SupplyItem(perror); + inst_row << new SupplyItem(perror); + inst_row << new SupplyItem(perror); + anchor->appendRow(inst_row); +} + +#define PEAK_POSITION(e) \ + auto start_pos = (e).attribute("start-pos"); \ + auto end_pos = (e).attribute("end-pos"); \ + QRegExp exp("(\\d+)"); \ + auto xidx = exp.indexIn(start_pos); \ + auto start_row = exp.cap(1).toInt(); \ + exp.indexIn(start_pos, xidx + exp.cap(1).length()); \ + auto start_col = exp.cap(1).toInt(); \ + xidx = exp.indexIn(end_pos); \ + auto end_row = exp.cap(1).toInt(); \ + exp.indexIn(start_pos, xidx + exp.cap(1).length()); \ + auto end_col = exp.cap(1).toInt(); + +void ParseBridge::load_story(QStandardItemModel *model, const QDomElement &chain_elm, DocumentInst *pinst) { + auto name = chain_elm.attribute("name"); + auto index = chain_elm.attribute("sort"); + auto story = new StorychainInst(pinst, name); + model->appendRow(story); + story->indexSet(index.toInt()); + + PEAK_POSITION(chain_elm); + + story->loadPos(start_row, start_col, end_row, end_col); + + auto children = chain_elm.childNodes(); + for (auto idx = 0; idx < children.size(); ++idx) { + auto node = children.at(idx); + if (node.isElement()) { + load_element(node.toElement(), nullptr, story); + } + } +} + +void ParseBridge::load_desc(const QDomElement &desc_elm, ContentNode *pitem) { + auto content = desc_elm.attribute("content"); + pitem->append(content); +} + +void ParseBridge::load_fragment(const QDomElement &frag_elm, QStandardItem *pinst) { + auto name = frag_elm.attribute("name"); + auto logic_index = frag_elm.attribute("logic-index"); + PEAK_POSITION(frag_elm); + + auto frag_inst = new StoryfragmentInst(name); + pinst->appendRow(frag_inst); + + frag_inst->setLogicIndex(logic_index.toInt()); + frag_inst->loadPos(start_row, start_col, end_row, end_col); + + auto children = frag_elm.childNodes(); + for (auto idx = 0; idx < children.size(); ++idx) { + auto node = children.at(idx); + if (node.isElement()) { + load_element(node.toElement(), nullptr, frag_inst); + } + } +} + +void ParseBridge::load_frag_refer(const QDomElement &refer_elm, QStandardItem *pitem) { + auto story = refer_elm.attribute("story-ref"); + auto frag = refer_elm.attribute("fragment-ref"); + PEAK_POSITION(refer_elm); + + auto item = locate_node(chainsPresentModel(), QStringList() << story << frag); + auto refer_inst = new StoryfragmentRefer(static_cast(item)); + pitem->appendRow(refer_inst); + refer_inst->appointStory(story); + refer_inst->appointFragment(frag); + refer_inst->loadPos(start_row, start_col, end_row, end_col); + + auto children = refer_elm.childNodes(); + for (auto idx = 0; idx < children.size(); ++idx) { + auto node = children.at(idx); + if (node.isElement()) { + load_element(node.toElement(), nullptr, refer_inst); + } + } +} + +void ParseBridge::load_volumes(QStandardItemModel *model, const QDomElement &volume_elm, DocumentInst *pinst) { + auto name = volume_elm.attribute("content"); + PEAK_POSITION(volume_elm); + + auto volume = new StoryvolumeInst(pinst, name); + model->appendRow(volume); + volume->loadPos(start_row, start_col, end_row, end_col); + + auto children = volume_elm.childNodes(); + for (auto idx = 0; idx < children.size(); ++idx) { + auto node = children.at(idx); + if (node.isElement()) { + load_element(node.toElement(), nullptr, volume); + } + } +} + +void ParseBridge::load_article(const QDomElement &article_elm, QStandardItem *pitem) { + auto name = article_elm.attribute("content"); + PEAK_POSITION(article_elm); + + auto article = new StoryarticleInst(name); + pitem->appendRow(article); + article->loadPos(start_row, start_col, end_row, end_col); + + auto children = article_elm.childNodes(); + for (auto idx = 0; idx < children.size(); ++idx) { + auto node = children.at(idx); + if (node.isElement()) { + load_element(node.toElement(), nullptr, article); + } + } +} + +QStandardItem *ParseBridge::locate_node(QStandardItemModel *model, const QStringList path) { + QStandardItem *current_item = nullptr; + for (auto n : path) { + if (!current_item) + current_item = model->findChild(n, Qt::FindChildOption::FindDirectChildrenOnly); + else { + for (auto idx = 0; idx < current_item->rowCount(); ++idx) { + if (current_item->child(idx)->text() == n) { + current_item = current_item->child(idx); + continue; + } + } + } + } + + return current_item; +} + +ParseException::ParseException(DocumentInst *pinst) : key_store(std::make_tuple(pinst, "尚未载入异常信息", 0, 0)) { setText(std::get<1>(key_store)); } + +void ParseException::load(const QString &message, int row, int col) { + this->key_store = std::make_tuple(std::get<0>(key_store), message, row, col); + setText(std::get<1>(key_store)); +} + +const DocumentInst *ParseException::doc() const { return std::get<0>(key_store); } + +QString ParseException::message() const { return std::get<1>(key_store); } + +int ParseException::row() const { return std::get<2>(key_store); } + +int ParseException::col() const { return std::get<3>(key_store); } + +QString ParseException::operator[](int index) { + switch (index) { + case 0: + return message(); + case 1: + return QString("%1").arg(row()); + case 2: + return QString("%1").arg(col()); + case 3: + return QString("%1").arg(doc()->name()); + default: + return "超出索引范围"; + } +} + +DocumentInst::DocumentInst(const QString &name, const QString &path) : n(name), p(path) {} + +QString DocumentInst::name() const { return n; } + +QString DocumentInst::path() const { return p; } + +StorychainInst::StorychainInst(DocumentInst *pinst, const QString &name) : ContentNode(name), pinst_store(pinst) {} + +void StorychainInst::indexSet(int sort) { this->sort_store = sort; } + +int StorychainInst::sortIndex() const { return sort_store; } + +ContentNode::ContentNode(const QString &name) { + setText(name); + name_store = name; +} + +std::tuple SyntaxNode::startPos() const { return this->start; } + +std::tuple SyntaxNode::endPos() const { return this->end; } + +void SyntaxNode::loadPos(int start_r, int start_c, int end_r, int end_c) { + this->start = std::make_tuple(start_r, start_c); + this->end = std::make_tuple(end_r, end_c); +} + +void ContentNode::append(const QString §ion) { this->desc_sections += section + "\n"; } + +QString ContentNode::desc() const { return desc_sections; } + +void ContentNode::clear() { desc_sections = ""; } + +DocumentInst *StorychainInst::doc() const { return pinst_store; } + +QString StorychainInst::operator[](int index) { + switch (index) { + case 0: + return text(); + case 1: + return QString("%1").arg(sortIndex()); + case 2: + return desc(); + default: + return "超出索引范围"; + } +} + +StoryfragmentInst::StoryfragmentInst(const QString &name) : ContentNode(name) {} + +int StoryfragmentInst::logicIndex() const { return sort_store; } + +void StoryfragmentInst::setLogicIndex(int index) { this->sort_store = index; } + +QString StoryfragmentInst::operator[](int index) { + switch (index) { + case 0: + return text(); + case 1: + return QString("%1").arg(logicIndex()); + case 2: + return desc(); + default: + return "超出有效索引范围"; + } +} + +QString StoryfragmentRefer::storyRef() const { return this->story; } + +void StoryfragmentRefer::appointStory(const QString &ref) { this->story = ref; } + +QString StoryfragmentRefer::fragmentRef() const { return fragment; } + +void StoryfragmentRefer::appointFragment(const QString &ref) { fragment = ref; } + +QString StoryfragmentRefer::operator[](int index) { + switch (index) { + case 0: + return storyRef(); + case 1: + return fragmentRef(); + case 2: + return desc(); + default: + return "超出有效索引范围"; + } +} + +StoryvolumeInst::StoryvolumeInst(DocumentInst *inst, const QString &name) : ContentNode(name), doc_store(inst) {} + +DocumentInst *StoryvolumeInst::doc() const { return doc_store; } + +QString StoryvolumeInst::operator[](int index) { + switch (index) { + case 0: + return text(); + case 1: + return desc(); + default: + return "超出有效索引范围"; + } +} + +StoryarticleInst::StoryarticleInst(const QString &name) : ContentNode(name) {} + +QString StoryarticleInst::operator[](int index) { + switch (index) { + case 0: + return text(); + case 1: + return desc(); + default: + return "超出有效索引范围"; + } +} diff --git a/WordsIDE/parsebridge.h b/WordsIDE/parsebridge.h new file mode 100644 index 0000000..c987c2e --- /dev/null +++ b/WordsIDE/parsebridge.h @@ -0,0 +1,174 @@ +#ifndef PARSEBRIDGE_H +#define PARSEBRIDGE_H + +#include +#include + +namespace bridge { + + class DocumentInst { + public: + DocumentInst(const QString &name, const QString &path); + + QString name() const; + QString path() const; + + private: + QString n, p; + }; + + class ContentNode : public QStandardItem { + public: + ContentNode(const QString &name); + virtual ~ContentNode() = default; + + virtual void append(const QString §ion); + virtual QString desc() const; + + virtual void clear(); + + private: + QString desc_sections; + QString name_store; + }; + + class SyntaxNode { + public: + virtual ~SyntaxNode() = default; + + virtual std::tuple startPos() const; + virtual std::tuple endPos() const; + virtual void loadPos(int start_r, int start_c, int end_r, int end_c); + + private: + std::tuple start, end; + }; + + class ParseException : public QStandardItem { + public: + ParseException(DocumentInst *pinst); + + void load(const QString &message, int row, int col); + + const DocumentInst *doc() const; + QString message() const; + int row() const; + int col() const; + + QString operator[](int index); + + private: + std::tuple key_store; + }; + + class StorychainInst : public ContentNode, public SyntaxNode { + public: + StorychainInst(DocumentInst *pinst, const QString &name); + + void indexSet(int sort); + int sortIndex() const; + + DocumentInst *doc() const; + QString operator[](int index); + + private: + int sort_store; + DocumentInst *const pinst_store; + }; + + class StoryfragmentInst : public SyntaxNode, public ContentNode { + public: + StoryfragmentInst(const QString &name); + + int logicIndex() const; + void setLogicIndex(int index); + + QString operator[](int index); + + private: + int sort_store; + }; + + class StoryfragmentRefer : public SyntaxNode, public ContentNode { + public: + StoryfragmentRefer(StoryfragmentInst *inst); + + QString storyRef() const; + void appointStory(const QString &ref); + + QString fragmentRef() const; + void appointFragment(const QString &ref); + + QString operator[](int index); + + private: + QString story, fragment; + }; + + class StoryvolumeInst : public SyntaxNode, public ContentNode { + public: + StoryvolumeInst(DocumentInst *inst, const QString &name); + + DocumentInst *doc() const; + + QString operator[](int index); + + private: + DocumentInst *const doc_store; + }; + + class StoryarticleInst : public SyntaxNode, public ContentNode { + public: + StoryarticleInst(const QString &name); + + QString operator[](int index); + }; + + template class SupplyItem : public QStandardItem { + public: + SupplyItem(const T *bitem) : value_store(bitem) { setText(bitem[idx]); } + + private: + const T *const value_store; + }; + + /** + * @brief 小说解析核心 + */ + class ParseBridge { + public: + ParseBridge(); + virtual ~ParseBridge(); + + QString novelName() const; + + QStandardItemModel *chainsPresentModel() const; + QStandardItemModel *volumesPresentModel() const; + QStandardItemModel *errorsPresentModel() const; + + void load(const QString &data_path); + + private: + QStandardItemModel *const chains_model, *const volumes_model, *const errors_model; + QDomDocument doc_ins; + QString name_store; + std::vector docs_store; + + void load_document(const QDomElement &pdoc, std::vector node_sets); + void load_element(const QDomElement &telm, DocumentInst *pinst, QStandardItem *pitem = nullptr); + + void load_errors(QStandardItemModel *anchor, const QDomElement &error_elm, DocumentInst *pinst); + void load_story(QStandardItemModel *model, const QDomElement &chain_elm, DocumentInst *pinst); + void load_desc(const QDomElement &desc_elm, ContentNode *pitem); + void load_fragment(const QDomElement &frag_elm, QStandardItem *pinst); + void load_frag_refer(const QDomElement &refer_elm, QStandardItem *pitem); + + void load_volumes(QStandardItemModel *model, const QDomElement &volume_elm, DocumentInst *pinst); + void load_article(const QDomElement &article_elm, QStandardItem *pitem); + + QStandardItem *locate_node(QStandardItemModel *model, const QStringList path); + }; + +} // namespace bridge + +#endif // PARSEBRIDGE_H diff --git a/libProjectManager/libProjectManager.h b/libProjectManager/libProjectManager.h index 8aea218..3beedff 100644 --- a/libProjectManager/libProjectManager.h +++ b/libProjectManager/libProjectManager.h @@ -76,6 +76,7 @@ namespace Project { * @return 文件集合 */ virtual QList> filesWithEnds(const QString &suffix) const = 0; + /** * @brief 查询节点文件信息,文件节点返回文件的info,包节点返回文简介的info * @param path 树节点路径 @@ -182,6 +183,7 @@ namespace Project { */ virtual bool isModified() const noexcept = 0; }; + } // namespace Project #endif // LIBPROJECTMANAGER_H diff --git a/libProjectManager/xmlprojectmanager.cpp b/libProjectManager/xmlprojectmanager.cpp index 35cb1b1..ea3d508 100644 --- a/libProjectManager/xmlprojectmanager.cpp +++ b/libProjectManager/xmlprojectmanager.cpp @@ -193,11 +193,12 @@ void XMLProjectManager::structure_parser(QDomElement struct_elm, ProjectNode *pn ProjectNode *node = nullptr; if(xnode.tagName()=="package"){ node = new ProjectNode(NodeType::GROUP, xnode.attribute("name")); - } - else if(xnode.tagName() == "file"){ + } else if (xnode.tagName() == "file") { node = new ProjectNode(NodeType::FILE, xnode.attribute("name")); node->setFile(xnode.attribute("path")); all_files_managed << node->file(); + } else { + throw new Impl_ProjectException("项目解析错误", "未对指定节点类型进行解析:" + xnode.tagName()); } pnode->appendRow(node); diff --git a/u_test/main.cpp b/u_test/main.cpp new file mode 100644 index 0000000..9e1ee59 --- /dev/null +++ b/u_test/main.cpp @@ -0,0 +1,18 @@ +#include +#include +#include + +int main(int argc, char *argv[]) +{ + QCoreApplication a(argc, argv); + + QString value = "row:23212,col:5234"; + QRegExp exp("(\\d+)"); + auto offset = exp.indexIn(value); + qDebug() << exp.cap(1); + + exp.indexIn(value, offset + exp.cap(1).length()); + qDebug() << exp.cap(1); + + return a.exec(); +} diff --git a/u_test/u_test.pro b/u_test/u_test.pro new file mode 100644 index 0000000..43177ff --- /dev/null +++ b/u_test/u_test.pro @@ -0,0 +1,18 @@ +QT -= gui + +QT += xml + +CONFIG += c++11 console +CONFIG -= app_bundle + +# You can make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + main.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target