exporter.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. #include "exporter.h"
  2. #include <QWidget>
  3. #include <notebook/notebook.h>
  4. #include <notebook/node.h>
  5. #include <buffer/buffer.h>
  6. #include <core/file.h>
  7. #include <utils/fileutils.h>
  8. #include <utils/pathutils.h>
  9. #include <utils/contentmediautils.h>
  10. #include "webviewexporter.h"
  11. using namespace vnotex;
  12. Exporter::Exporter(QWidget *p_parent)
  13. : QObject(p_parent)
  14. {
  15. }
  16. QString Exporter::doExport(const ExportOption &p_option, Buffer *p_buffer)
  17. {
  18. m_askedToStop = false;
  19. QString outputFile;
  20. auto file = p_buffer->getFile();
  21. if (!file) {
  22. emit logRequested(tr("Skipped buffer (%1) without file base.").arg(p_buffer->getName()));
  23. return outputFile;
  24. }
  25. // Make sure output folder exists.
  26. if (!QDir().mkpath(p_option.m_outputDir)) {
  27. emit logRequested(tr("Failed to create output folder %1.").arg(p_option.m_outputDir));
  28. return outputFile;
  29. }
  30. outputFile = doExport(p_option, p_option.m_outputDir, file.data());
  31. cleanUp();
  32. return outputFile;
  33. }
  34. QString Exporter::doExportMarkdown(const ExportOption &p_option, const QString &p_outputDir, const File *p_file)
  35. {
  36. QString outputFile;
  37. if (!p_file->getContentType().isMarkdown()) {
  38. emit logRequested(tr("Format %1 is not supported to export as Markdown.").arg(p_file->getContentType().m_displayName));
  39. return outputFile;
  40. }
  41. // Export it to a folder with the same name.
  42. auto name = FileUtils::generateFileNameWithSequence(p_outputDir, p_file->getName(), "");
  43. auto outputFolder = PathUtils::concatenateFilePath(p_outputDir, name);
  44. QDir outDir(outputFolder);
  45. if (!outDir.mkpath(outputFolder)) {
  46. emit logRequested(tr("Failed to create output folder %1.").arg(outputFolder));
  47. return outputFile;
  48. }
  49. // Copy source file itself.
  50. const auto srcFilePath = p_file->getFilePath();
  51. auto destFilePath = outDir.filePath(p_file->getName());
  52. FileUtils::copyFile(srcFilePath, destFilePath, false);
  53. outputFile = destFilePath;
  54. ContentMediaUtils::copyMediaFiles(p_file, destFilePath);
  55. // Copy attachments if available.
  56. if (p_option.m_exportAttachments) {
  57. exportAttachments(p_file->getNode(), srcFilePath, outputFolder, destFilePath);
  58. }
  59. return outputFile;
  60. }
  61. void Exporter::exportAttachments(Node *p_node,
  62. const QString &p_srcFilePath,
  63. const QString &p_outputFolder,
  64. const QString &p_destFilePath)
  65. {
  66. if (!p_node) {
  67. return;
  68. }
  69. const auto &attachmentFolder = p_node->getAttachmentFolder();
  70. if (!attachmentFolder.isEmpty()) {
  71. auto relativePath = PathUtils::relativePath(PathUtils::parentDirPath(p_srcFilePath),
  72. p_node->fetchAttachmentFolderPath());
  73. auto destAttachmentFolderPath = QDir(p_outputFolder).filePath(relativePath);
  74. destAttachmentFolderPath = FileUtils::renameIfExistsCaseInsensitive(destAttachmentFolderPath);
  75. ContentMediaUtils::copyAttachment(p_node, nullptr, p_destFilePath, destAttachmentFolderPath);
  76. }
  77. }
  78. QString Exporter::doExport(const ExportOption &p_option, Node *p_note)
  79. {
  80. m_askedToStop = false;
  81. QString outputFile;
  82. auto file = p_note->getContentFile();
  83. // Make sure output folder exists.
  84. if (!QDir().mkpath(p_option.m_outputDir)) {
  85. emit logRequested(tr("Failed to create output folder %1.").arg(p_option.m_outputDir));
  86. return outputFile;
  87. }
  88. outputFile = doExport(p_option, p_option.m_outputDir, file.data());
  89. cleanUp();
  90. return outputFile;
  91. }
  92. QStringList Exporter::doExportFolder(const ExportOption &p_option, Node *p_folder)
  93. {
  94. m_askedToStop = false;
  95. auto outputFiles = doExport(p_option, p_option.m_outputDir, p_folder);
  96. cleanUp();
  97. return outputFiles;
  98. }
  99. QStringList Exporter::doExport(const ExportOption &p_option, const QString &p_outputDir, Node *p_folder)
  100. {
  101. Q_ASSERT(p_folder->isContainer());
  102. QStringList outputFiles;
  103. // Make path.
  104. auto name = FileUtils::generateFileNameWithSequence(p_outputDir, p_folder->getName());
  105. auto outputFolder = PathUtils::concatenateFilePath(p_outputDir, name);
  106. if (!QDir().mkpath(outputFolder)) {
  107. emit logRequested(tr("Failed to create output folder %1.").arg(outputFolder));
  108. return outputFiles;
  109. }
  110. p_folder->load();
  111. const auto &children = p_folder->getChildrenRef();
  112. emit progressUpdated(0, children.size());
  113. for (int i = 0; i < children.size(); ++i) {
  114. if (checkAskedToStop()) {
  115. break;
  116. }
  117. const auto &child = children[i];
  118. if (child->hasContent()) {
  119. auto outputFile = doExport(p_option, outputFolder, child->getContentFile().data());
  120. if (!outputFile.isEmpty()) {
  121. outputFiles << outputFile;
  122. }
  123. }
  124. if (p_option.m_recursive && child->isContainer() && child->getUse() == Node::Use::Normal) {
  125. outputFiles.append(doExport(p_option, outputFolder, child.data()));
  126. }
  127. emit progressUpdated(i + 1, children.size());
  128. }
  129. return outputFiles;
  130. }
  131. QString Exporter::doExport(const ExportOption &p_option, const QString &p_outputDir, const File *p_file)
  132. {
  133. QString outputFile;
  134. switch (p_option.m_targetFormat) {
  135. case ExportFormat::Markdown:
  136. outputFile = doExportMarkdown(p_option, p_outputDir, p_file);
  137. break;
  138. case ExportFormat::HTML:
  139. outputFile = doExportHtml(p_option, p_outputDir, p_file);
  140. break;
  141. case ExportFormat::PDF:
  142. outputFile = doExportPdf(p_option, p_outputDir, p_file);
  143. break;
  144. default:
  145. emit logRequested(tr("Unknown target format %1.").arg(exportFormatString(p_option.m_targetFormat)));
  146. break;
  147. }
  148. if (!outputFile.isEmpty()) {
  149. emit logRequested(tr("File (%1) exported to (%2)").arg(p_file->getFilePath(), outputFile));
  150. } else {
  151. emit logRequested(tr("Failed to export file (%1)").arg(p_file->getFilePath()));
  152. }
  153. return outputFile;
  154. }
  155. QStringList Exporter::doExport(const ExportOption &p_option, Notebook *p_notebook)
  156. {
  157. m_askedToStop = false;
  158. QStringList outputFiles;
  159. // Make path.
  160. auto name = FileUtils::generateFileNameWithSequence(p_option.m_outputDir,
  161. tr("notebook_%1").arg(p_notebook->getName()));
  162. auto outputFolder = PathUtils::concatenateFilePath(p_option.m_outputDir, name);
  163. if (!QDir().mkpath(outputFolder)) {
  164. emit logRequested(tr("Failed to create output folder %1.").arg(outputFolder));
  165. return outputFiles;
  166. }
  167. auto rootNode = p_notebook->getRootNode();
  168. Q_ASSERT(rootNode->isLoaded());
  169. const auto &children = rootNode->getChildrenRef();
  170. emit progressUpdated(0, children.size());
  171. for (int i = 0; i < children.size(); ++i) {
  172. if (checkAskedToStop()) {
  173. break;
  174. }
  175. const auto &child = children[i];
  176. if (child->hasContent()) {
  177. auto outputFile = doExport(p_option, outputFolder, child->getContentFile().data());
  178. if (!outputFile.isEmpty()) {
  179. outputFiles << outputFile;
  180. }
  181. }
  182. if (child->isContainer() && child->getUse() == Node::Use::Normal) {
  183. outputFiles.append(doExport(p_option, outputFolder, child.data()));
  184. }
  185. emit progressUpdated(i + 1, children.size());
  186. }
  187. cleanUp();
  188. return outputFiles;
  189. }
  190. QString Exporter::doExportHtml(const ExportOption &p_option, const QString &p_outputDir, const File *p_file)
  191. {
  192. QString outputFile;
  193. if (!p_file->getContentType().isMarkdown()) {
  194. emit logRequested(tr("Format %1 is not supported to export as HTML.").arg(p_file->getContentType().m_displayName));
  195. return outputFile;
  196. }
  197. QString suffix = p_option.m_htmlOption.m_useMimeHtmlFormat ? QStringLiteral("mht") : QStringLiteral("html");
  198. auto fileName = FileUtils::generateFileNameWithSequence(p_outputDir,
  199. QFileInfo(p_file->getName()).completeBaseName(),
  200. suffix);
  201. auto destFilePath = PathUtils::concatenateFilePath(p_outputDir, fileName);
  202. bool success = getWebViewExporter(p_option)->doExport(p_option, p_file, destFilePath);
  203. if (success) {
  204. outputFile = destFilePath;
  205. // Copy attachments if available.
  206. if (p_option.m_exportAttachments) {
  207. exportAttachments(p_file->getNode(), p_file->getFilePath(), p_outputDir, destFilePath);
  208. }
  209. }
  210. return outputFile;
  211. }
  212. WebViewExporter *Exporter::getWebViewExporter(const ExportOption &p_option)
  213. {
  214. if (!m_webViewExporter) {
  215. m_webViewExporter = new WebViewExporter(static_cast<QWidget *>(parent()));
  216. connect(m_webViewExporter, &WebViewExporter::logRequested,
  217. this, &Exporter::logRequested);
  218. m_webViewExporter->prepare(p_option);
  219. }
  220. return m_webViewExporter;
  221. }
  222. void Exporter::cleanUpWebViewExporter()
  223. {
  224. if (m_webViewExporter) {
  225. m_webViewExporter->clear();
  226. delete m_webViewExporter;
  227. m_webViewExporter = nullptr;
  228. }
  229. }
  230. void Exporter::cleanUp()
  231. {
  232. cleanUpWebViewExporter();
  233. }
  234. void Exporter::stop()
  235. {
  236. m_askedToStop = true;
  237. if (m_webViewExporter) {
  238. m_webViewExporter->stop();
  239. }
  240. }
  241. bool Exporter::checkAskedToStop() const
  242. {
  243. if (m_askedToStop) {
  244. emit const_cast<Exporter *>(this)->logRequested(tr("Asked to stop. Aborting."));
  245. return true;
  246. }
  247. return false;
  248. }
  249. QString Exporter::doExportPdf(const ExportOption &p_option, const QString &p_outputDir, const File *p_file)
  250. {
  251. QString outputFile;
  252. if (!p_file->getContentType().isMarkdown()) {
  253. emit logRequested(tr("Format %1 is not supported to export as PDF.").arg(p_file->getContentType().m_displayName));
  254. return outputFile;
  255. }
  256. auto fileName = FileUtils::generateFileNameWithSequence(p_outputDir,
  257. QFileInfo(p_file->getName()).completeBaseName(),
  258. "pdf");
  259. auto destFilePath = PathUtils::concatenateFilePath(p_outputDir, fileName);
  260. bool success = getWebViewExporter(p_option)->doExport(p_option, p_file, destFilePath);
  261. if (success) {
  262. outputFile = destFilePath;
  263. // Copy attachments if available.
  264. if (p_option.m_exportAttachments) {
  265. exportAttachments(p_file->getNode(), p_file->getFilePath(), p_outputDir, destFilePath);
  266. }
  267. }
  268. return outputFile;
  269. }