markdowneditorpage.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  1. #include "markdowneditorpage.h"
  2. #include <QFormLayout>
  3. #include <QVBoxLayout>
  4. #include <QCheckBox>
  5. #include <QGroupBox>
  6. #include <QDoubleSpinBox>
  7. #include <QComboBox>
  8. #include <QSpinBox>
  9. #include <QHBoxLayout>
  10. #include <QPushButton>
  11. #include <QFileDialog>
  12. #include <QFontComboBox>
  13. #include <QFont>
  14. #include <widgets/widgetsfactory.h>
  15. #include <core/editorconfig.h>
  16. #include <core/markdowneditorconfig.h>
  17. #include <core/configmgr.h>
  18. #include <utils/widgetutils.h>
  19. #include "editorpage.h"
  20. #include <widgets/locationinputwithbrowsebutton.h>
  21. #include <widgets/messageboxhelper.h>
  22. #include <widgets/editors/plantumlhelper.h>
  23. #include <widgets/editors/graphvizhelper.h>
  24. using namespace vnotex;
  25. MarkdownEditorPage::MarkdownEditorPage(QWidget *p_parent)
  26. : SettingsPage(p_parent)
  27. {
  28. setupUI();
  29. }
  30. void MarkdownEditorPage::setupUI()
  31. {
  32. auto mainLayout = new QVBoxLayout(this);
  33. auto generalBox = setupGeneralGroup();
  34. mainLayout->addWidget(generalBox);
  35. auto readBox = setupReadGroup();
  36. mainLayout->addWidget(readBox);
  37. auto editBox = setupEditGroup();
  38. mainLayout->addWidget(editBox);
  39. }
  40. void MarkdownEditorPage::loadInternal()
  41. {
  42. const auto &markdownConfig = ConfigMgr::getInst().getEditorConfig().getMarkdownEditorConfig();
  43. m_insertFileNameAsTitleCheckBox->setChecked(markdownConfig.getInsertFileNameAsTitle());
  44. {
  45. int idx = m_sectionNumberComboBox->findData(static_cast<int>(markdownConfig.getSectionNumberMode()));
  46. Q_ASSERT(idx != -1);
  47. m_sectionNumberComboBox->setCurrentIndex(idx);
  48. m_sectionNumberBaseLevelSpinBox->setValue(markdownConfig.getSectionNumberBaseLevel());
  49. idx = m_sectionNumberStyleComboBox->findData(static_cast<int>(markdownConfig.getSectionNumberStyle()));
  50. Q_ASSERT(idx != -1);
  51. m_sectionNumberStyleComboBox->setCurrentIndex(idx);
  52. }
  53. m_constrainImageWidthCheckBox->setChecked(markdownConfig.getConstrainImageWidthEnabled());
  54. m_imageAlignCenterCheckBox->setChecked(markdownConfig.getImageAlignCenterEnabled());
  55. m_zoomFactorSpinBox->setValue(markdownConfig.getZoomFactorInReadMode());
  56. m_constrainInplacePreviewWidthCheckBox->setChecked(markdownConfig.getConstrainInplacePreviewWidthEnabled());
  57. {
  58. auto srcs = markdownConfig.getInplacePreviewSources();
  59. m_inplacePreviewSourceImageLinkCheckBox->setChecked(srcs & MarkdownEditorConfig::InplacePreviewSource::ImageLink);
  60. m_inplacePreviewSourceCodeBlockCheckBox->setChecked(srcs & MarkdownEditorConfig::InplacePreviewSource::CodeBlock);
  61. m_inplacePreviewSourceMathCheckBox->setChecked(srcs & MarkdownEditorConfig::InplacePreviewSource::Math);
  62. }
  63. m_fetchImagesToLocalCheckBox->setChecked(markdownConfig.getFetchImagesInParseAndPaste());
  64. m_htmlTagCheckBox->setChecked(markdownConfig.getHtmlTagEnabled());
  65. m_autoBreakCheckBox->setChecked(markdownConfig.getAutoBreakEnabled());
  66. m_linkifyCheckBox->setChecked(markdownConfig.getLinkifyEnabled());
  67. m_indentFirstLineCheckBox->setChecked(markdownConfig.getIndentFirstLineEnabled());
  68. m_smartTableCheckBox->setChecked(markdownConfig.getSmartTableEnabled());
  69. m_spellCheckCheckBox->setChecked(markdownConfig.isSpellCheckEnabled());
  70. {
  71. int idx = m_plantUmlModeComboBox->findData(markdownConfig.getWebPlantUml() ? 0 : 1);
  72. m_plantUmlModeComboBox->setCurrentIndex(idx);
  73. }
  74. m_plantUmlJarFileInput->setText(markdownConfig.getPlantUmlJar());
  75. {
  76. int idx = m_graphvizModeComboBox->findData(markdownConfig.getWebGraphviz() ? 0 : 1);
  77. m_graphvizModeComboBox->setCurrentIndex(idx);
  78. }
  79. m_graphvizFileInput->setText(markdownConfig.getGraphvizExe());
  80. {
  81. const auto &fontFamily = markdownConfig.getEditorOverriddenFontFamily();
  82. m_editorOverriddenFontFamilyCheckBox->setChecked(!fontFamily.isEmpty());
  83. if (!fontFamily.isEmpty()) {
  84. QFont font;
  85. font.setFamily(fontFamily);
  86. m_editorOverriddenFontFamilyComboBox->setCurrentFont(font);
  87. }
  88. }
  89. }
  90. bool MarkdownEditorPage::saveInternal()
  91. {
  92. auto &markdownConfig = ConfigMgr::getInst().getEditorConfig().getMarkdownEditorConfig();
  93. markdownConfig.setInsertFileNameAsTitle(m_insertFileNameAsTitleCheckBox->isChecked());
  94. {
  95. auto mode = m_sectionNumberComboBox->currentData().toInt();
  96. markdownConfig.setSectionNumberMode(static_cast<MarkdownEditorConfig::SectionNumberMode>(mode));
  97. if (m_sectionNumberBaseLevelSpinBox->isEnabled()) {
  98. markdownConfig.setSectionNumberBaseLevel(m_sectionNumberBaseLevelSpinBox->value());
  99. }
  100. if (m_sectionNumberStyleComboBox->isEnabled()) {
  101. auto style = m_sectionNumberStyleComboBox->currentData().toInt();
  102. markdownConfig.setSectionNumberStyle(static_cast<MarkdownEditorConfig::SectionNumberStyle>(style));
  103. }
  104. }
  105. markdownConfig.setConstrainImageWidthEnabled(m_constrainImageWidthCheckBox->isChecked());
  106. markdownConfig.setImageAlignCenterEnabled(m_imageAlignCenterCheckBox->isChecked());
  107. markdownConfig.setZoomFactorInReadMode(m_zoomFactorSpinBox->value());
  108. markdownConfig.setConstrainInplacePreviewWidthEnabled(m_constrainInplacePreviewWidthCheckBox->isChecked());
  109. {
  110. MarkdownEditorConfig::InplacePreviewSources srcs = MarkdownEditorConfig::InplacePreviewSource::NoInplacePreview;
  111. if (m_inplacePreviewSourceImageLinkCheckBox->isChecked()) {
  112. srcs |= MarkdownEditorConfig::InplacePreviewSource::ImageLink;
  113. }
  114. if (m_inplacePreviewSourceCodeBlockCheckBox->isChecked()) {
  115. srcs |= MarkdownEditorConfig::InplacePreviewSource::CodeBlock;
  116. }
  117. if (m_inplacePreviewSourceMathCheckBox->isChecked()) {
  118. srcs |= MarkdownEditorConfig::InplacePreviewSource::Math;
  119. }
  120. markdownConfig.setInplacePreviewSources(srcs);
  121. }
  122. markdownConfig.setFetchImagesInParseAndPaste(m_fetchImagesToLocalCheckBox->isChecked());
  123. markdownConfig.setHtmlTagEnabled(m_htmlTagCheckBox->isChecked());
  124. markdownConfig.setAutoBreakEnabled(m_autoBreakCheckBox->isChecked());
  125. markdownConfig.setLinkifyEnabled(m_linkifyCheckBox->isChecked());
  126. markdownConfig.setIndentFirstLineEnabled(m_indentFirstLineCheckBox->isChecked());
  127. markdownConfig.setSmartTableEnabled(m_smartTableCheckBox->isChecked());
  128. markdownConfig.setSpellCheckEnabled(m_spellCheckCheckBox->isChecked());
  129. markdownConfig.setWebPlantUml(m_plantUmlModeComboBox->currentData().toInt() == 0);
  130. markdownConfig.setPlantUmlJar(m_plantUmlJarFileInput->text());
  131. markdownConfig.setWebGraphviz(m_graphvizModeComboBox->currentData().toInt() == 0);
  132. markdownConfig.setGraphvizExe(m_graphvizFileInput->text());
  133. {
  134. bool checked = m_editorOverriddenFontFamilyCheckBox->isChecked();
  135. markdownConfig.setEditorOverriddenFontFamily(checked ? m_editorOverriddenFontFamilyComboBox->currentFont().family() : QString());
  136. }
  137. EditorPage::notifyEditorConfigChange();
  138. return true;
  139. }
  140. QString MarkdownEditorPage::title() const
  141. {
  142. return tr("Markdown Editor");
  143. }
  144. QGroupBox *MarkdownEditorPage::setupReadGroup()
  145. {
  146. auto box = new QGroupBox(tr("Read"), this);
  147. auto layout = WidgetsFactory::createFormLayout(box);
  148. {
  149. const QString label(tr("Constrain image width"));
  150. m_constrainImageWidthCheckBox = WidgetsFactory::createCheckBox(label, box);
  151. m_constrainImageWidthCheckBox->setToolTip(tr("Constrain image width to the window"));
  152. layout->addRow(m_constrainImageWidthCheckBox);
  153. addSearchItem(label, m_constrainImageWidthCheckBox->toolTip(), m_constrainImageWidthCheckBox);
  154. connect(m_constrainImageWidthCheckBox, &QCheckBox::stateChanged,
  155. this, &MarkdownEditorPage::pageIsChanged);
  156. }
  157. {
  158. const QString label(tr("Center image"));
  159. m_imageAlignCenterCheckBox = WidgetsFactory::createCheckBox(label, box);
  160. m_imageAlignCenterCheckBox->setToolTip(tr("Center images"));
  161. layout->addRow(m_imageAlignCenterCheckBox);
  162. addSearchItem(label, m_imageAlignCenterCheckBox->toolTip(), m_imageAlignCenterCheckBox);
  163. connect(m_imageAlignCenterCheckBox, &QCheckBox::stateChanged,
  164. this, &MarkdownEditorPage::pageIsChanged);
  165. }
  166. {
  167. m_zoomFactorSpinBox = WidgetsFactory::createDoubleSpinBox(box);
  168. m_zoomFactorSpinBox->setToolTip(tr("Zoom factor in read mode"));
  169. m_zoomFactorSpinBox->setRange(0.1, 10);
  170. m_zoomFactorSpinBox->setSingleStep(0.1);
  171. const QString label(tr("Zoom factor:"));
  172. layout->addRow(label, m_zoomFactorSpinBox);
  173. addSearchItem(label, m_zoomFactorSpinBox->toolTip(), m_zoomFactorSpinBox);
  174. connect(m_zoomFactorSpinBox, QOverload<double>::of(&QDoubleSpinBox::valueChanged),
  175. this, &MarkdownEditorPage::pageIsChanged);
  176. }
  177. {
  178. const QString label(tr("HTML tag"));
  179. m_htmlTagCheckBox = WidgetsFactory::createCheckBox(label, box);
  180. m_htmlTagCheckBox->setToolTip(tr("Allow HTML tags in source"));
  181. layout->addRow(m_htmlTagCheckBox);
  182. addSearchItem(label, m_htmlTagCheckBox->toolTip(), m_htmlTagCheckBox);
  183. connect(m_htmlTagCheckBox, &QCheckBox::stateChanged,
  184. this, &MarkdownEditorPage::pageIsChanged);
  185. }
  186. {
  187. const QString label(tr("Auto break"));
  188. m_autoBreakCheckBox = WidgetsFactory::createCheckBox(label, box);
  189. m_autoBreakCheckBox->setToolTip(tr("Automatically break a line with '\\n'"));
  190. layout->addRow(m_autoBreakCheckBox);
  191. addSearchItem(label, m_autoBreakCheckBox->toolTip(), m_autoBreakCheckBox);
  192. connect(m_autoBreakCheckBox, &QCheckBox::stateChanged,
  193. this, &MarkdownEditorPage::pageIsChanged);
  194. }
  195. {
  196. const QString label(tr("Linkify"));
  197. m_linkifyCheckBox = WidgetsFactory::createCheckBox(label, box);
  198. m_linkifyCheckBox->setToolTip(tr("Convert URL-like text to links"));
  199. layout->addRow(m_linkifyCheckBox);
  200. addSearchItem(label, m_linkifyCheckBox->toolTip(), m_linkifyCheckBox);
  201. connect(m_linkifyCheckBox, &QCheckBox::stateChanged,
  202. this, &MarkdownEditorPage::pageIsChanged);
  203. }
  204. {
  205. const QString label(tr("Indent first line"));
  206. m_indentFirstLineCheckBox = WidgetsFactory::createCheckBox(label, box);
  207. m_indentFirstLineCheckBox->setToolTip(tr("Indent the first line of each paragraph"));
  208. layout->addRow(m_indentFirstLineCheckBox);
  209. addSearchItem(label, m_indentFirstLineCheckBox->toolTip(), m_indentFirstLineCheckBox);
  210. connect(m_indentFirstLineCheckBox, &QCheckBox::stateChanged,
  211. this, &MarkdownEditorPage::pageIsChanged);
  212. }
  213. return box;
  214. }
  215. QGroupBox *MarkdownEditorPage::setupEditGroup()
  216. {
  217. auto box = new QGroupBox(tr("Edit"), this);
  218. auto layout = WidgetsFactory::createFormLayout(box);
  219. {
  220. const QString label(tr("Insert file name as title"));
  221. m_insertFileNameAsTitleCheckBox = WidgetsFactory::createCheckBox(label, box);
  222. m_insertFileNameAsTitleCheckBox->setToolTip(tr("Insert file name as title when creating note"));
  223. layout->addRow(m_insertFileNameAsTitleCheckBox);
  224. addSearchItem(label, m_insertFileNameAsTitleCheckBox->toolTip(), m_insertFileNameAsTitleCheckBox);
  225. connect(m_insertFileNameAsTitleCheckBox, &QCheckBox::stateChanged,
  226. this, &MarkdownEditorPage::pageIsChanged);
  227. }
  228. {
  229. const QString label(tr("Constrain in-place preview width"));
  230. m_constrainInplacePreviewWidthCheckBox = WidgetsFactory::createCheckBox(label, box);
  231. m_constrainInplacePreviewWidthCheckBox->setToolTip(tr("Constrain in-place preview width to the window"));
  232. layout->addRow(m_constrainInplacePreviewWidthCheckBox);
  233. addSearchItem(label, m_constrainInplacePreviewWidthCheckBox->toolTip(), m_constrainInplacePreviewWidthCheckBox);
  234. connect(m_constrainInplacePreviewWidthCheckBox, &QCheckBox::stateChanged,
  235. this, &MarkdownEditorPage::pageIsChanged);
  236. }
  237. {
  238. auto srcLayout = new QVBoxLayout();
  239. layout->addRow(tr("In-place preview sources:"), srcLayout);
  240. m_inplacePreviewSourceImageLinkCheckBox = WidgetsFactory::createCheckBox(tr("Image link"), box);
  241. srcLayout->addWidget(m_inplacePreviewSourceImageLinkCheckBox);
  242. connect(m_inplacePreviewSourceImageLinkCheckBox, &QCheckBox::stateChanged,
  243. this, &MarkdownEditorPage::pageIsChanged);
  244. m_inplacePreviewSourceCodeBlockCheckBox = WidgetsFactory::createCheckBox(tr("Code block"), box);
  245. srcLayout->addWidget(m_inplacePreviewSourceCodeBlockCheckBox);
  246. connect(m_inplacePreviewSourceCodeBlockCheckBox, &QCheckBox::stateChanged,
  247. this, &MarkdownEditorPage::pageIsChanged);
  248. m_inplacePreviewSourceMathCheckBox = WidgetsFactory::createCheckBox(tr("Math"), box);
  249. srcLayout->addWidget(m_inplacePreviewSourceMathCheckBox);
  250. connect(m_inplacePreviewSourceMathCheckBox, &QCheckBox::stateChanged,
  251. this, &MarkdownEditorPage::pageIsChanged);
  252. }
  253. {
  254. const QString label(tr("Fetch images to local in Parse And Paste"));
  255. m_fetchImagesToLocalCheckBox = WidgetsFactory::createCheckBox(label, box);
  256. m_fetchImagesToLocalCheckBox->setToolTip(tr("Fetch images to local in Parse To Markdown And Paste"));
  257. layout->addRow(m_fetchImagesToLocalCheckBox);
  258. addSearchItem(label, m_fetchImagesToLocalCheckBox->toolTip(), m_fetchImagesToLocalCheckBox);
  259. connect(m_fetchImagesToLocalCheckBox, &QCheckBox::stateChanged,
  260. this, &MarkdownEditorPage::pageIsChanged);
  261. }
  262. {
  263. const QString label(tr("Smart table"));
  264. m_smartTableCheckBox = WidgetsFactory::createCheckBox(label, box);
  265. m_smartTableCheckBox->setToolTip(tr("Smart table formation"));
  266. layout->addRow(m_smartTableCheckBox);
  267. addSearchItem(label, m_smartTableCheckBox->toolTip(), m_smartTableCheckBox);
  268. connect(m_smartTableCheckBox, &QCheckBox::stateChanged,
  269. this, &MarkdownEditorPage::pageIsChanged);
  270. }
  271. {
  272. const QString label(tr("Spell check"));
  273. m_spellCheckCheckBox = WidgetsFactory::createCheckBox(label, box);
  274. m_spellCheckCheckBox->setToolTip(tr("Spell check"));
  275. layout->addRow(m_spellCheckCheckBox);
  276. addSearchItem(label, m_spellCheckCheckBox->toolTip(), m_spellCheckCheckBox);
  277. connect(m_spellCheckCheckBox, &QCheckBox::stateChanged,
  278. this, &MarkdownEditorPage::pageIsChanged);
  279. }
  280. {
  281. auto fontLayout = new QHBoxLayout();
  282. fontLayout->setContentsMargins(0, 0, 0, 0);
  283. const QString label(tr("Override font"));
  284. m_editorOverriddenFontFamilyCheckBox = WidgetsFactory::createCheckBox(label, box);
  285. m_editorOverriddenFontFamilyCheckBox->setToolTip(tr("Override editor font family of theme"));
  286. fontLayout->addWidget(m_editorOverriddenFontFamilyCheckBox);
  287. addSearchItem(label, m_editorOverriddenFontFamilyCheckBox->toolTip(), m_editorOverriddenFontFamilyCheckBox);
  288. m_editorOverriddenFontFamilyComboBox = new QFontComboBox(box);
  289. m_editorOverriddenFontFamilyComboBox->setEnabled(false);
  290. fontLayout->addWidget(m_editorOverriddenFontFamilyComboBox);
  291. connect(m_editorOverriddenFontFamilyComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
  292. this, &MarkdownEditorPage::pageIsChanged);
  293. fontLayout->addStretch();
  294. connect(m_editorOverriddenFontFamilyCheckBox, &QCheckBox::stateChanged,
  295. this, [this](int state) {
  296. m_editorOverriddenFontFamilyComboBox->setEnabled(state == Qt::Checked);
  297. emit pageIsChanged();
  298. });
  299. layout->addRow(fontLayout);
  300. }
  301. return box;
  302. }
  303. QGroupBox *MarkdownEditorPage::setupGeneralGroup()
  304. {
  305. auto box = new QGroupBox(tr("General"), this);
  306. auto layout = WidgetsFactory::createFormLayout(box);
  307. {
  308. auto sectionLayout = new QHBoxLayout();
  309. sectionLayout->setContentsMargins(0, 0, 0, 0);
  310. m_sectionNumberComboBox = WidgetsFactory::createComboBox(box);
  311. m_sectionNumberComboBox->setToolTip(tr("Section number mode"));
  312. m_sectionNumberComboBox->addItem(tr("None"), (int)MarkdownEditorConfig::SectionNumberMode::None);
  313. m_sectionNumberComboBox->addItem(tr("Read"), (int)MarkdownEditorConfig::SectionNumberMode::Read);
  314. m_sectionNumberComboBox->addItem(tr("Edit"), (int)MarkdownEditorConfig::SectionNumberMode::Edit);
  315. sectionLayout->addWidget(m_sectionNumberComboBox);
  316. connect(m_sectionNumberComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
  317. this, &MarkdownEditorPage::pageIsChanged);
  318. m_sectionNumberBaseLevelSpinBox = WidgetsFactory::createSpinBox(box);
  319. m_sectionNumberBaseLevelSpinBox->setToolTip(tr("Base level to start section numbering in edit mode"));
  320. m_sectionNumberBaseLevelSpinBox->setRange(1, 6);
  321. m_sectionNumberBaseLevelSpinBox->setSingleStep(1);
  322. m_sectionNumberBaseLevelSpinBox->setEnabled(false);
  323. sectionLayout->addWidget(m_sectionNumberBaseLevelSpinBox);
  324. connect(m_sectionNumberBaseLevelSpinBox, QOverload<int>::of(&QSpinBox::valueChanged),
  325. this, &MarkdownEditorPage::pageIsChanged);
  326. m_sectionNumberStyleComboBox = WidgetsFactory::createComboBox(box);
  327. m_sectionNumberStyleComboBox->setToolTip(tr("Section number style"));
  328. m_sectionNumberStyleComboBox->addItem(tr("1.1."), (int)MarkdownEditorConfig::SectionNumberStyle::DigDotDigDot);
  329. m_sectionNumberStyleComboBox->addItem(tr("1.1"), (int)MarkdownEditorConfig::SectionNumberStyle::DigDotDig);
  330. m_sectionNumberStyleComboBox->setEnabled(false);
  331. sectionLayout->addWidget(m_sectionNumberStyleComboBox);
  332. connect(m_sectionNumberStyleComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
  333. this, &MarkdownEditorPage::pageIsChanged);
  334. connect(m_sectionNumberComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
  335. this, [this](int p_index) {
  336. m_sectionNumberBaseLevelSpinBox->setEnabled(p_index != MarkdownEditorConfig::SectionNumberMode::None);
  337. m_sectionNumberStyleComboBox->setEnabled(p_index == MarkdownEditorConfig::SectionNumberMode::Edit);
  338. });
  339. const QString label(tr("Section number:"));
  340. layout->addRow(label, sectionLayout);
  341. addSearchItem(label, m_sectionNumberComboBox->toolTip(), m_sectionNumberComboBox);
  342. }
  343. {
  344. m_plantUmlModeComboBox = WidgetsFactory::createComboBox(box);
  345. m_plantUmlModeComboBox->setToolTip(tr("Use online service or local JAR file to render PlantUml graphs"));
  346. m_plantUmlModeComboBox->addItem(tr("Online Service"), 0);
  347. m_plantUmlModeComboBox->addItem(tr("Local JAR"), 1);
  348. const QString label(tr("PlantUml:"));
  349. layout->addRow(label, m_plantUmlModeComboBox);
  350. addSearchItem(label, m_plantUmlModeComboBox->toolTip(), m_plantUmlModeComboBox);
  351. connect(m_plantUmlModeComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
  352. this, &MarkdownEditorPage::pageIsChanged);
  353. }
  354. {
  355. auto jarLayout = new QHBoxLayout();
  356. jarLayout->setContentsMargins(0, 0, 0, 0);
  357. m_plantUmlJarFileInput = new LocationInputWithBrowseButton(box);
  358. m_plantUmlJarFileInput->setToolTip(tr("Local JAR file to render PlantUml graphs"));
  359. connect(m_plantUmlJarFileInput, &LocationInputWithBrowseButton::clicked,
  360. this, [this]() {
  361. auto filePath = QFileDialog::getOpenFileName(this,
  362. tr("Select PlantUml JAR File"),
  363. QDir::homePath(),
  364. "PlantUml JAR (*.jar)");
  365. if (!filePath.isEmpty()) {
  366. m_plantUmlJarFileInput->setText(filePath);
  367. }
  368. });
  369. jarLayout->addWidget(m_plantUmlJarFileInput, 1);
  370. auto testBtn = new QPushButton(tr("Test"), box);
  371. testBtn->setToolTip(tr("Test PlantUml JAR and Java Runtime Environment"));
  372. connect(testBtn, &QPushButton::clicked,
  373. this, [this]() {
  374. const auto jar = m_plantUmlJarFileInput->text();
  375. if (jar.isEmpty() || !QFileInfo::exists(jar)) {
  376. MessageBoxHelper::notify(MessageBoxHelper::Warning,
  377. tr("The JAR file (%1) specified does not exist.").arg(jar),
  378. this);
  379. return;
  380. }
  381. auto testRet = PlantUmlHelper::testPlantUml(jar);
  382. MessageBoxHelper::notify(MessageBoxHelper::Information,
  383. tr("Test %1.").arg(testRet.first ? tr("succeeded") : tr("failed")),
  384. QString(),
  385. testRet.second,
  386. this);
  387. });
  388. jarLayout->addWidget(testBtn);
  389. const QString label(tr("PlantUml JAR file:"));
  390. layout->addRow(label, jarLayout);
  391. addSearchItem(label, m_plantUmlJarFileInput->toolTip(), m_plantUmlJarFileInput);
  392. connect(m_plantUmlJarFileInput, &LocationInputWithBrowseButton::textChanged,
  393. this, &MarkdownEditorPage::pageIsChanged);
  394. }
  395. {
  396. m_graphvizModeComboBox = WidgetsFactory::createComboBox(box);
  397. m_graphvizModeComboBox->setToolTip(tr("Use online service or local executable file to render Graphviz graphs"));
  398. m_graphvizModeComboBox->addItem(tr("Online Service"), 0);
  399. m_graphvizModeComboBox->addItem(tr("Local Executable"), 1);
  400. const QString label(tr("Graphviz:"));
  401. layout->addRow(label, m_graphvizModeComboBox);
  402. addSearchItem(label, m_graphvizModeComboBox->toolTip(), m_graphvizModeComboBox);
  403. connect(m_graphvizModeComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
  404. this, &MarkdownEditorPage::pageIsChanged);
  405. }
  406. {
  407. auto fileLayout = new QHBoxLayout();
  408. fileLayout->setContentsMargins(0, 0, 0, 0);
  409. m_graphvizFileInput = new LocationInputWithBrowseButton(box);
  410. m_graphvizFileInput->setToolTip(tr("Local executable file to render Graphviz graphs"));
  411. connect(m_graphvizFileInput, &LocationInputWithBrowseButton::clicked,
  412. this, [this]() {
  413. auto filePath = QFileDialog::getOpenFileName(this,
  414. tr("Select Graphviz Executable File"),
  415. QDir::homePath());
  416. if (!filePath.isEmpty()) {
  417. m_graphvizFileInput->setText(filePath);
  418. }
  419. });
  420. fileLayout->addWidget(m_graphvizFileInput, 1);
  421. auto testBtn = new QPushButton(tr("Test"), box);
  422. testBtn->setToolTip(tr("Test Graphviz executable file"));
  423. connect(testBtn, &QPushButton::clicked,
  424. this, [this]() {
  425. const auto exe = m_graphvizFileInput->text();
  426. if (exe.isEmpty() || !QFileInfo::exists(exe)) {
  427. MessageBoxHelper::notify(MessageBoxHelper::Warning,
  428. tr("The executable file (%1) specified does not exist.").arg(exe),
  429. this);
  430. return;
  431. }
  432. auto testRet = GraphvizHelper::testGraphviz(exe);
  433. MessageBoxHelper::notify(MessageBoxHelper::Information,
  434. tr("Test %1.").arg(testRet.first ? tr("succeeded") : tr("failed")),
  435. QString(),
  436. testRet.second,
  437. this);
  438. });
  439. fileLayout->addWidget(testBtn);
  440. const QString label(tr("Graphviz executable file:"));
  441. layout->addRow(label, fileLayout);
  442. addSearchItem(label, m_graphvizFileInput->toolTip(), m_graphvizFileInput);
  443. connect(m_graphvizFileInput, &LocationInputWithBrowseButton::textChanged,
  444. this, &MarkdownEditorPage::pageIsChanged);
  445. }
  446. return box;
  447. }