vconfigmanager.cpp 51 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608
  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 <QCoreApplication>
  12. #include "utils/vutils.h"
  13. #include "vstyleparser.h"
  14. #include "vpalette.h"
  15. const QString VConfigManager::orgName = QString("vnote");
  16. const QString VConfigManager::appName = QString("vnote");
  17. const QString VConfigManager::c_version = QString("1.22");
  18. const QString VConfigManager::c_dirConfigFile = QString("_vnote.json");
  19. const QString VConfigManager::c_defaultConfigFilePath = QString(":/resources/vnote.ini");
  20. const QString VConfigManager::c_defaultConfigFile = QString("vnote.ini");
  21. const QString VConfigManager::c_sessionConfigFile = QString("session.ini");
  22. const QString VConfigManager::c_snippetConfigFile = QString("snippet.json");
  23. const QString VConfigManager::c_styleConfigFolder = QString("styles");
  24. const QString VConfigManager::c_themeConfigFolder = QString("themes");
  25. const QString VConfigManager::c_codeBlockStyleConfigFolder = QString("codeblock_styles");
  26. const QString VConfigManager::c_templateConfigFolder = QString("templates");
  27. const QString VConfigManager::c_snippetConfigFolder = QString("snippets");
  28. const QString VConfigManager::c_warningTextStyle = QString("color: #C9302C; font: bold");
  29. const QString VConfigManager::c_dataTextStyle = QString("font: bold");
  30. const QString VConfigManager::c_vnoteNotebookFolderName = QString("vnote_notebooks");
  31. const QString VConfigManager::c_exportFolderName = QString("vnote_exports");
  32. VConfigManager::VConfigManager(QObject *p_parent)
  33. : QObject(p_parent),
  34. m_noteListViewOrder(-1),
  35. m_explorerCurrentIndex(-1),
  36. m_hasReset(false),
  37. userSettings(NULL),
  38. defaultSettings(NULL),
  39. m_sessionSettings(NULL)
  40. {
  41. }
  42. void VConfigManager::initialize()
  43. {
  44. initSettings();
  45. initThemes();
  46. initEditorStyles();
  47. initCssStyles();
  48. initCodeBlockCssStyles();
  49. m_theme = getConfigFromSettings("global", "theme").toString();
  50. m_editorStyle = getConfigFromSettings("global", "editor_style").toString();
  51. m_cssStyle = getConfigFromSettings("global", "css_style").toString();
  52. m_codeBlockCssStyle = getConfigFromSettings("global", "code_block_css_style").toString();
  53. m_defaultEditPalette = QTextEdit().palette();
  54. welcomePagePath = getConfigFromSettings("global", "welcome_page_path").toString();
  55. markdownExtensions = hoedown_extensions(HOEDOWN_EXT_TABLES | HOEDOWN_EXT_FENCED_CODE |
  56. HOEDOWN_EXT_HIGHLIGHT | HOEDOWN_EXT_AUTOLINK |
  57. HOEDOWN_EXT_QUOTE | HOEDOWN_EXT_MATH | HOEDOWN_EXT_MATH_EXPLICIT);
  58. mdConverterType = (MarkdownConverterType)getConfigFromSettings("global", "markdown_converter").toInt();
  59. tabStopWidth = getConfigFromSettings("global", "tab_stop_width").toInt();
  60. isExpandTab = getConfigFromSettings("global", "is_expand_tab").toBool();
  61. m_highlightCursorLine = getConfigFromSettings("global", "highlight_cursor_line").toBool();
  62. m_highlightSelectedWord = getConfigFromSettings("global", "highlight_selected_word").toBool();
  63. m_highlightSearchedWord = getConfigFromSettings("global", "highlight_searched_word").toBool();
  64. readCustomColors();
  65. curBackgroundColor = getConfigFromSettings("global", "current_background_color").toString();
  66. updateEditStyle();
  67. curRenderBackgroundColor = getConfigFromSettings("global",
  68. "current_render_background_color").toString();
  69. m_findCaseSensitive = getConfigFromSettings("global",
  70. "find_case_sensitive").toBool();
  71. m_findWholeWordOnly = getConfigFromSettings("global",
  72. "find_whole_word_only").toBool();
  73. m_findRegularExpression = getConfigFromSettings("global",
  74. "find_regular_expression").toBool();
  75. m_findIncrementalSearch = getConfigFromSettings("global",
  76. "find_incremental_search").toBool();
  77. m_language = getConfigFromSettings("global", "language").toString();
  78. m_enableMermaid = getConfigFromSettings("global", "enable_mermaid").toBool();
  79. m_enableFlowchart = getConfigFromSettings("global", "enable_flowchart").toBool();
  80. m_enableMathjax = getConfigFromSettings("global", "enable_mathjax").toBool();
  81. m_webZoomFactor = getConfigFromSettings("global", "web_zoom_factor").toReal();
  82. if (!isCustomWebZoomFactor()) {
  83. // Calculate the zoom factor based on DPI.
  84. m_webZoomFactor = VUtils::calculateScaleFactor();
  85. qDebug() << "set WebZoomFactor to" << m_webZoomFactor;
  86. }
  87. m_editorZoomDelta = getConfigFromSettings("global", "editor_zoom_delta").toInt();
  88. m_enableCodeBlockHighlight = getConfigFromSettings("global",
  89. "enable_code_block_highlight").toBool();
  90. m_enablePreviewImages = getConfigFromSettings("global",
  91. "enable_preview_images").toBool();
  92. m_enablePreviewImageConstraint = getConfigFromSettings("global",
  93. "enable_preview_image_constraint").toBool();
  94. m_enableImageConstraint = getConfigFromSettings("global",
  95. "enable_image_constraint").toBool();
  96. m_enableImageCaption = getConfigFromSettings("global",
  97. "enable_image_caption").toBool();
  98. m_imageFolder = getConfigFromSettings("global",
  99. "image_folder").toString();
  100. m_imageFolderExt = getConfigFromSettings("global",
  101. "external_image_folder").toString();
  102. m_attachmentFolder = getConfigFromSettings("global",
  103. "attachment_folder").toString();
  104. if (m_attachmentFolder.isEmpty()) {
  105. // Reset the default folder.
  106. m_attachmentFolder = resetDefaultConfig("global", "attachment_folder").toString();
  107. }
  108. m_enableTrailingSpaceHighlight = getConfigFromSettings("global",
  109. "enable_trailing_space_highlight").toBool();
  110. m_editorLineNumber = getConfigFromSettings("global",
  111. "editor_line_number").toInt();
  112. m_minimizeToSystemTray = getConfigFromSettings("global",
  113. "minimize_to_system_tray").toInt();
  114. if (m_minimizeToSystemTray > 1 || m_minimizeToSystemTray < -1) {
  115. setMinimizeToSystemTray(0);
  116. }
  117. readShortcutsFromSettings();
  118. readCaptainShortcutsFromSettings();
  119. initDocSuffixes();
  120. m_markdownHighlightInterval = getConfigFromSettings("global",
  121. "markdown_highlight_interval").toInt();
  122. m_lineDistanceHeight = getConfigFromSettings("global",
  123. "line_distance_height").toInt();
  124. m_insertTitleFromNoteName = getConfigFromSettings("global",
  125. "insert_title_from_note_name").toBool();
  126. int openMode = getConfigFromSettings("global",
  127. "note_open_mode").toInt();
  128. if (openMode == 1) {
  129. m_noteOpenMode = OpenFileMode::Edit;
  130. } else {
  131. m_noteOpenMode = OpenFileMode::Read;
  132. }
  133. int tmpHeadingSequenceType = getConfigFromSettings("global",
  134. "heading_sequence_type").toInt();
  135. if (tmpHeadingSequenceType < (int)HeadingSequenceType::Invalid
  136. && tmpHeadingSequenceType >= (int)HeadingSequenceType::Disabled) {
  137. m_headingSequenceType = (HeadingSequenceType)tmpHeadingSequenceType;
  138. } else {
  139. m_headingSequenceType = HeadingSequenceType::Disabled;
  140. }
  141. m_headingSequenceBaseLevel = getConfigFromSettings("global",
  142. "heading_sequence_base_level").toInt();
  143. m_colorColumn = getConfigFromSettings("global", "color_column").toInt();
  144. m_enableCodeBlockLineNumber = getConfigFromSettings("global",
  145. "enable_code_block_line_number").toBool();
  146. m_toolBarIconSize = getConfigFromSettings("global",
  147. "tool_bar_icon_size").toInt();
  148. m_markdownItOpt = MarkdownitOption::fromConfig(getConfigFromSettings("web",
  149. "markdownit_opt").toStringList());
  150. m_recycleBinFolder = getConfigFromSettings("global",
  151. "recycle_bin_folder").toString();
  152. m_recycleBinFolderExt = getConfigFromSettings("global",
  153. "external_recycle_bin_folder").toString();
  154. m_confirmImagesCleanUp = getConfigFromSettings("global",
  155. "confirm_images_clean_up").toBool();
  156. m_confirmReloadFolder = getConfigFromSettings("global",
  157. "confirm_reload_folder").toBool();
  158. m_mathjaxJavascript = getConfigFromSettings("web",
  159. "mathjax_javascript").toString();
  160. m_doubleClickCloseTab = getConfigFromSettings("global",
  161. "double_click_close_tab").toBool();
  162. m_middleClickCloseTab = getConfigFromSettings("global",
  163. "middle_click_close_tab").toBool();
  164. int tmpStartupPageMode = getConfigFromSettings("global",
  165. "startup_page_type").toInt();
  166. if (tmpStartupPageMode < (int)StartupPageType::Invalid
  167. && tmpStartupPageMode >= (int)StartupPageType::None) {
  168. m_startupPageType = (StartupPageType)tmpStartupPageMode;
  169. } else {
  170. m_startupPageType = StartupPageType::None;
  171. }
  172. m_startupPages = getConfigFromSettings("global",
  173. "startup_pages").toStringList();
  174. initFromSessionSettings();
  175. m_fileTimerInterval = getConfigFromSettings("global",
  176. "file_timer_interval").toInt();
  177. if (m_fileTimerInterval < 100) {
  178. m_fileTimerInterval = 100;
  179. }
  180. m_backupDirectory = getConfigFromSettings("global",
  181. "backup_directory").toString();
  182. m_backupExtension = getConfigFromSettings("global",
  183. "backup_extension").toString();
  184. if (m_backupExtension.isEmpty()) {
  185. m_backupExtension = ".";
  186. }
  187. m_vimExemptionKeys = getConfigFromSettings("global",
  188. "vim_exemption_keys").toString();
  189. m_closeBeforeExternalEditor = getConfigFromSettings("global",
  190. "close_before_external_editor").toBool();
  191. m_stylesToInlineWhenCopied = getConfigFromSettings("web",
  192. "styles_to_inline_when_copied").toStringList().join(",");
  193. m_singleClickClosePreviousTab = getConfigFromSettings("global",
  194. "single_click_close_previous_tab").toBool();
  195. m_enableFlashAnchor = getConfigFromSettings("web",
  196. "enable_flash_anchor").toBool();
  197. m_plantUMLMode = getConfigFromSettings("global", "plantuml_mode").toInt();
  198. m_plantUMLServer = getConfigFromSettings("web", "plantuml_server").toString();
  199. m_plantUMLJar = getConfigFromSettings("web", "plantuml_jar").toString();
  200. QString plantUMLArgs = getConfigFromSettings("web", "plantuml_args").toString();
  201. m_plantUMLArgs = VUtils::parseCombinedArgString(plantUMLArgs);
  202. m_plantUMLCmd = getConfigFromSettings("web", "plantuml_cmd").toString();
  203. m_enableGraphviz = getConfigFromSettings("global", "enable_graphviz").toBool();
  204. m_graphvizDot = getConfigFromSettings("web", "graphviz_dot").toString();
  205. m_historySize = getConfigFromSettings("global", "history_size").toInt();
  206. if (m_historySize < 0) {
  207. m_historySize = 0;
  208. }
  209. m_outlineExpandedLevel = getConfigFromSettings("global",
  210. "outline_expanded_level").toInt();
  211. m_imageNamePrefix = getConfigFromSettings("global",
  212. "image_name_prefix").toString();
  213. m_panelViewState = getConfigFromSettings("global",
  214. "panel_view_state").toInt();
  215. m_maxTagLabelLength = getConfigFromSettings("global",
  216. "max_tag_label_length").toInt();
  217. m_maxNumOfTagLabels = getConfigFromSettings("global",
  218. "max_num_of_tag_labels").toInt();
  219. m_smartLivePreview = getConfigFromSettings("global",
  220. "smart_live_preview").toInt();
  221. m_multipleKeyboardLayout = getConfigFromSettings("global",
  222. "multiple_keyboard_layout").toBool();
  223. m_insertNewNoteInFront = getConfigFromSettings("global",
  224. "insert_new_note_in_front").toBool();
  225. initEditorConfigs();
  226. }
  227. void VConfigManager::initEditorConfigs()
  228. {
  229. m_autoIndent = getConfigFromSettings("editor", "auto_indent").toBool();
  230. m_autoList = getConfigFromSettings("editor", "auto_list").toBool();
  231. m_autoQuote = getConfigFromSettings("editor", "auto_quote").toBool();
  232. int keyMode = getConfigFromSettings("editor", "key_mode").toInt();
  233. if (keyMode < 0 || keyMode >= (int)KeyMode::Invalid) {
  234. keyMode = 0;
  235. }
  236. m_keyMode = (KeyMode)keyMode;
  237. m_enableSmartImInVimMode = getConfigFromSettings("editor",
  238. "enable_smart_im_in_vim_mode").toBool();
  239. QString tmpLeader = getConfigFromSettings("editor",
  240. "vim_leader_key").toString();
  241. if (tmpLeader.isEmpty()) {
  242. m_vimLeaderKey = QChar(' ');
  243. } else {
  244. m_vimLeaderKey = tmpLeader[0];
  245. if (m_vimLeaderKey.isNull()) {
  246. m_vimLeaderKey = QChar(' ');
  247. }
  248. }
  249. }
  250. void VConfigManager::initSettings()
  251. {
  252. Q_ASSERT(!userSettings && !defaultSettings && !m_sessionSettings);
  253. const char *codecForIni = "UTF-8";
  254. // vnote.ini.
  255. // First try to read vnote.ini from the directory of the executable.
  256. QString userIniPath = QDir(QCoreApplication::applicationDirPath()).filePath(c_defaultConfigFile);
  257. if (QFileInfo::exists(userIniPath)) {
  258. userSettings = new QSettings(userIniPath,
  259. QSettings::IniFormat,
  260. this);
  261. } else {
  262. userSettings = new QSettings(QSettings::IniFormat,
  263. QSettings::UserScope,
  264. orgName,
  265. appName,
  266. this);
  267. }
  268. userSettings->setIniCodec(codecForIni);
  269. qDebug() << "use user config" << userSettings->fileName();
  270. // Default vnote.ini from resource file.
  271. defaultSettings = new QSettings(c_defaultConfigFilePath, QSettings::IniFormat, this);
  272. defaultSettings->setIniCodec(codecForIni);
  273. // session.ini.
  274. m_sessionSettings = new QSettings(QDir(getConfigFolder()).filePath(c_sessionConfigFile),
  275. QSettings::IniFormat,
  276. this);
  277. m_sessionSettings->setIniCodec(codecForIni);
  278. }
  279. void VConfigManager::initFromSessionSettings()
  280. {
  281. curNotebookIndex = getConfigFromSessionSettings("global", "current_notebook").toInt();
  282. }
  283. void VConfigManager::readCustomColors()
  284. {
  285. m_customColors.clear();
  286. QStringList str = getConfigFromSettings("global", "custom_colors").toStringList();
  287. for (auto const & item : str) {
  288. QStringList parts = item.split(':', QString::SkipEmptyParts);
  289. if (parts.size() != 2) {
  290. continue;
  291. }
  292. if (!QColor(parts[1]).isValid()) {
  293. continue;
  294. }
  295. VColor color;
  296. color.m_name = parts[0];
  297. color.m_color = parts[1];
  298. m_customColors.append(color);
  299. }
  300. }
  301. void VConfigManager::readNotebookFromSettings(QSettings *p_settings,
  302. QVector<VNotebook *> &p_notebooks,
  303. QObject *parent)
  304. {
  305. Q_ASSERT(p_notebooks.isEmpty());
  306. int size = p_settings->beginReadArray("notebooks");
  307. for (int i = 0; i < size; ++i) {
  308. p_settings->setArrayIndex(i);
  309. QString name = p_settings->value("name").toString();
  310. QString path = p_settings->value("path").toString();
  311. VNotebook *notebook = new VNotebook(name, path, parent);
  312. notebook->readConfigNotebook();
  313. p_notebooks.append(notebook);
  314. }
  315. p_settings->endArray();
  316. qDebug() << "read" << p_notebooks.size()
  317. << "notebook items from [notebooks] section";
  318. }
  319. void VConfigManager::writeNotebookToSettings(QSettings *p_settings,
  320. const QVector<VNotebook *> &p_notebooks)
  321. {
  322. // Clear it first
  323. p_settings->beginGroup("notebooks");
  324. p_settings->remove("");
  325. p_settings->endGroup();
  326. p_settings->beginWriteArray("notebooks");
  327. for (int i = 0; i < p_notebooks.size(); ++i) {
  328. p_settings->setArrayIndex(i);
  329. const VNotebook &notebook = *p_notebooks[i];
  330. p_settings->setValue("name", notebook.getName());
  331. p_settings->setValue("path", notebook.getPathInConfig());
  332. }
  333. p_settings->endArray();
  334. qDebug() << "write" << p_notebooks.size()
  335. << "notebook items in [notebooks] section";
  336. }
  337. static QVariant getConfigFromSettingsBySectionKey(const QSettings *p_settings,
  338. const QString &p_section,
  339. const QString &p_key)
  340. {
  341. QString fullKey = p_section + "/" + p_key;
  342. return p_settings->value(fullKey);
  343. }
  344. static void setConfigToSettingsBySectionKey(QSettings *p_settings,
  345. const QString &p_section,
  346. const QString &p_key,
  347. const QVariant &p_value)
  348. {
  349. QString fullKey = p_section + "/" + p_key;
  350. return p_settings->setValue(fullKey, p_value);
  351. }
  352. QVariant VConfigManager::getConfigFromSettings(const QString &section, const QString &key) const
  353. {
  354. // First, look up the user-scoped config file
  355. QVariant value = getConfigFromSettingsBySectionKey(userSettings, section, key);
  356. if (!value.isNull()) {
  357. qDebug() << "user config:" << (section + "/" + key) << value;
  358. return value;
  359. }
  360. // Second, look up the default config file
  361. return getDefaultConfig(section, key);
  362. }
  363. void VConfigManager::setConfigToSettings(const QString &section, const QString &key, const QVariant &value)
  364. {
  365. if (m_hasReset) {
  366. return;
  367. }
  368. // Set the user-scoped config file
  369. setConfigToSettingsBySectionKey(userSettings, section, key, value);
  370. qDebug() << "set user config:" << (section + "/" + key) << value;
  371. }
  372. QVariant VConfigManager::getDefaultConfig(const QString &p_section, const QString &p_key) const
  373. {
  374. QVariant value = getConfigFromSettingsBySectionKey(defaultSettings, p_section, p_key);
  375. qDebug() << "default config:" << (p_section + "/" + p_key) << value;
  376. return value;
  377. }
  378. QVariant VConfigManager::resetDefaultConfig(const QString &p_section, const QString &p_key)
  379. {
  380. QVariant defaultValue = getDefaultConfig(p_section, p_key);
  381. setConfigToSettings(p_section, p_key, defaultValue);
  382. return defaultValue;
  383. }
  384. QVariant VConfigManager::getConfigFromSessionSettings(const QString &p_section,
  385. const QString &p_key) const
  386. {
  387. return getConfigFromSettingsBySectionKey(m_sessionSettings,
  388. p_section,
  389. p_key);
  390. }
  391. void VConfigManager::setConfigToSessionSettings(const QString &p_section,
  392. const QString &p_key,
  393. const QVariant &p_value)
  394. {
  395. if (m_hasReset) {
  396. return;
  397. }
  398. setConfigToSettingsBySectionKey(m_sessionSettings,
  399. p_section,
  400. p_key,
  401. p_value);
  402. }
  403. QJsonObject VConfigManager::readDirectoryConfig(const QString &path)
  404. {
  405. QString configFile = fetchDirConfigFilePath(path);
  406. QFile config(configFile);
  407. if (!config.open(QIODevice::ReadOnly)) {
  408. qWarning() << "fail to read directory configuration file:"
  409. << configFile;
  410. return QJsonObject();
  411. }
  412. QByteArray configData = config.readAll();
  413. return QJsonDocument::fromJson(configData).object();
  414. }
  415. bool VConfigManager::directoryConfigExist(const QString &path)
  416. {
  417. return QFileInfo::exists(fetchDirConfigFilePath(path));
  418. }
  419. bool VConfigManager::writeDirectoryConfig(const QString &path, const QJsonObject &configJson)
  420. {
  421. QString configFile = fetchDirConfigFilePath(path);
  422. QFile config(configFile);
  423. // We use Unix LF for config file.
  424. if (!config.open(QIODevice::WriteOnly)) {
  425. qWarning() << "fail to open directory configuration file for write:"
  426. << configFile;
  427. return false;
  428. }
  429. QJsonDocument configDoc(configJson);
  430. config.write(configDoc.toJson());
  431. return true;
  432. }
  433. bool VConfigManager::deleteDirectoryConfig(const QString &path)
  434. {
  435. QString configFile = fetchDirConfigFilePath(path);
  436. QFile config(configFile);
  437. if (!config.remove()) {
  438. qWarning() << "fail to delete directory configuration file:"
  439. << configFile;
  440. return false;
  441. }
  442. qDebug() << "delete config file:" << configFile;
  443. return true;
  444. }
  445. QString VConfigManager::getLogFilePath() const
  446. {
  447. return QDir(getConfigFolder()).filePath("vnote.log");
  448. }
  449. void VConfigManager::updateMarkdownEditStyle()
  450. {
  451. static const QString defaultColor = "#00897B";
  452. // Read style file .mdhl
  453. QString file(getEditorStyleFile());
  454. qDebug() << "use editor style file" << file;
  455. QString styleStr = VUtils::readFileFromDisk(file);
  456. if (styleStr.isEmpty()) {
  457. return;
  458. }
  459. mdEditPalette = baseEditPalette;
  460. mdEditFont = baseEditFont;
  461. VStyleParser parser;
  462. parser.parseMarkdownStyle(styleStr);
  463. QMap<QString, QMap<QString, QString>> styles;
  464. parser.fetchMarkdownEditorStyles(mdEditPalette, mdEditFont, styles);
  465. mdHighlightingStyles = parser.fetchMarkdownStyles(mdEditFont);
  466. m_codeBlockStyles = parser.fetchCodeBlockStyles(mdEditFont);
  467. m_editorCurrentLineBg = defaultColor;
  468. m_editorVimInsertBg = defaultColor;
  469. m_editorVimNormalBg = defaultColor;
  470. m_editorVimVisualBg = defaultColor;
  471. m_editorVimReplaceBg = defaultColor;
  472. auto editorCurrentLineIt = styles.find("editor-current-line");
  473. if (editorCurrentLineIt != styles.end()) {
  474. auto backgroundIt = editorCurrentLineIt->find("background");
  475. if (backgroundIt != editorCurrentLineIt->end()) {
  476. // Do not need to add "#" here, since this is a built-in attribute.
  477. m_editorCurrentLineBg = *backgroundIt;
  478. }
  479. auto vimBgIt = editorCurrentLineIt->find("vim-insert-background");
  480. if (vimBgIt != editorCurrentLineIt->end()) {
  481. m_editorVimInsertBg = "#" + *vimBgIt;
  482. }
  483. vimBgIt = editorCurrentLineIt->find("vim-normal-background");
  484. if (vimBgIt != editorCurrentLineIt->end()) {
  485. m_editorVimNormalBg = "#" + *vimBgIt;
  486. }
  487. vimBgIt = editorCurrentLineIt->find("vim-visual-background");
  488. if (vimBgIt != editorCurrentLineIt->end()) {
  489. m_editorVimVisualBg = "#" + *vimBgIt;
  490. }
  491. vimBgIt = editorCurrentLineIt->find("vim-replace-background");
  492. if (vimBgIt != editorCurrentLineIt->end()) {
  493. m_editorVimReplaceBg = "#" + *vimBgIt;
  494. }
  495. }
  496. m_editorTrailingSpaceBg = defaultColor;
  497. m_editorSelectedWordFg = defaultColor;
  498. m_editorSelectedWordBg = defaultColor;
  499. m_editorSearchedWordFg = defaultColor;
  500. m_editorSearchedWordBg = defaultColor;
  501. m_editorSearchedWordCursorFg = defaultColor;
  502. m_editorSearchedWordCursorBg = defaultColor;
  503. m_editorIncrementalSearchedWordFg = defaultColor;
  504. m_editorIncrementalSearchedWordBg = defaultColor;
  505. m_editorLineNumberBg = defaultColor;
  506. m_editorLineNumberFg = defaultColor;
  507. m_editorColorColumnBg = defaultColor;
  508. m_editorColorColumnFg = defaultColor;
  509. m_editorPreviewImageLineFg = defaultColor;
  510. m_editorPreviewImageBg.clear();
  511. auto editorIt = styles.find("editor");
  512. if (editorIt != styles.end()) {
  513. auto it = editorIt->find("trailing-space");
  514. if (it != editorIt->end()) {
  515. m_editorTrailingSpaceBg = "#" + *it;
  516. }
  517. it = editorIt->find("line-number-background");
  518. if (it != editorIt->end()) {
  519. m_editorLineNumberBg = "#" + *it;
  520. }
  521. it = editorIt->find("line-number-foreground");
  522. if (it != editorIt->end()) {
  523. m_editorLineNumberFg = "#" + *it;
  524. }
  525. it = editorIt->find("selected-word-foreground");
  526. if (it != editorIt->end()) {
  527. m_editorSelectedWordFg = "#" + *it;
  528. }
  529. it = editorIt->find("selected-word-background");
  530. if (it != editorIt->end()) {
  531. m_editorSelectedWordBg = "#" + *it;
  532. }
  533. it = editorIt->find("searched-word-foreground");
  534. if (it != editorIt->end()) {
  535. m_editorSearchedWordFg = "#" + *it;
  536. }
  537. it = editorIt->find("searched-word-background");
  538. if (it != editorIt->end()) {
  539. m_editorSearchedWordBg = "#" + *it;
  540. }
  541. it = editorIt->find("searched-word-cursor-foreground");
  542. if (it != editorIt->end()) {
  543. m_editorSearchedWordCursorFg = "#" + *it;
  544. }
  545. it = editorIt->find("searched-word-cursor-background");
  546. if (it != editorIt->end()) {
  547. m_editorSearchedWordCursorBg = "#" + *it;
  548. }
  549. it = editorIt->find("incremental-searched-word-foreground");
  550. if (it != editorIt->end()) {
  551. m_editorIncrementalSearchedWordFg = "#" + *it;
  552. }
  553. it = editorIt->find("incremental-searched-word-background");
  554. if (it != editorIt->end()) {
  555. m_editorIncrementalSearchedWordBg = "#" + *it;
  556. }
  557. it = editorIt->find("color-column-background");
  558. if (it != editorIt->end()) {
  559. m_editorColorColumnBg = "#" + *it;
  560. }
  561. it = editorIt->find("color-column-foreground");
  562. if (it != editorIt->end()) {
  563. m_editorColorColumnFg = "#" + *it;
  564. }
  565. it = editorIt->find("preview-image-line-foreground");
  566. if (it != editorIt->end()) {
  567. m_editorPreviewImageLineFg = "#" + *it;
  568. }
  569. it = editorIt->find("preview-image-background");
  570. if (it != editorIt->end()) {
  571. m_editorPreviewImageBg = "#" + *it;
  572. }
  573. }
  574. }
  575. void VConfigManager::updateEditStyle()
  576. {
  577. // Reset font and palette.
  578. baseEditFont = mdEditFont = m_defaultEditFont;
  579. baseEditPalette = mdEditPalette = m_defaultEditPalette;
  580. static const QColor defaultColor = m_defaultEditPalette.color(QPalette::Base);
  581. QColor newColor = defaultColor;
  582. bool force = false;
  583. if (curBackgroundColor != "System") {
  584. for (int i = 0; i < m_customColors.size(); ++i) {
  585. if (m_customColors[i].m_name == curBackgroundColor) {
  586. newColor = QColor(m_customColors[i].m_color);
  587. force = true;
  588. break;
  589. }
  590. }
  591. }
  592. baseEditPalette.setColor(QPalette::Base, newColor);
  593. // Update markdown editor palette
  594. updateMarkdownEditStyle();
  595. // Base editor will use the same font size as the markdown editor by now.
  596. if (mdEditFont.pointSize() > -1) {
  597. baseEditFont.setPointSize(mdEditFont.pointSize());
  598. }
  599. if (force) {
  600. mdEditPalette.setColor(QPalette::Base, newColor);
  601. }
  602. }
  603. void VConfigManager::setWebZoomFactor(qreal p_factor)
  604. {
  605. if (isCustomWebZoomFactor()) {
  606. if (VUtils::realEqual(m_webZoomFactor, p_factor)) {
  607. return;
  608. } else if (VUtils::realEqual(p_factor, -1)) {
  609. m_webZoomFactor = VUtils::calculateScaleFactor();
  610. setConfigToSettings("global", "web_zoom_factor", -1);
  611. return;
  612. }
  613. } else {
  614. if (VUtils::realEqual(p_factor, -1)) {
  615. return;
  616. }
  617. }
  618. m_webZoomFactor = p_factor;
  619. setConfigToSettings("global", "web_zoom_factor", m_webZoomFactor);
  620. }
  621. QString VConfigManager::getConfigFolder() const
  622. {
  623. V_ASSERT(userSettings);
  624. QString iniPath = userSettings->fileName();
  625. return VUtils::basePathFromPath(iniPath);
  626. }
  627. QString VConfigManager::getConfigFilePath() const
  628. {
  629. V_ASSERT(userSettings);
  630. return userSettings->fileName();
  631. }
  632. const QString &VConfigManager::getStyleConfigFolder() const
  633. {
  634. static QString path = QDir(getConfigFolder()).filePath(c_styleConfigFolder);
  635. return path;
  636. }
  637. const QString &VConfigManager::getThemeConfigFolder() const
  638. {
  639. static QString path = QDir(getConfigFolder()).filePath(c_themeConfigFolder);
  640. return path;
  641. }
  642. const QString &VConfigManager::getCodeBlockStyleConfigFolder() const
  643. {
  644. static QString path = QDir(getStyleConfigFolder()).filePath(c_codeBlockStyleConfigFolder);
  645. return path;
  646. }
  647. const QString &VConfigManager::getTemplateConfigFolder() const
  648. {
  649. static QString path = QDir(getConfigFolder()).filePath(c_templateConfigFolder);
  650. return path;
  651. }
  652. const QString &VConfigManager::getSnippetConfigFolder() const
  653. {
  654. static QString path = QDir(getConfigFolder()).filePath(c_snippetConfigFolder);
  655. return path;
  656. }
  657. const QString &VConfigManager::getSnippetConfigFilePath() const
  658. {
  659. static QString path = QDir(getSnippetConfigFolder()).filePath(c_snippetConfigFile);
  660. return path;
  661. }
  662. QString VConfigManager::getThemeFile() const
  663. {
  664. auto it = m_themes.find(m_theme);
  665. if (it != m_themes.end()) {
  666. return it.value();
  667. } else {
  668. qWarning() << "use default theme due to missing specified theme" << m_theme;
  669. const_cast<VConfigManager *>(this)->m_theme = getDefaultConfig("global", "theme").toString();
  670. return m_themes[m_theme];
  671. }
  672. }
  673. QVector<QString> VConfigManager::getNoteTemplates(DocType p_type) const
  674. {
  675. QVector<QString> res;
  676. QDir dir(getTemplateConfigFolder());
  677. if (!dir.exists()) {
  678. dir.mkpath(getTemplateConfigFolder());
  679. return res;
  680. }
  681. dir.setFilter(QDir::Files | QDir::NoSymLinks);
  682. QStringList files = dir.entryList();
  683. res.reserve(files.size());
  684. for (auto const &item : files) {
  685. if (p_type == DocType::Unknown
  686. || p_type == VUtils::docTypeFromName(item)) {
  687. res.push_back(item);
  688. }
  689. }
  690. return res;
  691. }
  692. // The URL will be used in the Web page.
  693. QString VConfigManager::getCssStyleUrl() const
  694. {
  695. Q_ASSERT(!m_themes.isEmpty());
  696. Q_ASSERT(!m_cssStyles.isEmpty());
  697. if (m_cssStyle.isEmpty()) {
  698. // Use theme's style.
  699. const_cast<VConfigManager *>(this)->m_cssStyle = VPalette::themeCssStyle(getThemeFile());
  700. }
  701. QString cssPath = getCssStyleUrl(m_cssStyle);
  702. qDebug() << "use css style file" << cssPath;
  703. return cssPath;
  704. }
  705. QString VConfigManager::getCssStyleUrl(const QString &p_style) const
  706. {
  707. Q_ASSERT(!m_themes.isEmpty());
  708. Q_ASSERT(!m_cssStyles.isEmpty());
  709. if (p_style.isEmpty()) {
  710. return QString();
  711. }
  712. QString cssPath;
  713. auto it = m_cssStyles.find(p_style);
  714. if (it != m_cssStyles.end()) {
  715. cssPath = it.value();
  716. }
  717. if (cssPath.startsWith(":")) {
  718. cssPath = "qrc" + cssPath;
  719. } else {
  720. QUrl cssUrl = QUrl::fromLocalFile(cssPath);
  721. cssPath = cssUrl.toString();
  722. }
  723. return cssPath;
  724. }
  725. QString VConfigManager::getCodeBlockCssStyleUrl() const
  726. {
  727. Q_ASSERT(!m_themes.isEmpty());
  728. Q_ASSERT(!m_codeBlockCssStyles.isEmpty());
  729. if (m_codeBlockCssStyle.isEmpty()) {
  730. // Use theme's style.
  731. const_cast<VConfigManager *>(this)->m_codeBlockCssStyle =
  732. VPalette::themeCodeBlockCssStyle(getThemeFile());
  733. }
  734. QString cssPath = getCodeBlockCssStyleUrl(m_codeBlockCssStyle);
  735. qDebug() << "use code block css style file" << cssPath;
  736. return cssPath;
  737. }
  738. QString VConfigManager::getCodeBlockCssStyleUrl(const QString &p_style) const
  739. {
  740. Q_ASSERT(!m_themes.isEmpty());
  741. Q_ASSERT(!m_codeBlockCssStyles.isEmpty());
  742. if (p_style.isEmpty()) {
  743. return QString();
  744. }
  745. QString cssPath;
  746. auto it = m_codeBlockCssStyles.find(p_style);
  747. if (it != m_codeBlockCssStyles.end()) {
  748. cssPath = it.value();
  749. }
  750. if (cssPath.startsWith(":")) {
  751. cssPath = "qrc" + cssPath;
  752. } else {
  753. QUrl cssUrl = QUrl::fromLocalFile(cssPath);
  754. cssPath = cssUrl.toString();
  755. }
  756. return cssPath;
  757. }
  758. QString VConfigManager::getMermaidCssStyleUrl() const
  759. {
  760. Q_ASSERT(!m_themes.isEmpty());
  761. Q_ASSERT(!m_theme.isEmpty());
  762. static QString mermaidCssPath;
  763. if (mermaidCssPath.isEmpty()) {
  764. VPaletteMetaData data = VPalette::getPaletteMetaData(getThemeFile());
  765. mermaidCssPath = data.m_mermaidCssFile;
  766. if (mermaidCssPath.startsWith(":")) {
  767. mermaidCssPath = "qrc" + mermaidCssPath;
  768. } else {
  769. QUrl cssUrl = QUrl::fromLocalFile(mermaidCssPath);
  770. mermaidCssPath = cssUrl.toString();
  771. }
  772. qDebug() << "use mermaid css style file" << mermaidCssPath;
  773. }
  774. return mermaidCssPath;
  775. }
  776. QString VConfigManager::getEditorStyleFile() const
  777. {
  778. Q_ASSERT(!m_themes.isEmpty());
  779. Q_ASSERT(!m_editorStyles.isEmpty());
  780. if (m_editorStyle.isEmpty()) {
  781. // Use theme's style.
  782. const_cast<VConfigManager *>(this)->m_editorStyle = VPalette::themeEditorStyle(getThemeFile());
  783. }
  784. auto it = m_editorStyles.find(m_editorStyle);
  785. if (it != m_editorStyles.end()) {
  786. return it.value();
  787. }
  788. return QString();
  789. }
  790. QString VConfigManager::getVnoteNotebookFolderPath()
  791. {
  792. QStringList folders = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation);
  793. if (folders.isEmpty()) {
  794. return QDir::home().filePath(c_vnoteNotebookFolderName);
  795. } else {
  796. return QDir(folders[0]).filePath(c_vnoteNotebookFolderName);
  797. }
  798. }
  799. QString VConfigManager::getExportFolderPath()
  800. {
  801. QStringList folders = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation);
  802. if (folders.isEmpty()) {
  803. return QDir::home().filePath(c_exportFolderName);
  804. } else {
  805. return QDir(folders[0]).filePath(c_exportFolderName);
  806. }
  807. }
  808. QString VConfigManager::getDocumentPathOrHomePath()
  809. {
  810. QStringList folders = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation);
  811. if (folders.isEmpty()) {
  812. return QDir::homePath();
  813. } else {
  814. return folders[0];
  815. }
  816. }
  817. QHash<QString, QString> VConfigManager::readShortcutsFromSettings(QSettings *p_settings,
  818. const QString &p_group)
  819. {
  820. QHash<QString, QString> ret;
  821. p_settings->beginGroup(p_group);
  822. QStringList keys = p_settings->childKeys();
  823. for (auto const & key : keys) {
  824. if (key.isEmpty()) {
  825. continue;
  826. }
  827. QVariant varVal = p_settings->value(key);
  828. QString sequence = varVal.toString();
  829. if (varVal.type() == QVariant::StringList) {
  830. sequence = varVal.toStringList().join(",");
  831. }
  832. sequence = sequence.trimmed();
  833. if (isValidKeySequence(sequence)) {
  834. ret.insert(key, sequence);
  835. }
  836. }
  837. p_settings->endGroup();
  838. return ret;
  839. }
  840. bool VConfigManager::isValidKeySequence(const QString &p_seq)
  841. {
  842. return p_seq.isEmpty()
  843. || (p_seq.toLower() != "ctrl+q" && !QKeySequence(p_seq).isEmpty());
  844. }
  845. void VConfigManager::readShortcutsFromSettings()
  846. {
  847. const QString group("shortcuts");
  848. m_shortcuts.clear();
  849. m_shortcuts = readShortcutsFromSettings(defaultSettings, group);
  850. // Update default settings according to user settings.
  851. QHash<QString, QString> userShortcuts = readShortcutsFromSettings(userSettings,
  852. group);
  853. QSet<QString> matched;
  854. matched.reserve(m_shortcuts.size());
  855. for (auto it = userShortcuts.begin(); it != userShortcuts.end(); ++it) {
  856. auto defaultIt = m_shortcuts.find(it.key());
  857. if (defaultIt != m_shortcuts.end()) {
  858. QString sequence = it.value().trimmed();
  859. if (sequence != defaultIt.value()) {
  860. if (isValidKeySequence(sequence)) {
  861. matched.insert(it.key());
  862. *defaultIt = sequence;
  863. }
  864. } else {
  865. matched.insert(it.key());
  866. }
  867. }
  868. }
  869. if (matched.size() < m_shortcuts.size()) {
  870. qDebug() << "override user shortcuts settings using default settings";
  871. writeShortcutsToSettings(userSettings, group, m_shortcuts);
  872. }
  873. }
  874. void VConfigManager::readCaptainShortcutsFromSettings()
  875. {
  876. const QString group("captain_mode_shortcuts");
  877. m_captainShortcuts.clear();
  878. m_captainShortcuts = readShortcutsFromSettings(defaultSettings, group);
  879. // Update default settings according to user settings.
  880. QHash<QString, QString> userShortcuts = readShortcutsFromSettings(userSettings,
  881. group);
  882. QSet<QString> matched;
  883. matched.reserve(m_captainShortcuts.size());
  884. for (auto it = userShortcuts.begin(); it != userShortcuts.end(); ++it) {
  885. auto defaultIt = m_captainShortcuts.find(it.key());
  886. if (defaultIt != m_captainShortcuts.end()) {
  887. QString sequence = it.value().trimmed();
  888. if (sequence != defaultIt.value()) {
  889. if (isValidKeySequence(sequence)) {
  890. matched.insert(it.key());
  891. *defaultIt = sequence;
  892. }
  893. } else {
  894. matched.insert(it.key());
  895. }
  896. }
  897. }
  898. if (matched.size() < m_captainShortcuts.size()) {
  899. writeShortcutsToSettings(userSettings, group, m_captainShortcuts);
  900. }
  901. qDebug() << "captain mode shortcuts:" << m_captainShortcuts;
  902. }
  903. void VConfigManager::writeShortcutsToSettings(QSettings *p_settings,
  904. const QString &p_group,
  905. const QHash<QString, QString> &p_shortcuts)
  906. {
  907. p_settings->beginGroup(p_group);
  908. p_settings->remove("");
  909. for (auto it = p_shortcuts.begin(); it != p_shortcuts.end(); ++it) {
  910. p_settings->setValue(it.key(), it.value());
  911. }
  912. p_settings->endGroup();
  913. }
  914. QString VConfigManager::getShortcutKeySequence(const QString &p_operation) const
  915. {
  916. auto it = m_shortcuts.find(p_operation);
  917. if (it == m_shortcuts.end()) {
  918. return QString();
  919. }
  920. return *it;
  921. }
  922. QString VConfigManager::getCaptainShortcutKeySequence(const QString &p_operation) const
  923. {
  924. auto it = m_captainShortcuts.find(p_operation);
  925. if (it == m_captainShortcuts.end()) {
  926. return QString();
  927. }
  928. return *it;
  929. }
  930. void VConfigManager::initDocSuffixes()
  931. {
  932. m_docSuffixes.clear();
  933. QStringList mdSuffix = getConfigFromSettings("global",
  934. "markdown_suffix").toStringList();
  935. if (mdSuffix.isEmpty()) {
  936. mdSuffix = getDefaultConfig("global",
  937. "markdown_suffix").toStringList();
  938. }
  939. for (auto it = mdSuffix.begin(); it != mdSuffix.end();) {
  940. if (it->isEmpty()) {
  941. it = mdSuffix.erase(it);
  942. } else {
  943. *it = it->toLower();
  944. ++it;
  945. }
  946. }
  947. Q_ASSERT(!mdSuffix.isEmpty());
  948. mdSuffix.removeDuplicates();
  949. m_docSuffixes[(int)DocType::Markdown] = mdSuffix;
  950. QList<QString> list;
  951. list << "ls" << "list";
  952. m_docSuffixes[(int)DocType::List] = list;
  953. QList<QString> container;
  954. container << "co" << "container" << "con";
  955. m_docSuffixes[(int)DocType::Container] = container;
  956. QList<QString> html;
  957. html << "html";
  958. m_docSuffixes[(int)DocType::Html] = html;
  959. qDebug() << "doc suffixes" << m_docSuffixes;
  960. }
  961. QVector<VFileSessionInfo> VConfigManager::getLastOpenedFiles()
  962. {
  963. QVector<VFileSessionInfo> files;
  964. int size = m_sessionSettings->beginReadArray("last_opened_files");
  965. for (int i = 0; i < size; ++i) {
  966. m_sessionSettings->setArrayIndex(i);
  967. files.push_back(VFileSessionInfo::fromSettings(m_sessionSettings));
  968. }
  969. m_sessionSettings->endArray();
  970. qDebug() << "read" << files.size()
  971. << "items from [last_opened_files] section";
  972. return files;
  973. }
  974. void VConfigManager::setLastOpenedFiles(const QVector<VFileSessionInfo> &p_files)
  975. {
  976. if (m_hasReset) {
  977. return;
  978. }
  979. const QString section("last_opened_files");
  980. // Clear it first
  981. m_sessionSettings->beginGroup(section);
  982. m_sessionSettings->remove("");
  983. m_sessionSettings->endGroup();
  984. m_sessionSettings->beginWriteArray(section);
  985. for (int i = 0; i < p_files.size(); ++i) {
  986. m_sessionSettings->setArrayIndex(i);
  987. const VFileSessionInfo &info = p_files[i];
  988. info.toSettings(m_sessionSettings);
  989. }
  990. m_sessionSettings->endArray();
  991. }
  992. void VConfigManager::getHistory(QLinkedList<VHistoryEntry> &p_history) const
  993. {
  994. p_history.clear();
  995. int size = m_sessionSettings->beginReadArray("history");
  996. for (int i = 0; i < size; ++i) {
  997. m_sessionSettings->setArrayIndex(i);
  998. p_history.append(VHistoryEntry::fromSettings(m_sessionSettings));
  999. }
  1000. m_sessionSettings->endArray();
  1001. }
  1002. void VConfigManager::setHistory(const QLinkedList<VHistoryEntry> &p_history)
  1003. {
  1004. if (m_hasReset) {
  1005. return;
  1006. }
  1007. const QString section("history");
  1008. // Clear it first
  1009. m_sessionSettings->beginGroup(section);
  1010. m_sessionSettings->remove("");
  1011. m_sessionSettings->endGroup();
  1012. m_sessionSettings->beginWriteArray(section);
  1013. int i = 0;
  1014. for (auto it = p_history.begin(); it != p_history.end(); ++it, ++i) {
  1015. m_sessionSettings->setArrayIndex(i);
  1016. it->toSettings(m_sessionSettings);
  1017. }
  1018. m_sessionSettings->endArray();
  1019. }
  1020. void VConfigManager::getExplorerEntries(QVector<VExplorerEntry> &p_entries) const
  1021. {
  1022. p_entries.clear();
  1023. int size = m_sessionSettings->beginReadArray("explorer_starred");
  1024. for (int i = 0; i < size; ++i) {
  1025. m_sessionSettings->setArrayIndex(i);
  1026. p_entries.append(VExplorerEntry::fromSettings(m_sessionSettings));
  1027. }
  1028. m_sessionSettings->endArray();
  1029. }
  1030. void VConfigManager::setExplorerEntries(const QVector<VExplorerEntry> &p_entries)
  1031. {
  1032. if (m_hasReset) {
  1033. return;
  1034. }
  1035. const QString section("explorer_starred");
  1036. // Clear it first
  1037. m_sessionSettings->beginGroup(section);
  1038. m_sessionSettings->remove("");
  1039. m_sessionSettings->endGroup();
  1040. m_sessionSettings->beginWriteArray(section);
  1041. int idx = 0;
  1042. for (auto const & entry : p_entries) {
  1043. if (entry.m_isStarred) {
  1044. m_sessionSettings->setArrayIndex(idx);
  1045. entry.toSettings(m_sessionSettings);
  1046. ++idx;
  1047. }
  1048. }
  1049. m_sessionSettings->endArray();
  1050. }
  1051. QVector<VMagicWord> VConfigManager::getCustomMagicWords()
  1052. {
  1053. QVector<VMagicWord> words;
  1054. int size = userSettings->beginReadArray("magic_words");
  1055. for (int i = 0; i < size; ++i) {
  1056. userSettings->setArrayIndex(i);
  1057. VMagicWord word;
  1058. word.m_name = userSettings->value("name").toString();
  1059. word.m_definition = userSettings->value("definition").toString();
  1060. words.push_back(word);
  1061. }
  1062. userSettings->endArray();
  1063. return words;
  1064. }
  1065. QVector<VExternalEditor> VConfigManager::getExternalEditors() const
  1066. {
  1067. QVector<VExternalEditor> ret;
  1068. userSettings->beginGroup("external_editors");
  1069. QStringList keys = userSettings->childKeys();
  1070. for (auto const & key : keys) {
  1071. if (key.isEmpty()) {
  1072. continue;
  1073. }
  1074. QStringList val = userSettings->value(key).toStringList();
  1075. if (val.size() > 2
  1076. || val.isEmpty()) {
  1077. continue;
  1078. }
  1079. VExternalEditor editor;
  1080. editor.m_name = key;
  1081. editor.m_cmd = val[0].trimmed();
  1082. if (editor.m_cmd.isEmpty()) {
  1083. continue;
  1084. }
  1085. if (val.size() == 2) {
  1086. editor.m_shortcut = val[1].trimmed();
  1087. }
  1088. ret.push_back(editor);
  1089. }
  1090. userSettings->endGroup();
  1091. return ret;
  1092. }
  1093. const QString &VConfigManager::getFlashPage() const
  1094. {
  1095. if (m_flashPage.isEmpty()) {
  1096. VConfigManager *var = const_cast<VConfigManager *>(this);
  1097. var->m_flashPage = var->getConfigFromSettings("global",
  1098. "flash_page").toString();
  1099. if (var->m_flashPage.isEmpty()) {
  1100. var->m_flashPage = var->resetDefaultConfig("global", "flash_page").toString();
  1101. }
  1102. if (VUtils::checkFileNameLegal(m_flashPage)) {
  1103. var->m_flashPage = QDir(getConfigFolder()).filePath(m_flashPage);
  1104. }
  1105. }
  1106. if (!QFileInfo::exists(m_flashPage)) {
  1107. VUtils::touchFile(m_flashPage);
  1108. }
  1109. return m_flashPage;
  1110. }
  1111. void VConfigManager::initThemes()
  1112. {
  1113. m_themes.clear();
  1114. // Built-in.
  1115. QString file(":/resources/themes/v_native/v_native.palette");
  1116. m_themes.insert(VPalette::themeName(file), file);
  1117. file = ":/resources/themes/v_pure/v_pure.palette";
  1118. m_themes.insert(VPalette::themeName(file), file);
  1119. file = ":/resources/themes/v_moonlight/v_moonlight.palette";
  1120. m_themes.insert(VPalette::themeName(file), file);
  1121. file = ":/resources/themes/v_detorte/v_detorte.palette";
  1122. m_themes.insert(VPalette::themeName(file), file);
  1123. outputBuiltInThemes();
  1124. // User theme folder.
  1125. QDir dir(getThemeConfigFolder());
  1126. Q_ASSERT(dir.exists());
  1127. if (!dir.exists()) {
  1128. dir.mkpath(getThemeConfigFolder());
  1129. return;
  1130. }
  1131. dir.setFilter(QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks);
  1132. QStringList dirs = dir.entryList();
  1133. for (auto const &item : dirs) {
  1134. QDir themeDir(dir.filePath(item));
  1135. QStringList files = themeDir.entryList(QStringList() << "*.palette");
  1136. if (files.size() != 1) {
  1137. continue;
  1138. }
  1139. QFileInfo fi(files[0]);
  1140. m_themes.insert(VPalette::themeName(files[0]), themeDir.filePath(files[0]));
  1141. }
  1142. }
  1143. void VConfigManager::outputBuiltInThemes()
  1144. {
  1145. QDir dir(getThemeConfigFolder());
  1146. if (!dir.exists()) {
  1147. dir.mkpath(getThemeConfigFolder());
  1148. }
  1149. QStringList suffix({"*.palette"});
  1150. for (auto it = m_themes.begin(); it != m_themes.end(); ++it) {
  1151. QString file = it.value();
  1152. QString srcDir = VUtils::basePathFromPath(file);
  1153. QString folder = VUtils::directoryNameFromPath(srcDir);
  1154. bool needOutput = false;
  1155. if (dir.exists(folder)) {
  1156. QString folderPath = dir.filePath(folder);
  1157. QDir tmpDir(folderPath);
  1158. QStringList files = tmpDir.entryList(suffix);
  1159. if (files.size() == 1) {
  1160. int newVer = VPalette::getPaletteVersion(file);
  1161. int curVer = VPalette::getPaletteVersion(tmpDir.filePath(files[0]));
  1162. if (newVer != curVer) {
  1163. needOutput = true;
  1164. }
  1165. } else {
  1166. needOutput = true;
  1167. }
  1168. if (needOutput) {
  1169. // Delete the folder.
  1170. bool ret = VUtils::deleteDirectory(folderPath);
  1171. VUtils::sleepWait(100);
  1172. Q_UNUSED(ret);
  1173. qDebug() << "delete obsolete theme" << folderPath << ret;
  1174. }
  1175. } else {
  1176. needOutput = true;
  1177. }
  1178. if (needOutput) {
  1179. qDebug() << "output built-in theme" << file << folder;
  1180. VUtils::copyDirectory(srcDir, dir.filePath(folder), false);
  1181. }
  1182. }
  1183. }
  1184. void VConfigManager::initEditorStyles()
  1185. {
  1186. Q_ASSERT(!m_themes.isEmpty());
  1187. // Styles from themes.
  1188. m_editorStyles = VPalette::editorStylesFromThemes(m_themes.values());
  1189. // User style folder.
  1190. // Get all the .mdhl files in the folder.
  1191. QDir dir(getStyleConfigFolder());
  1192. if (!dir.exists()) {
  1193. dir.mkpath(getStyleConfigFolder());
  1194. return;
  1195. }
  1196. dir.setFilter(QDir::Files | QDir::NoSymLinks);
  1197. dir.setNameFilters(QStringList("*.mdhl"));
  1198. QStringList files = dir.entryList();
  1199. for (auto const &item : files) {
  1200. QFileInfo fi(item);
  1201. m_editorStyles.insert(fi.completeBaseName(), dir.filePath(item));
  1202. }
  1203. }
  1204. void VConfigManager::initCssStyles()
  1205. {
  1206. Q_ASSERT(!m_themes.isEmpty());
  1207. // Styles from themes.
  1208. m_cssStyles = VPalette::cssStylesFromThemes(m_themes.values());
  1209. // User style folder.
  1210. // Get all the .css files in the folder.
  1211. QDir dir(getStyleConfigFolder());
  1212. if (!dir.exists()) {
  1213. dir.mkpath(getStyleConfigFolder());
  1214. return;
  1215. }
  1216. dir.setFilter(QDir::Files | QDir::NoSymLinks);
  1217. dir.setNameFilters(QStringList("*.css"));
  1218. QStringList files = dir.entryList();
  1219. for (auto const &item : files) {
  1220. QFileInfo fi(item);
  1221. m_cssStyles.insert(fi.completeBaseName(), dir.filePath(item));
  1222. }
  1223. }
  1224. void VConfigManager::initCodeBlockCssStyles()
  1225. {
  1226. Q_ASSERT(!m_themes.isEmpty());
  1227. // Styles from themes.
  1228. m_codeBlockCssStyles = VPalette::codeBlockCssStylesFromThemes(m_themes.values());
  1229. // User style folder.
  1230. // Get all the .css files in the folder.
  1231. QDir dir(getCodeBlockStyleConfigFolder());
  1232. if (!dir.exists()) {
  1233. dir.mkpath(getCodeBlockStyleConfigFolder());
  1234. return;
  1235. }
  1236. dir.setFilter(QDir::Files | QDir::NoSymLinks);
  1237. dir.setNameFilters(QStringList("*.css"));
  1238. QStringList files = dir.entryList();
  1239. for (auto const &item : files) {
  1240. QFileInfo fi(item);
  1241. m_codeBlockCssStyles.insert(fi.completeBaseName(), dir.filePath(item));
  1242. }
  1243. }
  1244. void VConfigManager::resetConfigurations()
  1245. {
  1246. // Clear userSettings.
  1247. userSettings->clear();
  1248. // Clear m_sessionSettings except the notebooks information.
  1249. clearGroupOfSettings(m_sessionSettings, "last_opened_files");
  1250. clearGroupOfSettings(m_sessionSettings, "geometry");
  1251. m_hasReset = true;
  1252. }
  1253. void VConfigManager::resetLayoutConfigurations()
  1254. {
  1255. resetDefaultConfig("global", "tools_dock_checked");
  1256. resetDefaultConfig("global", "search_dock_checked");
  1257. resetDefaultConfig("global", "menu_bar_checked");
  1258. clearGroupOfSettings(m_sessionSettings, "geometry");
  1259. m_hasReset = true;
  1260. }
  1261. void VConfigManager::clearGroupOfSettings(QSettings *p_settings, const QString &p_group)
  1262. {
  1263. p_settings->beginGroup(p_group);
  1264. p_settings->remove("");
  1265. p_settings->endGroup();
  1266. }
  1267. QString VConfigManager::getRenderBackgroundColor(const QString &p_bgName) const
  1268. {
  1269. if (p_bgName == "Transparent") {
  1270. return "transparent";
  1271. } else if (p_bgName != "System") {
  1272. for (int i = 0; i < m_customColors.size(); ++i) {
  1273. if (m_customColors[i].m_name == p_bgName) {
  1274. return m_customColors[i].m_color;
  1275. }
  1276. }
  1277. }
  1278. return QString();
  1279. }