diff --git a/src/dialog/vtipsdialog.cpp b/src/dialog/vtipsdialog.cpp new file mode 100644 index 00000000..247c0db8 --- /dev/null +++ b/src/dialog/vtipsdialog.cpp @@ -0,0 +1,74 @@ +#include "vtipsdialog.h" + +#include +#include + +#include "vconfigmanager.h" +#include "vmarkdownconverter.h" +#include "utils/vutils.h" +#include "vnote.h" + +extern VConfigManager *g_config; + +VTipsDialog::VTipsDialog(const QString &p_tipFile, + const QString &p_actionText, + TipsDialogFunc p_action, + QWidget *p_parent) + : QDialog(p_parent), m_actionBtn(NULL), m_action(p_action) +{ + setupUI(p_actionText); + + readFile(p_tipFile); +} + +void VTipsDialog::setupUI(const QString &p_actionText) +{ + m_viewer = VUtils::getWebEngineView(); + + m_btnBox = new QDialogButtonBox(QDialogButtonBox::Ok); + connect(m_btnBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + + m_okBtn = m_btnBox->button(QDialogButtonBox::Ok); + + if (!p_actionText.isEmpty()) { + Q_ASSERT(m_action != nullptr); + m_actionBtn = m_btnBox->addButton(p_actionText, QDialogButtonBox::ActionRole); + m_actionBtn->setProperty("SpecialBtn", true); + m_actionBtn->setDefault(true); + + connect(m_actionBtn, &QPushButton::clicked, + this, [this]() { + m_action(); + }); + } + + QVBoxLayout *mainLayout = new QVBoxLayout(); + mainLayout->addWidget(m_viewer); + mainLayout->addWidget(m_btnBox); + + setLayout(mainLayout); + setWindowTitle(tr("VNote Tips")); +} + +void VTipsDialog::readFile(const QString &p_tipFile) +{ + QString content = VUtils::readFileFromDisk(p_tipFile); + VMarkdownConverter mdConverter; + QString toc; + QString html = mdConverter.generateHtml(content, + g_config->getMarkdownExtensions(), + toc); + html = VUtils::generateSimpleHtmlTemplate(html); + m_viewer->setHtml(html); +} + +void VTipsDialog::showEvent(QShowEvent *p_event) +{ + QDialog::showEvent(p_event); + + if (m_actionBtn) { + m_actionBtn->setFocus(); + } else { + m_okBtn->setFocus(); + } +} diff --git a/src/dialog/vtipsdialog.h b/src/dialog/vtipsdialog.h new file mode 100644 index 00000000..2c652e0c --- /dev/null +++ b/src/dialog/vtipsdialog.h @@ -0,0 +1,43 @@ +#ifndef VTIPSDIALOG_H +#define VTIPSDIALOG_H + +#include + +#include + +class QDialogButtonBox; +class QWebEngineView; +class QPushButton; +class QShowEvent; + +typedef std::function TipsDialogFunc; + +class VTipsDialog : public QDialog +{ + Q_OBJECT +public: + VTipsDialog(const QString &p_tipFile, + const QString &p_actionText = QString(), + TipsDialogFunc p_action = nullptr, + QWidget *p_parent = nullptr); + +protected: + void showEvent(QShowEvent *p_event) Q_DECL_OVERRIDE; + +private: + void setupUI(const QString &p_actionText); + + void readFile(const QString &p_tipFile); + + QWebEngineView *m_viewer; + + QDialogButtonBox *m_btnBox; + + QPushButton *m_actionBtn; + + QPushButton *m_okBtn; + + TipsDialogFunc m_action; +}; + +#endif // VTIPSDIALOG_H diff --git a/src/dialog/vupdater.cpp b/src/dialog/vupdater.cpp index 1518f3b8..c8369feb 100644 --- a/src/dialog/vupdater.cpp +++ b/src/dialog/vupdater.cpp @@ -4,9 +4,13 @@ #include #include #include +#include #include "vconfigmanager.h" #include "vdownloader.h" +#include "vmarkdownconverter.h" +#include "utils/vutils.h" +#include "vnote.h" extern VConfigManager *g_config; @@ -31,7 +35,8 @@ void VUpdater::setupUI() m_proBar = new QProgressBar(); m_proBar->setTextVisible(false); - m_descriptionTb = new QTextBrowser(); + m_descriptionWV = VUtils::getWebEngineView(); + m_descriptionWV->setHtml(VUtils::generateSimpleHtmlTemplate(VNote::s_sloganTemplate)); m_btnBox = new QDialogButtonBox(QDialogButtonBox::Ok); m_btnBox->button(QDialogButtonBox::Ok)->setProperty("SpecialBtn", true); @@ -47,15 +52,17 @@ void VUpdater::setupUI() QHBoxLayout *topLayout = new QHBoxLayout(); topLayout->addWidget(imgLabel); topLayout->addLayout(verLayout); + topLayout->addStretch(); - QVBoxLayout *mainLayout = new QVBoxLayout(this); + QVBoxLayout *mainLayout = new QVBoxLayout(); mainLayout->addLayout(topLayout); - mainLayout->addWidget(m_descriptionTb, 1); + mainLayout->addWidget(m_descriptionWV, 1); mainLayout->addWidget(m_btnBox); m_proLabel->hide(); m_proBar->hide(); - m_descriptionTb->hide(); + + m_descriptionWV->setMaximumSize(600, 400); setLayout(mainLayout); mainLayout->setSizeConstraint(QLayout::SetFixedSize); @@ -64,7 +71,6 @@ void VUpdater::setupUI() void VUpdater::showEvent(QShowEvent *p_event) { - Q_UNUSED(p_event); QDialog::showEvent(p_event); QTimer *timer = new QTimer(this); @@ -166,7 +172,13 @@ void VUpdater::parseResult(const QByteArray &p_data) m_proLabel->setText(tr("VNote is already the latest version.")); } - m_descriptionTb->setText(releaseName + "\n==========\n" + body); - m_descriptionTb->show(); + QString mdText = "# " + releaseName + "\n" + body; + VMarkdownConverter mdConverter; + QString toc; + QString html = mdConverter.generateHtml(mdText, + g_config->getMarkdownExtensions(), + toc); + html = VUtils::generateSimpleHtmlTemplate(html); + m_descriptionWV->setHtml(html); m_proBar->hide(); } diff --git a/src/dialog/vupdater.h b/src/dialog/vupdater.h index d6d4a816..dcff3bcc 100644 --- a/src/dialog/vupdater.h +++ b/src/dialog/vupdater.h @@ -6,7 +6,7 @@ class QLabel; class QDialogButtonBox; -class QTextBrowser; +class QWebEngineView; class QProgressBar; class QShowEvent; @@ -30,7 +30,7 @@ private: void checkUpdates(); QLabel *m_versionLabel; - QTextBrowser *m_descriptionTb; + QWebEngineView *m_descriptionWV; QDialogButtonBox *m_btnBox; // Progress label and bar. diff --git a/src/resources/docs/tips_add_style_en.md b/src/resources/docs/tips_add_style_en.md new file mode 100644 index 00000000..bce20209 --- /dev/null +++ b/src/resources/docs/tips_add_style_en.md @@ -0,0 +1,19 @@ +# VNote Styles +VNote supports custom styles for both edit and read modes. The best way to make a custom style is to download the default styles [here](https://github.com/tamlok/vnote/tree/master/src/resources/themes), rename them, put them in the style folder, and tune it to your taste. + +A restart is needed to detect a new style. A re-open of current tabs is needed to apply a new style. + +For detailed information about a style, please visit [VNote](https://github.com/tamlok/vnote). + +## Editor Style +An editor style is a file with suffix `.mdhl`. By default, it locates in subfolder `styles` in VNote's configuration folder. + +You could visit [Stylesheets from PEG Markdown Highlight](http://hasseg.org/peg-markdown-highlight/docs/stylesheet_syntax.html) for detailed syntax. + +## Read Mode Style +A read mode style is a file with suffix `.css`. By default, it locates in subfolder `styles` in VNote's configuration folder. + +### Code Block Style +A code block style is a file with suffix `.css`. By default, it locates in subfolder `styles/codeblock_styles` in VNote's configuration folder. + +You could visit [Highlight.js](https://github.com/isagalaev/highlight.js) for more styles. diff --git a/src/resources/docs/tips_add_style_zh.md b/src/resources/docs/tips_add_style_zh.md new file mode 100644 index 00000000..3ca8b456 --- /dev/null +++ b/src/resources/docs/tips_add_style_zh.md @@ -0,0 +1,19 @@ +# VNote样式 +VNote支持自定义编辑和阅读模式的样式。自定义样式最好的方法是下载默认的[样式](https://github.com/tamlok/vnote/tree/master/src/resources/themes),重命名,将这些文件放到样式文件夹下,并逐步修改调试。 + +VNote需要重新启动以检测新的样式。需要重新打开当前标签页以应用新的样式。 + +关于样式的更多信息,请访问 [VNote](https://github.com/tamlok/vnote) 。 + +## 编辑器样式 +一个编辑器样式是一个后缀名为`.mhdl`的文件。编辑器样式默认位于VNote的配置文件夹的子文件夹`styles`中。 + +关于样式的详细语法,请访问 [Stylesheets from PEG Markdown Highlight](http://hasseg.org/peg-markdown-highlight/docs/stylesheet_syntax.html) 。 + +## 阅读模式样式 +一个阅读模式样式是一个后缀名为`.css`的文件。阅读模式样式默认位于VNote的配置文件夹的子文件夹`styles`中。 + +### 代码块样式 +一个代码块样式是一个后缀名为`.css`的文件。代码块样式默认位于VNote的配置文件夹的子文件夹`styles/codeblock_styles`中。 + +请访问 [Highlight.js](https://github.com/isagalaev/highlight.js) 来获取更多的样式。 diff --git a/src/resources/docs/tips_add_theme_en.md b/src/resources/docs/tips_add_theme_en.md new file mode 100644 index 00000000..25afe6e6 --- /dev/null +++ b/src/resources/docs/tips_add_theme_en.md @@ -0,0 +1,6 @@ +# VNote Themes +VNote supports themes. A theme is a folder in the subfolder `themes` in VNote's configuration folder. The best way to make a custom theme is to download the default themes [here](https://github.com/tamlok/vnote/tree/master/src/resources/themes), rename related files, put them in the theme folder, and tune it to your taste. + +A restart is needed to detect or apply a new theme. + +For detailed information about a theme, please visit [VNote](https://github.com/tamlok/vnote). diff --git a/src/resources/docs/tips_add_theme_zh.md b/src/resources/docs/tips_add_theme_zh.md new file mode 100644 index 00000000..605ef0e2 --- /dev/null +++ b/src/resources/docs/tips_add_theme_zh.md @@ -0,0 +1,6 @@ +# VNote主题 +VNote支持主题。一个主题对应于VNote的配置文件夹的子文件夹`themes`下的一个文件夹。自定义主题最好的方法是下载默认的[主题](https://github.com/tamlok/vnote/tree/master/src/resources/themes),重命名相关文件,将该文件夹放到主题文件夹下,并逐步修改调试。 + +VNote需要重新启动以检测新的主题或应用一个主题。 + +关于主题的更多信息,请访问 [VNote](https://github.com/tamlok/vnote) 。 diff --git a/src/resources/docs/tips_custom_shortcut_en.md b/src/resources/docs/tips_custom_shortcut_en.md new file mode 100644 index 00000000..bc0f1920 --- /dev/null +++ b/src/resources/docs/tips_custom_shortcut_en.md @@ -0,0 +1,91 @@ +# Custom Shortcuts +VNote supports customing some standard shortcuts, though it is not recommended. VNote stores shortcuts' configuration information in the `[shortcuts]` and `[captain_mode_shortcuts]` sections of user configuration file `vnote.ini`. + +For example, the default configruation may look like this: + +```ini +[shortcuts] +; Define shortcuts here, with each item in the form "operation=keysequence". +; Leave keysequence empty to disable the shortcut of an operation. +; Custom shortcuts may conflict with some key bindings in edit mode or Vim mode. +; Ctrl+Q is reserved for quitting VNote. + +; Leader key of Captain mode +CaptainMode=Ctrl+E +; Create a note in current folder +NewNote=Ctrl+Alt+N +; Save current note +SaveNote=Ctrl+S +; Save changes and enter read mode +SaveAndRead=Ctrl+T +; Edit current note +EditNote=Ctrl+W +; Close current note +CloseNote= +; Open file/replace dialog +Find=Ctrl+F +; Find next occurence +FindNext=F3 +; Find previous occurence +FindPrevious=Shift+F3 + +[captain_mode_shortcuts] +; Define shortcuts in Captain mode here. +; There shortcuts are the sub-sequence after the CaptainMode key sequence +; in [shortcuts]. + +; Enter Navigation mode +NavigationMode=W +; Show attachment list of current note +AttachmentList=A +; Locate to the folder of current note +LocateCurrentFile=D +; Toggle Expand mode +ExpandMode=E +; Alternate one/two panels view +OnePanelView=P +; Discard changes and enter read mode +DiscardAndRead=Q +; Toggle Tools dock widget +ToolsDock=T +; Close current note +CloseNote=X +; Show shortcuts help document +ShortcutsHelp=? +; Flush the log file +FlushLogFile=";" +; Show opened files list +OpenedFileList=F +; Activate the ith tab +ActivateTab1=1 +ActivateTab2=2 +ActivateTab3=3 +ActivateTab4=4 +ActivateTab5=5 +ActivateTab6=6 +ActivateTab7=7 +ActivateTab8=8 +ActivateTab9=9 +; Alternate between current and last tab +AlternateTab=0 +; Activate next tab +ActivateNextTab=J +; Activate previous tab +ActivatePreviousTab=K +; Activate the window split on the left +ActivateSplitLeft=H +; Activate the window split on the right +ActivateSplitRight=L +; Move current tab one split left +MoveTabSplitLeft=Shift+H +; Move current tab one split right +MoveTabSplitRight=Shift+L +; Create a vertical split +VerticalSplit=V +; Remove current split +RemoveSplit=R +``` + +Each item is in the form `operation=keysequence`, with `keysequence` empty to disable shortcuts for that operation. + +Pay attention that `Ctrl+Q` is reserved for quitting VNote. diff --git a/src/resources/docs/tips_custom_shortcut_zh.md b/src/resources/docs/tips_custom_shortcut_zh.md new file mode 100644 index 00000000..8c379c5d --- /dev/null +++ b/src/resources/docs/tips_custom_shortcut_zh.md @@ -0,0 +1,93 @@ +# 自定义快捷键 +VNote支持自定义部分标准快捷键(但并不建议这么做)。VNote将快捷键信息保存在用户配置文件`vnote.ini`中的`[shortcuts]`和`[captain_mode_shortcuts]`两个小节。 + +例如,默认的配置可能是这样子的: + + +```ini +[shortcuts] +; Define shortcuts here, with each item in the form "operation=keysequence". +; Leave keysequence empty to disable the shortcut of an operation. +; Custom shortcuts may conflict with some key bindings in edit mode or Vim mode. +; Ctrl+Q is reserved for quitting VNote. + +; Leader key of Captain mode +CaptainMode=Ctrl+E +; Create a note in current folder +NewNote=Ctrl+Alt+N +; Save current note +SaveNote=Ctrl+S +; Save changes and enter read mode +SaveAndRead=Ctrl+T +; Edit current note +EditNote=Ctrl+W +; Close current note +CloseNote= +; Open file/replace dialog +Find=Ctrl+F +; Find next occurence +FindNext=F3 +; Find previous occurence +FindPrevious=Shift+F3 + +[captain_mode_shortcuts] +; Define shortcuts in Captain mode here. +; There shortcuts are the sub-sequence after the CaptainMode key sequence +; in [shortcuts]. + +; Enter Navigation mode +NavigationMode=W +; Show attachment list of current note +AttachmentList=A +; Locate to the folder of current note +LocateCurrentFile=D +; Toggle Expand mode +ExpandMode=E +; Alternate one/two panels view +OnePanelView=P +; Discard changes and enter read mode +DiscardAndRead=Q +; Toggle Tools dock widget +ToolsDock=T +; Close current note +CloseNote=X +; Show shortcuts help document +ShortcutsHelp=? +; Flush the log file +FlushLogFile=";" +; Show opened files list +OpenedFileList=F +; Activate the ith tab +ActivateTab1=1 +ActivateTab2=2 +ActivateTab3=3 +ActivateTab4=4 +ActivateTab5=5 +ActivateTab6=6 +ActivateTab7=7 +ActivateTab8=8 +ActivateTab9=9 +; Alternate between current and last tab +AlternateTab=0 +; Activate next tab +ActivateNextTab=J +; Activate previous tab +ActivatePreviousTab=K +; Activate the window split on the left +ActivateSplitLeft=H +; Activate the window split on the right +ActivateSplitRight=L +; Move current tab one split left +MoveTabSplitLeft=Shift+H +; Move current tab one split right +MoveTabSplitRight=Shift+L +; Create a vertical split +VerticalSplit=V +; Remove current split +RemoveSplit=R +``` + +每一项配置的形式为`操作=按键序列`。如果`按键序列`为空,则表示禁用该操作的快捷键。 + +注意,`Ctrl+Q`保留为退出VNote。 + diff --git a/src/resources/docs/tips_external_program_en.md b/src/resources/docs/tips_external_program_en.md new file mode 100644 index 00000000..040f6181 --- /dev/null +++ b/src/resources/docs/tips_external_program_en.md @@ -0,0 +1,18 @@ +# External Programs +VNote supports opening notes with external programs. VNote stores external programs' configuration information in the `[external_editors]` section of user configuration file `vnote.ini`. + +A sample configuration may look like this: + +```ini +[external_editors] +; Define external editors which could be called to edit notes +; One program per line with the format name="program %0 arg1 arg2" +; in which %0 will be replaced with the note file path +; Need to escape \ and ", use double quotes to quote paths/arguments with spaces + +GVim=C:\\\"Program Files (x86)\"\\Vim\\vim80\\gvim.exe %0 +Notepad=notepad %0 +Notepad%2B%2B=C:\\\"Program Files (x86)\"\\notepad++\\notepad++.exe %0 +``` + +A restart is needed to detect new external programs. diff --git a/src/resources/docs/tips_external_program_zh.md b/src/resources/docs/tips_external_program_zh.md new file mode 100644 index 00000000..32eeff93 --- /dev/null +++ b/src/resources/docs/tips_external_program_zh.md @@ -0,0 +1,18 @@ +# 外部程序 +VNote支持使用外部程序来打开笔记。VNote将外部程序的配置信息保存在用户配置文件`vnote.ini`的`[external_editors]`小节中。 + +一个配置可能如下: + +```ini +[external_editors] +; Define external editors which could be called to edit notes +; One program per line with the format name="program %0 arg1 arg2" +; in which %0 will be replaced with the note file path +; Need to escape \ and ", use double quotes to quote paths/arguments with spaces + +GVim=C:\\\"Program Files (x86)\"\\Vim\\vim80\\gvim.exe %0 +Notepad=notepad %0 +Notepad%2B%2B=C:\\\"Program Files (x86)\"\\notepad++\\notepad++.exe %0 +``` + +VNote需要重启以检测新的外部程序。 diff --git a/src/resources/icons/add_program.svg b/src/resources/icons/add_program.svg new file mode 100644 index 00000000..b9e8f00d --- /dev/null +++ b/src/resources/icons/add_program.svg @@ -0,0 +1,7 @@ + + + + + + diff --git a/src/resources/icons/add_style.svg b/src/resources/icons/add_style.svg new file mode 100644 index 00000000..b9e8f00d --- /dev/null +++ b/src/resources/icons/add_style.svg @@ -0,0 +1,7 @@ + + + + + + diff --git a/src/resources/simple_template.html b/src/resources/simple_template.html new file mode 100644 index 00000000..165cde37 --- /dev/null +++ b/src/resources/simple_template.html @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/resources/themes/v_moonlight/v_moonlight.css b/src/resources/themes/v_moonlight/v_moonlight.css index ec81d9c8..cbd9d548 100644 --- a/src/resources/themes/v_moonlight/v_moonlight.css +++ b/src/resources/themes/v_moonlight/v_moonlight.css @@ -90,9 +90,10 @@ code { } pre code { - margin: 0; - padding: 0; - border: none; + display: block; + overflow-x: auto; + padding: 0.5em; + border: 1px solid #373E47; color: #98C379; } diff --git a/src/resources/themes/v_pure/v_pure.css b/src/resources/themes/v_pure/v_pure.css index 336862e2..58d1a79f 100644 --- a/src/resources/themes/v_pure/v_pure.css +++ b/src/resources/themes/v_pure/v_pure.css @@ -90,9 +90,10 @@ code { } pre code { - margin: 0; - padding: 0; - border: none; + display: block; + overflow-x: auto; + padding: 0.5em; + border: 1px solid #D3D3D3; color: #363636; } diff --git a/src/resources/themes/v_white/v_white.css b/src/resources/themes/v_white/v_white.css index 2420870c..94194520 100644 --- a/src/resources/themes/v_white/v_white.css +++ b/src/resources/themes/v_white/v_white.css @@ -89,9 +89,10 @@ code { } pre code { - margin: 0; - padding: 0; - border: none; + display: block; + overflow-x: auto; + padding: 0.5em; + border: 1px solid #C0C0C0; color: #363636; } diff --git a/src/resources/typewriter.css b/src/resources/typewriter.css new file mode 100644 index 00000000..7f7de22c --- /dev/null +++ b/src/resources/typewriter.css @@ -0,0 +1,16 @@ +.typewriter h3 { + font-family: monospace; + padding: 4px 0px 4px 4px; + display: inline-block; + overflow: hidden; + border-right: 0.5em solid #00897B; + white-space: nowrap; + margin: 0 auto; + animation: + blink-caret 1s step-end infinite; +} + +@keyframes blink-caret { + from, to { border-color: transparent } + 50% { border-color: #00897B } +} diff --git a/src/src.pro b/src/src.pro index 1996e1fb..f7756163 100644 --- a/src/src.pro +++ b/src/src.pro @@ -102,7 +102,8 @@ SOURCES += main.cpp\ vpalette.cpp \ vbuttonmenuitem.cpp \ utils/viconutils.cpp \ - lineeditdelegate.cpp + lineeditdelegate.cpp \ + dialog/vtipsdialog.cpp HEADERS += vmainwindow.h \ vdirectorytree.h \ @@ -191,7 +192,8 @@ HEADERS += vmainwindow.h \ vpalette.h \ vbuttonmenuitem.h \ utils/viconutils.h \ - lineeditdelegate.h + lineeditdelegate.h \ + dialog/vtipsdialog.h RESOURCES += \ vnote.qrc \ diff --git a/src/utils/vutils.cpp b/src/utils/vutils.cpp index 9c934ba0..bacaa293 100644 --- a/src/utils/vutils.cpp +++ b/src/utils/vutils.cpp @@ -23,11 +23,13 @@ #include #include #include +#include #include "vorphanfile.h" #include "vnote.h" #include "vnotebook.h" #include "hgmarkdownhighlighter.h" +#include "vpreviewpage.h" extern VConfigManager *g_config; @@ -564,6 +566,7 @@ QString VUtils::getLocale() if (locale == "System" || !isValidLanguage(locale)) { locale = QLocale::system().name(); } + return locale; } @@ -598,6 +601,12 @@ DocType VUtils::docTypeFromName(const QString &p_name) return DocType::Unknown; } +QString VUtils::generateSimpleHtmlTemplate(const QString &p_body) +{ + QString html = VNote::s_simpleHtmlTemplate; + return html.replace(HtmlHolder::c_bodyHolder, p_body); +} + QString VUtils::generateHtmlTemplate(MarkdownConverterType p_conType, bool p_exportPdf) { QString jsFile, extraFile; @@ -684,9 +693,9 @@ QString VUtils::generateHtmlTemplate(MarkdownConverterType p_conType, bool p_exp htmlTemplate = VNote::s_markdownTemplate; } - htmlTemplate.replace(c_htmlJSHolder, jsFile); + htmlTemplate.replace(HtmlHolder::c_JSHolder, jsFile); if (!extraFile.isEmpty()) { - htmlTemplate.replace(c_htmlExtraHolder, extraFile); + htmlTemplate.replace(HtmlHolder::c_extraHolder, extraFile); } return htmlTemplate; @@ -1128,3 +1137,36 @@ void VUtils::setDynamicProperty(QWidget *p_widget, const char *p_prop, bool p_va p_widget->style()->unpolish(p_widget); p_widget->style()->polish(p_widget); } + +QWebEngineView *VUtils::getWebEngineView(QWidget *p_parent) +{ + QWebEngineView *viewer = new QWebEngineView(p_parent); + VPreviewPage *page = new VPreviewPage(viewer); + page->setBackgroundColor(Qt::transparent); + viewer->setPage(page); + viewer->setZoomFactor(g_config->getWebZoomFactor()); + + return viewer; +} + +QString VUtils::getFileNameWithLocale(const QString &p_name) +{ + QString locale = getLocale(); + locale = locale.split('_')[0]; + + QFileInfo fi(p_name); + QString baseName = fi.completeBaseName(); + QString suffix = fi.suffix(); + + if (suffix.isEmpty()) { + return QString("%1_%2").arg(baseName).arg(locale); + } else { + return QString("%1_%2.%3").arg(baseName).arg(locale).arg(suffix); + } +} + +QString VUtils::getDocFile(const QString &p_name) +{ + QDir dir(VNote::c_docFileFolder); + return dir.filePath(getFileNameWithLocale(p_name)); +} diff --git a/src/utils/vutils.h b/src/utils/vutils.h index bf998d94..19e5d016 100644 --- a/src/utils/vutils.h +++ b/src/utils/vutils.h @@ -17,6 +17,7 @@ class VOrphanFile; class VNotebook; class QWidget; class QComboBox; +class QWebEngineView; #if !defined(V_ASSERT) #define V_ASSERT(cond) ((!(cond)) ? qt_assert(#cond, __FILE__, __LINE__) : qt_noop()) @@ -171,6 +172,8 @@ public: // Generate HTML template. static QString generateHtmlTemplate(MarkdownConverterType p_conType, bool p_exportPdf); + static QString generateSimpleHtmlTemplate(const QString &p_body); + // Get an available file name in @p_directory with base @p_baseFileName. // If there already exists a file named @p_baseFileName, try to add sequence // suffix to the name, such as _001. @@ -273,8 +276,16 @@ public: // Create and return a QComboBox. static QComboBox *getComboBox(QWidget *p_parent = nullptr); + static QWebEngineView *getWebEngineView(QWidget *p_parent = nullptr); + static void setDynamicProperty(QWidget *p_widget, const char *p_prop, bool p_val = true); + // Return a file name with locale. + static QString getFileNameWithLocale(const QString &p_name); + + // Return a doc file path. + static QString getDocFile(const QString &p_name); + // Regular expression for image link. // ![image title]( http://github.com/tamlok/vnote.jpg "alt \" text" ) // Captured texts (need to be trimmed): diff --git a/src/vconstants.h b/src/vconstants.h index 26ca8ccf..76283e48 100644 --- a/src/vconstants.h +++ b/src/vconstants.h @@ -32,8 +32,12 @@ static const qreal c_webZoomFactorMin = 0.25; static const int c_tabSequenceBase = 1; // HTML and JS. -static const QString c_htmlJSHolder = "JS_PLACE_HOLDER"; -static const QString c_htmlExtraHolder = ""; +namespace HtmlHolder +{ + static const QString c_JSHolder = "JS_PLACE_HOLDER"; + static const QString c_extraHolder = ""; + static const QString c_bodyHolder = ""; +} // Directory Config file items. namespace DirConfig diff --git a/src/vfilelist.cpp b/src/vfilelist.cpp index 7970e4d0..e9c0e59d 100644 --- a/src/vfilelist.cpp +++ b/src/vfilelist.cpp @@ -17,6 +17,7 @@ #include "vmainwindow.h" #include "utils/vimnavigationforwidget.h" #include "utils/viconutils.h" +#include "dialog/vtipsdialog.h" extern VConfigManager *g_config; extern VNote *g_vnote; @@ -1000,6 +1001,29 @@ void VFileList::initOpenWithMenu() }); m_openWithMenu->addAction(defaultAct); + + QAction *addAct = new QAction(VIconUtils::menuIcon(":/resources/icons/add_program.svg"), + tr("Add External Program"), + this); + addAct->setToolTip(tr("Add external program")); + connect(addAct, &QAction::triggered, + this, [this]() { + VTipsDialog dialog(VUtils::getDocFile("tips_external_program.md"), + tr("Add External Program"), + []() { +#if defined(Q_OS_MACOS) || defined(Q_OS_MAC) + // On macOS, it seems that we could not open that ini file directly. + QUrl url = QUrl::fromLocalFile(g_config->getConfigFolder()); +#else + QUrl url = QUrl::fromLocalFile(g_config->getConfigFilePath()); +#endif + QDesktopServices::openUrl(url); + }, + this); + dialog.exec(); + }); + + m_openWithMenu->addAction(addAct); } void VFileList::handleOpenWithActionTriggered() diff --git a/src/vmainwindow.cpp b/src/vmainwindow.cpp index 72a667ee..d3611496 100644 --- a/src/vmainwindow.cpp +++ b/src/vmainwindow.cpp @@ -35,6 +35,7 @@ #include "vbuttonmenuitem.h" #include "vpalette.h" #include "utils/viconutils.h" +#include "dialog/vtipsdialog.h" VMainWindow *g_mainWin; @@ -706,13 +707,8 @@ void VMainWindow::initHelpMenu() mdGuideAct->setToolTip(tr("A quick guide of Markdown syntax")); connect(mdGuideAct, &QAction::triggered, this, [this](){ - QString locale = VUtils::getLocale(); - QString docName = VNote::c_markdownGuideDocFile_en; - if (locale == "zh_CN") { - docName = VNote::c_markdownGuideDocFile_zh; - } - - VFile *file = vnote->getOrphanFile(docName, false, true); + QString docFile = VUtils::getDocFile(VNote::c_markdownGuideDocFile); + VFile *file = vnote->getOrphanFile(docFile, false, true); editArea->openFile(file, OpenFileMode::Read); }); @@ -965,28 +961,7 @@ void VMainWindow::initFileMenu() QAction *customShortcutAct = new QAction(tr("Custom Shortcuts"), this); customShortcutAct->setToolTip(tr("Custom some standard shortcuts")); connect(customShortcutAct, &QAction::triggered, - this, [this](){ - int ret = VUtils::showMessage(QMessageBox::Information, - tr("Custom Shortcuts"), - tr("VNote supports customing some standard shorcuts by " - "editing user's configuration file (vnote.ini). Please " - "reference the shortcuts help documentation for more " - "information."), - tr("Click \"OK\" to custom shortcuts."), - QMessageBox::Ok | QMessageBox::Cancel, - QMessageBox::Ok, - this); - - if (ret == QMessageBox::Ok) { -#if defined(Q_OS_MACOS) || defined(Q_OS_MAC) - // On macOS, it seems that we could not open that ini file directly. - QUrl url = QUrl::fromLocalFile(g_config->getConfigFolder()); -#else - QUrl url = QUrl::fromLocalFile(g_config->getConfigFilePath()); -#endif - QDesktopServices::openUrl(url); - } - }); + this, &VMainWindow::customShortcut); fileMenu->addAction(customShortcutAct); @@ -1523,6 +1498,24 @@ void VMainWindow::initRenderStyleMenu(QMenu *p_menu) QMenu *styleMenu = p_menu->addMenu(tr("Rendering &Style")); styleMenu->setToolTipsVisible(true); + QAction *addAct = newAction(VIconUtils::menuIcon(":/resources/icons/add_style.svg"), + tr("Add Style"), + styleMenu); + addAct->setToolTip(tr("Add custom style of read mode")); + connect(addAct, &QAction::triggered, + this, [this]() { + VTipsDialog dialog(VUtils::getDocFile("tips_add_style.md"), + tr("Add Style"), + []() { + QUrl url = QUrl::fromLocalFile(g_config->getStyleConfigFolder()); + QDesktopServices::openUrl(url); + }, + this); + dialog.exec(); + }); + + styleMenu->addAction(addAct); + QActionGroup *ag = new QActionGroup(this); connect(ag, &QActionGroup::triggered, this, [this](QAction *p_action) { @@ -1558,6 +1551,24 @@ void VMainWindow::initCodeBlockStyleMenu(QMenu *p_menu) QMenu *styleMenu = p_menu->addMenu(tr("Code Block Style")); styleMenu->setToolTipsVisible(true); + QAction *addAct = newAction(VIconUtils::menuIcon(":/resources/icons/add_style.svg"), + tr("Add Style"), + styleMenu); + addAct->setToolTip(tr("Add custom style of code block in read mode")); + connect(addAct, &QAction::triggered, + this, [this]() { + VTipsDialog dialog(VUtils::getDocFile("tips_add_style.md"), + tr("Add Style"), + []() { + QUrl url = QUrl::fromLocalFile(g_config->getCodeBlockStyleConfigFolder()); + QDesktopServices::openUrl(url); + }, + this); + dialog.exec(); + }); + + styleMenu->addAction(addAct); + QActionGroup *ag = new QActionGroup(this); connect(ag, &QActionGroup::triggered, this, [this](QAction *p_action) { @@ -1684,6 +1695,24 @@ void VMainWindow::initEditorStyleMenu(QMenu *p_menu) QMenu *styleMenu = p_menu->addMenu(tr("Editor &Style")); styleMenu->setToolTipsVisible(true); + QAction *addAct = newAction(VIconUtils::menuIcon(":/resources/icons/add_style.svg"), + tr("Add Style"), + styleMenu); + addAct->setToolTip(tr("Add custom style of editor")); + connect(addAct, &QAction::triggered, + this, [this]() { + VTipsDialog dialog(VUtils::getDocFile("tips_add_style.md"), + tr("Add Style"), + []() { + QUrl url = QUrl::fromLocalFile(g_config->getStyleConfigFolder()); + QDesktopServices::openUrl(url); + }, + this); + dialog.exec(); + }); + + styleMenu->addAction(addAct); + QActionGroup *ag = new QActionGroup(this); connect(ag, &QActionGroup::triggered, this, [this](QAction *p_action) { @@ -2243,13 +2272,8 @@ void VMainWindow::enableImageCaption(bool p_checked) void VMainWindow::shortcutsHelp() { - QString locale = VUtils::getLocale(); - QString docName = VNote::c_shortcutsDocFile_en; - if (locale == "zh_CN") { - docName = VNote::c_shortcutsDocFile_zh; - } - - VFile *file = vnote->getOrphanFile(docName, false, true); + QString docFile = VUtils::getDocFile(VNote::c_shortcutsDocFile); + VFile *file = vnote->getOrphanFile(docFile, false, true); editArea->openFile(file, OpenFileMode::Read); } @@ -2717,6 +2741,24 @@ void VMainWindow::initThemeMenu(QMenu *p_menu) QMenu *themeMenu = p_menu->addMenu(tr("Theme")); themeMenu->setToolTipsVisible(true); + QAction *addAct = newAction(VIconUtils::menuIcon(":/resources/icons/add_style.svg"), + tr("Add Theme"), + themeMenu); + addAct->setToolTip(tr("Add custom theme")); + connect(addAct, &QAction::triggered, + this, [this]() { + VTipsDialog dialog(VUtils::getDocFile("tips_add_theme.md"), + tr("Add Theme"), + []() { + QUrl url = QUrl::fromLocalFile(g_config->getThemeConfigFolder()); + QDesktopServices::openUrl(url); + }, + this); + dialog.exec(); + }); + + themeMenu->addAction(addAct); + QActionGroup *ag = new QActionGroup(this); connect(ag, &QActionGroup::triggered, this, [this](QAction *p_action) { @@ -2744,3 +2786,20 @@ void VMainWindow::initThemeMenu(QMenu *p_menu) } } } + +void VMainWindow::customShortcut() +{ + VTipsDialog dialog(VUtils::getDocFile("tips_custom_shortcut.md"), + tr("Custom Shortcuts"), + []() { +#if defined(Q_OS_MACOS) || defined(Q_OS_MAC) + // On macOS, it seems that we could not open that ini file directly. + QUrl url = QUrl::fromLocalFile(g_config->getConfigFolder()); +#else + QUrl url = QUrl::fromLocalFile(g_config->getConfigFilePath()); +#endif + QDesktopServices::openUrl(url); + }, + this); + dialog.exec(); +} diff --git a/src/vmainwindow.h b/src/vmainwindow.h index d65ab430..eccc35a4 100644 --- a/src/vmainwindow.h +++ b/src/vmainwindow.h @@ -161,6 +161,8 @@ private slots: // Open flash page in edit mode. void openFlashPage(); + void customShortcut(); + protected: void closeEvent(QCloseEvent *event) Q_DECL_OVERRIDE; void resizeEvent(QResizeEvent *event) Q_DECL_OVERRIDE; diff --git a/src/vnote.cpp b/src/vnote.cpp index 62eb1847..3d7693f5 100644 --- a/src/vnote.cpp +++ b/src/vnote.cpp @@ -22,9 +22,14 @@ extern VPalette *g_palette; // Meta word manager. VMetaWordManager *g_mwMgr; +QString VNote::s_simpleHtmlTemplate; + QString VNote::s_markdownTemplate; + QString VNote::s_markdownTemplatePDF; +QString VNote::s_sloganTemplate = "

