veditor.cpp 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. #include <QtWidgets>
  2. #include <QTextBrowser>
  3. #include <QWebChannel>
  4. #include <QWebEngineView>
  5. #include "veditor.h"
  6. #include "vedit.h"
  7. #include "vdocument.h"
  8. #include "vnote.h"
  9. #include "utils/vutils.h"
  10. #include "vpreviewpage.h"
  11. #include "hgmarkdownhighlighter.h"
  12. VEditor::VEditor(const QString &path, const QString &name, bool modifiable,
  13. QWidget *parent)
  14. : QStackedWidget(parent)
  15. {
  16. DocType docType = isMarkdown(name) ? DocType::Markdown : DocType::Html;
  17. QString fileText = VUtils::readFileFromDisk(QDir(path).filePath(name));
  18. noteFile = new VNoteFile(path, name, fileText, docType, modifiable);
  19. isEditMode = false;
  20. mdHighlighter = NULL;
  21. setupUI();
  22. showFileReadMode();
  23. }
  24. VEditor::~VEditor()
  25. {
  26. delete noteFile;
  27. }
  28. void VEditor::setupUI()
  29. {
  30. textEditor = new VEdit(noteFile);
  31. addWidget(textEditor);
  32. switch (noteFile->docType) {
  33. case DocType::Markdown:
  34. setupMarkdownPreview();
  35. textBrowser = NULL;
  36. mdHighlighter = new HGMarkdownHighlighter(textEditor->document(), 500);
  37. break;
  38. case DocType::Html:
  39. textBrowser = new QTextBrowser();
  40. addWidget(textBrowser);
  41. textBrowser->setFont(VNote::editorAndBrowserFont);
  42. webPreviewer = NULL;
  43. break;
  44. default:
  45. qWarning() << "error: unknown doc type" << int(noteFile->docType);
  46. }
  47. }
  48. bool VEditor::isMarkdown(const QString &name)
  49. {
  50. const QVector<QString> mdPostfix({"md", "markdown", "mkd"});
  51. QStringList list = name.split('.', QString::SkipEmptyParts);
  52. if (list.isEmpty()) {
  53. return false;
  54. }
  55. const QString &postfix = list.last();
  56. for (int i = 0; i < mdPostfix.size(); ++i) {
  57. if (postfix == mdPostfix[i]) {
  58. return true;
  59. }
  60. }
  61. return false;
  62. }
  63. void VEditor::showFileReadMode()
  64. {
  65. isEditMode = false;
  66. switch (noteFile->docType) {
  67. case DocType::Html:
  68. textBrowser->setHtml(noteFile->content);
  69. setCurrentWidget(textBrowser);
  70. break;
  71. case DocType::Markdown:
  72. document.setText(noteFile->content);
  73. setCurrentWidget(webPreviewer);
  74. break;
  75. default:
  76. qWarning() << "error: unknown doc type" << int(noteFile->docType);
  77. }
  78. }
  79. void VEditor::showFileEditMode()
  80. {
  81. isEditMode = true;
  82. textEditor->beginEdit();
  83. setCurrentWidget(textEditor);
  84. }
  85. bool VEditor::requestClose()
  86. {
  87. readFile();
  88. return !isEditMode;
  89. }
  90. void VEditor::editFile()
  91. {
  92. if (isEditMode || !noteFile->modifiable) {
  93. return;
  94. }
  95. showFileEditMode();
  96. }
  97. void VEditor::readFile()
  98. {
  99. if (!isEditMode) {
  100. return;
  101. }
  102. bool canExit = textEditor->tryEndEdit();
  103. if (!canExit) {
  104. // Need to save the changes
  105. QMessageBox msgBox;
  106. msgBox.setText("The note has been modified.");
  107. msgBox.setInformativeText("Do you want to save your changes?");
  108. msgBox.setIcon(QMessageBox::Information);
  109. msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
  110. msgBox.setDefaultButton(QMessageBox::Save);
  111. int ret = msgBox.exec();
  112. switch (ret) {
  113. case QMessageBox::Save:
  114. saveFile();
  115. // Fall through
  116. case QMessageBox::Discard:
  117. textEditor->reloadFile();
  118. break;
  119. case QMessageBox::Cancel:
  120. // Nothing to do if user cancel this action
  121. return;
  122. default:
  123. qWarning() << "error: wrong return value from QMessageBox:" << ret;
  124. return;
  125. }
  126. }
  127. textEditor->setReadOnly(true);
  128. showFileReadMode();
  129. }
  130. bool VEditor::saveFile()
  131. {
  132. if (!isEditMode || !noteFile->modifiable) {
  133. return true;
  134. }
  135. textEditor->beginSave();
  136. bool ret = VUtils::writeFileToDisk(QDir(noteFile->path).filePath(noteFile->name),
  137. noteFile->content);
  138. if (!ret) {
  139. QMessageBox msgBox(QMessageBox::Warning, tr("Fail to save to file"),
  140. QString("Fail to write to disk when saving a note. Please try it again."));
  141. msgBox.setStandardButtons(QMessageBox::Ok);
  142. msgBox.setDefaultButton(QMessageBox::Ok);
  143. msgBox.exec();
  144. return false;
  145. }
  146. textEditor->endSave();
  147. return true;
  148. }
  149. void VEditor::setupMarkdownPreview()
  150. {
  151. webPreviewer = new QWebEngineView(this);
  152. VPreviewPage *page = new VPreviewPage(this);
  153. webPreviewer->setPage(page);
  154. QWebChannel *channel = new QWebChannel(this);
  155. channel->registerObject(QStringLiteral("content"), &document);
  156. page->setWebChannel(channel);
  157. webPreviewer->setHtml(VNote::templateHtml, QUrl::fromLocalFile(noteFile->path + QDir::separator()));
  158. addWidget(webPreviewer);
  159. }