/***********************************************************************
*
* Copyright (C) 2014-2019 wereturtle
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
***********************************************************************/
#include
#include
#include
#include "ExporterFactory.h"
#include "CmarkGfmExporter.h"
#include "CommandLineExporter.h"
ExporterFactory* ExporterFactory::instance = NULL;
ExporterFactory::~ExporterFactory()
{
// No need to delete Exporter instances, since this is a singleton class,
// and all will be destroyed upon quitting the application.
;
}
ExporterFactory* ExporterFactory::getInstance()
{
if (NULL == instance)
{
instance = new ExporterFactory();
}
return instance;
}
QList ExporterFactory::getFileExporters()
{
return fileExporters;
}
QList ExporterFactory::getHtmlExporters()
{
return htmlExporters;
}
Exporter* ExporterFactory::getExporterByName(const QString& name)
{
// Search in HTML exporter list first.
foreach (Exporter* exporter, htmlExporters)
{
if (exporter->getName() == name)
{
// Found a match!
return exporter;
}
}
// If HTML exporter list does not contain an exporter
// with the desired name, search in the file exporter
// list next.
//
foreach (Exporter* exporter, fileExporters)
{
if (exporter->getName() == name)
{
// Found a match!
return exporter;
}
}
// No match found.
return NULL;
}
ExporterFactory::ExporterFactory()
{
CommandLineExporter* exporter = NULL;
bool pandocIsAvailable = isCommandAvailable("pandoc --version");
bool mmdIsAvailable = isCommandAvailable("multimarkdown --version");
bool cmarkIsAvailable = isCommandAvailable("cmark --version");
CmarkGfmExporter* cmarkGfmExporter = new CmarkGfmExporter();
fileExporters.append(cmarkGfmExporter);
htmlExporters.append(cmarkGfmExporter);
if (pandocIsAvailable)
{
int majorVersion = 0;
int minorVersion = 0;
// Check whether version of Pandoc can read CommonMark.
QList versionNumber = extractVersionNumber("pandoc --version");
if (versionNumber.length() > 0)
{
majorVersion = versionNumber[0];
if (versionNumber.length() > 1)
{
minorVersion = versionNumber[1];
}
}
addPandocExporter("Pandoc", "markdown", majorVersion, minorVersion);
if
(
(majorVersion > 1) ||
((1 == majorVersion) && (minorVersion >= 14))
)
{
addPandocExporter("Pandoc CommonMark", "commonmark", majorVersion, minorVersion);
}
addPandocExporter("Pandoc GitHub-flavored Markdown", "markdown_github-hard_line_breaks", majorVersion, minorVersion);
addPandocExporter("Pandoc PHP Markdown Extra", "markdown_phpextra", majorVersion, minorVersion);
addPandocExporter("Pandoc MultiMarkdown", "markdown_mmd", majorVersion, minorVersion);
addPandocExporter("Pandoc Strict", "markdown_strict", majorVersion, minorVersion);
}
if (mmdIsAvailable)
{
int majorVersion = 0;
QList versionNumber = extractVersionNumber("multimarkdown --version");
if (versionNumber.length() > 0)
{
majorVersion = versionNumber[0];
}
exporter = new CommandLineExporter("MultiMarkdown");
// Smart typography option (--smart) is only availabe in version 5 and below.
// The option is was removed and enabled by default in version 6 and above.
//
if (majorVersion < 6)
{
exporter->setSmartTypographyOnArgument("--smart");
}
exporter->setSmartTypographyOffArgument("--nosmart");
exporter->setHtmlRenderCommand(QString("multimarkdown %1 -t html")
.arg(CommandLineExporter::SMART_TYPOGRAPHY_ARG));
exporter->addFileExportCommand
(
ExportFormat::HTML,
QString("multimarkdown %1 -t html -o %2")
.arg(CommandLineExporter::SMART_TYPOGRAPHY_ARG)
.arg(CommandLineExporter::OUTPUT_FILE_PATH_VAR)
);
// Version 6 removed ODF option and replaced it with ODT and FODT.
if (majorVersion >= 6)
{
exporter->addFileExportCommand
(
ExportFormat::ODT,
QString("multimarkdown %1 -t odt -o %2")
.arg(CommandLineExporter::SMART_TYPOGRAPHY_ARG)
.arg(CommandLineExporter::OUTPUT_FILE_PATH_VAR)
);
exporter->addFileExportCommand
(
ExportFormat::ODF,
QString("multimarkdown %1 -t fodt -o %2")
.arg(CommandLineExporter::SMART_TYPOGRAPHY_ARG)
.arg(CommandLineExporter::OUTPUT_FILE_PATH_VAR)
);
}
else
{
exporter->addFileExportCommand
(
ExportFormat::ODF,
QString("multimarkdown %1 -t odf -o %2")
.arg(CommandLineExporter::SMART_TYPOGRAPHY_ARG)
.arg(CommandLineExporter::OUTPUT_FILE_PATH_VAR)
);
}
// Version 6 added EPUB 3
if (majorVersion >= 6)
{
exporter->addFileExportCommand
(
ExportFormat::EPUBV3,
QString("multimarkdown %1 -b -t epub -o %2")
.arg(CommandLineExporter::SMART_TYPOGRAPHY_ARG)
.arg(CommandLineExporter::OUTPUT_FILE_PATH_VAR)
);
}
exporter->addFileExportCommand
(
ExportFormat::LATEX,
QString("multimarkdown %1 -t latex -o %2")
.arg(CommandLineExporter::SMART_TYPOGRAPHY_ARG)
.arg(CommandLineExporter::OUTPUT_FILE_PATH_VAR)
);
exporter->addFileExportCommand
(
ExportFormat::MEMOIR,
QString("multimarkdown %1 -t memoir -o %2")
.arg(CommandLineExporter::SMART_TYPOGRAPHY_ARG)
.arg(CommandLineExporter::OUTPUT_FILE_PATH_VAR)
);
exporter->addFileExportCommand
(
ExportFormat::LYX,
QString("multimarkdown %1 -t lyx -o %2")
.arg(CommandLineExporter::SMART_TYPOGRAPHY_ARG)
.arg(CommandLineExporter::OUTPUT_FILE_PATH_VAR)
);
fileExporters.append(exporter);
htmlExporters.append(exporter);
}
if (cmarkIsAvailable)
{
exporter = new CommandLineExporter("cmark");
exporter->setSmartTypographyOnArgument("--smart");
exporter->setHtmlRenderCommand(QString("cmark -t html --smart %1")
.arg(CommandLineExporter::SMART_TYPOGRAPHY_ARG));
exporter->addFileExportCommand
(
ExportFormat::HTML,
QString("cmark -t html %1")
.arg(CommandLineExporter::SMART_TYPOGRAPHY_ARG)
);
exporter->addFileExportCommand
(
ExportFormat::LATEX,
QString("cmark -t latex %1")
.arg(CommandLineExporter::SMART_TYPOGRAPHY_ARG)
);
exporter->addFileExportCommand
(
ExportFormat::MANPAGE,
QString("cmark -t man %1")
.arg(CommandLineExporter::SMART_TYPOGRAPHY_ARG)
);
fileExporters.append(exporter);
htmlExporters.append(exporter);
}
}
QList ExporterFactory::extractVersionNumber(const QString& command) const
{
QList versionNumber;
QProcess process;
process.start(command);
if (!process.waitForStarted(500))
{
return versionNumber;
}
else if (!process.waitForFinished(500))
{
process.kill();
return versionNumber;
}
QString versionStr = QString::fromUtf8(process.readAllStandardOutput().data());
QRegularExpression versionRegex1("v(\\d+(\\.\\d+)*)");
QRegularExpression versionRegex2("(\\d+(\\.\\d+)*)");
QRegularExpressionMatch match;
// Prefer searching for "v1.6.3" version format over "1.6.3" format
int pos = versionStr.indexOf(versionRegex1, 0, &match);
if ((pos >= 0) && match.hasMatch())
{
versionStr = match.captured(1);
}
// Else try the "1.6.3" format without the "v" in front
else
{
pos = versionStr.indexOf(versionRegex2, 0, &match);
if ((pos >= 0) && match.hasMatch())
{
versionStr = match.captured(1);
}
}
QStringList numbers = versionStr.split('.', QString::SkipEmptyParts);
foreach (QString num, numbers)
{
versionNumber.append(num.toInt());
}
return versionNumber;
}
bool ExporterFactory::isCommandAvailable(const QString& testCommand) const
{
QProcess process;
process.start(testCommand);
if (!process.waitForStarted(500))
{
return false;
}
else if (!process.waitForFinished(500))
{
process.kill();
}
return true;
}
void ExporterFactory::addPandocExporter
(
const QString& name,
const QString& inputFormat,
int majorVersion,
int minorVersion
)
{
Q_UNUSED(minorVersion)
CommandLineExporter* exporter = new CommandLineExporter(name);
if (majorVersion >= 2)
{
exporter->setSmartTypographyOnArgument("+smart");
exporter->setSmartTypographyOffArgument("-smart");
}
else
{
exporter->setSmartTypographyOnArgument(" --smart");
}
exporter->setHtmlRenderCommand
(
QString("pandoc --mathml -f ") +
inputFormat +
CommandLineExporter::SMART_TYPOGRAPHY_ARG +
" -t html"
);
QString standardExportStr;
if (majorVersion >= 2)
{
standardExportStr =
QString("pandoc -f ") +
inputFormat +
CommandLineExporter::SMART_TYPOGRAPHY_ARG +
" -t %1 --standalone --mathml --quiet -o " +
CommandLineExporter::OUTPUT_FILE_PATH_VAR;
}
else
{
// older Pandoc releases don't know the option '--quiet'
standardExportStr =
QString("pandoc -f ") +
inputFormat +
CommandLineExporter::SMART_TYPOGRAPHY_ARG +
" -t %1 --standalone --mathml -o " +
CommandLineExporter::OUTPUT_FILE_PATH_VAR;
}
exporter->addFileExportCommand
(
ExportFormat::HTML,
standardExportStr.arg("html")
);
exporter->addFileExportCommand
(
ExportFormat::HTML5,
standardExportStr.arg("html5")
);
exporter->addFileExportCommand
(
ExportFormat::ODT,
standardExportStr.arg("odt")
);
exporter->addFileExportCommand
(
ExportFormat::ODF,
standardExportStr.arg("opendocument")
);
exporter->addFileExportCommand
(
ExportFormat::RTF,
standardExportStr.arg("rtf")
);
exporter->addFileExportCommand
(
ExportFormat::DOCX,
standardExportStr.arg("docx")
);
exporter->addFileExportCommand
(
ExportFormat::PDF_LATEX,
standardExportStr.arg("latex") +
" -Vlinkcolor=blue -Vcitecolor=blue -Vurlcolor=blue -Vtoccolor=blue -Vmargin-left=1in -Vmargin-right=1in -Vmargin-top=1in -Vmargin-bottom=1in"
);
exporter->addFileExportCommand
(
ExportFormat::PDF_CONTEXT,
standardExportStr.arg("context") +
" --variable pagenumbering:location=footer --variable layout:header=0mm --variable layout:top=1in --variable layout:bottom=1in --variable layout:leftmargin=1in --variable layout:rightmargin=1in -Vlinkcolor=blue"
);
// Note: Do not use --mathjax option with WKHTMLTOPDF export, as this will
// cause pandoc to hang.
//
exporter->addFileExportCommand
(
ExportFormat::PDF_WKHTML,
standardExportStr.arg("html5") +
" -Vmargin-left=1in -Vmargin-right=1in -Vmargin-top=1in -Vmargin-bottom=1in"
);
exporter->addFileExportCommand
(
ExportFormat::EPUBV2,
standardExportStr.arg("epub") +
" --toc --toc-depth 6"
);
exporter->addFileExportCommand
(
ExportFormat::EPUBV3,
standardExportStr.arg("epub3") +
" --toc --toc-depth 6"
);
exporter->addFileExportCommand
(
ExportFormat::FICTIONBOOK2,
standardExportStr.arg("fb2") +
" --toc --toc-depth 6"
);
exporter->addFileExportCommand
(
ExportFormat::LATEX,
standardExportStr.arg("latex")
);
exporter->addFileExportCommand
(
ExportFormat::GROFFMAN,
standardExportStr.arg("man")
);
fileExporters.append(exporter);
htmlExporters.append(exporter);
}