diff --git a/QtNovelDesc.pro b/QtNovelDesc.pro index ba0217f..cb79ad9 100644 --- a/QtNovelDesc.pro +++ b/QtNovelDesc.pro @@ -6,4 +6,5 @@ SUBDIRS += \ WordsIDE \ libConfig \ libProjectManager \ + libTextEdit \ u_test diff --git a/QtNovelDesc.pro.user b/QtNovelDesc.pro.user index 1b59f3b..8c98337 100644 --- a/QtNovelDesc.pro.user +++ b/QtNovelDesc.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/WordsIDE/command_list.cpp b/WordsIDE/command_list.cpp index 07b3b5c..8bbc9b0 100644 --- a/WordsIDE/command_list.cpp +++ b/WordsIDE/command_list.cpp @@ -89,9 +89,12 @@ QString SaveAll::name() const void SaveAll::run(Schedule::CommandsDispatcher *core) const { - auto vmgr = core->get(NAME(SaveAll)); - vmgr->save(); - vmgr->projectManager()->save(); + auto vmgr = core->get(NAME(DocumentsManager)); + + if (vmgr->projectManager()->isOpenning()) { + vmgr->save(); + vmgr->projectManager()->save(); + } } QString SaveAll::toText() const diff --git a/WordsIDE/mainwindow.cpp b/WordsIDE/mainwindow.cpp index e3005c0..63ea269 100644 --- a/WordsIDE/mainwindow.cpp +++ b/WordsIDE/mainwindow.cpp @@ -34,7 +34,7 @@ MainWindow::MainWindow(XApp *core, const QString &layout, QWidget *parent) core_bind(core), sync_kernel(new StatusSyncCore(this)), present_host(new SplitFrame::ViewPresent(this)), - session_service(new ViewSession(XApp::global_configration, this)), + session_service(new ViewSession(XApp::gconfig, this)), actions_stack(new QToolBar(this)), views_bar(new ViewStackedBar(present_host, this)), center_frame(new PresentContainerView(present_host)), @@ -43,12 +43,9 @@ MainWindow::MainWindow(XApp *core, const QString &layout, QWidget *parent) setWindowTitle(tr("提线木偶")); QApplication::instance()->installEventFilter(this); - initial_commandlist(XApp::disp_core); auto mbar = menuBar(); initial_menubar(mbar); - XApp::disp_core->registerMember(core->docsManager()); - setCentralWidget(present_host->bind()); addToolBar(Qt::LeftToolBarArea, views_bar); present_host->addListener(views_bar); @@ -67,6 +64,8 @@ SplitFrame::ViewPresent *MainWindow::bindPresent() const { return present_host; QString MainWindow::layoutName() const { return layout_name_store; } +void MainWindow::resetLayoutName(const QString &name) { layout_name_store = name; } + void MainWindow::initial_menubar(QMenuBar *mbar) { // 项目菜单树 @@ -81,35 +80,15 @@ void MainWindow::initial_menubar(QMenuBar *mbar) { auto view = mbar->addMenu("视图"); build_view_menu(view); - // 项目管理 + // 版本管理 // 工具菜单 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内容"); + build_tools_menu(tool); // 窗口菜单 auto window = mbar->addMenu("窗口"); - auto newa = window->addMenu("新建窗口"); - newa->addAction("LayoutName1"); - newa->addAction("LayoutNameB"); - window->addAction("关闭窗口"); - window->addSeparator(); - window->addAction("保存当前布局"); - window->addMenu("布局切换"); - window->addMenu("布局删除"); + build_window_menu(window); // 系统 auto sys = mbar->addMenu("系统"); @@ -219,15 +198,69 @@ void MainWindow::build_view_menu(QMenu *view) { sync_kernel->widgetEnableSync(func, [this]() { return this->core_bind->pjtManager()->isOpenning(); }); } -void MainWindow::initial_commandlist(Schedule::CommandsDispatcher *host) { - host->registerCommand(new CloseProject()); +void MainWindow::build_tools_menu(QMenu *tool) { + 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内容"); +} - host->registerCommand(new NewFile(Route(), "", "txt")); - host->registerCommand(new NewPackage("")); - host->registerCommand(new NewProject(QDir(), "")); - host->registerCommand(new OpenFile(Route())); - host->registerCommand(new OpenProject("")); - host->registerCommand(new SaveAll()); +QList layout_peak_path = {"sys-configs", "foreground", "view-layouts"}; +void MainWindow::build_window_menu(QMenu *window) { + auto new_window = window->addMenu("新建窗口"); + connect(new_window, &QMenu::aboutToShow, [new_window]() { + auto names = XApp::gconfig->getList(layout_peak_path); + if (!names.size()) { + names << "default"; + XApp::gconfig->setList(layout_peak_path, names); + } + + new_window->clear(); + + for (auto &n : names) + new_window->addAction(n); + }); + connect(new_window, &QMenu::triggered, [this](QAction *s) { + auto layout = s->text(); + auto newone = new MainWindow(this->core_bind, layout); + newone->show(); + }); + + window->addAction("关闭窗口", [this]() { + XApp::disp_core->postCommand(SaveAll()); + this->close(); + }); + + window->addSeparator(); + window->addAction("保存当前布局", [this]() { + auto new_name = QInputDialog::getText(this, "输入新布局名称", "名称:"); + if (new_name.isEmpty()) + return; + + auto names = XApp::gconfig->getList(layout_peak_path); + if (names.contains(new_name)) { + QMessageBox::critical(this, "数据校验", "输入错误,输入了重复的布局名称!"); + return; + } + names << new_name; + XApp::gconfig->setList(layout_peak_path, names); + + this->resetLayoutName(new_name); + session_service->viewStatesSave(this, this->present_host); + }); + + window->addMenu("布局切换"); + window->addMenu("布局删除"); } void MainWindow::closeEvent(QCloseEvent *event) { @@ -237,7 +270,7 @@ void MainWindow::closeEvent(QCloseEvent *event) { } session_service->viewStatesSave(this, present_host); - XApp::global_configration->save(); + XApp::gconfig->save(); QMainWindow::closeEvent(event); } diff --git a/WordsIDE/mainwindow.h b/WordsIDE/mainwindow.h index ace096a..b91adc0 100644 --- a/WordsIDE/mainwindow.h +++ b/WordsIDE/mainwindow.h @@ -29,6 +29,7 @@ public: SplitFrame::ViewPresent *bindPresent() const; QString layoutName() const; + void resetLayoutName(const QString &name); private: QString layout_name_store; @@ -45,12 +46,13 @@ private: Components::ProjectView *const project_present; // 内部逻辑 =========================================== - void initial_commandlist(Schedule::CommandsDispatcher *host); void initial_menubar(QMenuBar *mbar); void build_project_menu(QMenu *pmenu); void build_edit_menu(QMenu *pmenu); void build_view_menu(QMenu *pmenu); + void build_tools_menu(QMenu *pmenu); + void build_window_menu(QMenu *pmenu); // QWidget interface protected: diff --git a/WordsIDE/tools.h b/WordsIDE/tools.h index 0c1d62f..4164493 100644 --- a/WordsIDE/tools.h +++ b/WordsIDE/tools.h @@ -1,7 +1,7 @@ #ifndef COMNTOOLS_H #define COMNTOOLS_H -#include "opstream.h" +#include #include #include diff --git a/WordsIDE/xapp.cpp b/WordsIDE/xapp.cpp index c6ea89f..47794f7 100644 --- a/WordsIDE/xapp.cpp +++ b/WordsIDE/xapp.cpp @@ -1,4 +1,5 @@ #include "xapp.h" +#include "command_list.h" #include #include #include @@ -15,7 +16,11 @@ XApp::XApp(int argc, char **argv) parse_service(new ParseBridge()), project_manager(new XMLProjectManager(this)), active_docscollect(new DocumentsManager(project_manager)) { - global_configration->loadFile("./software.config"); + gconfig->loadFile("./software.config"); + + init_commands(disp_core); + + XApp::disp_core->registerMember(active_docscollect); } bool XApp::notify(QObject *receiver, QEvent *event) { @@ -35,5 +40,17 @@ ProjectManager *XApp::pjtManager() const { return project_manager; } DocumentsManager *XApp::docsManager() const { return active_docscollect; } +using namespace CommandList; +void XApp::init_commands(Schedule::CommandsDispatcher *host) { + host->registerCommand(new CloseProject()); + + host->registerCommand(new NewFile(Route(), "", "txt")); + host->registerCommand(new NewPackage("")); + host->registerCommand(new NewProject(QDir(), "")); + host->registerCommand(new OpenFile(Route())); + host->registerCommand(new OpenProject("")); + host->registerCommand(new SaveAll()); +} + CommandsDispatcher *const XApp::disp_core = new CommandsDispatcher(QDir("./"), true); -Configration *const XApp::global_configration = new XMLConfig(); +Configration *const XApp::gconfig = new XMLConfig(); diff --git a/WordsIDE/xapp.h b/WordsIDE/xapp.h index 2adf651..213fd4d 100644 --- a/WordsIDE/xapp.h +++ b/WordsIDE/xapp.h @@ -21,12 +21,14 @@ class XApp : public QApplication { public: static Schedule::CommandsDispatcher *const disp_core; - static Config::Configration *const global_configration; + static Config::Configration *const gconfig; private: bridge::ParseBridge *const parse_service; Project::ProjectManager *const project_manager; Core::DocumentsManager *const active_docscollect; + + void init_commands(Schedule::CommandsDispatcher *core); }; #endif // XAPPLICATION_H diff --git a/libConfig/xmlconfig.cpp b/libConfig/xmlconfig.cpp index a3a52b9..27ffe8f 100644 --- a/libConfig/xmlconfig.cpp +++ b/libConfig/xmlconfig.cpp @@ -113,13 +113,11 @@ void XMLConfig::setList(const QList &path, const QList &list) { auto root = doc_ins.documentElement(); auto telm = rebuild_exists_elms(root, path); - auto childs = telm.childNodes(); + auto childs = telm.elementsByTagName("list"); - for(auto idx= 0; idx= 0; --idx) { auto node = childs.at(idx); - - if(node.isElement() && node.toElement().tagName() == "list") - telm.removeChild(node); + telm.removeChild(node); } for(auto &it : list){ diff --git a/libTextEdit/entitydata.cpp b/libTextEdit/entitydata.cpp new file mode 100644 index 0000000..d870823 --- /dev/null +++ b/libTextEdit/entitydata.cpp @@ -0,0 +1,40 @@ +#include "entitydata.h" + +using namespace PresentDatas; + +SpecificEntityData::SpecificEntityData(EntityType type, const QString &uid) : type_store(type), document_id(uid) {} + +void SpecificEntityData::resetContentLayout(MemberOri oritation, MemberType child_type) { + this->oritation_store = oritation; + this->layout_type = child_type; +} + +void SpecificEntityData::setAnchorTo(AnchorTarget type, EntityData *tptr) { + anchor_info = std::make_tuple(type, tptr, std::get<2>(anchor_info), std::get<3>(anchor_info), std::get<4>(anchor_info)); +} + +void SpecificEntityData::setAnchorPos(AnchorPos point, offset_h hoffset, offset_v v_offset) { + anchor_info = std::make_tuple(std::get<0>(anchor_info), std::get<1>(anchor_info), point, hoffset, v_offset); +} + +QString SpecificEntityData::uID() const { return document_id; } + +EntityType SpecificEntityData::type() const { return type_store; } + +MemberOri SpecificEntityData::oritation() const { return oritation_store; } + +MemberType SpecificEntityData::displayType() const { return layout_type; } + +std::pair SpecificEntityData::anchorTarget() const { + return std::make_pair(std::get<0>(anchor_info), std::get<1>(anchor_info)); +} + +std::tuple SpecificEntityData::anchorPos() const { + return std::make_tuple(std::get<2>(anchor_info), std::get<3>(anchor_info), std::get<4>(anchor_info)); +} + +DocumentData::DocumentData(const QString &name) : SpecificEntityData(EntityType::DOCUMENT_ENTITY, "Document-Unique") { + resetContentLayout(MemberOri::H_LEFT_TO_RIGHT, MemberType::BLOCKS); +} + +void DocumentData::resetContentLayout(MemberOri oritation, MemberType) { SpecificEntityData::resetContentLayout(oritation, MemberType::BLOCKS); } diff --git a/libTextEdit/entitydata.h b/libTextEdit/entitydata.h new file mode 100644 index 0000000..2d73e4f --- /dev/null +++ b/libTextEdit/entitydata.h @@ -0,0 +1,231 @@ +#ifndef ENTITYDATA_H +#define ENTITYDATA_H + +#include +#include +#include + +namespace PresentDatas { + + enum class EntityType { + TEXT_RANGE, // 字符集合,包含段落和句子 + IMAGE_CUBE, // 图片展示块 + HREF_FRAGS, // 超链接 + TABLE_VIEW, // 表格视图 + LIST_VIEW, // 列表视图 + INTERACTIVE_EXTENSION, // 交互式拓展插件视图 + DISPLAY_GROUP, // 元素混合组织成包 + DOCUMENT_ENTITY + }; + + enum class MemberOri { + H_LEFT_TO_RIGHT, // 从左到右横向排版 + H_RIGHT_TO_LEFT, // 从右到左横向排版 + H_CENTER_IN, // 中央对准横向排布 + V_LEFT_TO_RIGHT, // 从左到右纵向排布 + V_RIGHT_TO_LEFT, // 从右到左纵向排布 + V_CENTER_IN // 中央对准纵向排布 + }; + + enum class MemberType { + BLOCKS, // 成员被视为块元素 + INLINES // 成员被视图行内元素 + }; + + enum class AnchorTarget { + NONE, // 文档二维平面排版 + WINDOW, // 窗口相对偏移定位 + DOCUMENT, // 文档相对偏移定位 + ELEMENT //元素相对偏移定位 + }; + + enum class AnchorPos { + NONE, + + POINT_LEFT_TOP, + POINT_LEFT_CENTER, + POINT_LEFT_BOTTOM, + + POINT_CENTER_TOP, + POINT_CENTER_BOTH, + POINT_CENTER_BOTTOM, + + POINT_RIGHT_TOP, + POINT_RIGHT_CENTER, + POINT_RIGHT_BOTTOM + }; + + /** + * @brief 基础实体数据 + */ + class EntityData { + public: + virtual ~EntityData() = default; + + // 标定相关 ================================================================= + /** + * @brief 获取实体的ID + * @return + */ + virtual QString uID() const = 0; + + /** + * @brief 内容文本 + * @return + */ + virtual QString styledText() const = 0; + + /** + * @brief 不带格式的普通文本 + * @return + */ + virtual QString plainText() const = 0; + // 实体属性 =================================================================== + /** + * @brief 获取元素可视性 + * @return + */ + virtual bool isVisible() const = 0; + + /** + * @brief 本实体的种类 + * @return + */ + virtual EntityType type() const = 0; + + // 排版相关 =================================================================== + /** + * @brief 成员排布朝向 + * @return + */ + virtual MemberOri oritation() const = 0; + + /** + * @brief 成员排版类型 + * @return + */ + virtual MemberType displayType() const = 0; + + /** + * @brief 获取元素锚定位置 + * // pair 文档二维平面排版 + * // pair 浮动排版,文档元素定位 + * // pair 浮动排版,窗口偏移定位 + * // pair 浮动排版,文档偏移定位 + * @return + */ + virtual std::pair anchorTarget() const = 0; + + typedef float offset_h; + typedef float offset_v; + /** + * @brief 锚定偏移位置 + * @return + */ + virtual std::tuple anchorPos() const = 0; + + /** + * @brief 计算最小尺寸 + * @param outline + * @return + */ + virtual QSizeF minSizeHint(const QRectF &outline) const = 0; + + /** + * @brief 计算当前尺寸 + * @param outline + * @return + */ + virtual QSizeF sizeHint(const QRectF &outline) const = 0; + + /** + * @brief 子元素数据,安装元素书序 + * @return + */ + virtual QList children() const = 0; + }; + + /** + * 具体化的实体数据类型,实现共同的接口逻辑 + */ + class SpecificEntityData : public EntityData { + public: + SpecificEntityData(EntityType type, const QString &uid); + virtual ~SpecificEntityData() = default; + + /** + * @brief 设置内容排版约束信息 + * @param oritation + * @param child_type + */ + virtual void resetContentLayout(MemberOri oritation, MemberType child_type); + + /** + * @brief 设置相对布局元素 + * @param type + * @param tptr + */ + virtual void setAnchorTo(AnchorTarget type, EntityData *tptr = nullptr); + + /** + * @brief 设置相对布局偏移量 + * @param point + * @param hoffset + * @param v_offset + */ + virtual void setAnchorPos(AnchorPos point, EntityData::offset_h hoffset, EntityData::offset_v v_offset); + + /** + * @brief 在指定位置插入子元素 + * @param inst + * @param index -1:尾缀位置 + */ + virtual void insertChild(EntityData *inst, int index = -1); + /** + * @brief 移除指定子元素 + * @param inst + */ + virtual void removeChild(EntityData *inst); + + // EntityData ==================================================== + virtual QString uID() const; + virtual EntityType type() const; + virtual MemberOri oritation() const; + virtual MemberType displayType() const; + virtual std::pair anchorTarget() const; + virtual std::tuple anchorPos() const; + virtual QList children() const; + + private: + EntityType type_store; + QString document_id; + MemberOri oritation_store; + MemberType layout_type; + std::tuple anchor_info; + }; + + /** + * @brief 文档数据模型 + */ + class DocumentData : public SpecificEntityData { + public: + DocumentData(const QString &name); + + // EntityData interface + public: + virtual QString styledText() const override; + virtual QString plainText() const override; + virtual bool isVisible() const override; + virtual QSizeF minSizeHint(const QRectF &outline) const override; + virtual QSizeF sizeHint(const QRectF &outline) const override; + + // SpecificEntityData interface + public: + virtual void resetContentLayout(MemberOri oritation, MemberType) override; + + private: + }; + +} // namespace PresentDatas + +#endif // ENTITYDATA_H diff --git a/libTextEdit/libTextEdit.pro b/libTextEdit/libTextEdit.pro new file mode 100644 index 0000000..51ede69 --- /dev/null +++ b/libTextEdit/libTextEdit.pro @@ -0,0 +1,30 @@ +QT -= gui + +TEMPLATE = lib +DEFINES += LIBTEXTEDIT_LIBRARY + +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 += \ + entitydata.cpp \ + libtextedit.cpp + +HEADERS += \ + entitydata.h \ + libTextEdit_global.h \ + libtextedit.h + +msvc { + QMAKE_CFLAGS += /utf-8 + QMAKE_CXXFLAGS += /utf-8 +} + +# Default rules for deployment. +unix { + target.path = /usr/lib +} +!isEmpty(target.path): INSTALLS += target diff --git a/libTextEdit/libTextEdit_global.h b/libTextEdit/libTextEdit_global.h new file mode 100644 index 0000000..16c1cbe --- /dev/null +++ b/libTextEdit/libTextEdit_global.h @@ -0,0 +1,12 @@ +#ifndef LIBTEXTEDIT_GLOBAL_H +#define LIBTEXTEDIT_GLOBAL_H + +#include + +#if defined(LIBTEXTEDIT_LIBRARY) +# define LIBTEXTEDIT_EXPORT Q_DECL_EXPORT +#else +# define LIBTEXTEDIT_EXPORT Q_DECL_IMPORT +#endif + +#endif // LIBTEXTEDIT_GLOBAL_H diff --git a/libTextEdit/libtextedit.cpp b/libTextEdit/libtextedit.cpp new file mode 100644 index 0000000..d0a5b19 --- /dev/null +++ b/libTextEdit/libtextedit.cpp @@ -0,0 +1,5 @@ +#include "libtextedit.h" + +LibTextEdit::LibTextEdit() +{ +} diff --git a/libTextEdit/libtextedit.h b/libTextEdit/libtextedit.h new file mode 100644 index 0000000..dbe672d --- /dev/null +++ b/libTextEdit/libtextedit.h @@ -0,0 +1,12 @@ +#ifndef LIBTEXTEDIT_H +#define LIBTEXTEDIT_H + +#include "libTextEdit_global.h" + +class LIBTEXTEDIT_EXPORT LibTextEdit +{ +public: + LibTextEdit(); +}; + +#endif // LIBTEXTEDIT_H