diff --git a/QtNovelDesc.pro b/QtNovelDesc.pro index 10626ee..d73425c 100644 --- a/QtNovelDesc.pro +++ b/QtNovelDesc.pro @@ -2,6 +2,7 @@ TEMPLATE = subdirs SUBDIRS += \ DesParser \ + TestWidget \ Testpad \ WordsIDE \ libConfig \ diff --git a/QtNovelDesc.pro.user b/QtNovelDesc.pro.user index 4a29a94..2580f3f 100644 --- a/QtNovelDesc.pro.user +++ b/QtNovelDesc.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/TestWidget/TestWidget.pro b/TestWidget/TestWidget.pro new file mode 100644 index 0000000..9cc6dbc --- /dev/null +++ b/TestWidget/TestWidget.pro @@ -0,0 +1,26 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# 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 \ + widget.cpp + +HEADERS += \ + widget.h + +TRANSLATIONS += \ + TestWidget_zh_CN.ts +CONFIG += lrelease +CONFIG += embed_translations + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/TestWidget/TestWidget_zh_CN.ts b/TestWidget/TestWidget_zh_CN.ts new file mode 100644 index 0000000..630fd35 --- /dev/null +++ b/TestWidget/TestWidget_zh_CN.ts @@ -0,0 +1,3 @@ + + + diff --git a/TestWidget/main.cpp b/TestWidget/main.cpp new file mode 100644 index 0000000..8cb42b6 --- /dev/null +++ b/TestWidget/main.cpp @@ -0,0 +1,29 @@ +#include "widget.h" + +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + + QTranslator translator; + const QStringList uiLanguages = QLocale::system().uiLanguages(); + for (const QString &locale : uiLanguages) { + const QString baseName = "TestWidget_" + QLocale(locale).name(); + if (translator.load(":/i18n/" + baseName)) { + a.installTranslator(&translator); + break; + } + } + Widget w; + w.show(); + + QFontDatabase xbase; + qDebug() << xbase.families(QFontDatabase::WritingSystem::SimplifiedChinese); + + return a.exec(); +} diff --git a/TestWidget/widget.cpp b/TestWidget/widget.cpp new file mode 100644 index 0000000..7350ff4 --- /dev/null +++ b/TestWidget/widget.cpp @@ -0,0 +1,11 @@ +#include "widget.h" + +Widget::Widget(QWidget *parent) + : QWidget(parent) +{ +} + +Widget::~Widget() +{ +} + diff --git a/TestWidget/widget.h b/TestWidget/widget.h new file mode 100644 index 0000000..47b6270 --- /dev/null +++ b/TestWidget/widget.h @@ -0,0 +1,14 @@ +#ifndef WIDGET_H +#define WIDGET_H + +#include + +class Widget : public QWidget +{ + Q_OBJECT + +public: + Widget(QWidget *parent = nullptr); + ~Widget(); +}; +#endif // WIDGET_H diff --git a/WordsIDE/ContentPresent.h b/WordsIDE/ContentPresent.h index 1eb3102..c7a52d3 100644 --- a/WordsIDE/ContentPresent.h +++ b/WordsIDE/ContentPresent.h @@ -2,18 +2,52 @@ #define CONTENTPRESENT_H #include +#include +#include "appcore.h" +namespace Core +{ + class ConfigHost + { + public: + virtual ~ConfigHost() = default; + + /** + * @brief 获取所有指定的配置端口类型 + * @return + */ + virtual QList configs() const = 0; + /** + * @brief 载入指定的配置端口实例 + * @param configs + */ + virtual void reload(QList configs) = 0; + + /** + * @brief getPanel 获取配置面板,配置内容 + * @param config + * @return + */ + virtual QWidget* getPanel(Config::Configration* config) = 0; + }; +} namespace ContentPresent { /** - * @brief 具有多种显示模式的视图组件 + * @brief 允许具有多种显示模式的视图组件 */ class ModeView { public: virtual ~ModeView() = default; + /** + * @brief 获取配置端口 + * @return + */ + virtual Core::ConfigHost* getConfigHost() const = 0; + /** * @brief 设置视图显示模式 * @param type diff --git a/WordsIDE/SourceEditView.cpp b/WordsIDE/SourceEditView.cpp index 5b757bc..fbb3409 100644 --- a/WordsIDE/SourceEditView.cpp +++ b/WordsIDE/SourceEditView.cpp @@ -1,10 +1,13 @@ #include "SourceEditView.h" #include "keywordshightlighter.h" +#include +#include #include using namespace Components; using namespace Parse::Result; using namespace Enhancement; +using namespace Core; StoryChainSourceEdit::StoryChainSourceEdit(const QFileInfo &file, QWidget *parent) : MakeTools::VariedTextView(file,parent), edit_square(new QTextEdit(parent)), @@ -64,14 +67,14 @@ void StoryChainSourceEdit::textContentReset(const QString &value) this->edit_square->setText(value); } -TextContentEdit::TextContentEdit(const QFileInfo &refer, QWidget *parent) - : MakeTools::VariedTextView(refer, parent), edit_square(new QTextEdit(parent)), source_target(refer) +ConfigHost *StoryChainSourceEdit::getConfigHost() const { - connect(edit_square, &QTextEdit::textChanged, [this](){ - emit this->dataChanged(this->source_target.absoluteFilePath()); - }); + return nullptr; } +TextContentEdit::TextContentEdit(const QFileInfo &refer, QWidget *parent) + : FormattedTextEdit(refer, parent){} + void TextContentEdit::modeReset(const QString &) const { @@ -97,28 +100,29 @@ void TextContentEdit::reset(Parse::Result::DocCore *syntax_base) } -QWidget *TextContentEdit::textView() const +void TextContentEdit::rehighlighter() { - return edit_square; -} - -QString TextContentEdit::textContent() const -{ - return edit_square->toPlainText(); -} - -void TextContentEdit::textContentReset(const QString &value) -{ - edit_square->setText(value); } StoryUnitSourceEdit::StoryUnitSourceEdit(const QFileInfo &refer, QWidget *parent) - : MakeTools::VariedTextView(refer,parent), edit_square(new QTextEdit(parent)), source_target(refer) + : MakeTools::VariedTextView(refer,parent), + words_highlighter(new KeywordsHightlighter(this)), + edit_square(new QTextEdit(parent)), source_target(refer) { connect(edit_square, &QTextEdit::textChanged, [this](){ emit this->dataChanged(this->source_target.absoluteFilePath()); }); + + words_highlighter->setDocument(this->edit_square->document()); + + edit_square->setContextMenuPolicy(Qt::CustomContextMenu); + connect(edit_square, &QTextEdit::customContextMenuRequested, [this](const QPoint &pos){ + auto menu = edit_square->createStandardContextMenu(); + menu->addSeparator(); + menu->addAction("刷新", [this](){words_highlighter->rehighlight();}); + menu->exec(edit_square->mapToGlobal(pos)); + }); } void StoryUnitSourceEdit::modeReset(const QString &) const @@ -141,9 +145,15 @@ QString StoryUnitSourceEdit::title() const return source_target.fileName(); } +ConfigHost *StoryUnitSourceEdit::getConfigHost() const +{ + return nullptr; +} + void StoryUnitSourceEdit::reset(Parse::Result::DocCore *syntax_base) { + static_cast(words_highlighter)->reset(syntax_base); } QWidget *StoryUnitSourceEdit::textView() const @@ -162,11 +172,23 @@ void StoryUnitSourceEdit::textContentReset(const QString &value) } StoryBoardSourceEdit::StoryBoardSourceEdit(const QFileInfo &refer, QWidget *parent) - : MakeTools::VariedTextView(refer,parent), edit_square(new QTextEdit(parent)), source_target(refer) + : MakeTools::VariedTextView(refer,parent), + words_highlighter(new KeywordsHightlighter(this)), + edit_square(new QTextEdit(parent)), source_target(refer) { connect(edit_square, &QTextEdit::textChanged, [this](){ emit this->dataChanged(this->source_target.absoluteFilePath()); }); + + words_highlighter->setDocument(this->edit_square->document()); + + edit_square->setContextMenuPolicy(Qt::CustomContextMenu); + connect(edit_square, &QTextEdit::customContextMenuRequested, [this](const QPoint &pos){ + auto menu = edit_square->createStandardContextMenu(); + menu->addSeparator(); + menu->addAction("刷新", [this](){words_highlighter->rehighlight();}); + menu->exec(edit_square->mapToGlobal(pos)); + }); } void StoryBoardSourceEdit::modeReset(const QString &) const{} @@ -186,9 +208,14 @@ QString StoryBoardSourceEdit::title() const return source_target.fileName(); } +ConfigHost *StoryBoardSourceEdit::getConfigHost() const +{ + return nullptr; +} + void StoryBoardSourceEdit::reset(Parse::Result::DocCore *syntax_base) { - + static_cast(words_highlighter)->reset(syntax_base); } QWidget *StoryBoardSourceEdit::textView() const @@ -207,11 +234,23 @@ void StoryBoardSourceEdit::textContentReset(const QString &value) } StoryVolumeSourceEdit::StoryVolumeSourceEdit(const QFileInfo &refer, QWidget *parent) - : MakeTools::VariedTextView(refer,parent), edit_square(new QTextEdit(parent)), source_target(refer) + : MakeTools::VariedTextView(refer,parent), + words_highlighter(new KeywordsHightlighter(this)), + edit_square(new QTextEdit(parent)), source_target(refer) { connect(edit_square, &QTextEdit::textChanged, [this](){ emit this->dataChanged(this->source_target.absoluteFilePath()); }); + + words_highlighter->setDocument(this->edit_square->document()); + + edit_square->setContextMenuPolicy(Qt::CustomContextMenu); + connect(edit_square, &QTextEdit::customContextMenuRequested, [this](const QPoint &pos){ + auto menu = edit_square->createStandardContextMenu(); + menu->addSeparator(); + menu->addAction("刷新", [this](){words_highlighter->rehighlight();}); + menu->exec(edit_square->mapToGlobal(pos)); + }); } void StoryVolumeSourceEdit::modeReset(const QString &) const{} @@ -231,9 +270,14 @@ QString StoryVolumeSourceEdit::title() const return source_target.fileName(); } +ConfigHost *StoryVolumeSourceEdit::getConfigHost() const +{ + return nullptr; +} + void StoryVolumeSourceEdit::reset(Parse::Result::DocCore *syntax_base) { - + static_cast(words_highlighter)->reset(syntax_base); } QWidget *StoryVolumeSourceEdit::textView() const @@ -250,3 +294,61 @@ void StoryVolumeSourceEdit::textContentReset(const QString &value) { this->edit_square->setText(value); } + +FormattedTextEdit::FormattedTextEdit(const QFileInfo &file, QWidget *parent) + : MakeTools::VariedTextView(file, parent), edit_square(new QTextEdit(parent)), source_target(file) +{ + connect(edit_square, &QTextEdit::textChanged, [this](){ + emit this->dataChanged(this->source_target.absoluteFilePath()); + }); +} + +Core::ConfigHost *FormattedTextEdit::getConfigHost() const +{ + return const_cast(this); +} + +QWidget *FormattedTextEdit::textView() const +{ + return edit_square; +} + +QString FormattedTextEdit::textContent() const +{ + return edit_square->toPlainText(); +} + +void FormattedTextEdit::textContentReset(const QString &value) +{ + edit_square->setPlainText(value); +} + +QList FormattedTextEdit::configs() const +{ + return QList() << Scale::Global << Scale::Project; +} + +void FormattedTextEdit::reload(QList configs) +{ + this->configrations_host = configs; + + // TODO: 设置格式 + auto font_family = Config::ConfigHelper::getConfigAsDefaultSequence + (configs, {"sourcecode_edit","default_font","font_family"}, "微软雅黑"); + QFont default_font; + default_font.setFamily(font_family); + + this->edit_square->document()->setDefaultFont(default_font); + this->rehighlighter(); +} + +QWidget *FormattedTextEdit::getPanel(Config::Configration *config) +{ + auto combobox = new QComboBox(); + combobox->addItems(QFontDatabase().families(QFontDatabase::WritingSystem::SimplifiedChinese)); + connect(combobox, &QComboBox::currentTextChanged, [this](const QString &text){ + this->edit_square->setFont(QFont(text)); + }); + + return combobox; +} diff --git a/WordsIDE/SourceEditView.h b/WordsIDE/SourceEditView.h index 9a897d7..5dd9810 100644 --- a/WordsIDE/SourceEditView.h +++ b/WordsIDE/SourceEditView.h @@ -9,6 +9,39 @@ #include namespace Components { + class FormattedTextEdit : public MakeTools::VariedTextView, + public ContentPresent::ModeView, public Core::ConfigHost + { + public: + FormattedTextEdit(const QFileInfo &file, QWidget *parent = nullptr); + virtual ~FormattedTextEdit() = default; + + // ModeView interface + public: + virtual Core::ConfigHost *getConfigHost() const override; + + // VariedTextView interface + public: + virtual QWidget *textView() const override; + virtual QString textContent() const override; + virtual void textContentReset(const QString &value) override; + + // ConfigHost interface + public: + virtual QList configs() const override; + virtual void reload(QList configs) override; + virtual QWidget *getPanel(Config::Configration *config) override; + + private: + QTextEdit *const edit_square; + QFileInfo source_target; + + protected: + QList configrations_host; + + virtual void rehighlighter() = 0; + }; + /** * @brief StoryChain源码编辑器 */ @@ -24,6 +57,7 @@ namespace Components { virtual QList modes() const override; virtual QString currentMode() const override; virtual QString title() const override; + virtual Core::ConfigHost *getConfigHost() const override; // VariedTextView interface public: @@ -36,10 +70,11 @@ namespace Components { QTextEdit *const edit_square; QSyntaxHighlighter *const highter_ins; Parse::Result::DocCore * core_ins; + }; - class TextContentEdit : public MakeTools::VariedTextView, public ContentPresent::ModeView + class TextContentEdit : public FormattedTextEdit { public: TextContentEdit(const QFileInfo &refer, QWidget *parent = nullptr); @@ -55,13 +90,13 @@ namespace Components { // VariedTextView interface public: virtual void reset(Parse::Result::DocCore *syntax_base) override; - virtual QWidget *textView() const override; - virtual QString textContent() const override; - virtual void textContentReset(const QString &value) override; private: - QTextEdit *const edit_square; QFileInfo source_target; + + // FormattedTextEdit interface + protected: + virtual void rehighlighter() override; }; /** @@ -79,6 +114,7 @@ namespace Components { virtual QList modes() const override; virtual QString currentMode() const override; virtual QString title() const override; + virtual Core::ConfigHost *getConfigHost() const override; // VariedTextView interface public: @@ -88,6 +124,7 @@ namespace Components { virtual void textContentReset(const QString &value) override; private: + QSyntaxHighlighter *const words_highlighter; QTextEdit *const edit_square; QFileInfo source_target; }; @@ -105,6 +142,7 @@ namespace Components { virtual QList modes() const override; virtual QString currentMode() const override; virtual QString title() const override; + virtual Core::ConfigHost *getConfigHost() const override; // VariedTextView interface public: @@ -114,6 +152,7 @@ namespace Components { virtual void textContentReset(const QString &value) override; private: + QSyntaxHighlighter *const words_highlighter; QTextEdit *const edit_square; QFileInfo source_target; }; @@ -129,6 +168,7 @@ namespace Components { virtual QList modes() const override; virtual QString currentMode() const override; virtual QString title() const override; + virtual Core::ConfigHost *getConfigHost() const override; // VariedTextView interface public: @@ -138,6 +178,7 @@ namespace Components { virtual void textContentReset(const QString &value) override; private: + QSyntaxHighlighter *const words_highlighter; QTextEdit *const edit_square; QFileInfo source_target; }; diff --git a/WordsIDE/WordsIDE.pro b/WordsIDE/WordsIDE.pro index dfb127f..d497e97 100644 --- a/WordsIDE/WordsIDE.pro +++ b/WordsIDE/WordsIDE.pro @@ -12,22 +12,26 @@ SOURCES += \ ContentPresent.cpp \ SensitiveCore.cpp \ SourceEditView.cpp \ + appcore.cpp \ keywordshightlighter.cpp \ main.cpp \ mainwindow.cpp \ messagepresent.cpp \ projectview.cpp \ - storychainspresent.cpp + storychainspresent.cpp \ + storyunitspresent.cpp HEADERS += \ ContentPresent.h \ SensitiveCore.h \ SourceEditView.h \ + appcore.h \ keywordshightlighter.h \ mainwindow.h \ messagepresent.h \ projectview.h \ - storychainspresent.h + storychainspresent.h \ + storyunitspresent.h TRANSLATIONS += \ WordsIDE_zh_CN.ts diff --git a/WordsIDE/appcore.cpp b/WordsIDE/appcore.cpp new file mode 100644 index 0000000..1327546 --- /dev/null +++ b/WordsIDE/appcore.cpp @@ -0,0 +1,8 @@ +#include "appcore.h" + +using namespace Core; + +AppCore::AppCore() +{ + +} diff --git a/WordsIDE/appcore.h b/WordsIDE/appcore.h new file mode 100644 index 0000000..d20f8c1 --- /dev/null +++ b/WordsIDE/appcore.h @@ -0,0 +1,28 @@ +#ifndef APPCORE_H +#define APPCORE_H + +#include +#include + +namespace Core { + + enum class Scale + { + Global, + Project, + File, + }; + + class AppCore + { + public: + AppCore(); + virtual ~AppCore() = default; + + QList getConfigs(QList types) const; + + }; + +} + +#endif // APPCORE_H diff --git a/WordsIDE/mainwindow.cpp b/WordsIDE/mainwindow.cpp index 093222a..25451ef 100644 --- a/WordsIDE/mainwindow.cpp +++ b/WordsIDE/mainwindow.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -21,6 +22,8 @@ using namespace Components; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), + global_config(new Config::XMLConfig(this)), + sync_kernel(new StatusSyncCore(this)), horizontal_split(new QSplitter(Qt::Horizontal, this)), vertical_split(new QSplitter(Qt::Vertical, this)), left_funcs(new QTabWidget(this)), @@ -31,18 +34,30 @@ MainWindow::MainWindow(QWidget *parent) parse_core(new ParseCore()), make_tool(new StoryTool(parse_core)), project_list(new QListView(this)), - project_view(new ProjectView(project_manager, this)), + project_structure(new ProjectView(project_manager, this)), chains_view(new StoryChainsPresent(parse_core, this)), + units_view(new StoryUnitsPresent(parse_core, this)), errors_present(new MessagePresent(make_tool, this)), framework(new SensitiveCore(make_tool)) { + QApplication::instance()->installEventFilter(this); + global_config->loadFile(QDir(QApplication::applicationDirPath()).filePath(".software.xml")); + setMinimumSize(1000, 600); setWindowTitle("提线木偶集成开发工具"); + chains_view->setVisible(false); + units_view->setVisible(false); + errors_present->setVisible(false); + project_structure->setVisible(false); + left_funcs->setVisible(false); + right_funcs->setVisible(false); + bottom_funcs->setVisible(false); auto xtool = new QToolBar(this); + xtool->setVisible(false); addToolBar(Qt::ToolBarArea::TopToolBarArea, xtool); - auto xstatus = statusBar(); + xstatus->setVisible(false); statusBar()->addWidget(new QLabel("文本消息", this)); auto mbar = menuBar(); @@ -72,25 +87,25 @@ MainWindow::MainWindow(QWidget *parent) _xnew->addAction("小说章节"); project->addSeparator(); auto sav = project->addAction("保存"); - sav->setEnabled(false); + sync_kernel->registerActionSync(sav, [this]()->bool{return project_manager->isOpen();}); connect(sav, &QAction::triggered, [this](){ this->project_manager->save(); framework->saveAll(); }); project->addSeparator(); auto opnp = project->addAction("打开项目"); - connect(opnp, &QAction::triggered, [this, sav](){ + sync_kernel->registerActionSync(opnp, [this]()->bool{return !project_manager->isOpen();}); + connect(opnp, &QAction::triggered, [this](){ auto file = QFileDialog::getOpenFileName(this, "打开项目", QString(), "小说项目(*.nsf)"); if(file == "") return; project_manager->openProject(file); - sav->setEnabled(true); - build_internal(true); }); auto newp = project->addAction("新建项目"); - connect(newp, &QAction::triggered, [this, sav](){ + sync_kernel->registerActionSync(newp, [this]()->bool{return !project_manager->isOpen();}); + connect(newp, &QAction::triggered, [this](){ auto name = QInputDialog::getText(this, "输入项目名称", "项目名称"); if(name == "") return; @@ -98,13 +113,12 @@ MainWindow::MainWindow(QWidget *parent) if(dir_path == "") return; - sav->setEnabled(true); this->project_manager->newProject(dir_path, name); }); auto clsp = project->addAction("关闭项目"); - connect(clsp, &QAction::triggered, [this, sav](){ + sync_kernel->registerActionSync(clsp, [this]()->bool{return project_manager->isOpen();}); + connect(clsp, &QAction::triggered, [this](){ this->project_manager->closeProject(); - sav->setEnabled(false); }); project->addSeparator(); project->addAction("项目配置"); @@ -123,25 +137,21 @@ MainWindow::MainWindow(QWidget *parent) // 视图菜单 auto view = mbar->addMenu("视图"); auto area = view->addMenu("区域管理"); + auto act_tool = area->addAction("工具栏"); act_tool->setCheckable(true); - act_tool->setChecked(true); connect(act_tool, &QAction::triggered, [xtool](bool v){ xtool->setVisible(v); }); auto act_status = area->addAction("状态栏"); act_status->setCheckable(true); - act_status->setChecked(true); connect(act_status,&QAction::triggered, [xstatus](bool v){xstatus->setVisible(v);}); auto act_left = area->addAction("左侧功能区"); act_left->setCheckable(true); - act_left->setChecked(true); connect(act_left, &QAction::triggered, [this](bool v){this->left_funcs->setVisible(v);}); auto act_right = area->addAction("右侧功能区"); act_right->setCheckable(true); - act_right->setChecked(true); connect(act_right, &QAction::triggered, [this](bool v){this->right_funcs->setVisible(v);}); auto act_bottom = area->addAction("底部功能区"); act_bottom->setCheckable(true); - act_bottom->setChecked(true); connect(act_bottom, &QAction::triggered, [this](bool v){this->bottom_funcs->setVisible(v);}); view->addSeparator(); auto change = view->addMenu("内容切换"); @@ -149,10 +159,44 @@ MainWindow::MainWindow(QWidget *parent) change->addAction("编辑视图"); view->addSeparator(); auto func = view->addMenu("功能视图"); - func->addAction("项目结构"); + // 项目管理 + { + auto project_v = func->addAction("项目管理", [this](bool v){ + toggle_widget_visible(v, left_funcs, project_structure, "项目管理"); + }); + project_v->setCheckable(true); + sync_kernel->registerAutoRun([this]()->bool{return this->project_structure->isVisible();}, + [project_v](bool v){ if(v != project_v->isChecked()) project_v->setChecked(v); }); + } func->addAction("引用统计"); func->addAction("脉络分蘖"); - func->addAction("终端输出"); + // 编译信息 + { + auto msgs = func->addAction("终端输出", [this](bool v){ + toggle_widget_visible(v, bottom_funcs, errors_present, "编译信息"); + }); + msgs->setCheckable(true); + sync_kernel->registerAutoRun([this]()->bool{return errors_present->isVisible();}, + [msgs](bool v){if(v!=msgs->isChecked()) msgs->setChecked(v);}); + } + // 脉络统计 + { + auto chain_v = func->addAction("脉络统计", [this](bool v){ + toggle_widget_visible(v, right_funcs, chains_view, "脉络统计"); + }); + chain_v->setCheckable(true); + sync_kernel->registerAutoRun([this]()->bool{return chains_view->isVisible();}, + [chain_v](bool v){ if(v != chain_v->isChecked()) chain_v->setChecked(v);}); + } + // 单元统计 + { + auto unit_v = func->addAction("单元统计", [this](bool v){ + toggle_widget_visible(v, right_funcs, units_view, "单元统计"); + }); + unit_v->setCheckable(true); + sync_kernel->registerAutoRun([this]()->bool{return units_view->isVisible();}, + [unit_v](bool v){if(v != unit_v->isChecked()) unit_v->setChecked(v);}); + } // 工具菜单 auto tool = mbar->addMenu("工具"); @@ -163,10 +207,13 @@ MainWindow::MainWindow(QWidget *parent) vcs->addAction("工具配置"); vcs->addAction("启用"); auto exp = tool->addMenu("导入导出"); - exp->addAction("导入TXT"); + exp->addAction("导入WsOutlines"); + exp->addSeparator(); + exp->addAction("导出TXT大纲"); + exp->addAction("导出Web大纲"); + exp->addAction("导出WsOutlines"); exp->addSeparator(); exp->addAction("导出TXT内容"); - exp->addAction("导出TXT大纲"); tool->addAction("编译", [this](){ this->build_internal(); }); @@ -188,16 +235,30 @@ MainWindow::MainWindow(QWidget *parent) sys->addAction("关于……"); + setCentralWidget(this->horizontal_split); this->horizontal_split->addWidget(left_funcs); this->horizontal_split->addWidget(vertical_split); this->horizontal_split->addWidget(right_funcs); this->vertical_split->addWidget(center_funcs); this->vertical_split->addWidget(bottom_funcs); - setCentralWidget(this->horizontal_split); + left_funcs->setTabsClosable(true); + connect(left_funcs, &QTabWidget::tabCloseRequested, + [this](int index){ toggle_widget_visible(false, left_funcs, left_funcs->widget(index)); }); + bottom_funcs->setTabsClosable(true); + connect(bottom_funcs, &QTabWidget::tabCloseRequested, + [this](int index){ toggle_widget_visible(false, bottom_funcs, bottom_funcs->widget(index)); }); + right_funcs->setTabsClosable(true); + connect(right_funcs, &QTabWidget::tabCloseRequested, + [this](int index){ toggle_widget_visible(false, right_funcs, right_funcs->widget(index)); }); + center_funcs->setTabsClosable(true); + connect(center_funcs, &QTabWidget::tabCloseRequested, + [this](int index){ toggle_widget_visible(false, center_funcs, center_funcs->widget(index)); }); + + center_funcs->addTab(project_list, "欢迎界面"); - left_funcs->addTab(project_view, "项目管理"); - connect(project_view, &ProjectView::activeDocument, [this](const QString &file_path, const QString &name){ + connect(project_structure, &ProjectView::activeDocument, + [this](const QString &file_path, const QString &name){ if(framework->contains(file_path)){ auto ins = framework->queryComponent(QFileInfo(file_path)); center_funcs->setCurrentWidget(ins->textView()); @@ -218,17 +279,37 @@ MainWindow::MainWindow(QWidget *parent) else if(file_path.endsWith("storyunit")){ tview = new Components::StoryUnitSourceEdit(QFileInfo(file_path), this); framework->addPerceptionList(tview); + auto doc = parse_core->queryDocument(QFileInfo(file_path)); + if(doc == nullptr){ + this->make_tool->compile(QFileInfo(file_path)); + doc = parse_core->queryDocument(QFileInfo(file_path)); + } + tview->reset(doc); } else if(file_path.endsWith("storyboard")){ tview = new Components::StoryBoardSourceEdit(QFileInfo(file_path), this); framework->addPerceptionList(tview); + auto doc = parse_core->queryDocument(QFileInfo(file_path)); + if(doc == nullptr){ + this->make_tool->compile(QFileInfo(file_path)); + doc = parse_core->queryDocument(QFileInfo(file_path)); + } + tview->reset(doc); } else if(file_path.endsWith("storyvolume")){ tview = new Components::StoryVolumeSourceEdit(QFileInfo(file_path), this); framework->addPerceptionList(tview); + auto doc = parse_core->queryDocument(QFileInfo(file_path)); + if(doc == nullptr){ + this->make_tool->compile(QFileInfo(file_path)); + doc = parse_core->queryDocument(QFileInfo(file_path)); + } + tview->reset(doc); } else{ - tview = new Components::TextContentEdit(QFileInfo(file_path), this); + auto xview = new Components::TextContentEdit(QFileInfo(file_path), this); + xview->getConfigHost()->reload(QList() << project_manager->configraions()); + tview = xview; framework->addPerceptionList(tview, SensitiveType::DoNothing); } if(tview == nullptr) @@ -249,12 +330,10 @@ MainWindow::MainWindow(QWidget *parent) center_funcs->addTab(tview->textView(), name); center_funcs->setCurrentWidget(tview->textView()); }); - bottom_funcs->addTab(errors_present, "错误列表"); - right_funcs->addTab(chains_view, "脉络展示"); - framework->addProcTrigger([this](){ errors_present->refresh(); chains_view->refresh(); + units_view->refresh(); }); } @@ -285,6 +364,18 @@ void MainWindow::build_internal(bool all_from_disk) errors_present->refresh(); chains_view->refresh(); + units_view->refresh(); +} + +void MainWindow::toggle_widget_visible(bool visible, QTabWidget *con, QWidget *target, const QString &title) +{ + if(visible && con->indexOf(target) == -1){ + con->addTab(target, title); + target->setVisible(true); + }else if(!visible && con->indexOf(target) != -1){ + target->setVisible(false); + con->removeTab(con->indexOf(target)); + } } void MainWindow::closeEvent(QCloseEvent *event) @@ -297,3 +388,88 @@ void MainWindow::closeEvent(QCloseEvent *event) QMainWindow::closeEvent(event); } + +bool MainWindow::eventFilter(QObject *watched, QEvent *event) +{ + auto ev = event->type(); + switch(ev){ + case QEvent::Type::MouseButtonPress: + case QEvent::Type::MouseButtonRelease: + case QEvent::Type::Wheel: + case QEvent::Type::MouseMove: + case QEvent::Type::KeyPress: + case QEvent::Type::KeyRelease: + sync_kernel->sync(); + break; + default: + break; + } + return QMainWindow::eventFilter(watched, event); +} + + + + + +Run::Run(bool manual_flag, std::function judge, std::function execution) + : manual(manual_flag), judgement(judge), execution(execution){} + +void Run::exec() +{ + if(!manual) + execution(judgement()); +} + +StatusSyncCore::StatusSyncCore(QObject *p) + : QObject(p){} + +void StatusSyncCore::registerWidgetSync(QWidget *tar, std::function proc) +{ + widget_trigger_map[tar] = proc; +} + +void StatusSyncCore::registerActionSync(QAction *tar, std::function proc) +{ + action_trigger_map[tar] = proc; +} + +void StatusSyncCore::registerAutoRun(std::function judge, std::function exec) +{ + auto run = new Run(false, judge, exec); + alltriggers << run; +} + +Run *StatusSyncCore::registerManualRun(std::function judge, std::function exec) +{ + auto run = new Run(true, judge, exec); + alltriggers << run; + return run; +} + +void StatusSyncCore::sync() +{ + for(auto &it : widget_trigger_map.keys()){ + auto status = widget_trigger_map[it](); + if(it->isEnabled() != status) + it->setEnabled(status); + } + + for(auto &it : action_trigger_map.keys()){ + auto status = action_trigger_map[it](); + if(it->isEnabled() != status) + it->setEnabled(status); + } + + for(auto &act : alltriggers){ + act->exec(); + } +} + + + + + + + + + diff --git a/WordsIDE/mainwindow.h b/WordsIDE/mainwindow.h index bbcc804..6f8e5f8 100644 --- a/WordsIDE/mainwindow.h +++ b/WordsIDE/mainwindow.h @@ -4,15 +4,49 @@ #include #include #include -#include +#include #include #include #include #include "SensitiveCore.h" #include "messagepresent.h" #include "storychainspresent.h" +#include "storyunitspresent.h" #include "projectview.h" + +class Run +{ +public: + Run(bool manual_flag, std::function judge, std::function execution); + + void exec(); + +private: + bool manual; + std::function judgement; + std::function execution; +}; + +class StatusSyncCore : public QObject +{ +public: + explicit StatusSyncCore(QObject *p = nullptr); + virtual ~StatusSyncCore() = default; + + + void registerWidgetSync(QWidget* tar, std::function proc); + void registerActionSync(QAction* tar, std::function proc); + void registerAutoRun(std::function judge, std::function exec); + Run* registerManualRun(std::function judge, std::function exec); + void sync(); + +private: + QHash> widget_trigger_map; + QHash> action_trigger_map; + QList alltriggers; +}; + class MainWindow : public QMainWindow { Q_OBJECT @@ -22,6 +56,8 @@ public: ~MainWindow(); private: + Config::Configration *const global_config; + StatusSyncCore *const sync_kernel; QSplitter *const horizontal_split; QSplitter *const vertical_split; @@ -36,8 +72,9 @@ private: MakeTools::StoryTool *const make_tool; QListView *const project_list; - Components::ProjectView *const project_view; + Components::ProjectView *const project_structure; Components::StoryChainsPresent *const chains_view; + Components::StoryUnitsPresent *const units_view; Components::MessagePresent *const errors_present; MakeTools::SensitiveCore *const framework; @@ -45,8 +82,14 @@ private: // 内部逻辑 =========================================== void build_internal(bool all_from_disk = false); + void toggle_widget_visible(bool visible, QTabWidget *con, QWidget *target, const QString& title=QString()); + // QWidget interface protected: virtual void closeEvent(QCloseEvent *event) override; + + // QObject interface +public: + virtual bool eventFilter(QObject *watched, QEvent *event) override; }; #endif // MAINWINDOW_H diff --git a/WordsIDE/projectview.h b/WordsIDE/projectview.h index c7ba503..6bce3cf 100644 --- a/WordsIDE/projectview.h +++ b/WordsIDE/projectview.h @@ -3,7 +3,7 @@ #include #include -#include +#include namespace Components { diff --git a/WordsIDE/storyunitspresent.cpp b/WordsIDE/storyunitspresent.cpp new file mode 100644 index 0000000..124959f --- /dev/null +++ b/WordsIDE/storyunitspresent.cpp @@ -0,0 +1,91 @@ +#include "storyunitspresent.h" + +#include +#include + +using namespace Components; +using namespace Parse::Result; + +StoryUnitsPresent::StoryUnitsPresent(Parse::Result::ParseCore *core, QWidget *parent) + : QWidget(parent), core_ins(core), + model_ins(new QStandardItemModel(this)), + units_view(new QTreeView(this)), + details_show(new QPlainTextEdit(this)) +{ + units_view->setHeaderHidden(true); + + auto layout = new QVBoxLayout(this); + layout->setMargin(0); + + auto splitter = new QSplitter(Qt::Vertical, this); + layout->addWidget(splitter); + + splitter->addWidget(units_view); + splitter->addWidget(details_show); + + units_view->setModel(model_ins); + details_show->setReadOnly(true); + + connect(units_view, &QTreeView::clicked, this, &StoryUnitsPresent::show_node_description); +} + +void StoryUnitsPresent::refresh() +{ + model_ins->clear(); + auto units = core_ins->allStoryUnits(); + for(auto &unit : units){ + auto unit_node = new QStandardItem(static_cast(unit)->name()); + unit_node->setEditable(false); + model_ins->appendRow(unit_node); + + auto children = unit->children(); + for(auto &frag : children){ + if(frag->typeValue() == NODE_STORYFRAGMENT){ + auto frag_node = new QStandardItem(static_cast(frag)->name()); + frag_node->setEditable(false); + unit_node->appendRow(frag_node); + } + } + } +} + +void StoryUnitsPresent::show_node_description(const QModelIndex &curr) +{ + if(!curr.isValid()) + return; + + details_show->clear(); + auto item = model_ins->itemFromIndex(curr); + if(item->parent() == nullptr){ + auto node = core_ins->queryStoryUnit(item->text()); + + auto children = node.first()->children(); + for(auto &it : children){ + if(it->typeValue() != NODE_STORYFRAGMENT){ + details_show->appendPlainText(it->toString()); + } + } + } + else{ + auto node = core_ins->queryStoryUnit(item->parent()->text()); + auto point = core_ins->queryStoryFragment(node.first(), item->text()); + + auto children = point.first()->children(); + for(auto &it : children){ + details_show->appendPlainText(it->toString()); + } + } +} + + + + + + + + + + + + + diff --git a/WordsIDE/storyunitspresent.h b/WordsIDE/storyunitspresent.h new file mode 100644 index 0000000..641a576 --- /dev/null +++ b/WordsIDE/storyunitspresent.h @@ -0,0 +1,36 @@ +#ifndef STORYUNITSPRESENT_H +#define STORYUNITSPRESENT_H + +#include +#include +#include +#include +#include + +#include "libParse.h" + +namespace Components { + + class StoryUnitsPresent : public QWidget + { + Q_OBJECT + public: + explicit StoryUnitsPresent(Parse::Result::ParseCore *core, QWidget *parent = nullptr); + + void refresh(); + + signals: + + private: + Parse::Result::ParseCore *const core_ins; + QStandardItemModel *const model_ins; + QTreeView *const units_view; + QPlainTextEdit *const details_show; + + void show_node_description(const QModelIndex &curr); + + }; +} + + +#endif // STORYUNITSPRESENT_H diff --git a/libConfig/Configration.h b/libConfig/libConfig.h similarity index 54% rename from libConfig/Configration.h rename to libConfig/libConfig.h index 296773f..2298686 100644 --- a/libConfig/Configration.h +++ b/libConfig/libConfig.h @@ -1,5 +1,5 @@ -#ifndef CONFIGRATION_H -#define CONFIGRATION_H +#ifndef LIBCONFIG_H +#define LIBCONFIG_H #include #include @@ -44,6 +44,24 @@ namespace Config { } return xval; } + static QString getConfigAsDefaultSequence(QList seqs, const QList &path, const QString & default_v) + { + QString xval; + for(auto &ins : seqs){ + if(!ins) continue; + + xval = ins->getConfig(path); + if(xval.trimmed() != "") + break; + } + if(xval.trimmed() == ""){ + seqs.last()->setConfig(path, default_v); + seqs.last()->save(); + xval = default_v; + } + + return xval; + } static QList getListAsDefault(Configration *ins, const QList &path, const QList & default_v) { @@ -55,6 +73,25 @@ namespace Config { } return xval; } + static QList getListAsDefaultSequence(QList seqs, const QList &path, const QList & default_v) + { + QList xval; + for(auto &ins : seqs){ + if(!ins) continue; + + xval = ins->getList(path); + if(!xval.size()) + break; + } + + if(!xval.size()){ + seqs.last()->setList(path, default_v); + seqs.last()->save(); + xval = default_v; + } + + return xval; + } static QHash getHashAsDefault(Configration *ins, const QList &path, const QHash & default_v) { @@ -66,6 +103,25 @@ namespace Config { } return xval; } + static QHash getHashAsDefaultSequence(QList seqs, const QList &path, const QHash & default_v) + { + QHash xval; + for(auto &ins : seqs){ + if(!ins) continue; + + xval = ins->getMap(path); + if(!xval.size()) + break; + } + + if(!xval.size()){ + seqs.last()->setMap(path, default_v); + seqs.last()->save(); + xval = default_v; + } + + return xval; + } }; @@ -74,4 +130,4 @@ namespace Config { } -#endif // CONFIGRATION_H +#endif // LIBCONFIG_H diff --git a/libConfig/libConfig.pro b/libConfig/libConfig.pro index 225c128..6653252 100644 --- a/libConfig/libConfig.pro +++ b/libConfig/libConfig.pro @@ -14,7 +14,7 @@ SOURCES += \ xmlconfig.cpp HEADERS += \ - Configration.h \ + libConfig.h \ libConfig_global.h \ xmlconfig.h diff --git a/libConfig/xmlconfig.h b/libConfig/xmlconfig.h index 3cf98b0..1a35c71 100644 --- a/libConfig/xmlconfig.h +++ b/libConfig/xmlconfig.h @@ -2,7 +2,7 @@ #define XMLCONFIG_H #include "libConfig_global.h" -#include "Configration.h" +#include "libConfig.h" #include diff --git a/libParse/libParse.cpp b/libParse/libParse.cpp index e599d91..bcc32e4 100644 --- a/libParse/libParse.cpp +++ b/libParse/libParse.cpp @@ -195,21 +195,31 @@ QList ParseCore::queryStoryPoint(DesNode *chain, const QString return retlist; } -QList ParseCore::queryStoryUnit(const QString &name) const +QList ParseCore::allStoryUnits() const { QList retlist; auto keys = nodes_map.keys(); for(auto &k : keys) if(k->docType() == DocType::STORYUNIT) for(auto &n : *nodes_map[k]){ - if(n->typeValue()==NODE_STORYUNIT && - static_cast(n)->name() == name) + if(n->typeValue()==NODE_STORYUNIT) retlist << n; } return retlist; } +QList ParseCore::queryStoryUnit(const QString &name) const +{ + QList retlist; + + for(auto &k : allStoryUnits()) + if(static_cast(k)->name() == name) + retlist << k; + + return retlist; +} + QList ParseCore::queryStoryFragment(DesNode *unit, const QString &name) const { QList retlist; diff --git a/libParse/libParse.h b/libParse/libParse.h index 2165971..a7ef82c 100644 --- a/libParse/libParse.h +++ b/libParse/libParse.h @@ -309,6 +309,7 @@ namespace Parse virtual QList queryStoryChain(const QString & name) const; virtual QList queryStoryPoint(Result::DesNode* chain, const QString &name) const; + virtual QList allStoryUnits() const; virtual QList queryStoryUnit(const QString &name) const; virtual QList queryStoryFragment(Result::DesNode *unit, const QString &name) const; diff --git a/libProjectManager/ProjectManager.h b/libProjectManager/libProjectManager.h similarity index 96% rename from libProjectManager/ProjectManager.h rename to libProjectManager/libProjectManager.h index e744c0e..92c6519 100644 --- a/libProjectManager/ProjectManager.h +++ b/libProjectManager/libProjectManager.h @@ -1,7 +1,7 @@ -#ifndef PROJECTMANAGER_H -#define PROJECTMANAGER_H +#ifndef LIBPROJECTMANAGER_H +#define LIBPROJECTMANAGER_H -#include +#include #include #include @@ -119,4 +119,4 @@ namespace Project { } -#endif // PROJECTMANAGER_H +#endif // LIBPROJECTMANAGER_H diff --git a/libProjectManager/libProjectManager.pro b/libProjectManager/libProjectManager.pro index 2dc447e..221061d 100644 --- a/libProjectManager/libProjectManager.pro +++ b/libProjectManager/libProjectManager.pro @@ -14,7 +14,7 @@ SOURCES += \ xmlprojectmanager.cpp HEADERS += \ - ProjectManager.h \ + libProjectManager.h \ libProjectManager_global.h \ xmlprojectmanager.h diff --git a/libProjectManager/xmlprojectmanager.h b/libProjectManager/xmlprojectmanager.h index 9704dea..968303c 100644 --- a/libProjectManager/xmlprojectmanager.h +++ b/libProjectManager/xmlprojectmanager.h @@ -5,7 +5,7 @@ #include #include -#include "ProjectManager.h" +#include "libProjectManager.h" namespace Project {