vconfigmanager.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876
  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_enableTrailingSpaceHighlight = getConfigFromSettings("global",
  111. "enable_trailing_space_highlight").toBool();
  112. m_enableVimMode = getConfigFromSettings("global",
  113. "enable_vim_mode").toBool();
  114. m_enableSmartImInVimMode = getConfigFromSettings("global",
  115. "enable_smart_im_in_vim_mode").toBool();
  116. m_editorLineNumber = getConfigFromSettings("global",
  117. "editor_line_number").toInt();
  118. m_minimizeToSystemTray = getConfigFromSettings("global",
  119. "minimize_to_system_tray").toInt();
  120. if (m_minimizeToSystemTray > 1 || m_minimizeToSystemTray < -1) {
  121. setMinimizeToSystemTray(0);
  122. }
  123. readShortcutsFromSettings();
  124. initDocSuffixes();
  125. m_markdownHighlightInterval = getConfigFromSettings("global",
  126. "markdown_highlight_interval").toInt();
  127. m_lineDistanceHeight = getConfigFromSettings("global",
  128. "line_distance_height").toInt();
  129. m_insertTitleFromNoteName = getConfigFromSettings("global",
  130. "insert_title_from_note_name").toBool();
  131. int openMode = getConfigFromSettings("global",
  132. "note_open_mode").toInt();
  133. if (openMode == 1) {
  134. m_noteOpenMode = OpenFileMode::Edit;
  135. } else {
  136. m_noteOpenMode = OpenFileMode::Read;
  137. }
  138. m_enableHeadingSequence = getConfigFromSettings("global",
  139. "enable_heading_sequence").toBool();
  140. m_colorColumn = getConfigFromSettings("global", "color_column").toInt();
  141. }
  142. void VConfigManager::readPredefinedColorsFromSettings()
  143. {
  144. predefinedColors.clear();
  145. int size = defaultSettings->beginReadArray("predefined_colors");
  146. for (int i = 0; i < size; ++i) {
  147. defaultSettings->setArrayIndex(i);
  148. VColor color;
  149. color.name = defaultSettings->value("name").toString();
  150. color.rgb = defaultSettings->value("rgb").toString();
  151. predefinedColors.append(color);
  152. }
  153. defaultSettings->endArray();
  154. qDebug() << "read" << predefinedColors.size()
  155. << "pre-defined colors from [predefined_colors] section";
  156. }
  157. void VConfigManager::readNotebookFromSettings(QVector<VNotebook *> &p_notebooks, QObject *parent)
  158. {
  159. Q_ASSERT(p_notebooks.isEmpty());
  160. int size = userSettings->beginReadArray("notebooks");
  161. for (int i = 0; i < size; ++i) {
  162. userSettings->setArrayIndex(i);
  163. QString name = userSettings->value("name").toString();
  164. QString path = userSettings->value("path").toString();
  165. VNotebook *notebook = new VNotebook(name, path, parent);
  166. notebook->readConfig();
  167. p_notebooks.append(notebook);
  168. }
  169. userSettings->endArray();
  170. qDebug() << "read" << p_notebooks.size()
  171. << "notebook items from [notebooks] section";
  172. }
  173. void VConfigManager::writeNotebookToSettings(const QVector<VNotebook *> &p_notebooks)
  174. {
  175. // Clear it first
  176. userSettings->beginGroup("notebooks");
  177. userSettings->remove("");
  178. userSettings->endGroup();
  179. userSettings->beginWriteArray("notebooks");
  180. for (int i = 0; i < p_notebooks.size(); ++i) {
  181. userSettings->setArrayIndex(i);
  182. const VNotebook &notebook = *p_notebooks[i];
  183. userSettings->setValue("name", notebook.getName());
  184. userSettings->setValue("path", notebook.getPath());
  185. }
  186. userSettings->endArray();
  187. qDebug() << "write" << p_notebooks.size()
  188. << "notebook items in [notebooks] section";
  189. }
  190. QVariant VConfigManager::getConfigFromSettings(const QString &section, const QString &key) const
  191. {
  192. QString fullKey = section + "/" + key;
  193. // First, look up the user-scoped config file
  194. QVariant value = userSettings->value(fullKey);
  195. if (!value.isNull()) {
  196. qDebug() << "user config:" << fullKey << value.toString();
  197. return value;
  198. }
  199. // Second, look up the default config file
  200. return getDefaultConfig(section, key);
  201. }
  202. void VConfigManager::setConfigToSettings(const QString &section, const QString &key, const QVariant &value)
  203. {
  204. // Set the user-scoped config file
  205. QString fullKey = section + "/" + key;
  206. userSettings->setValue(fullKey, value);
  207. qDebug() << "set user config:" << fullKey << value.toString();
  208. }
  209. QVariant VConfigManager::getDefaultConfig(const QString &p_section, const QString &p_key) const
  210. {
  211. QString fullKey = p_section + "/" + p_key;
  212. QVariant value = defaultSettings->value(fullKey);
  213. qDebug() << "default config:" << fullKey << value.toString();
  214. return value;
  215. }
  216. QVariant VConfigManager::resetDefaultConfig(const QString &p_section, const QString &p_key)
  217. {
  218. QVariant defaultValue = getDefaultConfig(p_section, p_key);
  219. setConfigToSettings(p_section, p_key, defaultValue);
  220. return defaultValue;
  221. }
  222. QString VConfigManager::fetchDirConfigFilePath(const QString &p_path)
  223. {
  224. QDir dir(p_path);
  225. QString fileName = c_dirConfigFile;
  226. if (dir.exists(c_obsoleteDirConfigFile)) {
  227. V_ASSERT(!dir.exists(c_dirConfigFile));
  228. if (!dir.rename(c_obsoleteDirConfigFile, c_dirConfigFile)) {
  229. fileName = c_obsoleteDirConfigFile;
  230. }
  231. qDebug() << "rename old directory config file:" << fileName;
  232. }
  233. QString filePath = QDir::cleanPath(dir.filePath(fileName));
  234. qDebug() << "use directory config file:" << filePath;
  235. return filePath;
  236. }
  237. QJsonObject VConfigManager::readDirectoryConfig(const QString &path)
  238. {
  239. QString configFile = fetchDirConfigFilePath(path);
  240. QFile config(configFile);
  241. if (!config.open(QIODevice::ReadOnly)) {
  242. qWarning() << "fail to read directory configuration file:"
  243. << configFile;
  244. return QJsonObject();
  245. }
  246. QByteArray configData = config.readAll();
  247. return QJsonDocument::fromJson(configData).object();
  248. }
  249. bool VConfigManager::directoryConfigExist(const QString &path)
  250. {
  251. return QFileInfo::exists(fetchDirConfigFilePath(path));
  252. }
  253. bool VConfigManager::writeDirectoryConfig(const QString &path, const QJsonObject &configJson)
  254. {
  255. QString configFile = fetchDirConfigFilePath(path);
  256. QFile config(configFile);
  257. if (!config.open(QIODevice::WriteOnly)) {
  258. qWarning() << "fail to open directory configuration file for write:"
  259. << configFile;
  260. return false;
  261. }
  262. QJsonDocument configDoc(configJson);
  263. config.write(configDoc.toJson());
  264. return true;
  265. }
  266. bool VConfigManager::deleteDirectoryConfig(const QString &path)
  267. {
  268. QString configFile = fetchDirConfigFilePath(path);
  269. QFile config(configFile);
  270. if (!config.remove()) {
  271. qWarning() << "fail to delete directory configuration file:"
  272. << configFile;
  273. return false;
  274. }
  275. qDebug() << "delete config file:" << configFile;
  276. return true;
  277. }
  278. QString VConfigManager::getLogFilePath()
  279. {
  280. static QString logPath;
  281. if (logPath.isEmpty()) {
  282. QString location = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
  283. V_ASSERT(!location.isEmpty());
  284. QDir dir(location);
  285. dir.mkdir("VNote");
  286. logPath = dir.filePath("VNote/vnote.log");
  287. }
  288. return logPath;
  289. }
  290. void VConfigManager::updateMarkdownEditStyle()
  291. {
  292. static const QString defaultCurrentLineBackground = "#C5CAE9";
  293. static const QString defaultVimNormalBg = "#BCBCBC";
  294. static const QString defaultVimInsertBg = "#C5CAE9";
  295. static const QString defaultVimVisualBg = "#90CAF9";
  296. static const QString defaultVimReplaceBg = "#F8BBD0";
  297. static const QString defaultTrailingSpaceBg = "#A8A8A8";
  298. static const QString defaultSelectedWordBg = "#DFDF00";
  299. static const QString defaultSearchedWordBg = "#81C784";
  300. static const QString defaultSearchedWordCursorBg = "#4DB6AC";
  301. static const QString defaultIncrementalSearchedWordBg = "#CE93D8";
  302. static const QString defaultLineNumberBg = "#BDBDBD";
  303. static const QString defaultLineNumberFg = "#424242";
  304. static const QString defaultColorColumnBg = "#DD0000";
  305. static const QString defaultColorColumnFg = "#FFFF00";
  306. // Read style file .mdhl
  307. QString file(getEditorStyleUrl());
  308. QString styleStr = VUtils::readFileFromDisk(file);
  309. if (styleStr.isEmpty()) {
  310. return;
  311. }
  312. mdEditPalette = baseEditPalette;
  313. mdEditFont = baseEditFont;
  314. VStyleParser parser;
  315. parser.parseMarkdownStyle(styleStr);
  316. QMap<QString, QMap<QString, QString>> styles;
  317. parser.fetchMarkdownEditorStyles(mdEditPalette, mdEditFont, styles);
  318. mdHighlightingStyles = parser.fetchMarkdownStyles(mdEditFont);
  319. m_codeBlockStyles = parser.fetchCodeBlockStyles(mdEditFont);
  320. m_editorCurrentLineBg = defaultCurrentLineBackground;
  321. m_editorVimInsertBg = defaultVimInsertBg;
  322. m_editorVimNormalBg = defaultVimNormalBg;
  323. m_editorVimVisualBg = defaultVimVisualBg;
  324. m_editorVimReplaceBg = defaultVimReplaceBg;
  325. auto editorCurrentLineIt = styles.find("editor-current-line");
  326. if (editorCurrentLineIt != styles.end()) {
  327. auto backgroundIt = editorCurrentLineIt->find("background");
  328. if (backgroundIt != editorCurrentLineIt->end()) {
  329. // Do not need to add "#" here, since this is a built-in attribute.
  330. m_editorCurrentLineBg = *backgroundIt;
  331. }
  332. auto vimBgIt = editorCurrentLineIt->find("vim-insert-background");
  333. if (vimBgIt != editorCurrentLineIt->end()) {
  334. m_editorVimInsertBg = "#" + *vimBgIt;
  335. }
  336. vimBgIt = editorCurrentLineIt->find("vim-normal-background");
  337. if (vimBgIt != editorCurrentLineIt->end()) {
  338. m_editorVimNormalBg = "#" + *vimBgIt;
  339. }
  340. vimBgIt = editorCurrentLineIt->find("vim-visual-background");
  341. if (vimBgIt != editorCurrentLineIt->end()) {
  342. m_editorVimVisualBg = "#" + *vimBgIt;
  343. }
  344. vimBgIt = editorCurrentLineIt->find("vim-replace-background");
  345. if (vimBgIt != editorCurrentLineIt->end()) {
  346. m_editorVimReplaceBg = "#" + *vimBgIt;
  347. }
  348. }
  349. m_editorTrailingSpaceBg = defaultTrailingSpaceBg;
  350. m_editorSelectedWordBg = defaultSelectedWordBg;
  351. m_editorSearchedWordBg = defaultSearchedWordBg;
  352. m_editorSearchedWordCursorBg = defaultSearchedWordCursorBg;
  353. m_editorIncrementalSearchedWordBg = defaultIncrementalSearchedWordBg;
  354. m_editorLineNumberBg = defaultLineNumberBg;
  355. m_editorLineNumberFg = defaultLineNumberFg;
  356. m_editorColorColumnBg = defaultColorColumnBg;
  357. m_editorColorColumnFg = defaultColorColumnFg;
  358. auto editorIt = styles.find("editor");
  359. if (editorIt != styles.end()) {
  360. auto it = editorIt->find("trailing-space");
  361. if (it != editorIt->end()) {
  362. m_editorTrailingSpaceBg = "#" + *it;
  363. }
  364. it = editorIt->find("line-number-background");
  365. if (it != editorIt->end()) {
  366. m_editorLineNumberBg = "#" + *it;
  367. }
  368. it = editorIt->find("line-number-foreground");
  369. if (it != editorIt->end()) {
  370. m_editorLineNumberFg = "#" + *it;
  371. }
  372. it = editorIt->find("selected-word-background");
  373. if (it != editorIt->end()) {
  374. m_editorSelectedWordBg = "#" + *it;
  375. }
  376. it = editorIt->find("searched-word-background");
  377. if (it != editorIt->end()) {
  378. m_editorSearchedWordBg = "#" + *it;
  379. }
  380. it = editorIt->find("searched-word-cursor-background");
  381. if (it != editorIt->end()) {
  382. m_editorSearchedWordCursorBg = "#" + *it;
  383. }
  384. it = editorIt->find("incremental-searched-word-background");
  385. if (it != editorIt->end()) {
  386. m_editorIncrementalSearchedWordBg = "#" + *it;
  387. }
  388. it = editorIt->find("color-column-background");
  389. if (it != editorIt->end()) {
  390. m_editorColorColumnBg = "#" + *it;
  391. }
  392. it = editorIt->find("color-column-foreground");
  393. if (it != editorIt->end()) {
  394. m_editorColorColumnFg = "#" + *it;
  395. }
  396. }
  397. }
  398. void VConfigManager::updateEditStyle()
  399. {
  400. // Reset font and palette.
  401. baseEditFont = mdEditFont = m_defaultEditFont;
  402. baseEditPalette = mdEditPalette = m_defaultEditPalette;
  403. static const QColor defaultColor = m_defaultEditPalette.color(QPalette::Base);
  404. QColor newColor = defaultColor;
  405. bool force = false;
  406. if (curBackgroundColor != "System") {
  407. for (int i = 0; i < predefinedColors.size(); ++i) {
  408. if (predefinedColors[i].name == curBackgroundColor) {
  409. QString rgb = predefinedColors[i].rgb;
  410. if (!rgb.isEmpty()) {
  411. newColor = QColor(VUtils::QRgbFromString(rgb));
  412. force = true;
  413. }
  414. break;
  415. }
  416. }
  417. }
  418. baseEditPalette.setColor(QPalette::Base, newColor);
  419. // Update markdown editor palette
  420. updateMarkdownEditStyle();
  421. // Base editor will use the same font size as the markdown editor by now.
  422. if (mdEditFont.pointSize() > -1) {
  423. baseEditFont.setPointSize(mdEditFont.pointSize());
  424. }
  425. if (force) {
  426. mdEditPalette.setColor(QPalette::Base, newColor);
  427. }
  428. }
  429. void VConfigManager::setWebZoomFactor(qreal p_factor)
  430. {
  431. if (isCustomWebZoomFactor()) {
  432. if (VUtils::realEqual(m_webZoomFactor, p_factor)) {
  433. return;
  434. } else if (VUtils::realEqual(p_factor, -1)) {
  435. m_webZoomFactor = VUtils::calculateScaleFactor();
  436. setConfigToSettings("global", "web_zoom_factor", -1);
  437. return;
  438. }
  439. } else {
  440. if (VUtils::realEqual(p_factor, -1)) {
  441. return;
  442. }
  443. }
  444. m_webZoomFactor = p_factor;
  445. setConfigToSettings("global", "web_zoom_factor", m_webZoomFactor);
  446. }
  447. QString VConfigManager::getConfigFolder() const
  448. {
  449. V_ASSERT(userSettings);
  450. QString iniPath = userSettings->fileName();
  451. return VUtils::basePathFromPath(iniPath);
  452. }
  453. QString VConfigManager::getConfigFilePath() const
  454. {
  455. V_ASSERT(userSettings);
  456. return userSettings->fileName();
  457. }
  458. QString VConfigManager::getStyleConfigFolder() const
  459. {
  460. return getConfigFolder() + QDir::separator() + c_styleConfigFolder;
  461. }
  462. QVector<QString> VConfigManager::getCssStyles() const
  463. {
  464. QVector<QString> res;
  465. QDir dir(getStyleConfigFolder());
  466. if (!dir.exists()) {
  467. // Output pre-defined css styles to this folder.
  468. outputDefaultCssStyle();
  469. }
  470. // Get all the .css files in the folder.
  471. dir.setFilter(QDir::Files | QDir::NoSymLinks);
  472. dir.setNameFilters(QStringList("*.css"));
  473. QStringList files = dir.entryList();
  474. res.reserve(files.size());
  475. for (auto const &item : files) {
  476. res.push_back(item.left(item.size() - 4));
  477. }
  478. return res;
  479. }
  480. QVector<QString> VConfigManager::getEditorStyles() const
  481. {
  482. QVector<QString> res;
  483. QDir dir(getStyleConfigFolder());
  484. if (!dir.exists()) {
  485. // Output pre-defined mdhl styles to this folder.
  486. outputDefaultEditorStyle();
  487. }
  488. // Get all the .mdhl files in the folder.
  489. dir.setFilter(QDir::Files | QDir::NoSymLinks);
  490. dir.setNameFilters(QStringList("*.mdhl"));
  491. QStringList files = dir.entryList();
  492. res.reserve(files.size());
  493. for (auto const &item : files) {
  494. res.push_back(item.left(item.size() - 5));
  495. }
  496. return res;
  497. }
  498. bool VConfigManager::outputDefaultCssStyle() const
  499. {
  500. // Make sure the styles folder exists.
  501. QDir dir(getConfigFolder());
  502. if (!dir.exists(c_styleConfigFolder)) {
  503. if (!dir.mkdir(c_styleConfigFolder)) {
  504. return false;
  505. }
  506. }
  507. QString srcPath = c_defaultCssFile;
  508. QString destPath = getStyleConfigFolder() + QDir::separator() + QFileInfo(srcPath).fileName();
  509. if (QFileInfo::exists(destPath)) {
  510. QString bakPath = destPath + ".bak";
  511. // We only keep one bak file.
  512. if (!QFileInfo::exists(bakPath)) {
  513. QFile::rename(destPath, bakPath);
  514. } else {
  515. // Just delete the default style.
  516. QFile file(destPath);
  517. file.setPermissions(QFile::ReadUser | QFile::WriteUser);
  518. file.remove();
  519. }
  520. }
  521. return VUtils::copyFile(srcPath, destPath, false);
  522. }
  523. bool VConfigManager::outputDefaultEditorStyle() const
  524. {
  525. // Make sure the styles folder exists.
  526. QDir dir(getConfigFolder());
  527. if (!dir.exists(c_styleConfigFolder)) {
  528. if (!dir.mkdir(c_styleConfigFolder)) {
  529. return false;
  530. }
  531. }
  532. // Always override the deafult style.
  533. QString srcPath = c_defaultMdhlFile;
  534. QString destPath = getStyleConfigFolder() + QDir::separator() + QFileInfo(srcPath).fileName();
  535. if (QFileInfo::exists(destPath)) {
  536. QString bakPath = destPath + ".bak";
  537. // We only keep one bak file.
  538. if (!QFileInfo::exists(bakPath)) {
  539. QFile::rename(destPath, bakPath);
  540. } else {
  541. // Just delete the default style.
  542. QFile file(destPath);
  543. file.setPermissions(QFile::ReadUser | QFile::WriteUser);
  544. file.remove();
  545. }
  546. }
  547. if (!VUtils::copyFile(srcPath, destPath, false)) {
  548. return false;
  549. }
  550. srcPath = c_solarizedDarkMdhlFile;
  551. destPath = getStyleConfigFolder() + QDir::separator() + QFileInfo(srcPath).fileName();
  552. if (!QFileInfo::exists(destPath)) {
  553. if (!VUtils::copyFile(srcPath, destPath, false)) {
  554. return false;
  555. }
  556. }
  557. srcPath = c_solarizedLightMdhlFile;
  558. destPath = getStyleConfigFolder() + QDir::separator() + QFileInfo(srcPath).fileName();
  559. if (!QFileInfo::exists(destPath)) {
  560. if (!VUtils::copyFile(srcPath, destPath, false)) {
  561. return false;
  562. }
  563. }
  564. return true;
  565. }
  566. // The URL will be used in the Web page.
  567. QString VConfigManager::getTemplateCssUrl()
  568. {
  569. QString cssPath = getStyleConfigFolder() +
  570. QDir::separator() +
  571. m_templateCss + ".css";
  572. QUrl cssUrl = QUrl::fromLocalFile(cssPath);
  573. cssPath = cssUrl.toString();
  574. if (!QFile::exists(cssUrl.toLocalFile())) {
  575. // Specified css not exists.
  576. if (m_templateCss == "default") {
  577. bool ret = outputDefaultCssStyle();
  578. if (!ret) {
  579. // Use embedded file.
  580. cssPath = "qrc" + c_defaultCssFile;
  581. }
  582. } else {
  583. setTemplateCss("default");
  584. return getTemplateCssUrl();
  585. }
  586. }
  587. qDebug() << "use template css:" << cssPath;
  588. return cssPath;
  589. }
  590. QString VConfigManager::getEditorStyleUrl()
  591. {
  592. QString mdhlPath = getStyleConfigFolder() + QDir::separator() + m_editorStyle + ".mdhl";
  593. if (!QFile::exists(mdhlPath)) {
  594. // Specified mdhl file not exists.
  595. if (m_editorStyle == "default") {
  596. bool ret = outputDefaultEditorStyle();
  597. if (!ret) {
  598. // Use embedded file.
  599. mdhlPath = c_defaultMdhlFile;
  600. }
  601. } else {
  602. setEditorStyle("default");
  603. return getEditorStyleUrl();
  604. }
  605. }
  606. qDebug() << "use editor style:" << mdhlPath;
  607. return mdhlPath;
  608. }
  609. const QString &VConfigManager::getTemplateCss() const
  610. {
  611. return m_templateCss;
  612. }
  613. void VConfigManager::setTemplateCss(const QString &p_css)
  614. {
  615. if (m_templateCss == p_css) {
  616. return;
  617. }
  618. m_templateCss = p_css;
  619. setConfigToSettings("global", "template_css", m_templateCss);
  620. }
  621. const QString &VConfigManager::getEditorStyle() const
  622. {
  623. return m_editorStyle;
  624. }
  625. void VConfigManager::setEditorStyle(const QString &p_style)
  626. {
  627. if (m_editorStyle == p_style) {
  628. return;
  629. }
  630. m_editorStyle = p_style;
  631. setConfigToSettings("global", "editor_style", m_editorStyle);
  632. updateEditStyle();
  633. }
  634. QString VConfigManager::getVnoteNotebookFolderPath()
  635. {
  636. return QDir::home().filePath(c_vnoteNotebookFolderName);
  637. }
  638. bool VConfigManager::isValidKeySequence(const QString &p_seq)
  639. {
  640. QString lower = p_seq.toLower();
  641. return lower != "ctrl+q" && lower != "ctrl+e";
  642. }
  643. void VConfigManager::readShortcutsFromSettings()
  644. {
  645. m_shortcuts.clear();
  646. int size = defaultSettings->beginReadArray("shortcuts");
  647. for (int i = 0; i < size; ++i) {
  648. defaultSettings->setArrayIndex(i);
  649. QString op = defaultSettings->value("operation").toString();
  650. QString seq = defaultSettings->value("keysequence").toString().trimmed();
  651. if (isValidKeySequence(seq)) {
  652. qDebug() << "read shortcut config" << op << seq;
  653. m_shortcuts[op] = seq;
  654. }
  655. }
  656. defaultSettings->endArray();
  657. // Whether we need to update user settings.
  658. bool needUpdate = false;
  659. size = userSettings->beginReadArray("shortcuts");
  660. QSet<QString> matched;
  661. matched.reserve(m_shortcuts.size());
  662. for (int i = 0; i < size; ++i) {
  663. userSettings->setArrayIndex(i);
  664. QString op = userSettings->value("operation").toString();
  665. QString seq = userSettings->value("keysequence").toString().trimmed();
  666. if (isValidKeySequence(seq)) {
  667. qDebug() << "read user shortcut config" << op << seq;
  668. auto it = m_shortcuts.find(op);
  669. if (it == m_shortcuts.end()) {
  670. // Could not find this in default settings.
  671. needUpdate = true;
  672. } else {
  673. matched.insert(op);
  674. *it = seq;
  675. }
  676. }
  677. }
  678. userSettings->endArray();
  679. if (needUpdate || matched.size() < m_shortcuts.size()) {
  680. // Write the combined config to user settings.
  681. writeShortcutsToSettings();
  682. }
  683. }
  684. void VConfigManager::writeShortcutsToSettings()
  685. {
  686. // Clear it first
  687. userSettings->beginGroup("shortcuts");
  688. userSettings->remove("");
  689. userSettings->endGroup();
  690. userSettings->beginWriteArray("shortcuts");
  691. int idx = 0;
  692. for (auto it = m_shortcuts.begin(); it != m_shortcuts.end(); ++it, ++idx) {
  693. userSettings->setArrayIndex(idx);
  694. userSettings->setValue("operation", it.key());
  695. userSettings->setValue("keysequence", it.value());
  696. }
  697. userSettings->endArray();
  698. }
  699. QString VConfigManager::getShortcutKeySequence(const QString &p_operation) const
  700. {
  701. auto it = m_shortcuts.find(p_operation);
  702. if (it == m_shortcuts.end()) {
  703. return QString();
  704. }
  705. return *it;
  706. }
  707. void VConfigManager::initDocSuffixes()
  708. {
  709. m_docSuffixes.clear();
  710. QString mdSuffix = getConfigFromSettings("global",
  711. "markdown_suffix").toString();
  712. if (mdSuffix.isEmpty()) {
  713. mdSuffix = getDefaultConfig("global",
  714. "markdown_suffix").toString();
  715. }
  716. Q_ASSERT(!mdSuffix.isEmpty());
  717. QList<QString> md = mdSuffix.toLower().split(':', QString::SkipEmptyParts);
  718. md.removeDuplicates();
  719. m_docSuffixes[(int)DocType::Markdown] = md;
  720. QList<QString> list;
  721. list << "ls" << "list";
  722. m_docSuffixes[(int)DocType::List] = list;
  723. QList<QString> container;
  724. container << "co" << "container" << "con";
  725. m_docSuffixes[(int)DocType::Container] = container;
  726. qDebug() << "doc suffixes" << m_docSuffixes;
  727. }