#include "default_textpresent.h" #include "mainwindow.h" #include "storyboardsourceedit.h" #include "storychain_sourceeditor.h" #include "storyunitsourceedit.h" #include "storyvolumesourceedit.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Project; using namespace MakeTools; using namespace Parse::Result; using namespace Components; using namespace Core; using namespace Tools; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), app_core(new AppCore(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)), right_funcs(new QTabWidget(this)), center_funcs(new QTabWidget(this)), bottom_funcs(new QTabWidget(this)), project_manager(new XMLProjectManager(this)), current_projects(new QListView(this)), project_structure(new VisiableProjectController(app_core, project_manager, this)), chains_view(new StoryChainsPresent(app_core, this)), units_view(new StoryUnitsPresent(app_core, this)), errors_present(new MessagePresent(app_core->getMakeCore(), this)), boards_view(new StoryBoardsPresent(app_core, this)), concept_view(new StoryConceptsPresent(app_core, this)), fragments_order(new FragmentsOrderView(app_core, this)) { QApplication::instance()->installEventFilter(this); this->app_core->setCurrentProject(project_manager); setMinimumSize(1000, 600); setWindowTitle("提线木偶"); chains_view->setVisible(false); units_view->setVisible(false); errors_present->setVisible(false); boards_view->setVisible(false); concept_view->setVisible(false); fragments_order->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(); // 项目菜单树 auto project = mbar->addMenu("项目"); auto pnew = project->addAction("新建路径", [this](){ auto packages = QInputDialog::getText(this, "输入包路径名称", "packagea#packageb#packagec"); if(packages == "") return; QList names; QRegExp exp("([^#]+)"); auto idx=0; while ((idx = exp.indexIn(packages, idx)) != -1) { names << exp.capturedTexts()[1]; idx += names.last().length(); } project_manager->newPackage(names); }); sync_kernel->registerActionSync(pnew, [this]()->bool{return project_manager->isOpen();}); auto _xnew = project->addMenu("最后卷新建文件"); _xnew->addAction("小说章节"); _xnew->addSeparator(); _xnew->addAction("发展脉络"); _xnew->addAction("故事单元"); _xnew->addAction("故事大纲"); _xnew->addAction("叙事大纲"); sync_kernel->registerWidgetSync(_xnew, [this]()->bool{return project_manager->isOpen();}); project->addSeparator(); auto sav = project->addAction("保存"); sav->setShortcut(QKeySequence::StandardKey::Save); sync_kernel->registerActionSync(sav, [this]()->bool{return project_manager->isOpen();}); connect(sav, &QAction::triggered, [this](){ this->project_manager->save(); app_core->getDocsManager()->saveAll(); }); project->addSeparator(); auto opnp = project->addAction("打开项目"); 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); build_internal(true); }); auto newp = project->addAction("新建项目"); sync_kernel->registerActionSync(newp, [this]()->bool{return !project_manager->isOpen();}); connect(newp, &QAction::triggered, [this](){ auto name = QInputDialog::getText(this, "输入项目名称", "项目名称"); if(name == "") return; auto dir_path = QFileDialog::getExistingDirectory(this, "指定项目存储路径"); if(dir_path == "") return; this->project_manager->newProject(dir_path, name); }); auto clsp = project->addAction("关闭项目"); sync_kernel->registerActionSync(clsp, [this]()->bool{return project_manager->isOpen();}); connect(clsp, &QAction::triggered, [this](){ this->project_manager->closeProject(); this->app_core->getDocsManager()->closeAll(); this->refresh_views(); }); project->addSeparator(); auto pcfg = project->addAction("项目配置"); connect(pcfg, &QAction::triggered, [this](){ QDialog x(this); auto layout = new QVBoxLayout(&x); auto widget = new QTabWidget(&x); widget->setTabPosition(QTabWidget::West); layout->addWidget(widget); // auto exts = app_core->extensions(); // for(auto &es : exts){ // auto cp = es->getNewPanel(app_core->currentProject()->configraions()); // if(cp) // widget->addTab(cp, es->extensionName()); // } x.exec(); }); sync_kernel->registerActionSync(pcfg, [this]()->bool{ return app_core->currentProject()->isOpen();}); auto scfg = project->addAction("软件配置"); connect(scfg, &QAction::triggered, [this](){ QDialog x(this); auto layout = new QVBoxLayout(&x); auto widget = new QTabWidget(&x); widget->setTabPosition(QTabWidget::West); layout->addWidget(widget); auto exts = app_core->extensions(); // for(auto &es : exts){ // auto cp = es->getNewPanel(app_core->globalConfig()); // if(cp) // widget->addTab(cp, es->extensionName()); // } x.exec(); }); project->addSeparator(); project->addAction("退出", [](){ QApplication::exit(0); }); // 编辑菜单 auto edit = mbar->addMenu("编辑"); edit->addAction("撤销一步"); edit->addAction("重做一步"); edit->addSeparator(); edit->addAction("查找关键词"); edit->addAction("替换关键词"); // 视图菜单 auto view = mbar->addMenu("视图"); auto area = view->addMenu("区域管理"); auto act_tool = area->addAction("工具栏"); act_tool->setCheckable(true); connect(act_tool, &QAction::triggered, [xtool](bool v){ xtool->setVisible(v); }); sync_kernel->registerAutoRun([xtool]()->bool{return xtool->isVisible();}, [act_tool](bool v){ if(v != act_tool->isChecked()) act_tool->setChecked(v); }); auto act_status = area->addAction("状态栏"); act_status->setCheckable(true); connect(act_status,&QAction::triggered, [xstatus](bool v){xstatus->setVisible(v);}); sync_kernel->registerAutoRun([xstatus]()->bool{return xstatus->isVisible();}, [act_status](bool v){ if(v != act_status->isChecked()) act_status->setChecked(v); }); auto act_left = area->addAction("左侧功能区"); act_left->setCheckable(true); connect(act_left, &QAction::triggered, [this](bool v){this->left_funcs->setVisible(v);}); sync_kernel->registerAutoRun([this]()->bool{return this->left_funcs->isVisible();}, [act_left](bool v){ if(v!= act_left->isChecked()) act_left->setChecked(v); }); auto act_right = area->addAction("右侧功能区"); act_right->setCheckable(true); connect(act_right, &QAction::triggered, [this](bool v){this->right_funcs->setVisible(v);}); sync_kernel->registerAutoRun([this]()->bool{return this->right_funcs->isVisible();}, [act_right](bool v){if(v != act_right->isChecked()) act_right->setChecked(v);}); auto act_bottom = area->addAction("底部功能区"); act_bottom->setCheckable(true); connect(act_bottom, &QAction::triggered, [this](bool v){this->bottom_funcs->setVisible(v);}); sync_kernel->registerAutoRun([this]()->bool{return this->bottom_funcs->isVisible();}, [act_bottom](bool v){ if(v!= act_bottom->isChecked()) act_bottom->setChecked(v);}); view->addSeparator(); auto change = view->addMenu("内容切换"); change->addAction("序列视图"); change->addAction("编辑视图"); view->addSeparator(); auto func = view->addMenu("功能视图"); // 项目管理 { 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("脉络分蘖"); // 编译信息 { auto msgs = func->addAction("编译输出", [this](bool v){ toggle_widget_visible(v, bottom_funcs, errors_present, "编译输出"); }); msgs->setCheckable(true); sync_kernel->registerAutoRun([this]()->bool{return bottom_funcs->indexOf(errors_present) != -1;}, [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 right_funcs->indexOf(chains_view) != -1;}, [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 right_funcs->indexOf(units_view)!=-1;}, [unit_v](bool v){if(v != unit_v->isChecked()) unit_v->setChecked(v);}); } // 故事统计 { auto board_v = func->addAction("故事统计", [this](bool v){ toggle_widget_visible(v, right_funcs, boards_view, "故事统计"); }); board_v->setCheckable(true); sync_kernel->registerAutoRun([this]()->bool{return right_funcs->indexOf(boards_view)!=-1;}, [board_v](bool v){if(v!=board_v->isChecked()) board_v->setChecked(v);}); } // 概念统计 { auto concept_v = func->addAction("概念统计", [this](bool v){ toggle_widget_visible(v, right_funcs, concept_view, "概念统计"); }); concept_v->setCheckable(true); sync_kernel->registerAutoRun([this]()->bool{return right_funcs->indexOf(concept_view)!=-1;}, [concept_v](bool v){if(v != concept_v->isChecked()) concept_v->setChecked(v);}); } // 情节序列 { auto fragments_v = func->addAction("情节序列", [this](bool v){ toggle_widget_visible(v, right_funcs, fragments_order, "情节序列"); }); fragments_v->setCheckable(true); sync_kernel->registerAutoRun([this]()->bool{return right_funcs->indexOf(fragments_order)!=-1;}, [fragments_v](bool v){if(v != fragments_v->isChecked()) fragments_v->setChecked(v);}); } // 工具菜单 auto tool = mbar->addMenu("工具"); auto word = tool->addMenu("敏感词检测"); word->addAction("工具配置"); word->addAction("敏感词编辑"); auto vcs = tool->addMenu("版本管理"); vcs->addAction("工具配置"); vcs->addAction("启用"); auto exp = tool->addMenu("导入导出"); exp->addAction("导入WsOutlines"); exp->addSeparator(); exp->addAction("导出TXT大纲"); exp->addAction("导出Web大纲"); exp->addAction("导出WsOutlines"); exp->addSeparator(); exp->addAction("导出TXT内容"); auto build = tool->addAction("编译", [this](){ this->build_internal(); }); sync_kernel->registerActionSync(build, [this]()->bool{ return project_manager->isOpen(); }); // 窗口菜单 auto window = mbar->addMenu("窗口"); window->addAction("新建窗口"); window->addAction("关闭窗口"); window->addSeparator(); window->addAction("布局管理"); window->addMenu("布局切换"); window->addMenu("窗口切换"); // 系统 auto sys = mbar->addMenu("系统"); sys->addAction("软件激活"); sys->addAction("系统信息"); sys->addSeparator(); sys->addAction("关于……"); setCentralWidget(this->vertical_split); this->vertical_split->addWidget(this->horizontal_split); this->vertical_split->addWidget(bottom_funcs); this->horizontal_split->addWidget(left_funcs); this->horizontal_split->addWidget(center_funcs); this->horizontal_split->addWidget(right_funcs); 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){ auto view = center_funcs->widget(index); toggle_widget_visible(false, center_funcs, view); auto comp = app_core->getDocsManager()->queryTextComponent(view); if(comp) app_core->getDocsManager()->closeTextComponent(QFileInfo(comp->absulateTargetPath())); }); connect(project_structure, &VisiableProjectController::aboutToBoDelete, [this](QList infos){ for(auto &key : infos){ auto comp = app_core->getDocsManager()->queryTextComponent(key); if(comp){ toggle_widget_visible(false, center_funcs, comp->widget()); app_core->getDocsManager()->closeTextComponent(key); } } }); this->app_core->getDocsManager()->addProcTrigger([this](){ this->refresh_views(); }); center_funcs->addTab(current_projects, "欢迎界面"); connect(project_structure, &VisiableProjectController::activeDocument, app_core->getDocsManager(), &MakeTools::DocsManager::openTextDocument); uilayout_load(); connect(horizontal_split, &QSplitter::splitterMoved, [this](){ splitter_layout_save({"uilayout","split-policy-h","lens"}, horizontal_split->sizes()); }); connect(vertical_split, &QSplitter::splitterMoved, [this](){ splitter_layout_save({"uilayout", "split-policy-v", "lens"}, vertical_split->sizes()); }); } MainWindow::~MainWindow() { } void MainWindow::contentViewAppend(QWidget *widget, const QString &name) { for(auto idx=0; idxcount(); ++idx){ if(center_funcs->widget(idx) == widget){ center_funcs->setCurrentWidget(widget); return; } } center_funcs->addTab(widget, name); center_funcs->setCurrentWidget(widget); } void MainWindow::contentViewClose(QWidget *widget) { for(auto idx=0; idxcount(); ++idx){ if(center_funcs->widget(idx) == widget){ } } } void MainWindow::refresh_views() { errors_present->refresh(); chains_view->refresh(); units_view->refresh(); boards_view->refresh(); concept_view->refresh(); fragments_order->refresh(); } void MainWindow::build_internal(bool all_from_disk) { if(!all_from_disk) app_core->getDocsManager()->saveAll(); auto chains = project_manager->filesWithEnds("storychain"); for(auto &it : chains) app_core->getMakeCore()->compile(std::get<0>(it), std::get<0>(it)); auto units = project_manager->filesWithEnds("storyunit"); for(auto &it : units) app_core->getMakeCore()->compile(std::get<0>(it), std::get<0>(it)); auto storys = project_manager->filesWithEnds("storyboard"); for(auto &it : storys) app_core->getMakeCore()->compile(std::get<0>(it), std::get<0>(it)); auto volumes = project_manager->filesWithEnds("storyvolume"); for(auto &it : volumes) app_core->getMakeCore()->compile(std::get<0>(it), std::get<0>(it)); auto concepts = project_manager->filesWithEnds("storyconcept"); for(auto &it : concepts) app_core->getMakeCore()->compile(std::get<0>(it), std::get<0>(it)); refresh_views(); } void MainWindow::toggle_widget_visible(bool visible, QTabWidget *con, QWidget *target, const QString &title) { if(visible && con->indexOf(target) == -1){ target->setVisible(true); con->addTab(target, title); }else if(!visible && con->indexOf(target) != -1){ target->setVisible(false); con->removeTab(con->indexOf(target)); } } void MainWindow::splitter_layout_save(const QList &path_type, const QList &size) { auto convert = [](QList sizes)->QStringList{ QStringList size_strs; for(auto i : sizes) size_strs << QString("%1").arg(i); return size_strs; }; app_core->globalConfig()->setList(path_type, convert(size)); } void MainWindow::uilayout_save() { auto global = app_core->globalConfig(); auto xvisible_save = [global](QWidget *ins, const QString &name){ global->setConfig({"uilayout", "visible", name}, QString("%1").arg(ins->isVisible())); }; xvisible_save(left_funcs, "area-left"); xvisible_save(right_funcs, "area-right"); xvisible_save(bottom_funcs, "area-bottom"); // xvisible_save(project_structure, "project_tree"); // xvisible_save(errors_present, "message-view"); // xvisible_save(chains_view, "chains-sum"); // xvisible_save(units_view, "units-sum"); } void MainWindow::uilayout_load() { auto global = app_core->globalConfig(); auto xvisible_load = [global](QWidget *ins, const QString &name){ auto visible = Config::ConfigHelper::getConfigAsDefault(global, {"uilayout","visible",name}, QString("%1").arg(false)); ins->setVisible(visible.toInt()); }; xvisible_load(left_funcs, "area-left"); xvisible_load(right_funcs, "area-right"); xvisible_load(bottom_funcs, "area-bottom"); // xvisible_load(project_structure, "project_tree"); // xvisible_load(errors_present, "message-view"); // xvisible_load(chains_view, "chains-sum"); // xvisible_load(units_view, "units-sum"); auto convert = [](QStringList in)->QList{ QList size; for(auto &s : in) size << s.toInt(); return size; }; auto strings = global->getList({"uilayout", "split-policy-h", "lens"}); horizontal_split->setSizes(convert(strings)); strings = global->getList({"uilayout", "split-policy-v", "lens"}); vertical_split->setSizes(convert(strings)); } void MainWindow::closeEvent(QCloseEvent *event) { // 关闭事件 if(project_manager->isOpen()){ project_manager->save(); app_core->getDocsManager()->closeAll(); } uilayout_save(); app_core->save(); 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); }