vconfigmanager.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920
  1. #include "vconfigmanager.h"
  2. #include <QDir>
  3. #include <QFile>
  4. #include <QString>
  5. #include <QJsonArray>
  6. #include <QJsonObject>
  7. #include <QJsonDocument>
  8. #include <QtDebug>
  9. #include <QTextEdit>
  10. #include <QStandardPaths>
  11. #include "utils/vutils.h"
  12. #include "vstyleparser.h"
  13. const QString VConfigManager::orgName = QString("vnote");
  14. const QString VConfigManager::appName = QString("vnote");
  15. const QString VConfigManager::c_version = QString("1.8");
  16. const QString VConfigManager::c_obsoleteDirConfigFile = QString(".vnote.json");
  17. const QString VConfigManager::c_dirConfigFile = QString("_vnote.json");
  18. const QString VConfigManager::defaultConfigFilePath = QString(":/resources/vnote.ini");
  19. const QString VConfigManager::c_styleConfigFolder = QString("styles");
  20. const QString VConfigManager::c_defaultCssFile = QString(":/resources/styles/default.css");
  21. const QString VConfigManager::c_defaultMdhlFile = QString(":/resources/styles/default.mdhl");
  22. const QString VConfigManager::c_solarizedDarkMdhlFile = QString(":/resources/styles/solarized-dark.mdhl");
  23. const QString VConfigManager::c_solarizedLightMdhlFile = QString(":/resources/styles/solarized-light.mdhl");
  24. const QString VConfigManager::c_warningTextStyle = QString("color: red; font: bold");
  25. const QString VConfigManager::c_dataTextStyle = QString("font: bold");
  26. const QString VConfigManager::c_dangerBtnStyle = QString("QPushButton {color: #fff; border-color: #d43f3a; background-color: #d9534f;}"
  27. "QPushButton::hover {color: #fff; border-color: #ac2925; background-color: #c9302c;}");
  28. const QString VConfigManager::c_vnoteNotebookFolderName = QString("vnote_notebooks");
  29. VConfigManager::VConfigManager(QObject *p_parent)
  30. : QObject(p_parent), userSettings(NULL), defaultSettings(NULL)
  31. {
  32. }
  33. void VConfigManager::migrateIniFile()
  34. {
  35. const QString originalFolder = "tamlok";
  36. const QString newFolder = orgName;
  37. QString configFolder = getConfigFolder();
  38. QDir dir(configFolder);
  39. dir.cdUp();
  40. dir.rename(originalFolder, newFolder);
  41. userSettings->sync();
  42. }
  43. void VConfigManager::initialize()
  44. {
  45. Q_ASSERT(!userSettings && !defaultSettings);
  46. userSettings = new QSettings(QSettings::IniFormat, QSettings::UserScope,
  47. orgName, appName, this);
  48. defaultSettings = new QSettings(defaultConfigFilePath, QSettings::IniFormat, this);
  49. migrateIniFile();
  50. // Override the default css styles on start up.
  51. outputDefaultCssStyle();
  52. outputDefaultEditorStyle();
  53. m_defaultEditPalette = QTextEdit().palette();
  54. m_editorStyle = getConfigFromSettings("global", "editor_style").toString();
  55. welcomePagePath = getConfigFromSettings("global", "welcome_page_path").toString();
  56. m_templateCss = getConfigFromSettings("global", "template_css").toString();
  57. curNotebookIndex = getConfigFromSettings("global", "current_notebook").toInt();
  58. markdownExtensions = hoedown_extensions(HOEDOWN_EXT_TABLES | HOEDOWN_EXT_FENCED_CODE |
  59. HOEDOWN_EXT_HIGHLIGHT | HOEDOWN_EXT_AUTOLINK |
  60. HOEDOWN_EXT_QUOTE | HOEDOWN_EXT_MATH | HOEDOWN_EXT_MATH_EXPLICIT);
  61. mdConverterType = (MarkdownConverterType)getConfigFromSettings("global", "markdown_converter").toInt();
  62. tabStopWidth = getConfigFromSettings("global", "tab_stop_width").toInt();
  63. isExpandTab = getConfigFromSettings("global", "is_expand_tab").toBool();
  64. m_highlightCursorLine = getConfigFromSettings("global", "highlight_cursor_line").toBool();
  65. m_highlightSelectedWord = getConfigFromSettings("global", "highlight_selected_word").toBool();
  66. m_highlightSearchedWord = getConfigFromSettings("global", "highlight_searched_word").toBool();
  67. m_autoIndent = getConfigFromSettings("global", "auto_indent").toBool();
  68. m_autoList = getConfigFromSettings("global", "auto_list").toBool();
  69. readPredefinedColorsFromSettings();
  70. curBackgroundColor = getConfigFromSettings("global", "current_background_color").toString();
  71. updateEditStyle();
  72. curRenderBackgroundColor = getConfigFromSettings("global",
  73. "current_render_background_color").toString();
  74. m_toolsDockChecked = getConfigFromSettings("session", "tools_dock_checked").toBool();
  75. m_mainWindowGeometry = getConfigFromSettings("session", "main_window_geometry").toByteArray();
  76. m_mainWindowState = getConfigFromSettings("session", "main_window_state").toByteArray();
  77. m_mainSplitterState = getConfigFromSettings("session", "main_splitter_state").toByteArray();
  78. m_findCaseSensitive = getConfigFromSettings("global",
  79. "find_case_sensitive").toBool();
  80. m_findWholeWordOnly = getConfigFromSettings("global",
  81. "find_whole_word_only").toBool();
  82. m_findRegularExpression = getConfigFromSettings("global",
  83. "find_regular_expression").toBool();
  84. m_findIncrementalSearch = getConfigFromSettings("global",
  85. "find_incremental_search").toBool();
  86. m_language = getConfigFromSettings("global", "language").toString();
  87. m_enableMermaid = getConfigFromSettings("global", "enable_mermaid").toBool();
  88. m_enableFlowchart = getConfigFromSettings("global", "enable_flowchart").toBool();
  89. m_enableMathjax = getConfigFromSettings("global", "enable_mathjax").toBool();
  90. m_webZoomFactor = getConfigFromSettings("global", "web_zoom_factor").toReal();
  91. if (!isCustomWebZoomFactor()) {
  92. // Calculate the zoom factor based on DPI.
  93. m_webZoomFactor = VUtils::calculateScaleFactor();
  94. qDebug() << "set WebZoomFactor to" << m_webZoomFactor;
  95. }
  96. m_enableCodeBlockHighlight = getConfigFromSettings("global",
  97. "enable_code_block_highlight").toBool();
  98. m_enablePreviewImages = getConfigFromSettings("global",
  99. "enable_preview_images").toBool();
  100. m_enablePreviewImageConstraint = getConfigFromSettings("global",
  101. "enable_preview_image_constraint").toBool();
  102. m_enableImageConstraint = getConfigFromSettings("global",
  103. "enable_image_constraint").toBool();
  104. m_enableImageCaption = getConfigFromSettings("global",
  105. "enable_image_caption").toBool();
  106. m_imageFolder = getConfigFromSettings("global",
  107. "image_folder").toString();
  108. m_imageFolderExt = getConfigFromSettings("global",
  109. "external_image_folder").toString();
  110. m_attachmentFolder = getConfigFromSettings("global",
  111. "attachment_folder").toString();
  112. if (m_attachmentFolder.isEmpty()) {
  113. // Reset the default folder.
  114. m_attachmentFolder = resetDefaultConfig("global", "attachment_folder").toString();
  115. }
  116. m_enableTrailingSpaceHighlight = getConfigFromSettings("global",
  117. "enable_trailing_space_highlight").toBool();
  118. m_enableVimMode = getConfigFromSettings("global",
  119. "enable_vim_mode").toBool();
  120. m_enableSmartImInVimMode = getConfigFromSettings("global",
  121. "enable_smart_im_in_vim_mode").toBool();
  122. m_editorLineNumber = getConfigFromSettings("global",
  123. "editor_line_number").toInt();
  124. m_minimizeToSystemTray = getConfigFromSettings("global",
  125. "minimize_to_system_tray").toInt();
  126. if (m_minimizeToSystemTray > 1 || m_minimizeToSystemTray < -1) {
  127. setMinimizeToSystemTray(0);
  128. }
  129. readShortcutsFromSettings();
  130. initDocSuffixes();
  131. m_markdownHighlightInterval = getConfigFromSettings("global",
  132. "markdown_highlight_interval").toInt();
  133. m_lineDistanceHeight = getConfigFromSettings("global",
  134. "line_distance_height").toInt();
  135. m_insertTitleFromNoteName = getConfigFromSettings("global",
  136. "insert_title_from_note_name").toBool();
  137. int openMode = getConfigFromSettings("global",
  138. "note_open_mode").toInt();
  139. if (openMode == 1) {
  140. m_noteOpenMode = OpenFileMode::Edit;
  141. } else {
  142. m_noteOpenMode = OpenFileMode::Read;
  143. }
  144. m_enableHeadingSequence = getConfigFromSettings("global",
  145. "enable_heading_sequence").toBool();
  146. m_headingSequenceBaseLevel = getConfigFromSettings("global",
  147. "heading_sequence_base_level").toInt();
  148. m_colorColumn = getConfigFromSettings("global", "color_column").toInt();
  149. m_enableCodeBlockLineNumber = getConfigFromSettings("global",
  150. "enable_code_block_line_number").toBool();
  151. m_toolBarIconSize = getConfigFromSettings("global",
  152. "tool_bar_icon_size").toInt();
  153. m_markdownitOptHtml = getConfigFromSettings("global",
  154. "markdownit_opt_html").toBool();
  155. m_markdownitOptBreaks = getConfigFromSettings("global",
  156. "markdownit_opt_breaks").toBool();
  157. m_markdownitOptLinkify = getConfigFromSettings("global",
  158. "markdownit_opt_linkify").toBool();
  159. m_recycleBinFolder = getConfigFromSettings("global",
  160. "recycle_bin_folder").toString();
  161. m_recycleBinFolderExt = getConfigFromSettings("global",
  162. "external_recycle_bin_folder").toString();
  163. m_confirmImagesCleanUp = getConfigFromSettings("global",
  164. "confirm_images_clean_up").toBool();
  165. m_confirmReloadFolder = getConfigFromSettings("global",
  166. "confirm_reload_folder").toBool();
  167. m_mathjaxJavascript = getConfigFromSettings("web",
  168. "mathjax_javascript").toString();
  169. }
  170. void VConfigManager::readPredefinedColorsFromSettings()
  171. {
  172. predefinedColors.clear();
  173. int size = defaultSettings->beginReadArray("predefined_colors");
  174. for (int i = 0; i < size; ++i) {
  175. defaultSettings->setArrayIndex(i);
  176. VColor color;
  177. color.name = defaultSettings->value("name").toString();
  178. color.rgb = defaultSettings->value("rgb").toString();
  179. predefinedColors.append(color);
  180. }
  181. defaultSettings->endArray();
  182. qDebug() << "read" << predefinedColors.size()
  183. << "pre-defined colors from [predefined_colors] section";
  184. }
  185. void VConfigManager::readNotebookFromSettings(QVector<VNotebook *> &p_notebooks, QObject *parent)
  186. {
  187. Q_ASSERT(p_notebooks.isEmpty());
  188. int size = userSettings->beginReadArray("notebooks");
  189. for (int i = 0; i < size; ++i) {
  190. userSettings->setArrayIndex(i);
  191. QString name = userSettings->value("name").toString();
  192. QString path = userSettings->value("path").toString();
  193. VNotebook *notebook = new VNotebook(name, path, parent);
  194. notebook->readConfigNotebook();
  195. p_notebooks.append(notebook);
  196. }
  197. userSettings->endArray();
  198. qDebug() << "read" << p_notebooks.size()
  199. << "notebook items from [notebooks] section";
  200. }
  201. void VConfigManager::writeNotebookToSettings(const QVector<VNotebook *> &p_notebooks)
  202. {
  203. // Clear it first
  204. userSettings->beginGroup("notebooks");
  205. userSettings->remove("");
  206. userSettings->endGroup();
  207. userSettings->beginWriteArray("notebooks");
  208. for (int i = 0; i < p_notebooks.size(); ++i) {
  209. userSettings->setArrayIndex(i);
  210. const VNotebook &notebook = *p_notebooks[i];
  211. userSettings->setValue("name", notebook.getName());
  212. userSettings->setValue("path", notebook.getPath());
  213. }
  214. userSettings->endArray();
  215. qDebug() << "write" << p_notebooks.size()
  216. << "notebook items in [notebooks] section";
  217. }
  218. QVariant VConfigManager::getConfigFromSettings(const QString &section, const QString &key) const
  219. {
  220. QString fullKey = section + "/" + key;
  221. // First, look up the user-scoped config file
  222. QVariant value = userSettings->value(fullKey);
  223. if (!value.isNull()) {
  224. qDebug() << "user config:" << fullKey << value.toString();
  225. return value;
  226. }
  227. // Second, look up the default config file
  228. return getDefaultConfig(section, key);
  229. }
  230. void VConfigManager::setConfigToSettings(const QString &section, const QString &key, const QVariant &value)
  231. {
  232. // Set the user-scoped config file
  233. QString fullKey = section + "/" + key;
  234. userSettings->setValue(fullKey, value);
  235. qDebug() << "set user config:" << fullKey << value.toString();
  236. }
  237. QVariant VConfigManager::getDefaultConfig(const QString &p_section, const QString &p_key) const
  238. {
  239. QString fullKey = p_section + "/" + p_key;
  240. QVariant value = defaultSettings->value(fullKey);
  241. qDebug() << "default config:" << fullKey << value.toString();
  242. return value;
  243. }
  244. QVariant VConfigManager::resetDefaultConfig(const QString &p_section, const QString &p_key)
  245. {
  246. QVariant defaultValue = getDefaultConfig(p_section, p_key);
  247. setConfigToSettings(p_section, p_key, defaultValue);
  248. return defaultValue;
  249. }
  250. QString VConfigManager::fetchDirConfigFilePath(const QString &p_path)
  251. {
  252. QDir dir(p_path);
  253. QString fileName = c_dirConfigFile;
  254. if (dir.exists(c_obsoleteDirConfigFile)) {
  255. V_ASSERT(!dir.exists(c_dirConfigFile));
  256. if (!dir.rename(c_obsoleteDirConfigFile, c_dirConfigFile)) {
  257. fileName = c_obsoleteDirConfigFile;
  258. }
  259. qDebug() << "rename old directory config file:" << fileName;
  260. }
  261. QString filePath = QDir::cleanPath(dir.filePath(fileName));
  262. qDebug() << "use directory config file:" << filePath;
  263. return filePath;
  264. }
  265. QJsonObject VConfigManager::readDirectoryConfig(const QString &path)
  266. {
  267. QString configFile = fetchDirConfigFilePath(path);
  268. QFile config(configFile);
  269. if (!config.open(QIODevice::ReadOnly)) {
  270. qWarning() << "fail to read directory configuration file:"
  271. << configFile;
  272. return QJsonObject();
  273. }
  274. QByteArray configData = config.readAll();
  275. return QJsonDocument::fromJson(configData).object();
  276. }
  277. bool VConfigManager::directoryConfigExist(const QString &path)
  278. {
  279. return QFileInfo::exists(fetchDirConfigFilePath(path));
  280. }
  281. bool VConfigManager::writeDirectoryConfig(const QString &path, const QJsonObject &configJson)
  282. {
  283. QString configFile = fetchDirConfigFilePath(path);
  284. QFile config(configFile);
  285. if (!config.open(QIODevice::WriteOnly)) {
  286. qWarning() << "fail to open directory configuration file for write:"
  287. << configFile;
  288. return false;
  289. }
  290. QJsonDocument configDoc(configJson);
  291. config.write(configDoc.toJson());
  292. return true;
  293. }
  294. bool VConfigManager::deleteDirectoryConfig(const QString &path)
  295. {
  296. QString configFile = fetchDirConfigFilePath(path);
  297. QFile config(configFile);
  298. if (!config.remove()) {
  299. qWarning() << "fail to delete directory configuration file:"
  300. << configFile;
  301. return false;
  302. }
  303. qDebug() << "delete config file:" << configFile;
  304. return true;
  305. }
  306. QString VConfigManager::getLogFilePath()
  307. {
  308. static QString logPath;
  309. if (logPath.isEmpty()) {
  310. QString location = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
  311. V_ASSERT(!location.isEmpty());
  312. QDir dir(location);
  313. dir.mkdir("VNote");
  314. logPath = dir.filePath("VNote/vnote.log");
  315. }
  316. return logPath;
  317. }
  318. void VConfigManager::updateMarkdownEditStyle()
  319. {
  320. static const QString defaultCurrentLineBackground = "#C5CAE9";
  321. static const QString defaultVimNormalBg = "#BCBCBC";
  322. static const QString defaultVimInsertBg = "#C5CAE9";
  323. static const QString defaultVimVisualBg = "#90CAF9";
  324. static const QString defaultVimReplaceBg = "#F8BBD0";
  325. static const QString defaultTrailingSpaceBg = "#A8A8A8";
  326. static const QString defaultSelectedWordBg = "#DFDF00";
  327. static const QString defaultSearchedWordBg = "#81C784";
  328. static const QString defaultSearchedWordCursorBg = "#4DB6AC";
  329. static const QString defaultIncrementalSearchedWordBg = "#CE93D8";
  330. static const QString defaultLineNumberBg = "#BDBDBD";
  331. static const QString defaultLineNumberFg = "#424242";
  332. static const QString defaultColorColumnBg = "#DD0000";
  333. static const QString defaultColorColumnFg = "#FFFF00";
  334. // Read style file .mdhl
  335. QString file(getEditorStyleUrl());
  336. QString styleStr = VUtils::readFileFromDisk(file);
  337. if (styleStr.isEmpty()) {
  338. return;
  339. }
  340. mdEditPalette = baseEditPalette;
  341. mdEditFont = baseEditFont;
  342. VStyleParser parser;
  343. parser.parseMarkdownStyle(styleStr);
  344. QMap<QString, QMap<QString, QString>> styles;
  345. parser.fetchMarkdownEditorStyles(mdEditPalette, mdEditFont, styles);
  346. mdHighlightingStyles = parser.fetchMarkdownStyles(mdEditFont);
  347. m_codeBlockStyles = parser.fetchCodeBlockStyles(mdEditFont);
  348. m_editorCurrentLineBg = defaultCurrentLineBackground;
  349. m_editorVimInsertBg = defaultVimInsertBg;
  350. m_editorVimNormalBg = defaultVimNormalBg;
  351. m_editorVimVisualBg = defaultVimVisualBg;
  352. m_editorVimReplaceBg = defaultVimReplaceBg;
  353. auto editorCurrentLineIt = styles.find("editor-current-line");
  354. if (editorCurrentLineIt != styles.end()) {
  355. auto backgroundIt = editorCurrentLineIt->find("background");
  356. if (backgroundIt != editorCurrentLineIt->end()) {
  357. // Do not need to add "#" here, since this is a built-in attribute.
  358. m_editorCurrentLineBg = *backgroundIt;
  359. }
  360. auto vimBgIt = editorCurrentLineIt->find("vim-insert-background");
  361. if (vimBgIt != editorCurrentLineIt->end()) {
  362. m_editorVimInsertBg = "#" + *vimBgIt;
  363. }
  364. vimBgIt = editorCurrentLineIt->find("vim-normal-background");
  365. if (vimBgIt != editorCurrentLineIt->end()) {
  366. m_editorVimNormalBg = "#" + *vimBgIt;
  367. }
  368. vimBgIt = editorCurrentLineIt->find("vim-visual-background");
  369. if (vimBgIt != editorCurrentLineIt->end()) {
  370. m_editorVimVisualBg = "#" + *vimBgIt;
  371. }
  372. vimBgIt = editorCurrentLineIt->find("vim-replace-background");
  373. if (vimBgIt != editorCurrentLineIt->end()) {
  374. m_editorVimReplaceBg = "#" + *vimBgIt;
  375. }
  376. }
  377. m_editorTrailingSpaceBg = defaultTrailingSpaceBg;
  378. m_editorSelectedWordBg = defaultSelectedWordBg;
  379. m_editorSearchedWordBg = defaultSearchedWordBg;
  380. m_editorSearchedWordCursorBg = defaultSearchedWordCursorBg;
  381. m_editorIncrementalSearchedWordBg = defaultIncrementalSearchedWordBg;
  382. m_editorLineNumberBg = defaultLineNumberBg;
  383. m_editorLineNumberFg = defaultLineNumberFg;
  384. m_editorColorColumnBg = defaultColorColumnBg;
  385. m_editorColorColumnFg = defaultColorColumnFg;
  386. auto editorIt = styles.find("editor");
  387. if (editorIt != styles.end()) {
  388. auto it = editorIt->find("trailing-space");
  389. if (it != editorIt->end()) {
  390. m_editorTrailingSpaceBg = "#" + *it;
  391. }
  392. it = editorIt->find("line-number-background");
  393. if (it != editorIt->end()) {
  394. m_editorLineNumberBg = "#" + *it;
  395. }
  396. it = editorIt->find("line-number-foreground");
  397. if (it != editorIt->end()) {
  398. m_editorLineNumberFg = "#" + *it;
  399. }
  400. it = editorIt->find("selected-word-background");
  401. if (it != editorIt->end()) {
  402. m_editorSelectedWordBg = "#" + *it;
  403. }
  404. it = editorIt->find("searched-word-background");
  405. if (it != editorIt->end()) {
  406. m_editorSearchedWordBg = "#" + *it;
  407. }
  408. it = editorIt->find("searched-word-cursor-background");
  409. if (it != editorIt->end()) {
  410. m_editorSearchedWordCursorBg = "#" + *it;
  411. }
  412. it = editorIt->find("incremental-searched-word-background");
  413. if (it != editorIt->end()) {
  414. m_editorIncrementalSearchedWordBg = "#" + *it;
  415. }
  416. it = editorIt->find("color-column-background");
  417. if (it != editorIt->end()) {
  418. m_editorColorColumnBg = "#" + *it;
  419. }
  420. it = editorIt->find("color-column-foreground");
  421. if (it != editorIt->end()) {
  422. m_editorColorColumnFg = "#" + *it;
  423. }
  424. }
  425. }
  426. void VConfigManager::updateEditStyle()
  427. {
  428. // Reset font and palette.
  429. baseEditFont = mdEditFont = m_defaultEditFont;
  430. baseEditPalette = mdEditPalette = m_defaultEditPalette;
  431. static const QColor defaultColor = m_defaultEditPalette.color(QPalette::Base);
  432. QColor newColor = defaultColor;
  433. bool force = false;
  434. if (curBackgroundColor != "System") {
  435. for (int i = 0; i < predefinedColors.size(); ++i) {
  436. if (predefinedColors[i].name == curBackgroundColor) {
  437. QString rgb = predefinedColors[i].rgb;
  438. if (!rgb.isEmpty()) {
  439. newColor = QColor(VUtils::QRgbFromString(rgb));
  440. force = true;
  441. }
  442. break;
  443. }
  444. }
  445. }
  446. baseEditPalette.setColor(QPalette::Base, newColor);
  447. // Update markdown editor palette
  448. updateMarkdownEditStyle();
  449. // Base editor will use the same font size as the markdown editor by now.
  450. if (mdEditFont.pointSize() > -1) {
  451. baseEditFont.setPointSize(mdEditFont.pointSize());
  452. }
  453. if (force) {
  454. mdEditPalette.setColor(QPalette::Base, newColor);
  455. }
  456. }
  457. void VConfigManager::setWebZoomFactor(qreal p_factor)
  458. {
  459. if (isCustomWebZoomFactor()) {
  460. if (VUtils::realEqual(m_webZoomFactor, p_factor)) {
  461. return;
  462. } else if (VUtils::realEqual(p_factor, -1)) {
  463. m_webZoomFactor = VUtils::calculateScaleFactor();
  464. setConfigToSettings("global", "web_zoom_factor", -1);
  465. return;
  466. }
  467. } else {
  468. if (VUtils::realEqual(p_factor, -1)) {
  469. return;
  470. }
  471. }
  472. m_webZoomFactor = p_factor;
  473. setConfigToSettings("global", "web_zoom_factor", m_webZoomFactor);
  474. }
  475. QString VConfigManager::getConfigFolder() const
  476. {
  477. V_ASSERT(userSettings);
  478. QString iniPath = userSettings->fileName();
  479. return VUtils::basePathFromPath(iniPath);
  480. }
  481. QString VConfigManager::getConfigFilePath() const
  482. {
  483. V_ASSERT(userSettings);
  484. return userSettings->fileName();
  485. }
  486. QString VConfigManager::getStyleConfigFolder() const
  487. {
  488. return getConfigFolder() + QDir::separator() + c_styleConfigFolder;
  489. }
  490. QVector<QString> VConfigManager::getCssStyles() const
  491. {
  492. QVector<QString> res;
  493. QDir dir(getStyleConfigFolder());
  494. if (!dir.exists()) {
  495. // Output pre-defined css styles to this folder.
  496. outputDefaultCssStyle();
  497. }
  498. // Get all the .css files in the folder.
  499. dir.setFilter(QDir::Files | QDir::NoSymLinks);
  500. dir.setNameFilters(QStringList("*.css"));
  501. QStringList files = dir.entryList();
  502. res.reserve(files.size());
  503. for (auto const &item : files) {
  504. res.push_back(item.left(item.size() - 4));
  505. }
  506. return res;
  507. }
  508. QVector<QString> VConfigManager::getEditorStyles() const
  509. {
  510. QVector<QString> res;
  511. QDir dir(getStyleConfigFolder());
  512. if (!dir.exists()) {
  513. // Output pre-defined mdhl styles to this folder.
  514. outputDefaultEditorStyle();
  515. }
  516. // Get all the .mdhl files in the folder.
  517. dir.setFilter(QDir::Files | QDir::NoSymLinks);
  518. dir.setNameFilters(QStringList("*.mdhl"));
  519. QStringList files = dir.entryList();
  520. res.reserve(files.size());
  521. for (auto const &item : files) {
  522. res.push_back(item.left(item.size() - 5));
  523. }
  524. return res;
  525. }
  526. bool VConfigManager::outputDefaultCssStyle() const
  527. {
  528. // Make sure the styles folder exists.
  529. QDir dir(getConfigFolder());
  530. if (!dir.exists(c_styleConfigFolder)) {
  531. if (!dir.mkdir(c_styleConfigFolder)) {
  532. return false;
  533. }
  534. }
  535. QString srcPath = c_defaultCssFile;
  536. QString destPath = getStyleConfigFolder() + QDir::separator() + QFileInfo(srcPath).fileName();
  537. if (QFileInfo::exists(destPath)) {
  538. QString bakPath = destPath + ".bak";
  539. // We only keep one bak file.
  540. if (!QFileInfo::exists(bakPath)) {
  541. QFile::rename(destPath, bakPath);
  542. } else {
  543. // Just delete the default style.
  544. QFile file(destPath);
  545. file.setPermissions(QFile::ReadUser | QFile::WriteUser);
  546. file.remove();
  547. }
  548. }
  549. return VUtils::copyFile(srcPath, destPath, false);
  550. }
  551. bool VConfigManager::outputDefaultEditorStyle() const
  552. {
  553. // Make sure the styles folder exists.
  554. QDir dir(getConfigFolder());
  555. if (!dir.exists(c_styleConfigFolder)) {
  556. if (!dir.mkdir(c_styleConfigFolder)) {
  557. return false;
  558. }
  559. }
  560. // Always override the deafult style.
  561. QString srcPath = c_defaultMdhlFile;
  562. QString destPath = getStyleConfigFolder() + QDir::separator() + QFileInfo(srcPath).fileName();
  563. if (QFileInfo::exists(destPath)) {
  564. QString bakPath = destPath + ".bak";
  565. // We only keep one bak file.
  566. if (!QFileInfo::exists(bakPath)) {
  567. QFile::rename(destPath, bakPath);
  568. } else {
  569. // Just delete the default style.
  570. QFile file(destPath);
  571. file.setPermissions(QFile::ReadUser | QFile::WriteUser);
  572. file.remove();
  573. }
  574. }
  575. if (!VUtils::copyFile(srcPath, destPath, false)) {
  576. return false;
  577. }
  578. srcPath = c_solarizedDarkMdhlFile;
  579. destPath = getStyleConfigFolder() + QDir::separator() + QFileInfo(srcPath).fileName();
  580. if (!QFileInfo::exists(destPath)) {
  581. if (!VUtils::copyFile(srcPath, destPath, false)) {
  582. return false;
  583. }
  584. }
  585. srcPath = c_solarizedLightMdhlFile;
  586. destPath = getStyleConfigFolder() + QDir::separator() + QFileInfo(srcPath).fileName();
  587. if (!QFileInfo::exists(destPath)) {
  588. if (!VUtils::copyFile(srcPath, destPath, false)) {
  589. return false;
  590. }
  591. }
  592. return true;
  593. }
  594. // The URL will be used in the Web page.
  595. QString VConfigManager::getTemplateCssUrl()
  596. {
  597. QString cssPath = getStyleConfigFolder() +
  598. QDir::separator() +
  599. m_templateCss + ".css";
  600. QUrl cssUrl = QUrl::fromLocalFile(cssPath);
  601. cssPath = cssUrl.toString();
  602. if (!QFile::exists(cssUrl.toLocalFile())) {
  603. // Specified css not exists.
  604. if (m_templateCss == "default") {
  605. bool ret = outputDefaultCssStyle();
  606. if (!ret) {
  607. // Use embedded file.
  608. cssPath = "qrc" + c_defaultCssFile;
  609. }
  610. } else {
  611. setTemplateCss("default");
  612. return getTemplateCssUrl();
  613. }
  614. }
  615. qDebug() << "use template css:" << cssPath;
  616. return cssPath;
  617. }
  618. QString VConfigManager::getEditorStyleUrl()
  619. {
  620. QString mdhlPath = getStyleConfigFolder() + QDir::separator() + m_editorStyle + ".mdhl";
  621. if (!QFile::exists(mdhlPath)) {
  622. // Specified mdhl file not exists.
  623. if (m_editorStyle == "default") {
  624. bool ret = outputDefaultEditorStyle();
  625. if (!ret) {
  626. // Use embedded file.
  627. mdhlPath = c_defaultMdhlFile;
  628. }
  629. } else {
  630. setEditorStyle("default");
  631. return getEditorStyleUrl();
  632. }
  633. }
  634. qDebug() << "use editor style:" << mdhlPath;
  635. return mdhlPath;
  636. }
  637. const QString &VConfigManager::getTemplateCss() const
  638. {
  639. return m_templateCss;
  640. }
  641. void VConfigManager::setTemplateCss(const QString &p_css)
  642. {
  643. if (m_templateCss == p_css) {
  644. return;
  645. }
  646. m_templateCss = p_css;
  647. setConfigToSettings("global", "template_css", m_templateCss);
  648. }
  649. const QString &VConfigManager::getEditorStyle() const
  650. {
  651. return m_editorStyle;
  652. }
  653. void VConfigManager::setEditorStyle(const QString &p_style)
  654. {
  655. if (m_editorStyle == p_style) {
  656. return;
  657. }
  658. m_editorStyle = p_style;
  659. setConfigToSettings("global", "editor_style", m_editorStyle);
  660. updateEditStyle();
  661. }
  662. QString VConfigManager::getVnoteNotebookFolderPath()
  663. {
  664. return QDir::home().filePath(c_vnoteNotebookFolderName);
  665. }
  666. bool VConfigManager::isValidKeySequence(const QString &p_seq)
  667. {
  668. QString lower = p_seq.toLower();
  669. return lower != "ctrl+q" && lower != "ctrl+e";
  670. }
  671. void VConfigManager::readShortcutsFromSettings()
  672. {
  673. m_shortcuts.clear();
  674. int size = defaultSettings->beginReadArray("shortcuts");
  675. for (int i = 0; i < size; ++i) {
  676. defaultSettings->setArrayIndex(i);
  677. QString op = defaultSettings->value("operation").toString();
  678. QString seq = defaultSettings->value("keysequence").toString().trimmed();
  679. if (isValidKeySequence(seq)) {
  680. qDebug() << "read shortcut config" << op << seq;
  681. m_shortcuts[op] = seq;
  682. }
  683. }
  684. defaultSettings->endArray();
  685. // Whether we need to update user settings.
  686. bool needUpdate = false;
  687. size = userSettings->beginReadArray("shortcuts");
  688. QSet<QString> matched;
  689. matched.reserve(m_shortcuts.size());
  690. for (int i = 0; i < size; ++i) {
  691. userSettings->setArrayIndex(i);
  692. QString op = userSettings->value("operation").toString();
  693. QString seq = userSettings->value("keysequence").toString().trimmed();
  694. if (isValidKeySequence(seq)) {
  695. qDebug() << "read user shortcut config" << op << seq;
  696. auto it = m_shortcuts.find(op);
  697. if (it == m_shortcuts.end()) {
  698. // Could not find this in default settings.
  699. needUpdate = true;
  700. } else {
  701. matched.insert(op);
  702. *it = seq;
  703. }
  704. }
  705. }
  706. userSettings->endArray();
  707. if (needUpdate || matched.size() < m_shortcuts.size()) {
  708. // Write the combined config to user settings.
  709. writeShortcutsToSettings();
  710. }
  711. }
  712. void VConfigManager::writeShortcutsToSettings()
  713. {
  714. // Clear it first
  715. userSettings->beginGroup("shortcuts");
  716. userSettings->remove("");
  717. userSettings->endGroup();
  718. userSettings->beginWriteArray("shortcuts");
  719. int idx = 0;
  720. for (auto it = m_shortcuts.begin(); it != m_shortcuts.end(); ++it, ++idx) {
  721. userSettings->setArrayIndex(idx);
  722. userSettings->setValue("operation", it.key());
  723. userSettings->setValue("keysequence", it.value());
  724. }
  725. userSettings->endArray();
  726. }
  727. QString VConfigManager::getShortcutKeySequence(const QString &p_operation) const
  728. {
  729. auto it = m_shortcuts.find(p_operation);
  730. if (it == m_shortcuts.end()) {
  731. return QString();
  732. }
  733. return *it;
  734. }
  735. void VConfigManager::initDocSuffixes()
  736. {
  737. m_docSuffixes.clear();
  738. QString mdSuffix = getConfigFromSettings("global",
  739. "markdown_suffix").toString();
  740. if (mdSuffix.isEmpty()) {
  741. mdSuffix = getDefaultConfig("global",
  742. "markdown_suffix").toString();
  743. }
  744. Q_ASSERT(!mdSuffix.isEmpty());
  745. QList<QString> md = mdSuffix.toLower().split(':', QString::SkipEmptyParts);
  746. md.removeDuplicates();
  747. m_docSuffixes[(int)DocType::Markdown] = md;
  748. QList<QString> list;
  749. list << "ls" << "list";
  750. m_docSuffixes[(int)DocType::List] = list;
  751. QList<QString> container;
  752. container << "co" << "container" << "con";
  753. m_docSuffixes[(int)DocType::Container] = container;
  754. QList<QString> html;
  755. html << "html";
  756. m_docSuffixes[(int)DocType::Html] = html;
  757. qDebug() << "doc suffixes" << m_docSuffixes;
  758. }