Hi Markdown, I'm VNote

"; + const QString VNote::c_hoedownJsFile = ":/resources/hoedown.js"; const QString VNote::c_markedJsFile = ":/resources/marked.js"; @@ -52,11 +57,11 @@ const QString VNote::c_raphaelJsFile = ":/utils/flowchart.js/raphael.min.js"; const QString VNote::c_highlightjsLineNumberExtraFile = ":/utils/highlightjs/highlightjs-line-numbers.min.js"; -const QString VNote::c_shortcutsDocFile_en = ":/resources/docs/shortcuts_en.md"; -const QString VNote::c_shortcutsDocFile_zh = ":/resources/docs/shortcuts_zh.md"; +const QString VNote::c_docFileFolder = ":/resources/docs"; -const QString VNote::c_markdownGuideDocFile_en = ":/resources/docs/markdown_guide_en.md"; -const QString VNote::c_markdownGuideDocFile_zh = ":/resources/docs/markdown_guide_zh.md"; +const QString VNote::c_shortcutsDocFile = "shortcuts.md"; + +const QString VNote::c_markdownGuideDocFile = "markdown_guide.md"; VNote::VNote(QObject *parent) : QObject(parent) @@ -73,10 +78,24 @@ VNote::VNote(QObject *parent) void VNote::initTemplate() { if (s_markdownTemplate.isEmpty()) { + updateSimpletHtmlTemplate(); + updateTemplate(); } } +void VNote::updateSimpletHtmlTemplate() +{ + const QString c_simpleHtmlTemplatePath(":/resources/simple_template.html"); + + const QString cssHolder("CSS_PLACE_HOLDER"); + + s_simpleHtmlTemplate = VUtils::readFileFromDisk(c_simpleHtmlTemplatePath); + g_palette->fillStyle(s_simpleHtmlTemplate); + + s_simpleHtmlTemplate.replace(cssHolder, g_config->getCssStyleUrl()); +} + void VNote::updateTemplate() { const QString c_markdownTemplatePath(":/resources/markdown_template.html"); diff --git a/src/vnote.h b/src/vnote.h index b3a4d890..5be9d5e6 100644 --- a/src/vnote.h +++ b/src/vnote.h @@ -29,7 +29,12 @@ public: void initTemplate(); + static QString s_sloganTemplate; + + static QString s_simpleHtmlTemplate; + static QString s_markdownTemplate; + static QString s_markdownTemplatePDF; // Hoedown @@ -66,11 +71,11 @@ public: // Highlight.js line number plugin static const QString c_highlightjsLineNumberExtraFile; - static const QString c_shortcutsDocFile_en; - static const QString c_shortcutsDocFile_zh; + static const QString c_docFileFolder; - static const QString c_markdownGuideDocFile_en; - static const QString c_markdownGuideDocFile_zh; + static const QString c_shortcutsDocFile; + + static const QString c_markdownGuideDocFile; // Get the label style in Navigation mode. QString getNavigationLabelStyle(const QString &p_str) const; @@ -97,6 +102,8 @@ public: public slots: void updateTemplate(); + void updateSimpletHtmlTemplate(); + private: const QString &getMonospacedFont() const; diff --git a/src/vnote.qrc b/src/vnote.qrc index 67dd17c5..caa331dd 100644 --- a/src/vnote.qrc +++ b/src/vnote.qrc @@ -218,5 +218,17 @@ resources/themes/v_moonlight/v_moonlight.palette resources/themes/v_moonlight/v_moonlight.qss resources/themes/v_moonlight/v_moonlight_codeblock.css + resources/simple_template.html + resources/typewriter.css + resources/docs/tips_custom_shortcut_en.md + resources/docs/tips_custom_shortcut_zh.md + resources/icons/add_style.svg + resources/docs/tips_add_theme_en.md + resources/docs/tips_add_theme_zh.md + resources/docs/tips_add_style_en.md + resources/docs/tips_add_style_zh.md + resources/icons/add_program.svg + resources/docs/tips_external_program_en.md + resources/docs/tips_external_program_zh.md