From d7bfb956ec0f635c97518e5dda162077b3cedcde Mon Sep 17 00:00:00 2001 From: Le Tan Date: Wed, 3 Nov 2021 20:43:11 +0800 Subject: [PATCH] support user.css for Markdown editor read mode style --- src/core/buffer/buffer.cpp | 2 + src/core/buffer/buffer.h | 3 + src/core/configmgr.cpp | 41 +++++++++- src/core/configmgr.h | 8 +- src/core/fileopenparameters.h | 10 +++ src/core/htmltemplatehelper.cpp | 4 +- src/core/htmltemplatehelper.h | 2 +- src/core/mainconfig.cpp | 2 +- src/data/core/vnotex.json | 3 +- src/data/extra/extra.qrc | 1 + src/data/extra/themes/moonlight/highlight.css | 1 - src/data/extra/themes/moonlight/interface.qss | 4 +- src/data/extra/themes/moonlight/palette.json | 4 + .../extra/themes/moonlight/text-editor.theme | 2 +- src/data/extra/themes/moonlight/web.css | 6 +- src/data/extra/themes/native/highlight.css | 1 - src/data/extra/themes/native/interface.qss | 2 +- .../extra/themes/native/text-editor.theme | 2 +- src/data/extra/themes/native/web.css | 6 +- src/data/extra/themes/pure/highlight.css | 1 - src/data/extra/themes/pure/interface.qss | 4 +- src/data/extra/themes/pure/palette.json | 4 + src/data/extra/themes/pure/text-editor.theme | 2 +- src/data/extra/themes/pure/web.css | 6 +- src/data/extra/web/css/user.css | 2 + src/widgets/mainwindow.cpp | 37 ++++++--- src/widgets/mainwindow.h | 15 ++-- src/widgets/notebookselector.cpp | 5 +- src/widgets/notebookselector.h | 2 + src/widgets/toolbarhelper.cpp | 81 +++++++++++-------- src/widgets/toolbarhelper.h | 2 + src/widgets/viewwindow.cpp | 17 +++- src/widgets/viewwindow.h | 7 +- 33 files changed, 211 insertions(+), 78 deletions(-) create mode 100644 src/data/extra/web/css/user.css diff --git a/src/core/buffer/buffer.cpp b/src/core/buffer/buffer.cpp index f84dc1b0..ce3a02c4 100644 --- a/src/core/buffer/buffer.cpp +++ b/src/core/buffer/buffer.cpp @@ -320,6 +320,8 @@ void Buffer::autoSave() case EditorConfig::AutoSavePolicy::AutoSave: if (save(false) != OperationCode::Success) { qWarning() << "AutoSave failed to save buffer, retry later"; + } else { + emit autoSaved(); } break; diff --git a/src/core/buffer/buffer.h b/src/core/buffer/buffer.h index 8c0f4651..7b6b2267 100644 --- a/src/core/buffer/buffer.h +++ b/src/core/buffer/buffer.h @@ -188,6 +188,9 @@ namespace vnotex void attachmentChanged(); + // This buffer is AutoSavePolicy::AutoSave. + void autoSaved(); + protected: virtual ViewWindow *createViewWindowInternal(const QSharedPointer &p_paras, QWidget *p_parent) = 0; diff --git a/src/core/configmgr.cpp b/src/core/configmgr.cpp index 53e640fe..69a2d9ee 100644 --- a/src/core/configmgr.cpp +++ b/src/core/configmgr.cpp @@ -75,7 +75,10 @@ ConfigMgr::ConfigMgr(bool p_isUnitTest, QObject *p_parent) } else { locateConfigFolder(); - checkAppConfig(); + bool needUpdate = checkAppConfig(); + if (needUpdate) { + checkUserConfig(); + } } m_config->init(); @@ -134,7 +137,7 @@ void ConfigMgr::locateConfigFolder() qInfo() << "user config folder" << m_userConfigFolderPath; } -void ConfigMgr::checkAppConfig() +bool ConfigMgr::checkAppConfig() { bool needUpdate = false; QDir appConfigDir(m_appConfigFolderPath); @@ -212,7 +215,7 @@ void ConfigMgr::checkAppConfig() FileUtils::copyFile(getConfigFilePath(Source::Default), mainConfigFilePath); FileUtils::copyDir(extraDataRoot + QStringLiteral("/web"), appConfigDir.filePath(QStringLiteral("web"))); - return; + return needUpdate; } #else Q_ASSERT(needUpdate); @@ -251,6 +254,27 @@ void ConfigMgr::checkAppConfig() // Main config file. FileUtils::copyFile(getConfigFilePath(Source::Default), appConfigDir.filePath(c_configFileName)); + return needUpdate; +} + +void ConfigMgr::checkUserConfig() +{ + // Mainly check if the user config and session config is read-only. + const auto userFile = getConfigFilePath(Source::User); + if (QFileInfo::exists(userFile)) { + if (!(QFile::permissions(userFile) & QFile::WriteUser)) { + qDebug() << "make user config file writable" << userFile; + QFile::setPermissions(userFile, QFile::WriteUser); + } + } + + const auto sessionFile = getConfigFilePath(Source::Session); + if (QFileInfo::exists(sessionFile)) { + if (!(QFile::permissions(sessionFile) & QFile::WriteUser)) { + qDebug() << "make session config file writable" << sessionFile; + QFile::setPermissions(sessionFile, QFile::WriteUser); + } + } } QString ConfigMgr::getConfigFilePath(Source p_src) const @@ -419,6 +443,17 @@ QString ConfigMgr::getUserSnippetFolder() const return folderPath; } +QString ConfigMgr::getUserMarkdownUserStyleFile() const +{ + auto folderPath = PathUtils::concatenateFilePath(m_userConfigFolderPath, QStringLiteral("web/css")); + auto filePath = PathUtils::concatenateFilePath(folderPath, QStringLiteral("user.css")); + if (!QFileInfo::exists(filePath)) { + QDir().mkpath(folderPath); + FileUtils::writeFile(filePath, QByteArray()); + } + return filePath; +} + QString ConfigMgr::getUserOrAppFile(const QString &p_filePath) const { QFileInfo fi(p_filePath); diff --git a/src/core/configmgr.h b/src/core/configmgr.h index 5fa2fa6f..ad4595ba 100644 --- a/src/core/configmgr.h +++ b/src/core/configmgr.h @@ -93,6 +93,9 @@ namespace vnotex QString getUserSnippetFolder() const; + // web/css/user.css. + QString getUserMarkdownUserStyleFile() const; + // If @p_filePath is absolute, just return it. // Otherwise, first try to find it in user folder, then in app folder. QString getUserOrAppFile(const QString &p_filePath) const; @@ -135,7 +138,10 @@ namespace vnotex // Check if app config exists and is updated. // Update it if in need. - void checkAppConfig(); + // Return true if there is update. + bool checkAppConfig(); + + void checkUserConfig(); static QString getDefaultConfigFilePath(); diff --git a/src/core/fileopenparameters.h b/src/core/fileopenparameters.h index 9ecd6b20..37b0b9c6 100644 --- a/src/core/fileopenparameters.h +++ b/src/core/fileopenparameters.h @@ -1,6 +1,8 @@ #ifndef FILEOPENPARAMETERS_H #define FILEOPENPARAMETERS_H +#include + #include #include "global.h" @@ -12,6 +14,12 @@ namespace vnotex struct FileOpenParameters { + enum Hook + { + PostSave, + MaxHook + }; + ViewWindowMode m_mode = ViewWindowMode::Read; // Force to enter m_mode. @@ -41,6 +49,8 @@ namespace vnotex // Whether should save this file into session. bool m_sessionEnabled = true; + + std::function m_hooks[Hook::MaxHook]; }; } diff --git a/src/core/htmltemplatehelper.cpp b/src/core/htmltemplatehelper.cpp index 17d151d3..817af3b4 100644 --- a/src/core/htmltemplatehelper.cpp +++ b/src/core/htmltemplatehelper.cpp @@ -176,9 +176,9 @@ const QString &HtmlTemplateHelper::getMarkdownViewerTemplate() return s_markdownViewerTemplate.m_template; } -void HtmlTemplateHelper::updateMarkdownViewerTemplate(const MarkdownEditorConfig &p_config) +void HtmlTemplateHelper::updateMarkdownViewerTemplate(const MarkdownEditorConfig &p_config, bool p_force) { - if (p_config.revision() == s_markdownViewerTemplate.m_revision) { + if (!p_force && p_config.revision() == s_markdownViewerTemplate.m_revision) { return; } diff --git a/src/core/htmltemplatehelper.h b/src/core/htmltemplatehelper.h index dc9ee111..b785d2aa 100644 --- a/src/core/htmltemplatehelper.h +++ b/src/core/htmltemplatehelper.h @@ -85,7 +85,7 @@ namespace vnotex HtmlTemplateHelper() = delete; static const QString &getMarkdownViewerTemplate(); - static void updateMarkdownViewerTemplate(const MarkdownEditorConfig &p_config); + static void updateMarkdownViewerTemplate(const MarkdownEditorConfig &p_config, bool p_force = false); static QString generateMarkdownViewerTemplate(const MarkdownEditorConfig &p_config, const Paras &p_paras); diff --git a/src/core/mainconfig.cpp b/src/core/mainconfig.cpp index f21a7509..74fa8bf6 100644 --- a/src/core/mainconfig.cpp +++ b/src/core/mainconfig.cpp @@ -118,5 +118,5 @@ QString MainConfig::getVersion(const QJsonObject &p_jobj) void MainConfig::doVersionSpecificOverride() { // In a new version, we may want to change one value by force. - m_editorConfig->getMarkdownEditorConfig().m_spellCheckEnabled = false; + m_coreConfig->m_docksTabBarIconSize = 26; } diff --git a/src/data/core/vnotex.json b/src/data/core/vnotex.json index cd8ab0ee..64c75f5a 100644 --- a/src/data/core/vnotex.json +++ b/src/data/core/vnotex.json @@ -62,7 +62,7 @@ "OpenLastClosedFile" : "Ctrl+Shift+T" }, "toolbar_icon_size" : 16, - "docks_tabbar_icon_size" : 20, + "docks_tabbar_icon_size" : 26, "note_management" : { "external_node" : { "//comment" : "Wildcard patterns of files and folders to exclude as external files", @@ -152,6 +152,7 @@ "name" : "global_styles", "enabled" : true, "styles" : [ + "web/css/user.css", "web/css/globalstyles.css" ] }, diff --git a/src/data/extra/extra.qrc b/src/data/extra/extra.qrc index 5666b499..2f09ac0d 100644 --- a/src/data/extra/extra.qrc +++ b/src/data/extra/extra.qrc @@ -16,6 +16,7 @@ docs/zh_CN/features_tips.txt web/markdown-viewer-template.html web/markdown-export-template.html + web/css/user.css web/css/globalstyles.css web/css/markdownit.css web/css/imageviewer.css diff --git a/src/data/extra/themes/moonlight/highlight.css b/src/data/extra/themes/moonlight/highlight.css index f06ec2b8..e2f0363a 100644 --- a/src/data/extra/themes/moonlight/highlight.css +++ b/src/data/extra/themes/moonlight/highlight.css @@ -10,7 +10,6 @@ code[class*="language-"], pre[class*="language-"] { color: #ccc; background: none; - font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; font-size: 1em; text-align: left; white-space: pre; diff --git a/src/data/extra/themes/moonlight/interface.qss b/src/data/extra/themes/moonlight/interface.qss index 0dde0f51..3e827831 100644 --- a/src/data/extra/themes/moonlight/interface.qss +++ b/src/data/extra/themes/moonlight/interface.qss @@ -434,8 +434,10 @@ vnotex--DragDropAreaIndicator QLabel { } vnotex--MainWindow QLabel#MainWindowTipsLabel { - font-size: 18pt; + font-size: 20pt; font-weight: bold; + color: @widgets#mainwindow#tips_label#fg; + background-color: @widgets#mainwindow#tips_label#bg; } /* QLineEdit */ diff --git a/src/data/extra/themes/moonlight/palette.json b/src/data/extra/themes/moonlight/palette.json index a0092bc1..54dccc5e 100644 --- a/src/data/extra/themes/moonlight/palette.json +++ b/src/data/extra/themes/moonlight/palette.json @@ -642,6 +642,10 @@ "fg" : "@base#icon#selected#fg" } } + }, + "tips_label" : { + "fg" : "@base#master#fg", + "bg" : "@base#master#bg" } } } diff --git a/src/data/extra/themes/moonlight/text-editor.theme b/src/data/extra/themes/moonlight/text-editor.theme index 8b35631a..ea4ffb92 100644 --- a/src/data/extra/themes/moonlight/text-editor.theme +++ b/src/data/extra/themes/moonlight/text-editor.theme @@ -67,7 +67,7 @@ "markdown-editor-styles" : { "Text" : { "//comment" : "Support a list of fonts separated by ,", - "font-family" : "冬青黑体, YaHei Consolas Hybrid, Microsoft YaHei, 微软雅黑, Microsoft YaHei UI, WenQuanYi Micro Hei, 文泉驿雅黑, Dengxian, 等线体, STXihei, 华文细黑, Liberation Sans, Droid Sans, NSimSun, 新宋体, SimSun, 宋体, Verdana, Helvetica, sans-serif, Tahoma, Arial, Geneva, Georgia, Times New Roman", + "font-family" : "YaHei Consolas Hybrid, 冬青黑体, Microsoft YaHei, 微软雅黑, Microsoft YaHei UI, WenQuanYi Micro Hei, 文泉驿雅黑, Dengxian, 等线体, STXihei, 华文细黑, Liberation Sans, Droid Sans, NSimSun, 新宋体, SimSun, 宋体, Verdana, Helvetica, Tahoma, Arial, Geneva, Georgia, Times New Roman", "font-size" : 12, "text-color" : "#ccd1d8", "background-color" : "#333842", diff --git a/src/data/extra/themes/moonlight/web.css b/src/data/extra/themes/moonlight/web.css index 893e5432..83226fad 100644 --- a/src/data/extra/themes/moonlight/web.css +++ b/src/data/extra/themes/moonlight/web.css @@ -1,6 +1,6 @@ body { margin: 0 auto; - font-family: -apple-system, "Noto Sans", "Helvetica Neue", "Segoe UI", Helvetica, sans-serif, Tahoma, Arial, Geneva, Georgia, Palatino, "Times New Roman", "冬青黑体", "YaHei Consolas Hybrid", "Microsoft YaHei", "微软雅黑", "Microsoft YaHei UI", "WenQuanYi Micro Hei", "文泉驿雅黑", Dengxian, "等线体", STXihei, "华文细黑", "Liberation Sans", "Droid Sans", NSimSun, "新宋体", SimSun, "宋体", "Apple Color Emoji", "Segoe UI Emoji"; + font-family: "YaHei Consolas Hybrid", "Noto Sans", "Helvetica Neue", "Segoe UI", Helvetica, Tahoma, Arial, Geneva, Georgia, Palatino, "Times New Roman", "冬青黑体", "Microsoft YaHei", "微软雅黑", "Microsoft YaHei UI", "WenQuanYi Micro Hei", "文泉驿雅黑", Dengxian, "等线体", STXihei, "华文细黑", "Liberation Sans", "Droid Sans", NSimSun, "新宋体", SimSun, "宋体", "Apple Color Emoji", "Segoe UI Emoji"; color: #ccd1d8; line-height: 1.5; padding: 16px; @@ -95,7 +95,7 @@ pre { } code { - font-family: "YaHei Consolas Hybrid", Consolas, Monaco, Monospace, Courier; + font-family: "YaHei Consolas Hybrid", Consolas, Monaco, "Andale Mono", Monospace, "Courier New"; color: #98c379; word-break: break-word; } @@ -107,7 +107,7 @@ pre code { color: #98c379; background-color: #2d323b; line-height: 1.5; - font-family: "YaHei Consolas Hybrid", Consolas, Monaco, Monospace, Courier; + font-family: "YaHei Consolas Hybrid", Consolas, Monaco, "Andale Mono", Monospace, "Courier New"; white-space: pre; -moz-tab-size: 4; -o-tab-size: 4; diff --git a/src/data/extra/themes/native/highlight.css b/src/data/extra/themes/native/highlight.css index 78433a67..f0980dc8 100644 --- a/src/data/extra/themes/native/highlight.css +++ b/src/data/extra/themes/native/highlight.css @@ -11,7 +11,6 @@ pre[class*="language-"] { color: black; background: none; text-shadow: 0 1px white; - font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; font-size: 1em; text-align: left; white-space: pre; diff --git a/src/data/extra/themes/native/interface.qss b/src/data/extra/themes/native/interface.qss index cb47fda9..90a1711e 100644 --- a/src/data/extra/themes/native/interface.qss +++ b/src/data/extra/themes/native/interface.qss @@ -120,7 +120,7 @@ vnotex--DragDropAreaIndicator QLabel { } vnotex--MainWindow QLabel#MainWindowTipsLabel { - font-size: 18pt; + font-size: 20pt; font-weight: bold; } diff --git a/src/data/extra/themes/native/text-editor.theme b/src/data/extra/themes/native/text-editor.theme index 6c36fa76..088afb1a 100644 --- a/src/data/extra/themes/native/text-editor.theme +++ b/src/data/extra/themes/native/text-editor.theme @@ -63,7 +63,7 @@ "markdown-editor-styles" : { "Text" : { "//comment" : "Support a list of fonts separated by ,", - "font-family" : "冬青黑体, YaHei Consolas Hybrid, Microsoft YaHei, 微软雅黑, Microsoft YaHei UI, WenQuanYi Micro Hei, 文泉驿雅黑, Dengxian, 等线体, STXihei, 华文细黑, Liberation Sans, Droid Sans, NSimSun, 新宋体, SimSun, 宋体, Verdana, Helvetica, sans-serif, Tahoma, Arial, Geneva, Georgia, Times New Roman", + "font-family" : "YaHei Consolas Hybrid, 冬青黑体, Microsoft YaHei, 微软雅黑, Microsoft YaHei UI, WenQuanYi Micro Hei, 文泉驿雅黑, Dengxian, 等线体, STXihei, 华文细黑, Liberation Sans, Droid Sans, NSimSun, 新宋体, SimSun, 宋体, Verdana, Helvetica, Tahoma, Arial, Geneva, Georgia, Times New Roman", "font-size" : 12 } }, diff --git a/src/data/extra/themes/native/web.css b/src/data/extra/themes/native/web.css index 58e7efb6..b4bdce44 100644 --- a/src/data/extra/themes/native/web.css +++ b/src/data/extra/themes/native/web.css @@ -1,6 +1,6 @@ body { margin: 0 auto; - font-family: -apple-system, "Noto Sans", "Helvetica Neue", "Segoe UI", Helvetica, sans-serif, Tahoma, Arial, Geneva, Georgia, Palatino, "Times New Roman", "冬青黑体", "YaHei Consolas Hybrid", "Microsoft YaHei", "微软雅黑", "Microsoft YaHei UI", "WenQuanYi Micro Hei", "文泉驿雅黑", Dengxian, "等线体", STXihei, "华文细黑", "Liberation Sans", "Droid Sans", NSimSun, "新宋体", SimSun, "宋体", "Apple Color Emoji", "Segoe UI Emoji"; + font-family: "YaHei Consolas Hybrid", "Noto Sans", "Helvetica Neue", "Segoe UI", Helvetica, Tahoma, Arial, Geneva, Georgia, Palatino, "Times New Roman", "冬青黑体", "Microsoft YaHei", "微软雅黑", "Microsoft YaHei UI", "WenQuanYi Micro Hei", "文泉驿雅黑", Dengxian, "等线体", STXihei, "华文细黑", "Liberation Sans", "Droid Sans", NSimSun, "新宋体", SimSun, "宋体", "Apple Color Emoji", "Segoe UI Emoji"; color: #222222; line-height: 1.5; padding: 16px; @@ -90,7 +90,7 @@ pre { } code { - font-family: "YaHei Consolas Hybrid", Consolas, Monaco, Monospace, Courier; + font-family: "YaHei Consolas Hybrid", Consolas, Monaco, "Andale Mono", Monospace, "Courier New"; color: #8E24AA; word-break: break-word; } @@ -102,7 +102,7 @@ pre code { color: #222222; background-color: #E0E0E0; line-height: 1.5; - font-family: "YaHei Consolas Hybrid", Consolas, Monaco, Monospace, Courier; + font-family: "YaHei Consolas Hybrid", Consolas, Monaco, "Andale Mono", Monospace, "Courier New"; white-space: pre; -moz-tab-size: 4; -o-tab-size: 4; diff --git a/src/data/extra/themes/pure/highlight.css b/src/data/extra/themes/pure/highlight.css index 4d980eb1..2c1818fd 100644 --- a/src/data/extra/themes/pure/highlight.css +++ b/src/data/extra/themes/pure/highlight.css @@ -10,7 +10,6 @@ code[class*="language-"], pre[class*="language-"] { color: black; background: none; - font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; font-size: 1em; text-align: left; white-space: pre; diff --git a/src/data/extra/themes/pure/interface.qss b/src/data/extra/themes/pure/interface.qss index 0dde0f51..3e827831 100644 --- a/src/data/extra/themes/pure/interface.qss +++ b/src/data/extra/themes/pure/interface.qss @@ -434,8 +434,10 @@ vnotex--DragDropAreaIndicator QLabel { } vnotex--MainWindow QLabel#MainWindowTipsLabel { - font-size: 18pt; + font-size: 20pt; font-weight: bold; + color: @widgets#mainwindow#tips_label#fg; + background-color: @widgets#mainwindow#tips_label#bg; } /* QLineEdit */ diff --git a/src/data/extra/themes/pure/palette.json b/src/data/extra/themes/pure/palette.json index f520c551..f51d1214 100644 --- a/src/data/extra/themes/pure/palette.json +++ b/src/data/extra/themes/pure/palette.json @@ -638,6 +638,10 @@ "fg" : "@base#icon#selected#fg" } } + }, + "tips_label" : { + "fg" : "@base#master#fg", + "bg" : "@base#master#bg" } } } diff --git a/src/data/extra/themes/pure/text-editor.theme b/src/data/extra/themes/pure/text-editor.theme index 882282dd..405ec3bd 100644 --- a/src/data/extra/themes/pure/text-editor.theme +++ b/src/data/extra/themes/pure/text-editor.theme @@ -67,7 +67,7 @@ "markdown-editor-styles" : { "Text" : { "//comment" : "Support a list of fonts separated by ,", - "font-family" : "冬青黑体, YaHei Consolas Hybrid, Microsoft YaHei, 微软雅黑, Microsoft YaHei UI, WenQuanYi Micro Hei, 文泉驿雅黑, Dengxian, 等线体, STXihei, 华文细黑, Liberation Sans, Droid Sans, NSimSun, 新宋体, SimSun, 宋体, Verdana, Helvetica, sans-serif, Tahoma, Arial, Geneva, Georgia, Times New Roman", + "font-family" : "YaHei Consolas Hybrid, 冬青黑体, Microsoft YaHei, 微软雅黑, Microsoft YaHei UI, WenQuanYi Micro Hei, 文泉驿雅黑, Dengxian, 等线体, STXihei, 华文细黑, Liberation Sans, Droid Sans, NSimSun, 新宋体, SimSun, 宋体, Verdana, Helvetica, Tahoma, Arial, Geneva, Georgia, Times New Roman", "font-size" : 12, "text-color" : "#222222", "background-color" : "#f5f5f5", diff --git a/src/data/extra/themes/pure/web.css b/src/data/extra/themes/pure/web.css index c1e144cf..5b36368b 100644 --- a/src/data/extra/themes/pure/web.css +++ b/src/data/extra/themes/pure/web.css @@ -1,6 +1,6 @@ body { margin: 0 auto; - font-family: -apple-system, "Noto Sans", "Helvetica Neue", "Segoe UI", Helvetica, sans-serif, Tahoma, Arial, Geneva, Georgia, Palatino, "Times New Roman", "冬青黑体", "YaHei Consolas Hybrid", "Microsoft YaHei", "微软雅黑", "Microsoft YaHei UI", "WenQuanYi Micro Hei", "文泉驿雅黑", Dengxian, "等线体", STXihei, "华文细黑", "Liberation Sans", "Droid Sans", NSimSun, "新宋体", SimSun, "宋体", "Apple Color Emoji", "Segoe UI Emoji"; + font-family: "YaHei Consolas Hybrid", "Noto Sans", "Helvetica Neue", "Segoe UI", Helvetica, Tahoma, Arial, Geneva, Georgia, Palatino, "Times New Roman", "冬青黑体", "Microsoft YaHei", "微软雅黑", "Microsoft YaHei UI", "WenQuanYi Micro Hei", "文泉驿雅黑", Dengxian, "等线体", STXihei, "华文细黑", "Liberation Sans", "Droid Sans", NSimSun, "新宋体", SimSun, "宋体", "Apple Color Emoji", "Segoe UI Emoji"; color: #222222; line-height: 1.5; padding: 16px; @@ -90,7 +90,7 @@ pre { } code { - font-family: "YaHei Consolas Hybrid", Consolas, Monaco, Monospace, Courier; + font-family: "YaHei Consolas Hybrid", Consolas, Monaco, "Andale Mono", Monospace, "Courier New"; color: #8e24aa; word-break: break-word; } @@ -102,7 +102,7 @@ pre code { color: #222222; background-color: #e0e0e0; line-height: 1.5; - font-family: "YaHei Consolas Hybrid", Consolas, Monaco, Monospace, Courier; + font-family: "YaHei Consolas Hybrid", Consolas, Monaco, "Andale Mono", Monospace, "Courier New"; white-space: pre; -moz-tab-size: 4; -o-tab-size: 4; diff --git a/src/data/extra/web/css/user.css b/src/data/extra/web/css/user.css new file mode 100644 index 00000000..8d807779 --- /dev/null +++ b/src/data/extra/web/css/user.css @@ -0,0 +1,2 @@ +/* Styles here will be placed in the header of the HTML template as global embedded styles. */ +/* This file is to hold customized styles provided by user. */ diff --git a/src/widgets/mainwindow.cpp b/src/widgets/mainwindow.cpp index d39e29a7..c2d23428 100644 --- a/src/widgets/mainwindow.cpp +++ b/src/widgets/mainwindow.cpp @@ -377,6 +377,11 @@ void MainWindow::closeEvent(QCloseEvent *p_event) } if (isVisible()) { + // Avoid geometry corruption caused by fullscreen or minimized window. + const auto state = windowState(); + if (state & (Qt::WindowMinimized | Qt::WindowFullScreen)) { + showNormal(); + } saveStateAndGeometry(); } @@ -626,6 +631,15 @@ void MainWindow::updateDockWidgetTabBar() void MainWindow::exportNotes() { + if (m_exportDialog) { + MessageBoxHelper::notify(MessageBoxHelper::Information, + tr("There is one export dialog running. Please close it first."), + this); + m_exportDialog->activateWindow(); + m_exportDialog->show(); + return; + } + auto currentNotebook = m_notebookExplorer->currentNotebook().data(); auto viewWindow = m_viewArea->getCurrentViewWindow(); auto folderNode = m_notebookExplorer->currentExploredFolderNode(); @@ -636,17 +650,20 @@ void MainWindow::exportNotes() if (noteNode && !noteNode->hasContent()) { noteNode = nullptr; } - auto dialog = new ExportDialog(currentNotebook, - folderNode, - noteNode, - viewWindow ? viewWindow->getBuffer() : nullptr, - nullptr); - connect(dialog, &QDialog::finished, - this, [this, dialog]() { - dialog->deleteLater(); + + m_exportDialog = new ExportDialog(currentNotebook, + folderNode, + noteNode, + viewWindow ? viewWindow->getBuffer() : nullptr, + nullptr); + connect(m_exportDialog, &QDialog::finished, + this, [this]() { + m_exportDialog->deleteLater(); + m_exportDialog = nullptr; }); + // Let it be able to run at background. - dialog->show(); + m_exportDialog->show(); } void MainWindow::showTips(const QString &p_message, int p_timeoutMilliseconds) @@ -675,7 +692,7 @@ void MainWindow::setTipsAreaVisible(bool p_visible) int labelW = m_tipsLabel->width(); int labelH = m_tipsLabel->height(); int x = (width() - labelW) / 2; - int y = (height() - labelH) / 2; + int y = (height() - labelH) / 3; if (x < 0) { x = 0; } diff --git a/src/widgets/mainwindow.h b/src/widgets/mainwindow.h index b8539ae2..c5d706a4 100644 --- a/src/widgets/mainwindow.h +++ b/src/widgets/mainwindow.h @@ -26,6 +26,7 @@ namespace vnotex class SearchPanel; class SnippetPanel; class HistoryPanel; + class ExportDialog; enum { RESTART_EXIT_CODE = 1000 }; @@ -169,6 +170,14 @@ namespace vnotex HistoryPanel *m_historyPanel = nullptr; + ExportDialog *m_exportDialog = nullptr; + + QSystemTrayIcon *m_trayIcon = nullptr; + + QLabel *m_tipsLabel = nullptr; + + QTimer *m_tipsTimer = nullptr; + bool m_layoutReset = false; // -1: do not request to quit; @@ -177,12 +186,6 @@ namespace vnotex Qt::WindowStates m_windowOldState = Qt::WindowMinimized; - QSystemTrayIcon *m_trayIcon = nullptr; - - QLabel *m_tipsLabel = nullptr; - - QTimer *m_tipsTimer = nullptr; - QStringList m_visibleDocksBeforeExpand; }; } // ns vnotex diff --git a/src/widgets/notebookselector.cpp b/src/widgets/notebookselector.cpp index 9553d434..b9db9c24 100644 --- a/src/widgets/notebookselector.cpp +++ b/src/widgets/notebookselector.cpp @@ -35,6 +35,8 @@ void NotebookSelector::setNotebooks(const QVector> &p_n } updateGeometry(); + + m_notebooksInitialized = true; } void NotebookSelector::reloadNotebook(const Notebook *p_notebook) @@ -179,7 +181,8 @@ void NotebookSelector::clearNavigation() void NotebookSelector::mousePressEvent(QMouseEvent *p_event) { - if (count() == 0) { + // Only when notebooks are loaded and there is no notebook, we could prompt for new notebook. + if (m_notebooksInitialized && count() == 0) { emit newNotebookRequested(); return; } diff --git a/src/widgets/notebookselector.h b/src/widgets/notebookselector.h index 10b62b48..3c27b0e3 100644 --- a/src/widgets/notebookselector.h +++ b/src/widgets/notebookselector.h @@ -53,6 +53,8 @@ namespace vnotex int findNotebook(ID p_id) const; + bool m_notebooksInitialized = false; + QVector m_navigationIndexes; }; } // ns vnotex diff --git a/src/widgets/toolbarhelper.cpp b/src/widgets/toolbarhelper.cpp index 670c12a0..be3fa3e9 100644 --- a/src/widgets/toolbarhelper.cpp +++ b/src/widgets/toolbarhelper.cpp @@ -22,7 +22,10 @@ #include #include #include +#include +#include #include +#include #include "propertydefs.h" #include "dialogs/settings/settingsdialog.h" #include "dialogs/updater.h" @@ -390,38 +393,7 @@ QToolBar *ToolBarHelper::setupSettingsToolBar(MainWindow *p_win, QToolBar *p_too menu->addSeparator(); - menu->addAction(MainWindow::tr("Open User Configuration Folder"), - menu, - []() { - auto folderPath = ConfigMgr::getInst().getUserFolder(); - WidgetUtils::openUrlByDesktop(QUrl::fromLocalFile(folderPath)); - }); - - menu->addAction(MainWindow::tr("Open Default Configuration Folder"), - menu, - []() { - auto folderPath = ConfigMgr::getInst().getAppFolder(); - WidgetUtils::openUrlByDesktop(QUrl::fromLocalFile(folderPath)); - }); - - menu->addSeparator(); - - menu->addAction(MainWindow::tr("Edit User Configuration"), - menu, - []() { - auto file = ConfigMgr::getInst().getConfigFilePath(ConfigMgr::Source::User); - auto paras = QSharedPointer::create(); - emit VNoteX::getInst().openFileRequested(file, paras); - }); - - menu->addAction(MainWindow::tr("Open Default Configuration"), - menu, - []() { - auto file = ConfigMgr::getInst().getConfigFilePath(ConfigMgr::Source::App); - auto paras = QSharedPointer::create(); - paras->m_readOnly = true; - emit VNoteX::getInst().openFileRequested(file, paras); - }); + setupConfigurationMenu(menu); menu->addSeparator(); @@ -546,6 +518,51 @@ QToolBar *ToolBarHelper::setupSettingsToolBar(MainWindow *p_win, QToolBar *p_too return tb; } +void ToolBarHelper::setupConfigurationMenu(QMenu *p_menu) +{ + auto menu = p_menu->addMenu(MainWindow::tr("Configuration")); + + menu->addAction(MainWindow::tr("Edit User Configuration File"), + menu, + []() { + auto file = ConfigMgr::getInst().getConfigFilePath(ConfigMgr::Source::User); + auto paras = QSharedPointer::create(); + paras->m_sessionEnabled = false; + emit VNoteX::getInst().openFileRequested(file, paras); + }); + + menu->addAction(MainWindow::tr("Open User Configuration Folder"), + menu, + []() { + auto folderPath = ConfigMgr::getInst().getUserFolder(); + WidgetUtils::openUrlByDesktop(QUrl::fromLocalFile(folderPath)); + }); + + menu->addAction(MainWindow::tr("Open Default Configuration Folder"), + menu, + []() { + auto folderPath = ConfigMgr::getInst().getAppFolder(); + WidgetUtils::openUrlByDesktop(QUrl::fromLocalFile(folderPath)); + }); + + menu->addSeparator(); + + auto act = menu->addAction(MainWindow::tr("Edit Markdown User Styles"), + menu, + []() { + const auto file = ConfigMgr::getInst().getUserMarkdownUserStyleFile(); + auto paras = QSharedPointer::create(); + paras->m_sessionEnabled = false; + paras->m_hooks[FileOpenParameters::PostSave] = []() { + qDebug() << "post save"; + const auto &markdownConfig = ConfigMgr::getInst().getEditorConfig().getMarkdownEditorConfig(); + HtmlTemplateHelper::updateMarkdownViewerTemplate(markdownConfig, true); + }; + emit VNoteX::getInst().openFileRequested(file, paras); + }); + act->setStatusTip(MainWindow::tr("Edit the user styles of Markdown editor read mode")); +} + static const QString c_fgPalette = QStringLiteral("widgets#toolbar#icon#fg"); static const QString c_disabledPalette = QStringLiteral("widgets#toolbar#icon#disabled#fg"); static const QString c_dangerousPalette = QStringLiteral("widgets#toolbar#icon#danger#fg"); diff --git a/src/widgets/toolbarhelper.h b/src/widgets/toolbarhelper.h index aa4bf8b3..029ef383 100644 --- a/src/widgets/toolbarhelper.h +++ b/src/widgets/toolbarhelper.h @@ -36,6 +36,8 @@ namespace vnotex static QToolBar *setupSettingsToolBar(MainWindow *p_win, QToolBar *p_toolBar); static void updateQuickAccessMenu(QMenu *p_menu); + + static void setupConfigurationMenu(QMenu *p_menu); }; } // ns vnotex diff --git a/src/widgets/viewwindow.cpp b/src/widgets/viewwindow.cpp index 7a1c4701..03bef67e 100644 --- a/src/widgets/viewwindow.cpp +++ b/src/widgets/viewwindow.cpp @@ -16,7 +16,6 @@ #include #include -#include #include "toolbarhelper.h" #include "vnotex.h" #include @@ -140,10 +139,17 @@ void ViewWindow::handleBufferChanged(const QSharedPointer &p connect(buffer, &Buffer::attachmentChanged, this, &ViewWindow::attachmentChanged); + + connect(buffer, &Buffer::autoSaved, + this, [this]() { + executeHook(FileOpenParameters::PostSave); + }); } m_sessionEnabled = p_paras->m_sessionEnabled; + m_openParas = p_paras; + handleBufferChangedInternal(p_paras); emit bufferChanged(); @@ -887,9 +893,18 @@ bool ViewWindow::save(bool p_force) return false; } + executeHook(FileOpenParameters::PostSave); + return true; } +void ViewWindow::executeHook(FileOpenParameters::Hook p_hook) const +{ + if (m_openParas && m_openParas->m_hooks[p_hook]) { + m_openParas->m_hooks[p_hook](); + } +} + void ViewWindow::updateEditReadDiscardActionState(EditReadDiscardAction *p_act) { switch (getMode()) { diff --git a/src/widgets/viewwindow.h b/src/widgets/viewwindow.h index f289365b..7237739d 100644 --- a/src/widgets/viewwindow.h +++ b/src/widgets/viewwindow.h @@ -7,6 +7,7 @@ #include #include +#include #include "viewwindowtoolbarhelper.h" #include "viewwindowsession.h" @@ -20,7 +21,6 @@ class QActionGroup; namespace vnotex { class ViewSplit; - struct FileOpenParameters; class DragDropAreaIndicator; class DragDropAreaIndicatorInterface; class OutlineProvider; @@ -262,6 +262,8 @@ namespace vnotex // Managed by QObject. FindAndReplaceWidget *m_findAndReplace = nullptr; + QSharedPointer m_openParas; + private: struct FindInfo { @@ -314,6 +316,8 @@ namespace vnotex void updateImageHostMenu(); + void executeHook(FileOpenParameters::Hook p_hook) const; + static ViewWindow::TypeAction toolBarActionToTypeAction(ViewWindowToolBarHelper::Action p_action); Buffer *m_buffer = nullptr; @@ -324,6 +328,7 @@ namespace vnotex // Last find info. FindInfo m_findInfo; + // Whether this ViewWindow should be recored to session. bool m_sessionEnabled = true; // Null if this window has not been added to any split.