| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328 |
- #include <QSettings>
- #include <QDebug>
- #include <QJsonObject>
- #include <QJsonArray>
- #include <QDir>
- #include <QFont>
- #include <QFontMetrics>
- #include <QStringList>
- #include <QFontDatabase>
- #include "vnote.h"
- #include "utils/vutils.h"
- #include "vconfigmanager.h"
- #include "vorphanfile.h"
- #include "vnotefile.h"
- #include "vpalette.h"
- extern VConfigManager *g_config;
- extern VPalette *g_palette;
- // Meta word manager.
- VMetaWordManager *g_mwMgr;
- QString VNote::s_simpleHtmlTemplate;
- QString VNote::s_markdownTemplate;
- QString VNote::s_sloganTemplate = "<div class=\"typewriter\"><h3>Hi Markdown, I'm VNote</h3></div>";
- const QString VNote::c_hoedownJsFile = ":/resources/hoedown.js";
- const QString VNote::c_markedJsFile = ":/resources/marked.js";
- const QString VNote::c_markedExtraFile = ":/utils/marked/marked.min.js";
- const QString VNote::c_markdownitJsFile = ":/resources/markdown-it.js";
- const QString VNote::c_markdownitExtraFile = ":/utils/markdown-it/markdown-it.min.js";
- const QString VNote::c_markdownitAnchorExtraFile = ":/utils/markdown-it/markdown-it-headinganchor.js";
- const QString VNote::c_markdownitTaskListExtraFile = ":/utils/markdown-it/markdown-it-task-lists.min.js";
- const QString VNote::c_markdownitSubExtraFile = ":/utils/markdown-it/markdown-it-sub.min.js";
- const QString VNote::c_markdownitSupExtraFile = ":/utils/markdown-it/markdown-it-sup.min.js";
- const QString VNote::c_markdownitFootnoteExtraFile = ":/utils/markdown-it/markdown-it-footnote.min.js";
- const QString VNote::c_showdownJsFile = ":/resources/showdown.js";
- const QString VNote::c_showdownExtraFile = ":/utils/showdown/showdown.min.js";
- const QString VNote::c_showdownAnchorExtraFile = ":/utils/showdown/showdown-headinganchor.js";
- const QString VNote::c_mermaidApiJsFile = ":/utils/mermaid/mermaidAPI.min.js";
- const QString VNote::c_mermaidForestCssFile = ":/utils/mermaid/mermaid.forest.css";
- const QString VNote::c_flowchartJsFile = ":/utils/flowchart.js/flowchart.min.js";
- 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_docFileFolder = ":/resources/docs";
- const QString VNote::c_shortcutsDocFile = "shortcuts.md";
- const QString VNote::c_markdownGuideDocFile = "markdown_guide.md";
- VNote::VNote(QObject *parent)
- : QObject(parent)
- {
- initTemplate();
- g_config->getNotebooks(m_notebooks, this);
- m_metaWordMgr.init();
- g_mwMgr = &m_metaWordMgr;
- }
- 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());
- }
- QString VNote::generateHtmlTemplate(const QString &p_renderBg,
- const QString &p_renderStyleUrl,
- const QString &p_codeBlockStyleUrl,
- bool p_isPDF)
- {
- const QString c_markdownTemplatePath(":/resources/markdown_template.html");
- QString cssStyle;
- if (!p_renderBg.isEmpty()) {
- cssStyle += "body { background-color: " + p_renderBg + " !important; }\n";
- }
- if (g_config->getEnableImageConstraint()) {
- // Constain the image width.
- cssStyle += "img { max-width: 100% !important; height: auto !important; }\n";
- }
- const QString styleHolder("/* BACKGROUND_PLACE_HOLDER */");
- const QString cssHolder("CSS_PLACE_HOLDER");
- const QString codeBlockCssHolder("HIGHLIGHTJS_CSS_PLACE_HOLDER");
- QString templ = VUtils::readFileFromDisk(c_markdownTemplatePath);
- g_palette->fillStyle(templ);
- // Must replace the code block holder first.
- templ.replace(codeBlockCssHolder, p_codeBlockStyleUrl);
- templ.replace(cssHolder, p_renderStyleUrl);
- if (p_isPDF) {
- // Shoudl not display scrollbar in PDF.
- cssStyle += "pre { white-space: pre-wrap !important; "
- "word-break: break-all !important; }\n"
- "pre code { white-space: pre-wrap !important; "
- "word-break: break-all !important; }\n"
- "code { word-break: break-all !important; }\n";
- if (!g_config->getEnableImageConstraint()) {
- // Constain the image width by force in PDF, otherwise, the PDF will
- // be cut off.
- cssStyle += "img { max-width: 100% !important; height: auto !important; }\n";
- }
- }
- if (!cssStyle.isEmpty()) {
- templ.replace(styleHolder, cssStyle);
- }
- return templ;
- }
- QString VNote::generateExportHtmlTemplate(const QString &p_renderBg)
- {
- const QString c_exportTemplatePath(":/resources/export_template.html");
- QString cssStyle;
- if (!p_renderBg.isEmpty()) {
- cssStyle += "body { background-color: " + p_renderBg + " !important; }\n";
- }
- if (g_config->getEnableImageConstraint()) {
- // Constain the image width.
- cssStyle += "img { max-width: 100% !important; height: auto !important; }\n";
- }
- const QString styleHolder("/* BACKGROUND_PLACE_HOLDER */");
- QString templ = VUtils::readFileFromDisk(c_exportTemplatePath);
- g_palette->fillStyle(templ);
- if (!cssStyle.isEmpty()) {
- templ.replace(styleHolder, cssStyle);
- }
- return templ;
- }
- void VNote::updateTemplate()
- {
- QString renderBg = g_config->getRenderBackgroundColor(g_config->getCurRenderBackgroundColor());
- s_markdownTemplate = generateHtmlTemplate(renderBg,
- g_config->getCssStyleUrl(),
- g_config->getCodeBlockCssStyleUrl(),
- false);
- }
- const QVector<VNotebook *> &VNote::getNotebooks() const
- {
- return m_notebooks;
- }
- QVector<VNotebook *> &VNote::getNotebooks()
- {
- return m_notebooks;
- }
- QString VNote::getNavigationLabelStyle(const QString &p_str) const
- {
- static int lastLen = -1;
- static int pxWidth = 24;
- const int fontPt = 15;
- QString fontFamily = getMonospacedFont();
- if (p_str.size() != lastLen) {
- QFont font(fontFamily, fontPt);
- font.setBold(true);
- QFontMetrics fm(font);
- pxWidth = fm.width(p_str);
- lastLen = p_str.size();
- }
- QColor bg(g_palette->color("navigation_label_bg"));
- bg.setAlpha(200);
- return QString("background-color: %1;"
- "color: %2;"
- "font-size: %3pt;"
- "font: bold;"
- "font-family: %4;"
- "border-radius: 3px;"
- "min-width: %5px;"
- "max-width: %5px;")
- .arg(bg.name(QColor::HexArgb))
- .arg(g_palette->color("navigation_label_fg"))
- .arg(fontPt)
- .arg(fontFamily)
- .arg(pxWidth);
- }
- const QString &VNote::getMonospacedFont() const
- {
- static QString font;
- if (font.isNull()) {
- QStringList candidates;
- candidates << "Consolas" << "Monaco" << "Andale Mono" << "Monospace" << "Courier New";
- QStringList availFamilies = QFontDatabase().families();
- for (int i = 0; i < candidates.size(); ++i) {
- QString family = candidates[i].trimmed().toLower();
- for (int j = 0; j < availFamilies.size(); ++j) {
- QString availFamily = availFamilies[j];
- availFamily.remove(QRegExp("\\[.*\\]"));
- if (family == availFamily.trimmed().toLower()) {
- font = availFamily;
- return font;
- }
- }
- }
- // Fallback to current font.
- font = QFont().family();
- }
- return font;
- }
- VOrphanFile *VNote::getOrphanFile(const QString &p_path, bool p_modifiable, bool p_systemFile)
- {
- if (p_path.isEmpty()) {
- return NULL;
- }
- QString path = QDir::cleanPath(p_path);
- // See if the file has already been opened before.
- for (auto const &file : m_externalFiles) {
- if (VUtils::equalPath(QDir::cleanPath(file->fetchPath()), path)) {
- Q_ASSERT(file->isModifiable() == p_modifiable);
- Q_ASSERT(file->isSystemFile() == p_systemFile);
- return file;
- }
- }
- freeOrphanFiles();
- // Create a VOrphanFile for path.
- VOrphanFile *file = new VOrphanFile(this, path, p_modifiable, p_systemFile);
- m_externalFiles.append(file);
- return file;
- }
- VNoteFile *VNote::getInternalFile(const QString &p_path)
- {
- VNoteFile *file = NULL;
- for (auto & nb : m_notebooks) {
- file = nb->tryLoadFile(p_path);
- if (file) {
- break;
- }
- }
- return file;
- }
- VFile *VNote::getFile(const QString &p_path)
- {
- VFile *file = getInternalFile(p_path);
- if (!file) {
- QFileInfo fi(p_path);
- if (fi.isNativePath()) {
- file = getOrphanFile(p_path, true, false);
- } else {
- // File in Qt resource system.
- file = getOrphanFile(p_path, false, true);
- }
- }
- return file;
- }
- VDirectory *VNote::getInternalDirectory(const QString &p_path)
- {
- VDirectory *dir = NULL;
- for (auto & nb : m_notebooks) {
- dir = nb->tryLoadDirectory(p_path);
- if (dir) {
- break;
- }
- }
- return dir;
- }
- void VNote::freeOrphanFiles()
- {
- for (int i = 0; i < m_externalFiles.size();) {
- VOrphanFile *file = m_externalFiles[i];
- if (!file->isOpened()) {
- qDebug() << "release orphan file" << file;
- m_externalFiles.removeAt(i);
- delete file;
- } else {
- ++i;
- }
- }
- }
|