From df4933c839671d075fcd78ef700c3eb0337cda32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=89=E5=AE=87=E6=B8=85=E9=9F=B3?= <2422523675@qq.com> Date: Fri, 25 Nov 2022 15:30:33 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84=E5=9F=BA=E7=A1=80=E5=B0=81?= =?UTF-8?q?=E8=A3=85=EF=BC=8C=E6=9B=B4=E6=96=B0=E9=83=A8=E5=88=86=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- WordsIDE/SourceEditView.cpp | 36 +++++- WordsIDE/SourceEditView.h | 21 +++- WordsIDE/WordsIDE.pro | 2 + WordsIDE/appcore.cpp | 22 ++-- WordsIDE/appcore.h | 13 +- WordsIDE/mainwindow.cpp | 1 + WordsIDE/sourcecodeeditor.cpp | 157 ++++++++++++++++++++++++ WordsIDE/sourcecodeeditor.h | 62 ++++++++++ WordsIDE/storyboardsourceedit.cpp | 23 ++-- WordsIDE/storyboardsourceedit.h | 4 + WordsIDE/storychainsourceeditor.cpp | 28 ++--- WordsIDE/storychainsourceeditor.h | 4 + WordsIDE/storyunitsourceedit.cpp | 28 ++--- WordsIDE/storyunitsourceedit.h | 4 + WordsIDE/storyvolumesourceedit.cpp | 16 +-- WordsIDE/storyvolumesourceedit.h | 4 +- libParse/storyconceptdocumentparser.cpp | 25 +++- libProjectManager/icons.qrc | 1 + libProjectManager/xmlprojectmanager.cpp | 2 + libProjectManager/概念.png | Bin 0 -> 7462 bytes 20 files changed, 384 insertions(+), 69 deletions(-) create mode 100644 WordsIDE/sourcecodeeditor.cpp create mode 100644 WordsIDE/sourcecodeeditor.h create mode 100644 libProjectManager/概念.png diff --git a/WordsIDE/SourceEditView.cpp b/WordsIDE/SourceEditView.cpp index df01cc6..8bcaf06 100644 --- a/WordsIDE/SourceEditView.cpp +++ b/WordsIDE/SourceEditView.cpp @@ -48,8 +48,6 @@ void TextContentEdit::jumpTo(const QList &path) void TextContentEdit::reload(QList configs) { - this->configrations_host = configs; - // TODO: 设置格式 auto font_family = Config::ConfigHelper::getConfigAsDefaultSequence (configs, {"sourcecode_edit","default_font","font_family"}, "微软雅黑"); @@ -68,18 +66,48 @@ void TextContentEdit::rehighlighter() } +void TextContentEdit::resetProcsType(const QString &suffix) +{ + +} + FormattedTextEdit::FormattedTextEdit() : edit_square(new QTextEdit()) { + ex_unit = [](QMenu*){}; connect(edit_square, &QTextEdit::textChanged, [this](){ emit this->dataChanged(this->filePath()); }); + + edit_square->setContextMenuPolicy(Qt::CustomContextMenu); + connect(edit_square, &QTextEdit::customContextMenuRequested, + [this](const QPoint& p){ + auto menu = edit_square->createStandardContextMenu(); + ex_unit(menu); + + menu->exec(edit_square->mapToGlobal(p)); + }); } -void FormattedTextEdit::resetHighlighter(QSyntaxHighlighter *lighter) +void FormattedTextEdit::setContexMenuProcess(std::function exu) { - lighter->setDocument(this->edit_square->document()); + this->ex_unit = exu; +} + +QTextCursor FormattedTextEdit::getTextCursor() +{ + return edit_square->textCursor(); +} + +void FormattedTextEdit::setTextCursor(QTextCursor s) +{ + edit_square->setTextCursor(s); +} + +QString FormattedTextEdit::title() const +{ + return docName(); } QTextDocument *FormattedTextEdit::textDocument() const diff --git a/WordsIDE/SourceEditView.h b/WordsIDE/SourceEditView.h index 849e50e..1eec32f 100644 --- a/WordsIDE/SourceEditView.h +++ b/WordsIDE/SourceEditView.h @@ -17,8 +17,14 @@ namespace Components { FormattedTextEdit(); virtual ~FormattedTextEdit() = default; - void resetHighlighter(QSyntaxHighlighter *lighter); - QTextDocument *textDocument() const; + virtual void rehighlighter() = 0; + virtual void setContexMenuProcess(std::function exu); + virtual QTextCursor getTextCursor(); + virtual void setTextCursor(QTextCursor s); + + // ModeView interface + public: + virtual QString title() const override; // VariedTextView interface public: @@ -26,11 +32,13 @@ namespace Components { virtual QString textContent() const override; virtual void textContentReset(const QString &value) override; + private: + QTextEdit *const edit_square; + std::function ex_unit; protected: - QList configrations_host; - virtual void rehighlighter() = 0; - QTextEdit *const edit_square; + QTextDocument *textDocument() const; + }; class TextContentEditFactory : public Core::FileExtensionFactory @@ -79,6 +87,9 @@ namespace Components { virtual void rehighlighter() override; + // Extension interface + public: + virtual void resetProcsType(const QString &suffix) override; }; } diff --git a/WordsIDE/WordsIDE.pro b/WordsIDE/WordsIDE.pro index 3361c4d..1cc8989 100644 --- a/WordsIDE/WordsIDE.pro +++ b/WordsIDE/WordsIDE.pro @@ -19,6 +19,7 @@ SOURCES += \ mainwindow.cpp \ messagepresent.cpp \ projectview.cpp \ + sourcecodeeditor.cpp \ storyboardsourceedit.cpp \ storyboardspresent.cpp \ storychainsourceeditor.cpp \ @@ -37,6 +38,7 @@ HEADERS += \ mainwindow.h \ messagepresent.h \ projectview.h \ + sourcecodeeditor.h \ storyboardsourceedit.h \ storyboardspresent.h \ storychainsourceeditor.h \ diff --git a/WordsIDE/appcore.cpp b/WordsIDE/appcore.cpp index 73edf4f..76c185d 100644 --- a/WordsIDE/appcore.cpp +++ b/WordsIDE/appcore.cpp @@ -6,6 +6,7 @@ #include "storyvolumesourceedit.h" #include "SensitiveCore.h" #include "mainwindow.h" +#include "sourcecodeeditor.h" #include #include @@ -29,7 +30,8 @@ AppCore::AppCore(MainWindow *win, QObject *parent) << new StoryUnitSourceEditFactory << new StoryBoardSourceEditFactory() << new StoryVolumeSourceEditFactory() - << new TextContentEditFactory(); + << new TextContentEditFactory() + << new SourceCodeEditorFactory(); } void AppCore::save() @@ -100,24 +102,23 @@ MakeTools::SensitiveCore *AppCore::getFramework() const void AppCore::openTextDocument(const QString &src, const QString &name) { + auto xfactorys = extensions(QFileInfo(src).suffix()); if(framework->contains(src)){ auto ins = framework->queryTextComponent(QFileInfo(src)); + + dynamic_cast(ins)->resetProcsType(QFileInfo(src).suffix()); + dynamic_cast(ins)->reload(this->getConfigs(xfactorys[0]->configs())); views->contentViewAppend(ins->textView(), name); return; } - auto xfactorys = extensions(QFileInfo(src).suffix()); VariedTextView *tview = dynamic_cast(xfactorys[0]->newInstance(this)); + dynamic_cast(tview)->resetProcsType(QFileInfo(src).suffix()); + dynamic_cast(tview)->reload(this->getConfigs(xfactorys[0]->configs())); - auto doc = parse_core->queryDocument(QFileInfo(src)); - if(doc == nullptr){ - this->make_tool->compile(QFileInfo(src), name); - doc = parse_core->queryDocument(QFileInfo(src)); - } - + this->make_tool->compile(QFileInfo(src), name); tview->setSource(this, QFileInfo(src), name, views); framework->addPerceptionList(tview); - dynamic_cast(tview)->reload(this->getConfigs(QList() << Scale::Global << Scale::Project)); QFile fin(src); if(!fin.open(QIODevice::ReadOnly | QIODevice::Text)){ @@ -130,3 +131,6 @@ void AppCore::openTextDocument(const QString &src, const QString &name) views->contentViewAppend(tview->textView(), name); } + + + diff --git a/WordsIDE/appcore.h b/WordsIDE/appcore.h index b3348a7..f7d606e 100644 --- a/WordsIDE/appcore.h +++ b/WordsIDE/appcore.h @@ -27,7 +27,8 @@ namespace Core { /** * @brief 功能拓展生成入口 */ - class ExtensionFactory{ + class ExtensionFactory + { public: virtual ~ExtensionFactory() = default; @@ -51,6 +52,10 @@ namespace Core { */ virtual QWidget* getNewPanel(Config::Configration* config) = 0; + /** + * @brief 拓展插件名称 + * @return + */ virtual QString extensionName() const = 0; }; @@ -68,6 +73,12 @@ namespace Core { */ virtual ExtensionFactory* factory() const = 0; + /** + * @brief 通过后缀名设置处理模式 + * @param suffix + */ + virtual void resetProcsType(const QString &suffix) = 0; + /** * @brief 载入指定的配置端口实例 * @param configs diff --git a/WordsIDE/mainwindow.cpp b/WordsIDE/mainwindow.cpp index 37003c7..3a1788b 100644 --- a/WordsIDE/mainwindow.cpp +++ b/WordsIDE/mainwindow.cpp @@ -348,6 +348,7 @@ MainWindow::MainWindow(QWidget *parent) this->units_view->refresh(); this->errors_present->refresh(); this->boards_view->refresh(); + this->concept_view->refresh(); }); diff --git a/WordsIDE/sourcecodeeditor.cpp b/WordsIDE/sourcecodeeditor.cpp new file mode 100644 index 0000000..410abfe --- /dev/null +++ b/WordsIDE/sourcecodeeditor.cpp @@ -0,0 +1,157 @@ +#include "sourcecodeeditor.h" +#include "keywordshightlighter.h" + +#include +#include +#include + +using namespace Components; +using namespace Enhancement; + +SourceCodeEditor::SourceCodeEditor(Core::FileExtensionFactory *factory) + : factory_ins(factory), + highlighter_ins(new KeywordsHightlighter(this)) +{ + highlighter_ins->setDocument(this->textDocument()); + +} + +void SourceCodeEditor::concept_jump(const QList &path) +{ + auto fpath = this->filePath(); + auto core = core_ins->parseCore(); + if(path.size()){ + auto storynode = core->queryStoryConcept(path[0]).first(); + auto first_word = storynode->refered()[0]; + + auto textblock = this->textDocument()->findBlockByNumber(first_word->row()); + auto cur = this->getTextCursor(); + cur.setPosition(textblock.position()); + cur.select(QTextCursor::SelectionType::LineUnderCursor); + this->setTextCursor(cur); + + if(path.size() > 1){ + auto storypoint = core->queryStoryStrongPoint(storynode, path[1]).first(); + first_word = storypoint->refered()[0]; + + auto textblock = this->textDocument()->findBlockByNumber(first_word->row()); + cur.setPosition(textblock.position()); + cur.select(QTextCursor::SelectionType::LineUnderCursor); + this->setTextCursor(cur); + } + } + + textView()->setFocus(); +} + +Core::ExtensionFactory *SourceCodeEditor::factory() const +{ + return factory_ins; +} + +void SourceCodeEditor::reload(QList configs) +{ + auto family = Config::ConfigHelper::getConfigAsDefaultSequence(configs, {"sourcecodeeditor-setting", "default", "font", "family"}, "微软雅黑"); + auto size = Config::ConfigHelper::getConfigAsDefaultSequence(configs, {"sourcecodeeditor-setting", "default", "font", "size"}, "20"); + + QFont font; + font.setFamily(family); + font.setPointSize(size.toUInt()); + this->textDocument()->setDefaultFont(font); +} + +void SourceCodeEditor::resetProcsType(const QString &suffix) +{ + procs_type = suffix; +} + +void SourceCodeEditor::modeReset(const QString &type) const +{ + +} + +QList SourceCodeEditor::modes() const +{ + return QList() << "源码编辑"; +} + +QString SourceCodeEditor::currentMode() const +{ + return "源码编辑"; +} + +void SourceCodeEditor::jumpTo(const QList &path) +{ + if(procs_type == "storyconcept") + concept_jump(path); +} + +void SourceCodeEditor::setSource(Core::AppCore *core, const QFileInfo &src, QWidget *parent) +{ + static_cast(highlighter_ins)->reset(core->parseCore()->queryDocument(src)); + FormattedTextEdit::setSource(core, src, parent); + this->core_ins = core; +} + +void SourceCodeEditor::rehighlighter() +{ + this->highlighter_ins->rehighlight(); +} + +Core::Extension *SourceCodeEditorFactory::newInstance(Core::AppCore *core) +{ + return new SourceCodeEditor(this); +} + +QList SourceCodeEditorFactory::configs() const +{ + return QList() << Core::Scale::Project << Core::Scale::Global; +} + +namespace __temp { + class XMarksConfig : public QWidget + { + public: + XMarksConfig(Config::Configration* port) + { + auto layout = new QVBoxLayout(this); + auto font_family = Config::ConfigHelper::getConfigAsDefault(port, {"sourcecodeeditor-setting", "default", "font", "family"}, "微软雅黑"); + + auto fontfamily = new QComboBox(this); + auto families = QFontDatabase().families(QFontDatabase::WritingSystem::SimplifiedChinese); + fontfamily->addItems(families); + fontfamily->setCurrentText(font_family); + connect(fontfamily, &QComboBox::currentTextChanged, [port](const QString &text){ + port->setConfig({"sourcecodeeditor-setting", "default", "font", "family"}, text); + }); + layout->addWidget(fontfamily); + + auto font_size = Config::ConfigHelper::getConfigAsDefault(port, {"sourcecodeeditor-setting", "default", "font", "size"}, "20"); + auto fontsize = new QSpinBox(this); + fontsize->setRange(10, 200); + fontsize->setSingleStep(1); + fontsize->setValue(font_size.toInt()); + connect(fontsize, QOverload::of(&QSpinBox::valueChanged), [port](int val){ + port->setConfig({"sourcecodeeditor-setting", "default", "font", "size"}, QString("%1").arg(val)); + }); + layout->addWidget(fontsize); + + layout->addWidget(new QWidget(this), 1); + } + }; +} + +QWidget *SourceCodeEditorFactory::getNewPanel(Config::Configration *config) +{ + return new __temp::XMarksConfig(config); +} + +QString SourceCodeEditorFactory::extensionName() const +{ + return "源码编辑器"; +} + +QList SourceCodeEditorFactory::suffixPeers() const +{ + return QList() << "storyconcept"; +} diff --git a/WordsIDE/sourcecodeeditor.h b/WordsIDE/sourcecodeeditor.h new file mode 100644 index 0000000..16db2c2 --- /dev/null +++ b/WordsIDE/sourcecodeeditor.h @@ -0,0 +1,62 @@ +#ifndef SOURCECODEEDITOR_H +#define SOURCECODEEDITOR_H + +#include "SourceEditView.h" +#include "appcore.h" + +#include + +namespace Components { + class SourceCodeEditorFactory : public Core::FileExtensionFactory + { + // ExtensionFactory interface + public: + virtual Core::Extension *newInstance(Core::AppCore *core) override; + virtual QList configs() const override; + virtual QWidget *getNewPanel(Config::Configration *config) override; + virtual QString extensionName() const override; + + // FileExtensionFactory interface + public: + virtual QList suffixPeers() const override; + }; + + class SourceCodeEditor : public FormattedTextEdit + { + public: + SourceCodeEditor(Core::FileExtensionFactory *factory); + + private: + Core::FileExtensionFactory *const factory_ins; + QSyntaxHighlighter *const highlighter_ins; + Core::AppCore *core_ins; + QString procs_type; + + void concept_jump(const QList &path); + + // Extension interface + public: + virtual Core::ExtensionFactory *factory() const override; + virtual void reload(QList configs) override; + virtual void resetProcsType(const QString &suffix) override; + + // ModeView interface + public: + virtual void modeReset(const QString &type) const override; + virtual QList modes() const override; + virtual QString currentMode() const override; + + // VariedTextView interface + public: + virtual void jumpTo(const QList &path) override; + virtual void setSource(Core::AppCore *core, const QFileInfo &src, QWidget *parent) override; + + // FormattedTextEdit interface + protected: + virtual void rehighlighter() override; + + }; +} + + +#endif // SOURCECODEEDITOR_H diff --git a/WordsIDE/storyboardsourceedit.cpp b/WordsIDE/storyboardsourceedit.cpp index 86c2119..278f908 100644 --- a/WordsIDE/storyboardsourceedit.cpp +++ b/WordsIDE/storyboardsourceedit.cpp @@ -14,14 +14,12 @@ using namespace Core; StoryBoardSourceEdit::StoryBoardSourceEdit(FileExtensionFactory *factory) : words_highlighter(new KeywordsHightlighter(this)), factory_ins(factory) { - this->resetHighlighter(words_highlighter); + words_highlighter->setDocument(this->textDocument()); - edit_square->setContextMenuPolicy(Qt::CustomContextMenu); - connect(edit_square, &QTextEdit::customContextMenuRequested, [this](const QPoint &pos){ - auto menu = edit_square->createStandardContextMenu(); + + this->setContexMenuProcess([this](QMenu *menu){ menu->addSeparator(); menu->addAction("刷新", [this](){words_highlighter->rehighlight();}); - menu->exec(edit_square->mapToGlobal(pos)); }); } @@ -32,8 +30,6 @@ FileExtensionFactory *StoryBoardSourceEdit::factory() const void StoryBoardSourceEdit::reload(QList configs) { - this->configrations_host = configs; - // TODO: 设置格式 auto font_family = Config::ConfigHelper::getConfigAsDefaultSequence (configs, {"sourcecode_boardedit","default_font","font_family"}, "微软雅黑"); @@ -43,7 +39,7 @@ void StoryBoardSourceEdit::reload(QList configs) default_font.setFamily(font_family); default_font.setPointSize(font_size.toInt()); - this->edit_square->document()->setDefaultFont(default_font); + this->textDocument()->setDefaultFont(default_font); this->rehighlighter(); } @@ -82,10 +78,10 @@ void StoryBoardSourceEdit::jumpTo(const QList &path) auto storynode = core->queryStoryBoard(path[0]).first(); auto first_word = storynode->refered()[0]; - auto textblock = this->edit_square->document()->findBlockByNumber(first_word->row()); - auto cur = this->edit_square->textCursor(); + auto textblock = this->textDocument()->findBlockByNumber(first_word->row()); + auto cur = this->getTextCursor(); cur.setPosition(textblock.position()); - this->edit_square->setTextCursor(cur); + this->setTextCursor(cur); } } @@ -94,6 +90,11 @@ void StoryBoardSourceEdit::rehighlighter() this->words_highlighter->rehighlight(); } +void StoryBoardSourceEdit::resetProcsType(const QString &suffix) +{ + +} + Extension *StoryBoardSourceEditFactory::newInstance(Core::AppCore *core) { return new StoryBoardSourceEdit(this); diff --git a/WordsIDE/storyboardsourceedit.h b/WordsIDE/storyboardsourceedit.h index ff85131..8b41ef4 100644 --- a/WordsIDE/storyboardsourceedit.h +++ b/WordsIDE/storyboardsourceedit.h @@ -50,6 +50,10 @@ namespace Components { Core::AppCore * core_temp; QFileInfo source_target; + + // Extension interface + public: + virtual void resetProcsType(const QString &suffix) override; }; } diff --git a/WordsIDE/storychainsourceeditor.cpp b/WordsIDE/storychainsourceeditor.cpp index 212d40d..97cae35 100644 --- a/WordsIDE/storychainsourceeditor.cpp +++ b/WordsIDE/storychainsourceeditor.cpp @@ -15,14 +15,11 @@ StoryChainSourceEdit::StoryChainSourceEdit(Core::FileExtensionFactory *factory) : highter_ins(new KeywordsHightlighter(this)), doc_ins(nullptr), factory_ins(factory) { - highter_ins->setDocument(this->edit_square->document()); + highter_ins->setDocument(this->textDocument()); - edit_square->setContextMenuPolicy(Qt::CustomContextMenu); - connect(edit_square, &QTextEdit::customContextMenuRequested, [this](const QPoint &pos){ - auto menu = edit_square->createStandardContextMenu(); + this->setContexMenuProcess([this](QMenu *menu){ menu->addSeparator(); menu->addAction("刷新", [this](){highter_ins->rehighlight();}); - menu->exec(edit_square->mapToGlobal(pos)); }); } @@ -59,8 +56,6 @@ FileExtensionFactory *StoryChainSourceEdit::factory() const void StoryChainSourceEdit::reload(QList configs) { - this->configrations_host = configs; - // TODO: 设置格式 auto font_family = Config::ConfigHelper::getConfigAsDefaultSequence (configs, {"sourcecode_chainedit","default_font","font_family"}, "微软雅黑"); @@ -70,7 +65,7 @@ void StoryChainSourceEdit::reload(QList configs) default_font.setFamily(font_family); default_font.setPointSize(font_size.toInt()); - this->edit_square->document()->setDefaultFont(default_font); + this->textDocument()->setDefaultFont(default_font); this->rehighlighter(); } @@ -79,6 +74,11 @@ void StoryChainSourceEdit::rehighlighter() this->highter_ins->rehighlight(); } +void StoryChainSourceEdit::resetProcsType(const QString &suffix) +{ + +} + void StoryChainSourceEdit::jumpTo(const QList &path) { auto fpath = this->filePath(); @@ -87,24 +87,24 @@ void StoryChainSourceEdit::jumpTo(const QList &path) auto storynode = core->queryStoryChain(path[0]).first(); auto first_word = storynode->refered()[0]; - auto textblock = this->edit_square->document()->findBlockByNumber(first_word->row()); - auto cur = this->edit_square->textCursor(); + auto textblock = this->textDocument()->findBlockByNumber(first_word->row()); + auto cur = this->getTextCursor(); cur.setPosition(textblock.position()); cur.select(QTextCursor::SelectionType::LineUnderCursor); - this->edit_square->setTextCursor(cur); + this->setTextCursor(cur); if(path.size() > 1){ auto storypoint = core->queryStoryPoint(storynode, path[1]).first(); first_word = storypoint->refered()[0]; - auto textblock = this->edit_square->document()->findBlockByNumber(first_word->row()); + auto textblock = this->textDocument()->findBlockByNumber(first_word->row()); cur.setPosition(textblock.position()); cur.select(QTextCursor::SelectionType::LineUnderCursor); - this->edit_square->setTextCursor(cur); + this->setTextCursor(cur); } } - edit_square->setFocus(); + this->textView()->setFocus(); } namespace __temp { diff --git a/WordsIDE/storychainsourceeditor.h b/WordsIDE/storychainsourceeditor.h index cdbc690..7254922 100644 --- a/WordsIDE/storychainsourceeditor.h +++ b/WordsIDE/storychainsourceeditor.h @@ -61,6 +61,10 @@ namespace Components { Core::AppCore *core_ins; Core::FileExtensionFactory *const factory_ins; + + // Extension interface + public: + virtual void resetProcsType(const QString &suffix) override; }; } diff --git a/WordsIDE/storyunitsourceedit.cpp b/WordsIDE/storyunitsourceedit.cpp index 6bd75eb..b7f7e80 100644 --- a/WordsIDE/storyunitsourceedit.cpp +++ b/WordsIDE/storyunitsourceedit.cpp @@ -13,14 +13,11 @@ using namespace Enhancement; StoryUnitSourceEdit::StoryUnitSourceEdit(FileExtensionFactory *factory) : words_highlighter(new KeywordsHightlighter(this)), factory_ins(factory) { - words_highlighter->setDocument(this->edit_square->document()); + words_highlighter->setDocument(this->textDocument()); - edit_square->setContextMenuPolicy(Qt::CustomContextMenu); - connect(edit_square, &QTextEdit::customContextMenuRequested, [this](const QPoint &pos){ - auto menu = edit_square->createStandardContextMenu(); + this->setContexMenuProcess([this](QMenu *menu){ menu->addSeparator(); menu->addAction("刷新", [this](){words_highlighter->rehighlight();}); - menu->exec(edit_square->mapToGlobal(pos)); }); } @@ -31,8 +28,6 @@ FileExtensionFactory *StoryUnitSourceEdit::factory() const void StoryUnitSourceEdit::reload(QList configs) { - this->configrations_host = configs; - // TODO: 设置格式 auto font_family = Config::ConfigHelper::getConfigAsDefaultSequence (configs, {"sourcecode_unitedit","default_font","font_family"}, "微软雅黑"); @@ -42,7 +37,7 @@ void StoryUnitSourceEdit::reload(QList configs) default_font.setFamily(font_family); default_font.setPointSize(font_size.toInt()); - this->edit_square->document()->setDefaultFont(default_font); + this->textDocument()->setDefaultFont(default_font); this->rehighlighter(); } @@ -89,24 +84,29 @@ void StoryUnitSourceEdit::jumpTo(const QList &path) auto storynode = core->queryStoryUnit(path[0]).first(); auto first_word = storynode->refered()[0]; - auto textblock = this->edit_square->document()->findBlockByNumber(first_word->row()); - auto cur = this->edit_square->textCursor(); + auto textblock = this->textDocument()->findBlockByNumber(first_word->row()); + auto cur = this->getTextCursor(); cur.setPosition(textblock.position()); cur.select(QTextCursor::SelectionType::LineUnderCursor); - this->edit_square->setTextCursor(cur); + this->setTextCursor(cur); if(path.size() > 1){ auto storypoint = core->queryStoryFragment(storynode, path[1]).first(); first_word = storypoint->refered()[0]; - auto textblock = this->edit_square->document()->findBlockByNumber(first_word->row()); + auto textblock = this->textDocument()->findBlockByNumber(first_word->row()); cur.setPosition(textblock.position()); cur.select(QTextCursor::SelectionType::LineUnderCursor); - this->edit_square->setTextCursor(cur); + this->setTextCursor(cur); } } - edit_square->setFocus(); + textView()->setFocus(); +} + +void StoryUnitSourceEdit::resetProcsType(const QString &suffix) +{ + } Extension *StoryUnitSourceEditFactory::newInstance(Core::AppCore *core) diff --git a/WordsIDE/storyunitsourceedit.h b/WordsIDE/storyunitsourceedit.h index df60d76..a5c2a26 100644 --- a/WordsIDE/storyunitsourceedit.h +++ b/WordsIDE/storyunitsourceedit.h @@ -51,6 +51,10 @@ namespace Components { // VariedTextView interface public: virtual void jumpTo(const QList &path) override; + + // Extension interface + public: + virtual void resetProcsType(const QString &suffix) override; }; } diff --git a/WordsIDE/storyvolumesourceedit.cpp b/WordsIDE/storyvolumesourceedit.cpp index 489de49..cf46aaf 100644 --- a/WordsIDE/storyvolumesourceedit.cpp +++ b/WordsIDE/storyvolumesourceedit.cpp @@ -18,8 +18,6 @@ FileExtensionFactory *StoryVolumeSourceEdit::factory() const void StoryVolumeSourceEdit::reload(QList configs) { - this->configrations_host = configs; - // TODO: 设置格式 auto font_family = Config::ConfigHelper::getConfigAsDefaultSequence (configs, {"sourcecode_voledit","default_font","font_family"}, "微软雅黑"); @@ -29,21 +27,23 @@ void StoryVolumeSourceEdit::reload(QList configs) default_font.setFamily(font_family); default_font.setPointSize(font_size.toInt()); - this->edit_square->document()->setDefaultFont(default_font); + this->textDocument()->setDefaultFont(default_font); this->rehighlighter(); } +void StoryVolumeSourceEdit::resetProcsType(const QString &suffix) +{ + +} + StoryVolumeSourceEdit::StoryVolumeSourceEdit(FileExtensionFactory *factory) : words_highlighter(new KeywordsHightlighter(this)), factory_ins(factory) { - words_highlighter->setDocument(this->edit_square->document()); + words_highlighter->setDocument(this->textDocument()); - edit_square->setContextMenuPolicy(Qt::CustomContextMenu); - connect(edit_square, &QTextEdit::customContextMenuRequested, [this](const QPoint &pos){ - auto menu = edit_square->createStandardContextMenu(); + this->setContexMenuProcess([this](QMenu *menu){ menu->addSeparator(); menu->addAction("刷新", [this](){words_highlighter->rehighlight();}); - menu->exec(edit_square->mapToGlobal(pos)); }); } diff --git a/WordsIDE/storyvolumesourceedit.h b/WordsIDE/storyvolumesourceedit.h index bdc5de0..1087060 100644 --- a/WordsIDE/storyvolumesourceedit.h +++ b/WordsIDE/storyvolumesourceedit.h @@ -23,10 +23,11 @@ namespace Components { public: StoryVolumeSourceEdit(Core::FileExtensionFactory *factory); - // Plugin interface + // Extension interface public: virtual Core::FileExtensionFactory *factory() const override; virtual void reload(QList configs) override; + virtual void resetProcsType(const QString &suffix) override; // ModeView interface public: @@ -51,6 +52,7 @@ namespace Components { // VariedTextView interface public: virtual void jumpTo(const QList &path) override; + }; } diff --git a/libParse/storyconceptdocumentparser.cpp b/libParse/storyconceptdocumentparser.cpp index b46e2b0..a3afb1f 100644 --- a/libParse/storyconceptdocumentparser.cpp +++ b/libParse/storyconceptdocumentparser.cpp @@ -30,7 +30,17 @@ Parse::NodeStoryConcept::NodeStoryConcept(const QString &name, DocCore *doc) bool NodeStoryConcept::check(QList &reasons) const { -return true; + auto nodes = doc()->core()->queryStoryConcept(name()[0]); + if(nodes.size() > 1){ + ErrorMessage ins; + ins.CodeRow = refered().first()->row(); + ins.CodeCol = refered().first()->column(); + ins.FilePath = doc()->filePath(); + ins.Reason = "概念重复定义"; + ins.Text = name()[0]; + reasons << ins; + } + return nodes.size() == 1; } QString NodeStoryConcept::toString() const @@ -53,7 +63,18 @@ NodeStoryStrongPoint::NodeStoryStrongPoint(NodeStoryConcept *parent, const QStri bool NodeStoryStrongPoint::check(QList &reasons) const { - return true; + auto concept = parent(); + auto nodes = doc()->core()->queryStoryStrongPoint(concept, name()[0]); + if(nodes.size() > 1){ + ErrorMessage ins; + ins.CodeRow = refered().first()->row(); + ins.CodeCol = refered().first()->column(); + ins.FilePath = doc()->filePath(); + ins.Reason = "要点重复定义"; + ins.Text = name()[0]; + reasons << ins; + } + return nodes.size() == 1; } QString NodeStoryStrongPoint::toString() const diff --git a/libProjectManager/icons.qrc b/libProjectManager/icons.qrc index 6cee67e..ea08728 100644 --- a/libProjectManager/icons.qrc +++ b/libProjectManager/icons.qrc @@ -7,5 +7,6 @@ 故事.png 叙述.png toplevel.png + 概念.png diff --git a/libProjectManager/xmlprojectmanager.cpp b/libProjectManager/xmlprojectmanager.cpp index d7d8ce9..adc85b2 100644 --- a/libProjectManager/xmlprojectmanager.cpp +++ b/libProjectManager/xmlprojectmanager.cpp @@ -368,6 +368,8 @@ void ProjectNode::setFile(const QString &name) setIcon(QIcon(":/icons/叙述.png")); if(name.endsWith("txt")) setIcon(QIcon(":/icons/文件.png")); + if(name.endsWith("storyconcept")) + setIcon(QIcon(":/icons/概念.png")); } QString ProjectNode::file() const diff --git a/libProjectManager/概念.png b/libProjectManager/概念.png new file mode 100644 index 0000000000000000000000000000000000000000..f02524c5716b7863b116bab8a686a62ee8cf2380 GIT binary patch literal 7462 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 literal 0 HcmV?d00001