mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 13:59:52 +08:00
refactor export
This commit is contained in:
parent
bc9dd643fc
commit
8ff520d0fd
630
src/dialog/vexportdialog.cpp
Normal file
630
src/dialog/vexportdialog.cpp
Normal file
@ -0,0 +1,630 @@
|
|||||||
|
#include "vexportdialog.h"
|
||||||
|
|
||||||
|
#include <QtWidgets>
|
||||||
|
#include <QCoreApplication>
|
||||||
|
|
||||||
|
#ifndef QT_NO_PRINTER
|
||||||
|
#include <QPrinter>
|
||||||
|
#include <QPageSetupDialog>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "utils/vutils.h"
|
||||||
|
#include "vlineedit.h"
|
||||||
|
#include "vnotebook.h"
|
||||||
|
#include "vfile.h"
|
||||||
|
#include "vdirectory.h"
|
||||||
|
#include "vcart.h"
|
||||||
|
#include "vconfigmanager.h"
|
||||||
|
#include "vnotefile.h"
|
||||||
|
#include "vnote.h"
|
||||||
|
#include "vexporter.h"
|
||||||
|
|
||||||
|
extern VConfigManager *g_config;
|
||||||
|
|
||||||
|
extern VNote *g_vnote;
|
||||||
|
|
||||||
|
QString VExportDialog::s_lastOutputFolder;
|
||||||
|
|
||||||
|
#define LOGERR(x) do { QString msg = (x); \
|
||||||
|
VUtils::addErrMsg(p_errMsg, msg); \
|
||||||
|
appendLogLine(msg); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
VExportDialog::VExportDialog(VNotebook *p_notebook,
|
||||||
|
VDirectory *p_directory,
|
||||||
|
VFile *p_file,
|
||||||
|
VCart *p_cart,
|
||||||
|
MarkdownConverterType p_renderer,
|
||||||
|
QWidget *p_parent)
|
||||||
|
: QDialog(p_parent),
|
||||||
|
m_notebook(p_notebook),
|
||||||
|
m_directory(p_directory),
|
||||||
|
m_file(p_file),
|
||||||
|
m_cart(p_cart),
|
||||||
|
m_pageLayout(QPageLayout(QPageSize(QPageSize::A4),
|
||||||
|
QPageLayout::Portrait,
|
||||||
|
QMarginsF(0.3, 0.3, 0.3, 0.3))),
|
||||||
|
m_inExport(false),
|
||||||
|
m_askedToStop(false)
|
||||||
|
{
|
||||||
|
if (s_lastOutputFolder.isEmpty()) {
|
||||||
|
s_lastOutputFolder = g_config->getExportFolderPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
setupUI();
|
||||||
|
|
||||||
|
m_exporter = new VExporter(this);
|
||||||
|
|
||||||
|
initUIFields(p_renderer);
|
||||||
|
|
||||||
|
handleInputChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VExportDialog::setupUI()
|
||||||
|
{
|
||||||
|
// Notes to export.
|
||||||
|
m_srcCB = VUtils::getComboBox();
|
||||||
|
m_srcCB->setToolTip(tr("Choose notes to export"));
|
||||||
|
m_srcCB->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon);
|
||||||
|
|
||||||
|
// Target format.
|
||||||
|
m_formatCB = VUtils::getComboBox();
|
||||||
|
m_formatCB->setToolTip(tr("Choose target format to export as"));
|
||||||
|
m_formatCB->setSizeAdjustPolicy(QComboBox::AdjustToContents);
|
||||||
|
connect(m_formatCB, SIGNAL(currentIndexChanged(int)),
|
||||||
|
this, SLOT(handleCurrentFormatChanged(int)));
|
||||||
|
|
||||||
|
// Markdown renderer.
|
||||||
|
m_rendererCB = VUtils::getComboBox();
|
||||||
|
m_rendererCB->setToolTip(tr("Choose converter to render Markdown"));
|
||||||
|
m_rendererCB->setSizeAdjustPolicy(QComboBox::AdjustToContents);
|
||||||
|
|
||||||
|
// Output directory.
|
||||||
|
m_outputEdit = new VLineEdit(s_lastOutputFolder);
|
||||||
|
connect(m_outputEdit, &QLineEdit::textChanged,
|
||||||
|
this, &VExportDialog::handleInputChanged);
|
||||||
|
m_browseBtn = new QPushButton(tr("&Browse"));
|
||||||
|
connect(m_browseBtn, &QPushButton::clicked,
|
||||||
|
this, &VExportDialog::handleBrowseBtnClicked);
|
||||||
|
QHBoxLayout *outputLayout = new QHBoxLayout();
|
||||||
|
outputLayout->addWidget(m_outputEdit);
|
||||||
|
outputLayout->addWidget(m_browseBtn);
|
||||||
|
|
||||||
|
m_basicBox = new QGroupBox(tr("Information"));
|
||||||
|
|
||||||
|
m_settingBox = new QGroupBox(tr("Advanced Settings"));
|
||||||
|
|
||||||
|
m_consoleEdit = new QPlainTextEdit();
|
||||||
|
m_consoleEdit->setReadOnly(true);
|
||||||
|
m_consoleEdit->setLineWrapMode(QPlainTextEdit::NoWrap);
|
||||||
|
m_consoleEdit->setProperty("LineEdit", true);
|
||||||
|
m_consoleEdit->setPlaceholderText(tr("Output logs will be shown here"));
|
||||||
|
|
||||||
|
// Ok is the default button.
|
||||||
|
m_btnBox = new QDialogButtonBox(QDialogButtonBox::Close);
|
||||||
|
m_exportBtn = m_btnBox->addButton(tr("Export"), QDialogButtonBox::ActionRole);
|
||||||
|
m_openBtn = m_btnBox->addButton(tr("Open Output Directory"), QDialogButtonBox::ActionRole);
|
||||||
|
connect(m_btnBox, &QDialogButtonBox::rejected,
|
||||||
|
this, [this]() {
|
||||||
|
if (m_inExport) {
|
||||||
|
// Just cancel the export. Do not exit.
|
||||||
|
m_askedToStop = true;
|
||||||
|
} else {
|
||||||
|
QDialog::reject();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
m_exportBtn->setProperty("SpecialBtn", true);
|
||||||
|
connect(m_exportBtn, &QPushButton::clicked,
|
||||||
|
this, &VExportDialog::startExport);
|
||||||
|
|
||||||
|
connect(m_openBtn, &QPushButton::clicked,
|
||||||
|
this, [this]() {
|
||||||
|
QUrl url = QUrl::fromLocalFile(getOutputDirectory());
|
||||||
|
QDesktopServices::openUrl(url);
|
||||||
|
});
|
||||||
|
|
||||||
|
QFormLayout *basicLayout = new QFormLayout();
|
||||||
|
basicLayout->addRow(tr("Notes to export:"), m_srcCB);
|
||||||
|
basicLayout->addRow(tr("Target format:"), m_formatCB);
|
||||||
|
basicLayout->addRow(tr("Markdown renderer:"), m_rendererCB);
|
||||||
|
basicLayout->addRow(tr("Output directory:"), outputLayout);
|
||||||
|
|
||||||
|
m_basicBox->setLayout(basicLayout);
|
||||||
|
|
||||||
|
// Settings box.
|
||||||
|
m_pdfSettings = setupPDFAdvancedSettings();
|
||||||
|
|
||||||
|
QVBoxLayout *advLayout = new QVBoxLayout();
|
||||||
|
advLayout->addWidget(m_pdfSettings);
|
||||||
|
|
||||||
|
m_settingBox->setLayout(advLayout);
|
||||||
|
|
||||||
|
QVBoxLayout *mainLayout = new QVBoxLayout();
|
||||||
|
mainLayout->addWidget(m_basicBox);
|
||||||
|
mainLayout->addWidget(m_settingBox);
|
||||||
|
mainLayout->addWidget(m_consoleEdit);
|
||||||
|
mainLayout->addWidget(m_btnBox);
|
||||||
|
|
||||||
|
setLayout(mainLayout);
|
||||||
|
|
||||||
|
setWindowTitle(tr("Export"));
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget *VExportDialog::setupPDFAdvancedSettings()
|
||||||
|
{
|
||||||
|
// Page layout settings.
|
||||||
|
m_layoutLabel = new QLabel();
|
||||||
|
m_layoutBtn = new QPushButton(tr("Settings"));
|
||||||
|
|
||||||
|
#ifndef QT_NO_PRINTER
|
||||||
|
connect(m_layoutBtn, &QPushButton::clicked,
|
||||||
|
this, &VExportDialog::handleLayoutBtnClicked);
|
||||||
|
#else
|
||||||
|
m_layoutBtn->hide();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
updatePageLayoutLabel();
|
||||||
|
|
||||||
|
QHBoxLayout *layoutLayout = new QHBoxLayout();
|
||||||
|
layoutLayout->addWidget(m_layoutLabel);
|
||||||
|
layoutLayout->addWidget(m_layoutBtn);
|
||||||
|
layoutLayout->addStretch();
|
||||||
|
|
||||||
|
QFormLayout *advLayout = new QFormLayout();
|
||||||
|
advLayout->addRow(tr("Page layout:"), layoutLayout);
|
||||||
|
|
||||||
|
advLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
|
||||||
|
QWidget *wid = new QWidget();
|
||||||
|
wid->setLayout(advLayout);
|
||||||
|
|
||||||
|
return wid;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VExportDialog::initUIFields(MarkdownConverterType p_renderer)
|
||||||
|
{
|
||||||
|
// Notes to export.
|
||||||
|
if (m_file) {
|
||||||
|
m_srcCB->addItem(tr("Current Note (%1)").arg(m_file->getName()),
|
||||||
|
(int)ExportSource::CurrentNote);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_directory) {
|
||||||
|
m_srcCB->addItem(tr("Current Directory (%1)").arg(m_directory->getName()),
|
||||||
|
(int)ExportSource::CurrentDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_notebook) {
|
||||||
|
m_srcCB->addItem(tr("Current Notebook (%1)").arg(m_notebook->getName()),
|
||||||
|
(int)ExportSource::CurrentNotebook);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_cart && m_cart->count() > 0) {
|
||||||
|
m_srcCB->addItem(tr("Cart (%1)").arg(m_cart->count()),
|
||||||
|
(int)ExportSource::Cart);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Export format.
|
||||||
|
m_formatCB->addItem(tr("Markdown"), (int)ExportFormat::Markdown);
|
||||||
|
m_formatCB->addItem(tr("HTML"), (int)ExportFormat::HTML);
|
||||||
|
m_formatCB->addItem(tr("PDF"), (int)ExportFormat::PDF);
|
||||||
|
|
||||||
|
// Markdown renderer.
|
||||||
|
m_rendererCB->addItem(tr("Hoedown"), MarkdownConverterType::Hoedown);
|
||||||
|
m_rendererCB->addItem(tr("Marked"), MarkdownConverterType::Marked);
|
||||||
|
m_rendererCB->addItem(tr("Markdown-it"), MarkdownConverterType::MarkdownIt);
|
||||||
|
m_rendererCB->addItem(tr("Showdown"), MarkdownConverterType::Showdown);
|
||||||
|
m_rendererCB->setCurrentIndex(m_rendererCB->findData(p_renderer));
|
||||||
|
}
|
||||||
|
|
||||||
|
void VExportDialog::startExport()
|
||||||
|
{
|
||||||
|
if (m_inExport) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_exportBtn->setEnabled(false);
|
||||||
|
m_askedToStop = false;
|
||||||
|
m_inExport = true;
|
||||||
|
|
||||||
|
QString outputFolder = QDir::cleanPath(QDir(getOutputDirectory()).absolutePath());
|
||||||
|
|
||||||
|
ExportOption opt((ExportSource)m_srcCB->currentData().toInt(),
|
||||||
|
(ExportFormat)m_formatCB->currentData().toInt(),
|
||||||
|
(MarkdownConverterType)m_rendererCB->currentData().toInt(),
|
||||||
|
&m_pageLayout);
|
||||||
|
|
||||||
|
m_consoleEdit->clear();
|
||||||
|
appendLogLine(tr("Export to %1.").arg(outputFolder));
|
||||||
|
|
||||||
|
if (opt.m_format == ExportFormat::PDF) {
|
||||||
|
m_exporter->prepareExport(opt);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret = 0;
|
||||||
|
QString msg;
|
||||||
|
|
||||||
|
switch ((int)opt.m_source) {
|
||||||
|
case (int)ExportSource::CurrentNote:
|
||||||
|
ret = doExport(m_file, opt, outputFolder, &msg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case (int)ExportSource::CurrentDirectory:
|
||||||
|
ret = doExport(m_directory, opt, outputFolder, &msg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case (int)ExportSource::CurrentNotebook:
|
||||||
|
ret = doExport(m_notebook, opt, outputFolder, &msg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case (int)ExportSource::Cart:
|
||||||
|
ret = doExport(m_cart, opt, outputFolder, &msg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_askedToStop) {
|
||||||
|
appendLogLine(tr("User cancelled the export. Aborted!"));
|
||||||
|
m_askedToStop = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!msg.isEmpty()) {
|
||||||
|
VUtils::showMessage(QMessageBox::Warning,
|
||||||
|
tr("Warning"),
|
||||||
|
tr("Errors found during export."),
|
||||||
|
msg,
|
||||||
|
QMessageBox::Ok,
|
||||||
|
QMessageBox::Ok,
|
||||||
|
this);
|
||||||
|
}
|
||||||
|
|
||||||
|
appendLogLine(tr("%1 notes exported.").arg(ret));
|
||||||
|
|
||||||
|
m_inExport = false;
|
||||||
|
m_exportBtn->setEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString VExportDialog::getOutputDirectory() const
|
||||||
|
{
|
||||||
|
return m_outputEdit->text();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VExportDialog::handleBrowseBtnClicked()
|
||||||
|
{
|
||||||
|
QString initPath = getOutputDirectory();
|
||||||
|
if (!QFileInfo::exists(initPath)) {
|
||||||
|
initPath = g_config->getDocumentPathOrHomePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString dirPath = QFileDialog::getExistingDirectory(this,
|
||||||
|
tr("Select Output Directory To Export To"),
|
||||||
|
initPath,
|
||||||
|
QFileDialog::ShowDirsOnly
|
||||||
|
| QFileDialog::DontResolveSymlinks);
|
||||||
|
|
||||||
|
if (!dirPath.isEmpty()) {
|
||||||
|
m_outputEdit->setText(dirPath);
|
||||||
|
s_lastOutputFolder = dirPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VExportDialog::handleInputChanged()
|
||||||
|
{
|
||||||
|
// Source.
|
||||||
|
bool sourceOk = true;
|
||||||
|
if (m_srcCB->count() == 0) {
|
||||||
|
sourceOk = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output folder.
|
||||||
|
bool pathOk = true;
|
||||||
|
QString path = getOutputDirectory();
|
||||||
|
if (path.isEmpty() || !VUtils::checkPathLegal(path)) {
|
||||||
|
pathOk = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_exportBtn->setEnabled(sourceOk && pathOk);
|
||||||
|
m_openBtn->setEnabled(pathOk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VExportDialog::appendLogLine(const QString &p_text)
|
||||||
|
{
|
||||||
|
m_consoleEdit->appendPlainText(p_text);
|
||||||
|
QCoreApplication::sendPostedEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
int VExportDialog::doExport(VFile *p_file,
|
||||||
|
const ExportOption &p_opt,
|
||||||
|
const QString &p_outputFolder,
|
||||||
|
QString *p_errMsg)
|
||||||
|
{
|
||||||
|
Q_ASSERT(p_file);
|
||||||
|
|
||||||
|
appendLogLine(tr("Exporting note %1.").arg(p_file->fetchPath()));
|
||||||
|
|
||||||
|
int ret = 0;
|
||||||
|
switch ((int)p_opt.m_format) {
|
||||||
|
case (int)ExportFormat::Markdown:
|
||||||
|
ret = doExportMarkdown(p_file, p_opt, p_outputFolder, p_errMsg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case (int)ExportFormat::PDF:
|
||||||
|
ret = doExportPDF(p_file, p_opt, p_outputFolder, p_errMsg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int VExportDialog::doExport(VDirectory *p_directory,
|
||||||
|
const ExportOption &p_opt,
|
||||||
|
const QString &p_outputFolder,
|
||||||
|
QString *p_errMsg)
|
||||||
|
{
|
||||||
|
Q_ASSERT(p_directory);
|
||||||
|
|
||||||
|
bool opened = p_directory->isOpened();
|
||||||
|
if (!opened && !p_directory->open()) {
|
||||||
|
LOGERR(tr("Fail to open folder %1.").arg(p_directory->fetchRelativePath()));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
QString folderName = VUtils::getDirNameWithSequence(p_outputFolder,
|
||||||
|
p_directory->getName());
|
||||||
|
QString outputPath = QDir(p_outputFolder).filePath(folderName);
|
||||||
|
if (!VUtils::makePath(outputPath)) {
|
||||||
|
LOGERR(tr("Fail to create directory %1.").arg(outputPath));
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Export child notes.
|
||||||
|
for (auto const & file : p_directory->getFiles()) {
|
||||||
|
if (!checkUserAction()) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret += doExport(file, p_opt, outputPath, p_errMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Export subfolder.
|
||||||
|
for (auto const & dir : p_directory->getSubDirs()) {
|
||||||
|
if (!checkUserAction()) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret += doExport(dir, p_opt, outputPath, p_errMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
if (!opened) {
|
||||||
|
p_directory->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int VExportDialog::doExport(VNotebook *p_notebook,
|
||||||
|
const ExportOption &p_opt,
|
||||||
|
const QString &p_outputFolder,
|
||||||
|
QString *p_errMsg)
|
||||||
|
{
|
||||||
|
Q_ASSERT(p_notebook);
|
||||||
|
|
||||||
|
bool opened = p_notebook->isOpened();
|
||||||
|
if (!opened && !p_notebook->open()) {
|
||||||
|
LOGERR(tr("Fail to open notebook %1.").arg(p_notebook->getName()));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
QString folderName = VUtils::getDirNameWithSequence(p_outputFolder,
|
||||||
|
p_notebook->getName());
|
||||||
|
QString outputPath = QDir(p_outputFolder).filePath(folderName);
|
||||||
|
if (!VUtils::makePath(outputPath)) {
|
||||||
|
LOGERR(tr("Fail to create directory %1.").arg(outputPath));
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Export subfolder.
|
||||||
|
for (auto const & dir : p_notebook->getRootDir()->getSubDirs()) {
|
||||||
|
if (!checkUserAction()) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret += doExport(dir, p_opt, outputPath, p_errMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
if (!opened) {
|
||||||
|
p_notebook->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int VExportDialog::doExport(VCart *p_cart,
|
||||||
|
const ExportOption &p_opt,
|
||||||
|
const QString &p_outputFolder,
|
||||||
|
QString *p_errMsg)
|
||||||
|
{
|
||||||
|
Q_ASSERT(p_cart);
|
||||||
|
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
QVector<QString> files = m_cart->getFiles();
|
||||||
|
for (auto const & it : files) {
|
||||||
|
VFile *file = g_vnote->getFile(it);
|
||||||
|
if (!file) {
|
||||||
|
LOGERR(tr("Fail to open file %1.").arg(it));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret += doExport(file, p_opt, p_outputFolder, p_errMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int VExportDialog::doExportMarkdown(VFile *p_file,
|
||||||
|
const ExportOption &p_opt,
|
||||||
|
const QString &p_outputFolder,
|
||||||
|
QString *p_errMsg)
|
||||||
|
{
|
||||||
|
Q_UNUSED(p_opt);
|
||||||
|
|
||||||
|
QString srcFilePath(p_file->fetchPath());
|
||||||
|
|
||||||
|
if (p_file->getDocType() != DocType::Markdown) {
|
||||||
|
LOGERR(tr("Skip exporting non-Markdown file %1 as Markdown.").arg(srcFilePath));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Export it to a folder with the same name.
|
||||||
|
QString name = VUtils::getDirNameWithSequence(p_outputFolder, p_file->getName());
|
||||||
|
QString outputPath = QDir(p_outputFolder).filePath(name);
|
||||||
|
if (!VUtils::makePath(outputPath)) {
|
||||||
|
LOGERR(tr("Fail to create directory %1.").arg(outputPath));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy the note file.
|
||||||
|
QString destPath = QDir(outputPath).filePath(p_file->getName());
|
||||||
|
if (!VUtils::copyFile(srcFilePath, destPath, false)) {
|
||||||
|
LOGERR(tr("Fail to copy the note file %1.").arg(srcFilePath));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy images.
|
||||||
|
int ret = 1;
|
||||||
|
int nrImageCopied = 0;
|
||||||
|
QVector<ImageLink> images = VUtils::fetchImagesFromMarkdownFile(p_file,
|
||||||
|
ImageLink::LocalRelativeInternal);
|
||||||
|
if (!VNoteFile::copyInternalImages(images,
|
||||||
|
outputPath,
|
||||||
|
false,
|
||||||
|
&nrImageCopied,
|
||||||
|
p_errMsg)) {
|
||||||
|
ret = 0;
|
||||||
|
appendLogLine(tr("Fail to copy images of note %1.").arg(srcFilePath));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy attachments.
|
||||||
|
if (p_file->getType() == FileType::Note) {
|
||||||
|
VNoteFile *noteFile = static_cast<VNoteFile *>(p_file);
|
||||||
|
QString attaFolder = noteFile->getAttachmentFolder();
|
||||||
|
if (!attaFolder.isEmpty()) {
|
||||||
|
QString attaFolderPath;
|
||||||
|
attaFolderPath = noteFile->fetchAttachmentFolderPath();
|
||||||
|
attaFolder = VUtils::getDirNameWithSequence(outputPath, attaFolder);
|
||||||
|
QString folderPath = QDir(outputPath).filePath(attaFolder);
|
||||||
|
|
||||||
|
// Copy attaFolder to folderPath.
|
||||||
|
if (!VUtils::copyDirectory(attaFolderPath, folderPath, false)) {
|
||||||
|
LOGERR(tr("Fail to copy attachments folder %1 to %2.")
|
||||||
|
.arg(attaFolderPath).arg(folderPath));
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
appendLogLine(tr("Note %1 exported to %2.").arg(srcFilePath).arg(outputPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int VExportDialog::doExportPDF(VFile *p_file,
|
||||||
|
const ExportOption &p_opt,
|
||||||
|
const QString &p_outputFolder,
|
||||||
|
QString *p_errMsg)
|
||||||
|
{
|
||||||
|
Q_UNUSED(p_opt);
|
||||||
|
|
||||||
|
QString srcFilePath(p_file->fetchPath());
|
||||||
|
|
||||||
|
if (p_file->getDocType() != DocType::Markdown) {
|
||||||
|
LOGERR(tr("Skip exporting non-Markdown file %1 as PDF.").arg(srcFilePath));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get output file.
|
||||||
|
QString suffix = ".pdf";
|
||||||
|
QString name = VUtils::getFileNameWithSequence(p_outputFolder,
|
||||||
|
QFileInfo(p_file->getName()).completeBaseName() + suffix);
|
||||||
|
QString outputPath = QDir(p_outputFolder).filePath(name);
|
||||||
|
|
||||||
|
if (m_exporter->exportPDF(p_file, p_opt, outputPath, p_errMsg)) {
|
||||||
|
appendLogLine(tr("Note %1 exported to %2.").arg(srcFilePath).arg(outputPath));
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
appendLogLine(tr("Fail to export note %1.").arg(srcFilePath));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VExportDialog::checkUserAction()
|
||||||
|
{
|
||||||
|
if (m_askedToStop) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QCoreApplication::processEvents();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VExportDialog::handleLayoutBtnClicked()
|
||||||
|
{
|
||||||
|
#ifndef QT_NO_PRINTER
|
||||||
|
QPrinter printer;
|
||||||
|
printer.setPageLayout(m_pageLayout);
|
||||||
|
|
||||||
|
QPageSetupDialog dlg(&printer, this);
|
||||||
|
if (dlg.exec() != QDialog::Accepted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pageLayout.setPageSize(printer.pageLayout().pageSize());
|
||||||
|
m_pageLayout.setMargins(printer.pageLayout().margins());
|
||||||
|
m_pageLayout.setOrientation(printer.pageLayout().orientation());
|
||||||
|
|
||||||
|
updatePageLayoutLabel();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void VExportDialog::updatePageLayoutLabel()
|
||||||
|
{
|
||||||
|
qDebug() << "page layout margins:" << m_pageLayout.margins();
|
||||||
|
|
||||||
|
m_layoutLabel->setText(QString("%1, %2").arg(m_pageLayout.pageSize().name())
|
||||||
|
.arg(m_pageLayout.orientation() == QPageLayout::Portrait ?
|
||||||
|
tr("Portrait") : tr("Landscape")));
|
||||||
|
}
|
||||||
|
|
||||||
|
void VExportDialog::handleCurrentFormatChanged(int p_index)
|
||||||
|
{
|
||||||
|
bool pdfEnabled = false;
|
||||||
|
|
||||||
|
if (p_index >= 0) {
|
||||||
|
switch (m_formatCB->currentData().toInt()) {
|
||||||
|
case (int)ExportFormat::PDF:
|
||||||
|
pdfEnabled = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pdfSettings->setVisible(pdfEnabled);
|
||||||
|
}
|
180
src/dialog/vexportdialog.h
Normal file
180
src/dialog/vexportdialog.h
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
#ifndef VEXPORTDIALOG_H
|
||||||
|
#define VEXPORTDIALOG_H
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QPageLayout>
|
||||||
|
|
||||||
|
#include "vconstants.h"
|
||||||
|
|
||||||
|
class QLabel;
|
||||||
|
class VLineEdit;
|
||||||
|
class QDialogButtonBox;
|
||||||
|
class QComboBox;
|
||||||
|
class QPushButton;
|
||||||
|
class QGroupBox;
|
||||||
|
class QPlainTextEdit;
|
||||||
|
class VNotebook;
|
||||||
|
class VDirectory;
|
||||||
|
class VFile;
|
||||||
|
class VCart;
|
||||||
|
class VExporter;
|
||||||
|
|
||||||
|
|
||||||
|
enum class ExportSource
|
||||||
|
{
|
||||||
|
CurrentNote = 0,
|
||||||
|
CurrentDirectory,
|
||||||
|
CurrentNotebook,
|
||||||
|
Cart
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
enum class ExportFormat
|
||||||
|
{
|
||||||
|
Markdown = 0,
|
||||||
|
HTML,
|
||||||
|
PDF
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct ExportOption
|
||||||
|
{
|
||||||
|
ExportOption(ExportSource p_source,
|
||||||
|
ExportFormat p_format,
|
||||||
|
MarkdownConverterType p_renderer,
|
||||||
|
QPageLayout *p_layout)
|
||||||
|
: m_source(p_source),
|
||||||
|
m_format(p_format),
|
||||||
|
m_renderer(p_renderer),
|
||||||
|
m_layout(p_layout)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ExportSource m_source;
|
||||||
|
ExportFormat m_format;
|
||||||
|
MarkdownConverterType m_renderer;
|
||||||
|
QPageLayout *m_layout;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class VExportDialog : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
VExportDialog(VNotebook *p_notebook,
|
||||||
|
VDirectory *p_directory,
|
||||||
|
VFile *p_file,
|
||||||
|
VCart *p_cart,
|
||||||
|
MarkdownConverterType p_renderer,
|
||||||
|
QWidget *p_parent = nullptr);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void startExport();
|
||||||
|
|
||||||
|
void handleBrowseBtnClicked();
|
||||||
|
|
||||||
|
void handleInputChanged();
|
||||||
|
|
||||||
|
void handleLayoutBtnClicked();
|
||||||
|
|
||||||
|
void handleCurrentFormatChanged(int p_index);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setupUI();
|
||||||
|
|
||||||
|
QWidget *setupPDFAdvancedSettings();
|
||||||
|
|
||||||
|
void initUIFields(MarkdownConverterType p_renderer);
|
||||||
|
|
||||||
|
QString getOutputDirectory() const;
|
||||||
|
|
||||||
|
void appendLogLine(const QString &p_text);
|
||||||
|
|
||||||
|
// Return number of files exported.
|
||||||
|
int doExport(VFile *p_file,
|
||||||
|
const ExportOption &p_opt,
|
||||||
|
const QString &p_outputFolder,
|
||||||
|
QString *p_errMsg = NULL);
|
||||||
|
|
||||||
|
int doExport(VDirectory *p_directory,
|
||||||
|
const ExportOption &p_opt,
|
||||||
|
const QString &p_outputFolder,
|
||||||
|
QString *p_errMsg = NULL);
|
||||||
|
|
||||||
|
int doExport(VNotebook *p_notebook,
|
||||||
|
const ExportOption &p_opt,
|
||||||
|
const QString &p_outputFolder,
|
||||||
|
QString *p_errMsg = NULL);
|
||||||
|
|
||||||
|
int doExport(VCart *p_cart,
|
||||||
|
const ExportOption &p_opt,
|
||||||
|
const QString &p_outputFolder,
|
||||||
|
QString *p_errMsg = NULL);
|
||||||
|
|
||||||
|
int doExportMarkdown(VFile *p_file,
|
||||||
|
const ExportOption &p_opt,
|
||||||
|
const QString &p_outputFolder,
|
||||||
|
QString *p_errMsg = NULL);
|
||||||
|
|
||||||
|
int doExportPDF(VFile *p_file,
|
||||||
|
const ExportOption &p_opt,
|
||||||
|
const QString &p_outputFolder,
|
||||||
|
QString *p_errMsg = NULL);
|
||||||
|
|
||||||
|
// Return false if we could not continue.
|
||||||
|
bool checkUserAction();
|
||||||
|
|
||||||
|
void updatePageLayoutLabel();
|
||||||
|
|
||||||
|
QComboBox *m_srcCB;
|
||||||
|
|
||||||
|
QComboBox *m_formatCB;
|
||||||
|
|
||||||
|
QComboBox *m_rendererCB;
|
||||||
|
|
||||||
|
VLineEdit *m_outputEdit;
|
||||||
|
|
||||||
|
QPushButton *m_browseBtn;
|
||||||
|
|
||||||
|
QGroupBox *m_basicBox;
|
||||||
|
|
||||||
|
QGroupBox *m_settingBox;
|
||||||
|
|
||||||
|
QWidget *m_pdfSettings;
|
||||||
|
|
||||||
|
QPlainTextEdit *m_consoleEdit;
|
||||||
|
|
||||||
|
QDialogButtonBox *m_btnBox;
|
||||||
|
|
||||||
|
QPushButton *m_openBtn;
|
||||||
|
|
||||||
|
QPushButton *m_exportBtn;
|
||||||
|
|
||||||
|
QLabel *m_layoutLabel;
|
||||||
|
|
||||||
|
QPushButton *m_layoutBtn;
|
||||||
|
|
||||||
|
VNotebook *m_notebook;
|
||||||
|
|
||||||
|
VDirectory *m_directory;
|
||||||
|
|
||||||
|
VFile *m_file;
|
||||||
|
|
||||||
|
VCart *m_cart;
|
||||||
|
|
||||||
|
QPageLayout m_pageLayout;
|
||||||
|
|
||||||
|
// Whether we are exporting files.
|
||||||
|
bool m_inExport;
|
||||||
|
|
||||||
|
// Asked to stop exporting by user.
|
||||||
|
bool m_askedToStop;
|
||||||
|
|
||||||
|
// Exporter used to export PDF and HTML.
|
||||||
|
VExporter *m_exporter;
|
||||||
|
|
||||||
|
// Last output folder path.
|
||||||
|
static QString s_lastOutputFolder;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // VEXPORTDIALOG_H
|
@ -143,7 +143,7 @@ void VNewNotebookDialog::handleBrowseBtnClicked()
|
|||||||
if (defaultPath.isEmpty()) {
|
if (defaultPath.isEmpty()) {
|
||||||
defaultPath = g_config->getVnoteNotebookFolderPath();
|
defaultPath = g_config->getVnoteNotebookFolderPath();
|
||||||
if (!QFileInfo::exists(defaultPath)) {
|
if (!QFileInfo::exists(defaultPath)) {
|
||||||
defaultPath = QDir::homePath();
|
defaultPath = g_config->getDocumentPathOrHomePath();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@ class QLabel;
|
|||||||
class VLineEdit;
|
class VLineEdit;
|
||||||
class VMetaWordLineEdit;
|
class VMetaWordLineEdit;
|
||||||
class QDialogButtonBox;
|
class QDialogButtonBox;
|
||||||
class QString;
|
|
||||||
class VNotebook;
|
class VNotebook;
|
||||||
|
|
||||||
class VNotebookInfoDialog : public QDialog
|
class VNotebookInfoDialog : public QDialog
|
||||||
|
10
src/src.pro
10
src/src.pro
@ -60,7 +60,6 @@ SOURCES += main.cpp\
|
|||||||
vorphanfile.cpp \
|
vorphanfile.cpp \
|
||||||
vcodeblockhighlighthelper.cpp \
|
vcodeblockhighlighthelper.cpp \
|
||||||
vwebview.cpp \
|
vwebview.cpp \
|
||||||
vexporter.cpp \
|
|
||||||
vmdtab.cpp \
|
vmdtab.cpp \
|
||||||
vhtmltab.cpp \
|
vhtmltab.cpp \
|
||||||
utils/vvim.cpp \
|
utils/vvim.cpp \
|
||||||
@ -112,7 +111,9 @@ SOURCES += main.cpp\
|
|||||||
vlistwidget.cpp \
|
vlistwidget.cpp \
|
||||||
vsimplesearchinput.cpp \
|
vsimplesearchinput.cpp \
|
||||||
vstyleditemdelegate.cpp \
|
vstyleditemdelegate.cpp \
|
||||||
vtreewidget.cpp
|
vtreewidget.cpp \
|
||||||
|
dialog/vexportdialog.cpp \
|
||||||
|
vexporter.cpp
|
||||||
|
|
||||||
HEADERS += vmainwindow.h \
|
HEADERS += vmainwindow.h \
|
||||||
vdirectorytree.h \
|
vdirectorytree.h \
|
||||||
@ -158,7 +159,6 @@ HEADERS += vmainwindow.h \
|
|||||||
vorphanfile.h \
|
vorphanfile.h \
|
||||||
vcodeblockhighlighthelper.h \
|
vcodeblockhighlighthelper.h \
|
||||||
vwebview.h \
|
vwebview.h \
|
||||||
vexporter.h \
|
|
||||||
vmdtab.h \
|
vmdtab.h \
|
||||||
vhtmltab.h \
|
vhtmltab.h \
|
||||||
utils/vvim.h \
|
utils/vvim.h \
|
||||||
@ -211,7 +211,9 @@ HEADERS += vmainwindow.h \
|
|||||||
vlistwidget.h \
|
vlistwidget.h \
|
||||||
vsimplesearchinput.h \
|
vsimplesearchinput.h \
|
||||||
vstyleditemdelegate.h \
|
vstyleditemdelegate.h \
|
||||||
vtreewidget.h
|
vtreewidget.h \
|
||||||
|
dialog/vexportdialog.h \
|
||||||
|
vexporter.h
|
||||||
|
|
||||||
RESOURCES += \
|
RESOURCES += \
|
||||||
vnote.qrc \
|
vnote.qrc \
|
||||||
|
@ -191,3 +191,19 @@ QString VCart::getFilePath(const QListWidgetItem *p_item) const
|
|||||||
{
|
{
|
||||||
return p_item->data(Qt::UserRole).toString();
|
return p_item->data(Qt::UserRole).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int VCart::count() const
|
||||||
|
{
|
||||||
|
return m_itemList->count();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<QString> VCart::getFiles() const
|
||||||
|
{
|
||||||
|
QVector<QString> files;
|
||||||
|
int cnt = m_itemList->count();
|
||||||
|
for (int i = 0; i < cnt; ++i) {
|
||||||
|
files.append(getFilePath(m_itemList->item(i)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
@ -22,6 +22,10 @@ public:
|
|||||||
|
|
||||||
void addFile(const QString &p_filePath);
|
void addFile(const QString &p_filePath);
|
||||||
|
|
||||||
|
int count() const;
|
||||||
|
|
||||||
|
QVector<QString> getFiles() const;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void handleContextMenuRequested(QPoint p_pos);
|
void handleContextMenuRequested(QPoint p_pos);
|
||||||
|
|
||||||
|
@ -47,6 +47,8 @@ const QString VConfigManager::c_dataTextStyle = QString("font: bold");
|
|||||||
|
|
||||||
const QString VConfigManager::c_vnoteNotebookFolderName = QString("vnote_notebooks");
|
const QString VConfigManager::c_vnoteNotebookFolderName = QString("vnote_notebooks");
|
||||||
|
|
||||||
|
const QString VConfigManager::c_exportFolderName = QString("vnote_exports");
|
||||||
|
|
||||||
VConfigManager::VConfigManager(QObject *p_parent)
|
VConfigManager::VConfigManager(QObject *p_parent)
|
||||||
: QObject(p_parent),
|
: QObject(p_parent),
|
||||||
m_hasReset(false),
|
m_hasReset(false),
|
||||||
@ -930,6 +932,26 @@ QString VConfigManager::getVnoteNotebookFolderPath()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString VConfigManager::getExportFolderPath()
|
||||||
|
{
|
||||||
|
QStringList folders = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation);
|
||||||
|
if (folders.isEmpty()) {
|
||||||
|
return QDir::home().filePath(c_exportFolderName);
|
||||||
|
} else {
|
||||||
|
return QDir(folders[0]).filePath(c_exportFolderName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString VConfigManager::getDocumentPathOrHomePath()
|
||||||
|
{
|
||||||
|
QStringList folders = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation);
|
||||||
|
if (folders.isEmpty()) {
|
||||||
|
return QDir::homePath();
|
||||||
|
} else {
|
||||||
|
return folders[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QHash<QString, QString> VConfigManager::readShortcutsFromSettings(QSettings *p_settings,
|
QHash<QString, QString> VConfigManager::readShortcutsFromSettings(QSettings *p_settings,
|
||||||
const QString &p_group)
|
const QString &p_group)
|
||||||
{
|
{
|
||||||
|
@ -14,20 +14,9 @@
|
|||||||
#include "vfilesessioninfo.h"
|
#include "vfilesessioninfo.h"
|
||||||
#include "utils/vmetawordmanager.h"
|
#include "utils/vmetawordmanager.h"
|
||||||
|
|
||||||
|
|
||||||
class QJsonObject;
|
class QJsonObject;
|
||||||
class QString;
|
class QString;
|
||||||
|
|
||||||
|
|
||||||
enum MarkdownConverterType
|
|
||||||
{
|
|
||||||
Hoedown = 0,
|
|
||||||
Marked,
|
|
||||||
MarkdownIt,
|
|
||||||
Showdown
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct VColor
|
struct VColor
|
||||||
{
|
{
|
||||||
QString m_name;
|
QString m_name;
|
||||||
@ -57,6 +46,7 @@ struct MarkdownitOption
|
|||||||
bool m_linkify;
|
bool m_linkify;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// Type of heading sequence.
|
// Type of heading sequence.
|
||||||
enum class HeadingSequenceType
|
enum class HeadingSequenceType
|
||||||
{
|
{
|
||||||
@ -69,6 +59,7 @@ enum class HeadingSequenceType
|
|||||||
Invalid
|
Invalid
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class VConfigManager : public QObject
|
class VConfigManager : public QObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -89,6 +80,11 @@ public:
|
|||||||
// Get the path of the folder used to store default notebook.
|
// Get the path of the folder used to store default notebook.
|
||||||
static QString getVnoteNotebookFolderPath();
|
static QString getVnoteNotebookFolderPath();
|
||||||
|
|
||||||
|
// Get the path of the default export folder.
|
||||||
|
static QString getExportFolderPath();
|
||||||
|
|
||||||
|
static QString getDocumentPathOrHomePath();
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
static const QString orgName;
|
static const QString orgName;
|
||||||
static const QString appName;
|
static const QString appName;
|
||||||
@ -892,6 +888,9 @@ private:
|
|||||||
|
|
||||||
// The folder name to store all notebooks if user does not specify one.
|
// The folder name to store all notebooks if user does not specify one.
|
||||||
static const QString c_vnoteNotebookFolderName;
|
static const QString c_vnoteNotebookFolderName;
|
||||||
|
|
||||||
|
// The default export output folder name.
|
||||||
|
static const QString c_exportFolderName;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -141,4 +141,12 @@ enum class UpdateAction
|
|||||||
Moved
|
Moved
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum MarkdownConverterType
|
||||||
|
{
|
||||||
|
Hoedown = 0,
|
||||||
|
Marked,
|
||||||
|
MarkdownIt,
|
||||||
|
Showdown
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1207,3 +1207,13 @@ void VDirectoryTree::sortItems(VDirectory *p_dir)
|
|||||||
updateItemDirectChildren(findVDirectory(p_dir));
|
updateItemDirectChildren(findVDirectory(p_dir));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VDirectory *VDirectoryTree::currentDirectory() const
|
||||||
|
{
|
||||||
|
QTreeWidgetItem *item = currentItem();
|
||||||
|
if (item) {
|
||||||
|
return getVDirectory(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
@ -30,6 +30,8 @@ public:
|
|||||||
|
|
||||||
const VNotebook *currentNotebook() const;
|
const VNotebook *currentNotebook() const;
|
||||||
|
|
||||||
|
VDirectory *currentDirectory() const;
|
||||||
|
|
||||||
// Implementations for VNavigationMode.
|
// Implementations for VNavigationMode.
|
||||||
void showNavigation() Q_DECL_OVERRIDE;
|
void showNavigation() Q_DECL_OVERRIDE;
|
||||||
bool handleKeyNavigation(int p_key, bool &p_succeed) Q_DECL_OVERRIDE;
|
bool handleKeyNavigation(int p_key, bool &p_succeed) Q_DECL_OVERRIDE;
|
||||||
|
@ -1,206 +1,111 @@
|
|||||||
#include "vexporter.h"
|
#include "vexporter.h"
|
||||||
|
|
||||||
#include <QtWidgets>
|
|
||||||
#include <QFileInfo>
|
|
||||||
#include <QDir>
|
|
||||||
#include <QWebChannel>
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QVBoxLayout>
|
#include <QWidget>
|
||||||
#include <QShowEvent>
|
#include <QWebChannel>
|
||||||
|
|
||||||
#ifndef QT_NO_PRINTER
|
|
||||||
#include <QPrinter>
|
|
||||||
#include <QPageSetupDialog>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "vconfigmanager.h"
|
#include "vconfigmanager.h"
|
||||||
#include "utils/vutils.h"
|
|
||||||
#include "vfile.h"
|
#include "vfile.h"
|
||||||
#include "vwebview.h"
|
#include "vwebview.h"
|
||||||
|
#include "utils/vutils.h"
|
||||||
#include "vpreviewpage.h"
|
#include "vpreviewpage.h"
|
||||||
#include "vconstants.h"
|
#include "vconstants.h"
|
||||||
#include "vnote.h"
|
|
||||||
#include "vmarkdownconverter.h"
|
#include "vmarkdownconverter.h"
|
||||||
#include "vdocument.h"
|
#include "vdocument.h"
|
||||||
#include "vlineedit.h"
|
|
||||||
|
|
||||||
extern VConfigManager *g_config;
|
extern VConfigManager *g_config;
|
||||||
|
|
||||||
QString VExporter::s_defaultPathDir = QDir::homePath();
|
VExporter::VExporter(QWidget *p_parent)
|
||||||
|
: QObject(p_parent),
|
||||||
VExporter::VExporter(MarkdownConverterType p_mdType, QWidget *p_parent)
|
m_webViewer(NULL),
|
||||||
: QDialog(p_parent), m_webViewer(NULL), m_mdType(p_mdType),
|
m_state(ExportState::Idle)
|
||||||
m_file(NULL), m_type(ExportType::PDF), m_source(ExportSource::Invalid),
|
|
||||||
m_noteState(NoteState::NotReady), m_state(ExportState::Idle),
|
|
||||||
m_pageLayout(QPageLayout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF(0.0, 0.0, 0.0, 0.0))),
|
|
||||||
m_exported(false)
|
|
||||||
{
|
{
|
||||||
initMarkdownTemplate();
|
|
||||||
|
|
||||||
setupUI();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VExporter::initMarkdownTemplate()
|
void VExporter::prepareExport(const ExportOption &p_opt)
|
||||||
{
|
{
|
||||||
m_htmlTemplate = VUtils::generateHtmlTemplate(m_mdType, true);
|
m_htmlTemplate = VUtils::generateHtmlTemplate(p_opt.m_renderer, true);
|
||||||
|
m_pageLayout = *(p_opt.m_layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VExporter::setupUI()
|
bool VExporter::exportPDF(VFile *p_file,
|
||||||
|
const ExportOption &p_opt,
|
||||||
|
const QString &p_outputFile,
|
||||||
|
QString *p_errMsg)
|
||||||
{
|
{
|
||||||
m_infoLabel = new QLabel();
|
Q_UNUSED(p_errMsg);
|
||||||
m_infoLabel->setWordWrap(true);
|
|
||||||
|
|
||||||
// Target file path.
|
bool ret = false;
|
||||||
QLabel *pathLabel = new QLabel(tr("Target &path:"));
|
|
||||||
m_pathEdit = new VLineEdit();
|
|
||||||
pathLabel->setBuddy(m_pathEdit);
|
|
||||||
m_browseBtn = new QPushButton(tr("&Browse"));
|
|
||||||
connect(m_browseBtn, &QPushButton::clicked,
|
|
||||||
this, &VExporter::handleBrowseBtnClicked);
|
|
||||||
|
|
||||||
// Page layout.
|
bool isOpened = p_file->isOpened();
|
||||||
QLabel *layoutLabel = new QLabel(tr("Page layout:"));
|
if (!isOpened && !p_file->open()) {
|
||||||
m_layoutLabel = new QLabel();
|
goto exit;
|
||||||
m_layoutBtn = new QPushButton(tr("&Settings"));
|
}
|
||||||
|
|
||||||
#ifndef QT_NO_PRINTER
|
Q_ASSERT(m_state == ExportState::Idle);
|
||||||
connect(m_layoutBtn, &QPushButton::clicked,
|
m_state = ExportState::Busy;
|
||||||
this, &VExporter::handleLayoutBtnClicked);
|
|
||||||
#else
|
|
||||||
m_layoutBtn->hide();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Progress.
|
clearNoteState();
|
||||||
m_proLabel = new QLabel(this);
|
|
||||||
m_proBar = new QProgressBar(this);
|
|
||||||
|
|
||||||
// Ok is the default button.
|
initWebViewer(p_file, p_opt);
|
||||||
m_btnBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
|
||||||
m_openBtn = m_btnBox->addButton(tr("Open File Location"), QDialogButtonBox::ActionRole);
|
|
||||||
connect(m_btnBox, &QDialogButtonBox::accepted, this, &VExporter::startExport);
|
|
||||||
connect(m_btnBox, &QDialogButtonBox::rejected, this, &VExporter::cancelExport);
|
|
||||||
connect(m_openBtn, &QPushButton::clicked, this, &VExporter::openTargetPath);
|
|
||||||
|
|
||||||
QPushButton *okBtn = m_btnBox->button(QDialogButtonBox::Ok);
|
while (!isNoteStateReady()) {
|
||||||
okBtn->setProperty("SpecialBtn", true);
|
VUtils::sleepWait(100);
|
||||||
m_pathEdit->setMinimumWidth(okBtn->sizeHint().width() * 3);
|
|
||||||
|
|
||||||
QGridLayout *mainLayout = new QGridLayout();
|
if (m_state == ExportState::Cancelled) {
|
||||||
mainLayout->addWidget(m_infoLabel, 0, 0, 1, 3);
|
goto exit;
|
||||||
mainLayout->addWidget(pathLabel, 1, 0);
|
}
|
||||||
mainLayout->addWidget(m_pathEdit, 1, 1);
|
|
||||||
mainLayout->addWidget(m_browseBtn, 1, 2);
|
|
||||||
mainLayout->addWidget(layoutLabel, 2, 0);
|
|
||||||
mainLayout->addWidget(m_layoutLabel, 2, 1);
|
|
||||||
mainLayout->addWidget(m_layoutBtn, 2, 2);
|
|
||||||
mainLayout->addWidget(m_proLabel, 3, 1, 1, 2);
|
|
||||||
mainLayout->addWidget(m_proBar, 4, 1, 1, 2);
|
|
||||||
mainLayout->addWidget(m_btnBox, 5, 1, 1, 2);
|
|
||||||
|
|
||||||
m_proLabel->hide();
|
if (isNoteStateFailed()) {
|
||||||
m_proBar->hide();
|
m_state = ExportState::Failed;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setLayout(mainLayout);
|
// Wait to ensure Web side is really ready.
|
||||||
mainLayout->setSizeConstraint(QLayout::SetFixedSize);
|
VUtils::sleepWait(200);
|
||||||
setWindowTitle(tr("Export Note"));
|
|
||||||
|
|
||||||
m_openBtn->hide();
|
if (m_state == ExportState::Cancelled) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
updatePageLayoutLabel();
|
{
|
||||||
}
|
bool exportRet = exportToPDF(m_webViewer,
|
||||||
|
p_outputFile,
|
||||||
|
m_pageLayout);
|
||||||
|
|
||||||
static QString exportTypeStr(ExportType p_type)
|
clearNoteState();
|
||||||
{
|
|
||||||
if (p_type == ExportType::PDF) {
|
if (!isOpened) {
|
||||||
return "PDF";
|
p_file->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exportRet) {
|
||||||
|
m_state = ExportState::Successful;
|
||||||
} else {
|
} else {
|
||||||
return "HTML";
|
m_state = ExportState::Failed;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void VExporter::handleBrowseBtnClicked()
|
|
||||||
{
|
|
||||||
QFileInfo fi(getFilePath());
|
|
||||||
QString fileType = m_type == ExportType::PDF ?
|
|
||||||
tr("Portable Document Format (*.pdf)") :
|
|
||||||
tr("WebPage, Complete (*.html)");
|
|
||||||
QString path = QFileDialog::getSaveFileName(this, tr("Export As"),
|
|
||||||
fi.absoluteFilePath(),
|
|
||||||
fileType);
|
|
||||||
if (path.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setFilePath(path);
|
exit:
|
||||||
s_defaultPathDir = VUtils::basePathFromPath(path);
|
clearWebViewer();
|
||||||
|
|
||||||
m_openBtn->hide();
|
if (m_state == ExportState::Successful) {
|
||||||
}
|
ret = true;
|
||||||
|
|
||||||
void VExporter::handleLayoutBtnClicked()
|
|
||||||
{
|
|
||||||
#ifndef QT_NO_PRINTER
|
|
||||||
QPrinter printer;
|
|
||||||
printer.setPageLayout(m_pageLayout);
|
|
||||||
|
|
||||||
QPageSetupDialog dlg(&printer, this);
|
|
||||||
if (dlg.exec() != QDialog::Accepted) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_pageLayout.setPageSize(printer.pageLayout().pageSize());
|
m_state = ExportState::Idle;
|
||||||
m_pageLayout.setOrientation(printer.pageLayout().orientation());
|
|
||||||
|
|
||||||
updatePageLayoutLabel();
|
return ret;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VExporter::updatePageLayoutLabel()
|
void VExporter::initWebViewer(VFile *p_file, const ExportOption &p_opt)
|
||||||
{
|
{
|
||||||
m_layoutLabel->setText(QString("%1, %2").arg(m_pageLayout.pageSize().name())
|
Q_ASSERT(!m_webViewer);
|
||||||
.arg(m_pageLayout.orientation() == QPageLayout::Portrait ?
|
|
||||||
tr("Portrait") : tr("Landscape")));
|
|
||||||
}
|
|
||||||
|
|
||||||
QString VExporter::getFilePath() const
|
m_webViewer = new VWebView(p_file, static_cast<QWidget *>(parent()));
|
||||||
{
|
|
||||||
return QDir::cleanPath(m_pathEdit->text());
|
|
||||||
}
|
|
||||||
|
|
||||||
void VExporter::setFilePath(const QString &p_path)
|
|
||||||
{
|
|
||||||
m_pathEdit->setText(QDir::toNativeSeparators(p_path));
|
|
||||||
}
|
|
||||||
|
|
||||||
void VExporter::exportNote(VFile *p_file, ExportType p_type)
|
|
||||||
{
|
|
||||||
m_file = p_file;
|
|
||||||
m_type = p_type;
|
|
||||||
m_source = ExportSource::Note;
|
|
||||||
|
|
||||||
if (!m_file || m_file->getDocType() != DocType::Markdown) {
|
|
||||||
// Do not support non-Markdown note now.
|
|
||||||
m_btnBox->button(QDialogButtonBox::Ok)->setEnabled(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_infoLabel->setText(tr("Export note <span style=\"%1\">%2</span> as %3.")
|
|
||||||
.arg(g_config->c_dataTextStyle)
|
|
||||||
.arg(m_file->getName())
|
|
||||||
.arg(exportTypeStr(p_type)));
|
|
||||||
|
|
||||||
setWindowTitle(tr("Export As %1").arg(exportTypeStr(p_type)));
|
|
||||||
|
|
||||||
setFilePath(QDir(s_defaultPathDir).filePath(QFileInfo(p_file->fetchPath()).baseName() +
|
|
||||||
"." + exportTypeStr(p_type).toLower()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void VExporter::initWebViewer(VFile *p_file)
|
|
||||||
{
|
|
||||||
V_ASSERT(!m_webViewer);
|
|
||||||
|
|
||||||
m_webViewer = new VWebView(p_file, this);
|
|
||||||
m_webViewer->hide();
|
m_webViewer->hide();
|
||||||
|
|
||||||
VPreviewPage *page = new VPreviewPage(m_webViewer);
|
VPreviewPage *page = new VPreviewPage(m_webViewer);
|
||||||
m_webViewer->setPage(page);
|
m_webViewer->setPage(page);
|
||||||
|
|
||||||
@ -216,7 +121,7 @@ void VExporter::initWebViewer(VFile *p_file)
|
|||||||
page->setWebChannel(channel);
|
page->setWebChannel(channel);
|
||||||
|
|
||||||
// Need to generate HTML using Hoedown.
|
// Need to generate HTML using Hoedown.
|
||||||
if (m_mdType == MarkdownConverterType::Hoedown) {
|
if (p_opt.m_renderer == MarkdownConverterType::Hoedown) {
|
||||||
VMarkdownConverter mdConverter;
|
VMarkdownConverter mdConverter;
|
||||||
QString toc;
|
QString toc;
|
||||||
QString html = mdConverter.generateHtml(p_file->getContent(),
|
QString html = mdConverter.generateHtml(p_file->getContent(),
|
||||||
@ -228,14 +133,6 @@ void VExporter::initWebViewer(VFile *p_file)
|
|||||||
m_webViewer->setHtml(m_htmlTemplate, p_file->getBaseUrl());
|
m_webViewer->setHtml(m_htmlTemplate, p_file->getBaseUrl());
|
||||||
}
|
}
|
||||||
|
|
||||||
void VExporter::clearWebViewer()
|
|
||||||
{
|
|
||||||
if (m_webViewer) {
|
|
||||||
delete m_webViewer;
|
|
||||||
m_webViewer = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VExporter::handleLogicsFinished()
|
void VExporter::handleLogicsFinished()
|
||||||
{
|
{
|
||||||
Q_ASSERT(!(m_noteState & NoteState::WebLogicsReady));
|
Q_ASSERT(!(m_noteState & NoteState::WebLogicsReady));
|
||||||
@ -252,130 +149,16 @@ void VExporter::handleLoadFinished(bool p_ok)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VExporter::clearNoteState()
|
void VExporter::clearWebViewer()
|
||||||
{
|
{
|
||||||
m_noteState = NoteState::NotReady;
|
if (m_webViewer) {
|
||||||
}
|
delete m_webViewer;
|
||||||
|
m_webViewer = NULL;
|
||||||
bool VExporter::isNoteStateReady() const
|
|
||||||
{
|
|
||||||
return m_noteState == NoteState::Ready;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VExporter::isNoteStateFailed() const
|
|
||||||
{
|
|
||||||
return m_noteState & NoteState::Failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VExporter::startExport()
|
|
||||||
{
|
|
||||||
QPushButton *cancelBtn = m_btnBox->button(QDialogButtonBox::Cancel);
|
|
||||||
|
|
||||||
if (m_exported) {
|
|
||||||
cancelBtn->show();
|
|
||||||
m_exported = false;
|
|
||||||
accept();
|
|
||||||
}
|
|
||||||
|
|
||||||
int exportedNum = 0;
|
|
||||||
enableUserInput(false);
|
|
||||||
V_ASSERT(m_state == ExportState::Idle);
|
|
||||||
m_state = ExportState::Busy;
|
|
||||||
|
|
||||||
m_openBtn->hide();
|
|
||||||
|
|
||||||
if (m_source == ExportSource::Note) {
|
|
||||||
V_ASSERT(m_file);
|
|
||||||
bool isOpened = m_file->isOpened();
|
|
||||||
if (!isOpened && !m_file->open()) {
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
clearNoteState();
|
|
||||||
initWebViewer(m_file);
|
|
||||||
|
|
||||||
// Update progress info.
|
|
||||||
m_proLabel->setText(tr("Exporting %1").arg(m_file->getName()));
|
|
||||||
m_proBar->setEnabled(true);
|
|
||||||
m_proBar->setMinimum(0);
|
|
||||||
m_proBar->setMaximum(100);
|
|
||||||
m_proBar->reset();
|
|
||||||
m_proLabel->show();
|
|
||||||
m_proBar->show();
|
|
||||||
|
|
||||||
while (!isNoteStateReady()) {
|
|
||||||
VUtils::sleepWait(100);
|
|
||||||
if (m_proBar->value() < 70) {
|
|
||||||
m_proBar->setValue(m_proBar->value() + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_state == ExportState::Cancelled) {
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isNoteStateFailed()) {
|
|
||||||
m_state = ExportState::Failed;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait to ensure Web side is really ready.
|
|
||||||
VUtils::sleepWait(200);
|
|
||||||
|
|
||||||
if (m_state == ExportState::Cancelled) {
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_proBar->setValue(80);
|
|
||||||
|
|
||||||
bool exportRet = exportToPDF(m_webViewer, getFilePath(), m_pageLayout);
|
|
||||||
|
|
||||||
clearNoteState();
|
|
||||||
|
|
||||||
if (!isOpened) {
|
|
||||||
m_file->close();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exportRet) {
|
|
||||||
m_proBar->setValue(100);
|
|
||||||
m_state = ExportState::Successful;
|
|
||||||
exportedNum++;
|
|
||||||
} else {
|
|
||||||
m_proBar->setEnabled(false);
|
|
||||||
m_state = ExportState::Failed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
exit:
|
|
||||||
clearWebViewer();
|
|
||||||
|
|
||||||
m_proLabel->setText("");
|
|
||||||
m_proLabel->hide();
|
|
||||||
enableUserInput(true);
|
|
||||||
|
|
||||||
if (m_state == ExportState::Cancelled) {
|
|
||||||
reject();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exportedNum) {
|
|
||||||
m_exported = true;
|
|
||||||
m_openBtn->show();
|
|
||||||
cancelBtn->hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_state = ExportState::Idle;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VExporter::cancelExport()
|
|
||||||
{
|
|
||||||
if (m_state == ExportState::Idle) {
|
|
||||||
reject();
|
|
||||||
} else {
|
|
||||||
m_state = ExportState::Cancelled;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VExporter::exportToPDF(VWebView *p_webViewer, const QString &p_filePath,
|
bool VExporter::exportToPDF(VWebView *p_webViewer,
|
||||||
|
const QString &p_filePath,
|
||||||
const QPageLayout &p_layout)
|
const QPageLayout &p_layout)
|
||||||
{
|
{
|
||||||
int pdfPrinted = 0;
|
int pdfPrinted = 0;
|
||||||
@ -411,16 +194,3 @@ bool VExporter::exportToPDF(VWebView *p_webViewer, const QString &p_filePath,
|
|||||||
return pdfPrinted == 1;
|
return pdfPrinted == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VExporter::enableUserInput(bool p_enabled)
|
|
||||||
{
|
|
||||||
m_btnBox->button(QDialogButtonBox::Ok)->setEnabled(p_enabled);
|
|
||||||
m_pathEdit->setEnabled(p_enabled);
|
|
||||||
m_browseBtn->setEnabled(p_enabled);
|
|
||||||
m_layoutBtn->setEnabled(p_enabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VExporter::openTargetPath() const
|
|
||||||
{
|
|
||||||
QUrl url = QUrl::fromLocalFile(VUtils::basePathFromPath(getFilePath()));
|
|
||||||
QDesktopServices::openUrl(url);
|
|
||||||
}
|
|
||||||
|
109
src/vexporter.h
109
src/vexporter.h
@ -1,51 +1,32 @@
|
|||||||
#ifndef VEXPORTER_H
|
#ifndef VEXPORTER_H
|
||||||
#define VEXPORTER_H
|
#define VEXPORTER_H
|
||||||
|
|
||||||
#include <QDialog>
|
#include <QObject>
|
||||||
#include <QPageLayout>
|
#include <QPageLayout>
|
||||||
#include <QString>
|
|
||||||
#include "vconfigmanager.h"
|
|
||||||
|
|
||||||
|
#include "dialog/vexportdialog.h"
|
||||||
|
|
||||||
|
class QWidget;
|
||||||
class VWebView;
|
class VWebView;
|
||||||
class VFile;
|
|
||||||
class VLineEdit;
|
|
||||||
class QLabel;
|
|
||||||
class QDialogButtonBox;
|
|
||||||
class QPushButton;
|
|
||||||
class QProgressBar;
|
|
||||||
|
|
||||||
enum class ExportType
|
class VExporter : public QObject
|
||||||
{
|
{
|
||||||
PDF = 0,
|
|
||||||
HTML
|
|
||||||
};
|
|
||||||
|
|
||||||
class VExporter : public QDialog
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
public:
|
||||||
explicit VExporter(MarkdownConverterType p_mdType = MarkdownIt, QWidget *p_parent = 0);
|
explicit VExporter(QWidget *p_parent = nullptr);
|
||||||
|
|
||||||
void exportNote(VFile *p_file, ExportType p_type);
|
void prepareExport(const ExportOption &p_opt);
|
||||||
|
|
||||||
|
bool exportPDF(VFile *p_file,
|
||||||
|
const ExportOption &p_opt,
|
||||||
|
const QString &p_outputFile,
|
||||||
|
QString *p_errMsg = NULL);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void handleBrowseBtnClicked();
|
|
||||||
void handleLayoutBtnClicked();
|
|
||||||
void startExport();
|
|
||||||
void cancelExport();
|
|
||||||
void handleLogicsFinished();
|
void handleLogicsFinished();
|
||||||
|
|
||||||
void handleLoadFinished(bool p_ok);
|
void handleLoadFinished(bool p_ok);
|
||||||
void openTargetPath() const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class ExportSource
|
|
||||||
{
|
|
||||||
Note = 0,
|
|
||||||
Directory,
|
|
||||||
Notebook,
|
|
||||||
Invalid
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class ExportState
|
enum class ExportState
|
||||||
{
|
{
|
||||||
Idle = 0,
|
Idle = 0,
|
||||||
@ -55,6 +36,7 @@ private:
|
|||||||
Successful
|
Successful
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
enum NoteState
|
enum NoteState
|
||||||
{
|
{
|
||||||
NotReady = 0,
|
NotReady = 0,
|
||||||
@ -64,59 +46,46 @@ private:
|
|||||||
Failed = 0x4
|
Failed = 0x4
|
||||||
};
|
};
|
||||||
|
|
||||||
void setupUI();
|
|
||||||
|
|
||||||
void initMarkdownTemplate();
|
void initWebViewer(VFile *p_file, const ExportOption &p_opt);
|
||||||
|
|
||||||
void updatePageLayoutLabel();
|
|
||||||
|
|
||||||
void setFilePath(const QString &p_path);
|
|
||||||
|
|
||||||
QString getFilePath() const;
|
|
||||||
|
|
||||||
void initWebViewer(VFile *p_file);
|
|
||||||
|
|
||||||
void clearWebViewer();
|
void clearWebViewer();
|
||||||
|
|
||||||
void enableUserInput(bool p_enabled);
|
|
||||||
|
|
||||||
bool exportToPDF(VWebView *p_webViewer, const QString &p_filePath, const QPageLayout &p_layout);
|
|
||||||
|
|
||||||
void clearNoteState();
|
void clearNoteState();
|
||||||
|
|
||||||
bool isNoteStateReady() const;
|
bool isNoteStateReady() const;
|
||||||
|
|
||||||
bool isNoteStateFailed() const;
|
bool isNoteStateFailed() const;
|
||||||
|
|
||||||
|
bool exportToPDF(VWebView *p_webViewer,
|
||||||
|
const QString &p_filePath,
|
||||||
|
const QPageLayout &p_layout);
|
||||||
|
|
||||||
|
QPageLayout m_pageLayout;
|
||||||
|
|
||||||
// Will be allocated and free for each conversion.
|
// Will be allocated and free for each conversion.
|
||||||
VWebView *m_webViewer;
|
VWebView *m_webViewer;
|
||||||
|
|
||||||
MarkdownConverterType m_mdType;
|
|
||||||
QString m_htmlTemplate;
|
QString m_htmlTemplate;
|
||||||
VFile *m_file;
|
|
||||||
ExportType m_type;
|
|
||||||
ExportSource m_source;
|
|
||||||
NoteState m_noteState;
|
NoteState m_noteState;
|
||||||
|
|
||||||
ExportState m_state;
|
ExportState m_state;
|
||||||
|
|
||||||
QLabel *m_infoLabel;
|
|
||||||
VLineEdit *m_pathEdit;
|
|
||||||
QPushButton *m_browseBtn;
|
|
||||||
QLabel *m_layoutLabel;
|
|
||||||
QPushButton *m_layoutBtn;
|
|
||||||
QDialogButtonBox *m_btnBox;
|
|
||||||
QPushButton *m_openBtn;
|
|
||||||
|
|
||||||
// Progress label and bar.
|
|
||||||
QLabel *m_proLabel;
|
|
||||||
QProgressBar *m_proBar;
|
|
||||||
|
|
||||||
QPageLayout m_pageLayout;
|
|
||||||
|
|
||||||
// Whether a PDF has been exported.
|
|
||||||
bool m_exported;
|
|
||||||
|
|
||||||
// The default directory.
|
|
||||||
static QString s_defaultPathDir;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline void VExporter::clearNoteState()
|
||||||
|
{
|
||||||
|
m_noteState = NoteState::NotReady;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool VExporter::isNoteStateReady() const
|
||||||
|
{
|
||||||
|
return m_noteState == NoteState::Ready;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool VExporter::isNoteStateFailed() const
|
||||||
|
{
|
||||||
|
return m_noteState & NoteState::Failed;
|
||||||
|
}
|
||||||
|
|
||||||
#endif // VEXPORTER_H
|
#endif // VEXPORTER_H
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
#include "utils/viconutils.h"
|
#include "utils/viconutils.h"
|
||||||
#include "dialog/vtipsdialog.h"
|
#include "dialog/vtipsdialog.h"
|
||||||
#include "vcart.h"
|
#include "vcart.h"
|
||||||
|
#include "dialog/vexportdialog.h"
|
||||||
|
|
||||||
extern VConfigManager *g_config;
|
extern VConfigManager *g_config;
|
||||||
|
|
||||||
@ -994,13 +995,12 @@ void VMainWindow::initFileMenu()
|
|||||||
fileMenu->addSeparator();
|
fileMenu->addSeparator();
|
||||||
|
|
||||||
// Export as PDF.
|
// Export as PDF.
|
||||||
m_exportAsPDFAct = new QAction(tr("Export As &PDF"), this);
|
m_exportAct = new QAction(tr("E&xport"), this);
|
||||||
m_exportAsPDFAct->setToolTip(tr("Export current note as PDF file"));
|
m_exportAct->setToolTip(tr("Export notes"));
|
||||||
connect(m_exportAsPDFAct, &QAction::triggered,
|
connect(m_exportAct, &QAction::triggered,
|
||||||
this, &VMainWindow::exportAsPDF);
|
this, &VMainWindow::handleExportAct);
|
||||||
m_exportAsPDFAct->setEnabled(false);
|
|
||||||
|
|
||||||
fileMenu->addAction(m_exportAsPDFAct);
|
fileMenu->addAction(m_exportAct);
|
||||||
|
|
||||||
// Print.
|
// Print.
|
||||||
m_printAct = new QAction(VIconUtils::menuIcon(":/resources/icons/print.svg"),
|
m_printAct = new QAction(VIconUtils::menuIcon(":/resources/icons/print.svg"),
|
||||||
@ -1349,8 +1349,6 @@ void VMainWindow::changeMarkdownConverter(QAction *action)
|
|||||||
|
|
||||||
MarkdownConverterType type = (MarkdownConverterType)action->data().toInt();
|
MarkdownConverterType type = (MarkdownConverterType)action->data().toInt();
|
||||||
|
|
||||||
qDebug() << "switch to converter" << type;
|
|
||||||
|
|
||||||
g_config->setMarkdownConverterType(type);
|
g_config->setMarkdownConverterType(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1418,7 +1416,7 @@ void VMainWindow::setEditorBackgroundColor(QAction *action)
|
|||||||
|
|
||||||
void VMainWindow::initConverterMenu(QMenu *p_menu)
|
void VMainWindow::initConverterMenu(QMenu *p_menu)
|
||||||
{
|
{
|
||||||
QMenu *converterMenu = p_menu->addMenu(tr("&Converter"));
|
QMenu *converterMenu = p_menu->addMenu(tr("&Renderer"));
|
||||||
converterMenu->setToolTipsVisible(true);
|
converterMenu->setToolTipsVisible(true);
|
||||||
|
|
||||||
QActionGroup *converterAct = new QActionGroup(this);
|
QActionGroup *converterAct = new QActionGroup(this);
|
||||||
@ -1828,7 +1826,6 @@ void VMainWindow::updateActionsStateFromTab(const VEditTab *p_tab)
|
|||||||
&& dynamic_cast<const VOrphanFile *>(file)->isSystemFile();
|
&& dynamic_cast<const VOrphanFile *>(file)->isSystemFile();
|
||||||
|
|
||||||
m_printAct->setEnabled(file && file->getDocType() == DocType::Markdown);
|
m_printAct->setEnabled(file && file->getDocType() == DocType::Markdown);
|
||||||
m_exportAsPDFAct->setEnabled(file && file->getDocType() == DocType::Markdown);
|
|
||||||
|
|
||||||
updateEditReadAct(p_tab);
|
updateEditReadAct(p_tab);
|
||||||
|
|
||||||
@ -2380,19 +2377,6 @@ void VMainWindow::printNote()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VMainWindow::exportAsPDF()
|
|
||||||
{
|
|
||||||
V_ASSERT(m_curTab);
|
|
||||||
V_ASSERT(m_curFile);
|
|
||||||
|
|
||||||
if (m_curFile->getDocType() == DocType::Markdown) {
|
|
||||||
VMdTab *mdTab = dynamic_cast<VMdTab *>((VEditTab *)m_curTab);
|
|
||||||
VExporter exporter(mdTab->getMarkdownConverterType(), this);
|
|
||||||
exporter.exportNote(m_curFile, ExportType::PDF);
|
|
||||||
exporter.exec();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QAction *VMainWindow::newAction(const QIcon &p_icon,
|
QAction *VMainWindow::newAction(const QIcon &p_icon,
|
||||||
const QString &p_text,
|
const QString &p_text,
|
||||||
QObject *p_parent)
|
QObject *p_parent)
|
||||||
@ -3015,3 +2999,19 @@ void VMainWindow::updateEditReadAct(const VEditTab *p_tab)
|
|||||||
|
|
||||||
m_editReadAct->setEnabled(p_tab);
|
m_editReadAct->setEnabled(p_tab);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VMainWindow::handleExportAct()
|
||||||
|
{
|
||||||
|
VExportDialog dialog(notebookSelector->currentNotebook(),
|
||||||
|
directoryTree->currentDirectory(),
|
||||||
|
m_curFile,
|
||||||
|
m_cart,
|
||||||
|
g_config->getMdConverterType(),
|
||||||
|
this);
|
||||||
|
dialog.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
VNotebook *VMainWindow::getCurrentNotebook() const
|
||||||
|
{
|
||||||
|
return notebookSelector->currentNotebook();
|
||||||
|
}
|
||||||
|
@ -97,6 +97,8 @@ public:
|
|||||||
|
|
||||||
VEditTab *getCurrentTab() const;
|
VEditTab *getCurrentTab() const;
|
||||||
|
|
||||||
|
VNotebook *getCurrentNotebook() const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
// Emit when editor related configurations were changed by user.
|
// Emit when editor related configurations were changed by user.
|
||||||
void editorConfigUpdated();
|
void editorConfigUpdated();
|
||||||
@ -139,7 +141,9 @@ private slots:
|
|||||||
void enableImageConstraint(bool p_checked);
|
void enableImageConstraint(bool p_checked);
|
||||||
void enableImageCaption(bool p_checked);
|
void enableImageCaption(bool p_checked);
|
||||||
void printNote();
|
void printNote();
|
||||||
void exportAsPDF();
|
|
||||||
|
// Open export dialog.
|
||||||
|
void handleExportAct();
|
||||||
|
|
||||||
// Set the panel view properly.
|
// Set the panel view properly.
|
||||||
void enableCompactMode(bool p_enabled);
|
void enableCompactMode(bool p_enabled);
|
||||||
@ -349,7 +353,7 @@ private:
|
|||||||
|
|
||||||
QAction *m_printAct;
|
QAction *m_printAct;
|
||||||
|
|
||||||
QAction *m_exportAsPDFAct;
|
QAction *m_exportAct;
|
||||||
|
|
||||||
QAction *m_findReplaceAct;
|
QAction *m_findReplaceAct;
|
||||||
|
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
#include "vnote.h"
|
#include "vnote.h"
|
||||||
#include "utils/vutils.h"
|
#include "utils/vutils.h"
|
||||||
#include "vconfigmanager.h"
|
#include "vconfigmanager.h"
|
||||||
#include "vmainwindow.h"
|
|
||||||
#include "vorphanfile.h"
|
#include "vorphanfile.h"
|
||||||
#include "vnotefile.h"
|
#include "vnotefile.h"
|
||||||
#include "vpalette.h"
|
#include "vpalette.h"
|
||||||
@ -238,15 +237,7 @@ VOrphanFile *VNote::getOrphanFile(const QString &p_path, bool p_modifiable, bool
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < m_externalFiles.size(); ++i) {
|
freeOrphanFiles();
|
||||||
VOrphanFile *file = m_externalFiles[i];
|
|
||||||
if (!file->isOpened()) {
|
|
||||||
qDebug() << "release orphan file" << file;
|
|
||||||
m_externalFiles.removeAt(i);
|
|
||||||
delete file;
|
|
||||||
--i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a VOrphanFile for path.
|
// Create a VOrphanFile for path.
|
||||||
VOrphanFile *file = new VOrphanFile(this, path, p_modifiable, p_systemFile);
|
VOrphanFile *file = new VOrphanFile(this, path, p_modifiable, p_systemFile);
|
||||||
@ -296,3 +287,17 @@ VDirectory *VNote::getInternalDirectory(const QString &p_path)
|
|||||||
return dir;
|
return dir;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VNote::freeOrphanFiles()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < m_externalFiles.size();) {
|
||||||
|
VOrphanFile *file = m_externalFiles[i];
|
||||||
|
if (!file->isOpened()) {
|
||||||
|
qDebug() << "release orphan file" << file;
|
||||||
|
m_externalFiles.removeAt(i);
|
||||||
|
delete file;
|
||||||
|
} else {
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -99,6 +99,8 @@ public:
|
|||||||
// Otherwise, returns NULL.
|
// Otherwise, returns NULL.
|
||||||
VDirectory *getInternalDirectory(const QString &p_path);
|
VDirectory *getInternalDirectory(const QString &p_path);
|
||||||
|
|
||||||
|
void freeOrphanFiles();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void updateTemplate();
|
void updateTemplate();
|
||||||
|
|
||||||
|
@ -621,3 +621,8 @@ VNotebook *VNotebookSelector::getNotebook(const QListWidgetItem *p_item) const
|
|||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VNotebook *VNotebookSelector::currentNotebook() const
|
||||||
|
{
|
||||||
|
return getNotebook(currentIndex());
|
||||||
|
}
|
||||||
|
@ -27,6 +27,8 @@ public:
|
|||||||
// Add notebook on popup if no notebooks currently.
|
// Add notebook on popup if no notebooks currently.
|
||||||
void showPopup() Q_DECL_OVERRIDE;
|
void showPopup() Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
VNotebook *currentNotebook() const;
|
||||||
|
|
||||||
// Implementations for VNavigationMode.
|
// Implementations for VNavigationMode.
|
||||||
void registerNavigation(QChar p_majorKey) Q_DECL_OVERRIDE;
|
void registerNavigation(QChar p_majorKey) Q_DECL_OVERRIDE;
|
||||||
void showNavigation() Q_DECL_OVERRIDE;
|
void showNavigation() Q_DECL_OVERRIDE;
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
#include "utils/vutils.h"
|
|
||||||
#include "vdirectory.h"
|
#include "vdirectory.h"
|
||||||
|
|
||||||
VNoteFile::VNoteFile(VDirectory *p_directory,
|
VNoteFile::VNoteFile(VDirectory *p_directory,
|
||||||
@ -510,42 +509,12 @@ bool VNoteFile::copyFile(VDirectory *p_destDir,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Copy images.
|
// Copy images.
|
||||||
QDir parentDir(destFile->fetchBasePath());
|
if (!copyInternalImages(images,
|
||||||
QSet<QString> processedImages;
|
destFile->fetchBasePath(),
|
||||||
for (int i = 0; i < images.size(); ++i) {
|
p_isCut,
|
||||||
const ImageLink &link = images[i];
|
&nrImageCopied,
|
||||||
if (processedImages.contains(link.m_path)) {
|
p_errMsg)) {
|
||||||
continue;
|
ret = false;
|
||||||
}
|
|
||||||
|
|
||||||
processedImages.insert(link.m_path);
|
|
||||||
|
|
||||||
if (!QFileInfo::exists(link.m_path)) {
|
|
||||||
VUtils::addErrMsg(p_errMsg, tr("Source image %1 does not exist.")
|
|
||||||
.arg(link.m_path));
|
|
||||||
ret = false;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString imageFolder = VUtils::directoryNameFromPath(VUtils::basePathFromPath(link.m_path));
|
|
||||||
QString destImagePath = QDir(parentDir.filePath(imageFolder)).filePath(VUtils::fileNameFromPath(link.m_path));
|
|
||||||
|
|
||||||
if (VUtils::equalPath(link.m_path, destImagePath)) {
|
|
||||||
VUtils::addErrMsg(p_errMsg, tr("Skip image with the same source and target path %1.")
|
|
||||||
.arg(link.m_path));
|
|
||||||
ret = false;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!VUtils::copyFile(link.m_path, destImagePath, p_isCut)) {
|
|
||||||
VUtils::addErrMsg(p_errMsg, tr("Fail to %1 image %2 to %3. "
|
|
||||||
"Please manually %1 it and modify the note.")
|
|
||||||
.arg(opStr).arg(link.m_path).arg(destImagePath));
|
|
||||||
ret = false;
|
|
||||||
} else {
|
|
||||||
++nrImageCopied;
|
|
||||||
qDebug() << opStr << "image" << link.m_path << "to" << destImagePath;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy attachment folder.
|
// Copy attachment folder.
|
||||||
@ -587,3 +556,53 @@ bool VNoteFile::copyFile(VDirectory *p_destDir,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool VNoteFile::copyInternalImages(const QVector<ImageLink> &p_images,
|
||||||
|
const QString &p_destDirPath,
|
||||||
|
bool p_isCut,
|
||||||
|
int *p_nrImageCopied,
|
||||||
|
QString *p_errMsg)
|
||||||
|
{
|
||||||
|
bool ret = true;
|
||||||
|
QDir parentDir(p_destDirPath);
|
||||||
|
QSet<QString> processedImages;
|
||||||
|
QString opStr = p_isCut ? tr("cut") : tr("copy");
|
||||||
|
int nrImageCopied = 0;
|
||||||
|
for (int i = 0; i < p_images.size(); ++i) {
|
||||||
|
const ImageLink &link = p_images[i];
|
||||||
|
if (processedImages.contains(link.m_path)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
processedImages.insert(link.m_path);
|
||||||
|
|
||||||
|
if (!QFileInfo::exists(link.m_path)) {
|
||||||
|
VUtils::addErrMsg(p_errMsg, tr("Source image %1 does not exist.")
|
||||||
|
.arg(link.m_path));
|
||||||
|
ret = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString imageFolder = VUtils::directoryNameFromPath(VUtils::basePathFromPath(link.m_path));
|
||||||
|
QString destImagePath = QDir(parentDir.filePath(imageFolder)).filePath(VUtils::fileNameFromPath(link.m_path));
|
||||||
|
|
||||||
|
if (VUtils::equalPath(link.m_path, destImagePath)) {
|
||||||
|
VUtils::addErrMsg(p_errMsg, tr("Skip image with the same source and target path %1.")
|
||||||
|
.arg(link.m_path));
|
||||||
|
ret = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!VUtils::copyFile(link.m_path, destImagePath, p_isCut)) {
|
||||||
|
VUtils::addErrMsg(p_errMsg, tr("Fail to %1 image %2 to %3. "
|
||||||
|
"Please manually %1 it and modify the note.")
|
||||||
|
.arg(opStr).arg(link.m_path).arg(destImagePath));
|
||||||
|
ret = false;
|
||||||
|
} else {
|
||||||
|
++nrImageCopied;
|
||||||
|
qDebug() << opStr << "image" << link.m_path << "to" << destImagePath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*p_nrImageCopied = nrImageCopied;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
#include "vfile.h"
|
#include "vfile.h"
|
||||||
|
#include "utils/vutils.h"
|
||||||
|
|
||||||
class VDirectory;
|
class VDirectory;
|
||||||
class VNotebook;
|
class VNotebook;
|
||||||
@ -129,6 +130,13 @@ public:
|
|||||||
VNoteFile **p_targetFile,
|
VNoteFile **p_targetFile,
|
||||||
QString *p_errMsg = NULL);
|
QString *p_errMsg = NULL);
|
||||||
|
|
||||||
|
// Copy images @p_images of a file to @p_destDirPath.
|
||||||
|
static bool copyInternalImages(const QVector<ImageLink> &p_images,
|
||||||
|
const QString &p_destDirPath,
|
||||||
|
bool p_isCut,
|
||||||
|
int *p_nrImageCopied,
|
||||||
|
QString *p_errMsg = NULL);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Delete internal images of this file.
|
// Delete internal images of this file.
|
||||||
// Return true only when all internal images were deleted successfully.
|
// Return true only when all internal images were deleted successfully.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user