vconfigmanager.cpp 48 KB

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