refactor export

This commit is contained in:
Le Tan 2018-02-10 21:28:25 +08:00
parent bc9dd643fc
commit 8ff520d0fd
22 changed files with 1114 additions and 458 deletions

View 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
View 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

View File

@ -143,7 +143,7 @@ void VNewNotebookDialog::handleBrowseBtnClicked()
if (defaultPath.isEmpty()) {
defaultPath = g_config->getVnoteNotebookFolderPath();
if (!QFileInfo::exists(defaultPath)) {
defaultPath = QDir::homePath();
defaultPath = g_config->getDocumentPathOrHomePath();
}
}

View File

@ -8,7 +8,6 @@ class QLabel;
class VLineEdit;
class VMetaWordLineEdit;
class QDialogButtonBox;
class QString;
class VNotebook;
class VNotebookInfoDialog : public QDialog

View File

@ -60,7 +60,6 @@ SOURCES += main.cpp\
vorphanfile.cpp \
vcodeblockhighlighthelper.cpp \
vwebview.cpp \
vexporter.cpp \
vmdtab.cpp \
vhtmltab.cpp \
utils/vvim.cpp \
@ -112,7 +111,9 @@ SOURCES += main.cpp\
vlistwidget.cpp \
vsimplesearchinput.cpp \
vstyleditemdelegate.cpp \
vtreewidget.cpp
vtreewidget.cpp \
dialog/vexportdialog.cpp \
vexporter.cpp
HEADERS += vmainwindow.h \
vdirectorytree.h \
@ -158,7 +159,6 @@ HEADERS += vmainwindow.h \
vorphanfile.h \
vcodeblockhighlighthelper.h \
vwebview.h \
vexporter.h \
vmdtab.h \
vhtmltab.h \
utils/vvim.h \
@ -211,7 +211,9 @@ HEADERS += vmainwindow.h \
vlistwidget.h \
vsimplesearchinput.h \
vstyleditemdelegate.h \
vtreewidget.h
vtreewidget.h \
dialog/vexportdialog.h \
vexporter.h
RESOURCES += \
vnote.qrc \

View File

@ -191,3 +191,19 @@ QString VCart::getFilePath(const QListWidgetItem *p_item) const
{
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;
}

View File

@ -22,6 +22,10 @@ public:
void addFile(const QString &p_filePath);
int count() const;
QVector<QString> getFiles() const;
private slots:
void handleContextMenuRequested(QPoint p_pos);

View File

@ -47,6 +47,8 @@ const QString VConfigManager::c_dataTextStyle = QString("font: bold");
const QString VConfigManager::c_vnoteNotebookFolderName = QString("vnote_notebooks");
const QString VConfigManager::c_exportFolderName = QString("vnote_exports");
VConfigManager::VConfigManager(QObject *p_parent)
: QObject(p_parent),
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,
const QString &p_group)
{

View File

@ -14,20 +14,9 @@
#include "vfilesessioninfo.h"
#include "utils/vmetawordmanager.h"
class QJsonObject;
class QString;
enum MarkdownConverterType
{
Hoedown = 0,
Marked,
MarkdownIt,
Showdown
};
struct VColor
{
QString m_name;
@ -57,6 +46,7 @@ struct MarkdownitOption
bool m_linkify;
};
// Type of heading sequence.
enum class HeadingSequenceType
{
@ -69,6 +59,7 @@ enum class HeadingSequenceType
Invalid
};
class VConfigManager : public QObject
{
public:
@ -89,6 +80,11 @@ public:
// Get the path of the folder used to store default notebook.
static QString getVnoteNotebookFolderPath();
// Get the path of the default export folder.
static QString getExportFolderPath();
static QString getDocumentPathOrHomePath();
// Constants
static const QString orgName;
static const QString appName;
@ -892,6 +888,9 @@ private:
// The folder name to store all notebooks if user does not specify one.
static const QString c_vnoteNotebookFolderName;
// The default export output folder name.
static const QString c_exportFolderName;
};

View File

@ -141,4 +141,12 @@ enum class UpdateAction
Moved
};
enum MarkdownConverterType
{
Hoedown = 0,
Marked,
MarkdownIt,
Showdown
};
#endif

View File

@ -1207,3 +1207,13 @@ void VDirectoryTree::sortItems(VDirectory *p_dir)
updateItemDirectChildren(findVDirectory(p_dir));
}
}
VDirectory *VDirectoryTree::currentDirectory() const
{
QTreeWidgetItem *item = currentItem();
if (item) {
return getVDirectory(item);
}
return NULL;
}

View File

@ -30,6 +30,8 @@ public:
const VNotebook *currentNotebook() const;
VDirectory *currentDirectory() const;
// Implementations for VNavigationMode.
void showNavigation() Q_DECL_OVERRIDE;
bool handleKeyNavigation(int p_key, bool &p_succeed) Q_DECL_OVERRIDE;

View File

@ -1,313 +1,56 @@
#include "vexporter.h"
#include <QtWidgets>
#include <QFileInfo>
#include <QDir>
#include <QWebChannel>
#include <QDebug>
#include <QVBoxLayout>
#include <QShowEvent>
#ifndef QT_NO_PRINTER
#include <QPrinter>
#include <QPageSetupDialog>
#endif
#include <QWidget>
#include <QWebChannel>
#include "vconfigmanager.h"
#include "utils/vutils.h"
#include "vfile.h"
#include "vwebview.h"
#include "utils/vutils.h"
#include "vpreviewpage.h"
#include "vconstants.h"
#include "vnote.h"
#include "vmarkdownconverter.h"
#include "vdocument.h"
#include "vlineedit.h"
extern VConfigManager *g_config;
QString VExporter::s_defaultPathDir = QDir::homePath();
VExporter::VExporter(MarkdownConverterType p_mdType, QWidget *p_parent)
: QDialog(p_parent), m_webViewer(NULL), m_mdType(p_mdType),
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)
VExporter::VExporter(QWidget *p_parent)
: QObject(p_parent),
m_webViewer(NULL),
m_state(ExportState::Idle)
{
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();
m_infoLabel->setWordWrap(true);
Q_UNUSED(p_errMsg);
// Target file path.
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);
bool ret = false;
// Page layout.
QLabel *layoutLabel = new QLabel(tr("Page layout:"));
m_layoutLabel = new QLabel();
m_layoutBtn = new QPushButton(tr("&Settings"));
#ifndef QT_NO_PRINTER
connect(m_layoutBtn, &QPushButton::clicked,
this, &VExporter::handleLayoutBtnClicked);
#else
m_layoutBtn->hide();
#endif
// Progress.
m_proLabel = new QLabel(this);
m_proBar = new QProgressBar(this);
// Ok is the default button.
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);
okBtn->setProperty("SpecialBtn", true);
m_pathEdit->setMinimumWidth(okBtn->sizeHint().width() * 3);
QGridLayout *mainLayout = new QGridLayout();
mainLayout->addWidget(m_infoLabel, 0, 0, 1, 3);
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();
m_proBar->hide();
setLayout(mainLayout);
mainLayout->setSizeConstraint(QLayout::SetFixedSize);
setWindowTitle(tr("Export Note"));
m_openBtn->hide();
updatePageLayoutLabel();
}
static QString exportTypeStr(ExportType p_type)
{
if (p_type == ExportType::PDF) {
return "PDF";
} else {
return "HTML";
}
}
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);
s_defaultPathDir = VUtils::basePathFromPath(path);
m_openBtn->hide();
}
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_pageLayout.setOrientation(printer.pageLayout().orientation());
updatePageLayoutLabel();
#endif
}
void VExporter::updatePageLayoutLabel()
{
m_layoutLabel->setText(QString("%1, %2").arg(m_pageLayout.pageSize().name())
.arg(m_pageLayout.orientation() == QPageLayout::Portrait ?
tr("Portrait") : tr("Landscape")));
}
QString VExporter::getFilePath() const
{
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();
VPreviewPage *page = new VPreviewPage(m_webViewer);
m_webViewer->setPage(page);
connect(page, &VPreviewPage::loadFinished,
this, &VExporter::handleLoadFinished);
VDocument *document = new VDocument(p_file, m_webViewer);
connect(document, &VDocument::logicsFinished,
this, &VExporter::handleLogicsFinished);
QWebChannel *channel = new QWebChannel(m_webViewer);
channel->registerObject(QStringLiteral("content"), document);
page->setWebChannel(channel);
// Need to generate HTML using Hoedown.
if (m_mdType == MarkdownConverterType::Hoedown) {
VMarkdownConverter mdConverter;
QString toc;
QString html = mdConverter.generateHtml(p_file->getContent(),
g_config->getMarkdownExtensions(),
toc);
document->setHtml(html);
}
m_webViewer->setHtml(m_htmlTemplate, p_file->getBaseUrl());
}
void VExporter::clearWebViewer()
{
if (m_webViewer) {
delete m_webViewer;
m_webViewer = NULL;
}
}
void VExporter::handleLogicsFinished()
{
Q_ASSERT(!(m_noteState & NoteState::WebLogicsReady));
m_noteState = NoteState(m_noteState | NoteState::WebLogicsReady);
}
void VExporter::handleLoadFinished(bool p_ok)
{
Q_ASSERT(!(m_noteState & NoteState::WebLoadFinished));
m_noteState = NoteState(m_noteState | NoteState::WebLoadFinished);
if (!p_ok) {
m_noteState = NoteState(m_noteState | NoteState::Failed);
}
}
void VExporter::clearNoteState()
{
m_noteState = NoteState::NotReady;
}
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()) {
bool isOpened = p_file->isOpened();
if (!isOpened && !p_file->open()) {
goto exit;
}
clearNoteState();
initWebViewer(m_file);
Q_ASSERT(m_state == ExportState::Idle);
m_state = ExportState::Busy;
// 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();
clearNoteState();
initWebViewer(p_file, p_opt);
while (!isNoteStateReady()) {
VUtils::sleepWait(100);
if (m_proBar->value() < 70) {
m_proBar->setValue(m_proBar->value() + 1);
}
if (m_state == ExportState::Cancelled) {
goto exit;
@ -326,22 +69,20 @@ void VExporter::startExport()
goto exit;
}
m_proBar->setValue(80);
bool exportRet = exportToPDF(m_webViewer, getFilePath(), m_pageLayout);
{
bool exportRet = exportToPDF(m_webViewer,
p_outputFile,
m_pageLayout);
clearNoteState();
if (!isOpened) {
m_file->close();
p_file->close();
}
if (exportRet) {
m_proBar->setValue(100);
m_state = ExportState::Successful;
exportedNum++;
} else {
m_proBar->setEnabled(false);
m_state = ExportState::Failed;
}
}
@ -349,33 +90,75 @@ void VExporter::startExport()
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();
if (m_state == ExportState::Successful) {
ret = true;
}
m_state = ExportState::Idle;
return ret;
}
void VExporter::cancelExport()
void VExporter::initWebViewer(VFile *p_file, const ExportOption &p_opt)
{
if (m_state == ExportState::Idle) {
reject();
} else {
m_state = ExportState::Cancelled;
Q_ASSERT(!m_webViewer);
m_webViewer = new VWebView(p_file, static_cast<QWidget *>(parent()));
m_webViewer->hide();
VPreviewPage *page = new VPreviewPage(m_webViewer);
m_webViewer->setPage(page);
connect(page, &VPreviewPage::loadFinished,
this, &VExporter::handleLoadFinished);
VDocument *document = new VDocument(p_file, m_webViewer);
connect(document, &VDocument::logicsFinished,
this, &VExporter::handleLogicsFinished);
QWebChannel *channel = new QWebChannel(m_webViewer);
channel->registerObject(QStringLiteral("content"), document);
page->setWebChannel(channel);
// Need to generate HTML using Hoedown.
if (p_opt.m_renderer == MarkdownConverterType::Hoedown) {
VMarkdownConverter mdConverter;
QString toc;
QString html = mdConverter.generateHtml(p_file->getContent(),
g_config->getMarkdownExtensions(),
toc);
document->setHtml(html);
}
m_webViewer->setHtml(m_htmlTemplate, p_file->getBaseUrl());
}
void VExporter::handleLogicsFinished()
{
Q_ASSERT(!(m_noteState & NoteState::WebLogicsReady));
m_noteState = NoteState(m_noteState | NoteState::WebLogicsReady);
}
void VExporter::handleLoadFinished(bool p_ok)
{
Q_ASSERT(!(m_noteState & NoteState::WebLoadFinished));
m_noteState = NoteState(m_noteState | NoteState::WebLoadFinished);
if (!p_ok) {
m_noteState = NoteState(m_noteState | NoteState::Failed);
}
}
bool VExporter::exportToPDF(VWebView *p_webViewer, const QString &p_filePath,
void VExporter::clearWebViewer()
{
if (m_webViewer) {
delete m_webViewer;
m_webViewer = NULL;
}
}
bool VExporter::exportToPDF(VWebView *p_webViewer,
const QString &p_filePath,
const QPageLayout &p_layout)
{
int pdfPrinted = 0;
@ -411,16 +194,3 @@ bool VExporter::exportToPDF(VWebView *p_webViewer, const QString &p_filePath,
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);
}

View File

@ -1,51 +1,32 @@
#ifndef VEXPORTER_H
#define VEXPORTER_H
#include <QDialog>
#include <QObject>
#include <QPageLayout>
#include <QString>
#include "vconfigmanager.h"
#include "dialog/vexportdialog.h"
class QWidget;
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:
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:
void handleBrowseBtnClicked();
void handleLayoutBtnClicked();
void startExport();
void cancelExport();
void handleLogicsFinished();
void handleLoadFinished(bool p_ok);
void openTargetPath() const;
private:
enum class ExportSource
{
Note = 0,
Directory,
Notebook,
Invalid
};
enum class ExportState
{
Idle = 0,
@ -55,6 +36,7 @@ private:
Successful
};
enum NoteState
{
NotReady = 0,
@ -64,59 +46,46 @@ private:
Failed = 0x4
};
void setupUI();
void initMarkdownTemplate();
void updatePageLayoutLabel();
void setFilePath(const QString &p_path);
QString getFilePath() const;
void initWebViewer(VFile *p_file);
void initWebViewer(VFile *p_file, const ExportOption &p_opt);
void clearWebViewer();
void enableUserInput(bool p_enabled);
bool exportToPDF(VWebView *p_webViewer, const QString &p_filePath, const QPageLayout &p_layout);
void clearNoteState();
bool isNoteStateReady() 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.
VWebView *m_webViewer;
MarkdownConverterType m_mdType;
QString m_htmlTemplate;
VFile *m_file;
ExportType m_type;
ExportSource m_source;
NoteState m_noteState;
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

View File

@ -37,6 +37,7 @@
#include "utils/viconutils.h"
#include "dialog/vtipsdialog.h"
#include "vcart.h"
#include "dialog/vexportdialog.h"
extern VConfigManager *g_config;
@ -994,13 +995,12 @@ void VMainWindow::initFileMenu()
fileMenu->addSeparator();
// Export as PDF.
m_exportAsPDFAct = new QAction(tr("Export As &PDF"), this);
m_exportAsPDFAct->setToolTip(tr("Export current note as PDF file"));
connect(m_exportAsPDFAct, &QAction::triggered,
this, &VMainWindow::exportAsPDF);
m_exportAsPDFAct->setEnabled(false);
m_exportAct = new QAction(tr("E&xport"), this);
m_exportAct->setToolTip(tr("Export notes"));
connect(m_exportAct, &QAction::triggered,
this, &VMainWindow::handleExportAct);
fileMenu->addAction(m_exportAsPDFAct);
fileMenu->addAction(m_exportAct);
// Print.
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();
qDebug() << "switch to converter" << type;
g_config->setMarkdownConverterType(type);
}
@ -1418,7 +1416,7 @@ void VMainWindow::setEditorBackgroundColor(QAction *action)
void VMainWindow::initConverterMenu(QMenu *p_menu)
{
QMenu *converterMenu = p_menu->addMenu(tr("&Converter"));
QMenu *converterMenu = p_menu->addMenu(tr("&Renderer"));
converterMenu->setToolTipsVisible(true);
QActionGroup *converterAct = new QActionGroup(this);
@ -1828,7 +1826,6 @@ void VMainWindow::updateActionsStateFromTab(const VEditTab *p_tab)
&& dynamic_cast<const VOrphanFile *>(file)->isSystemFile();
m_printAct->setEnabled(file && file->getDocType() == DocType::Markdown);
m_exportAsPDFAct->setEnabled(file && file->getDocType() == DocType::Markdown);
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,
const QString &p_text,
QObject *p_parent)
@ -3015,3 +2999,19 @@ void VMainWindow::updateEditReadAct(const VEditTab *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();
}

View File

@ -97,6 +97,8 @@ public:
VEditTab *getCurrentTab() const;
VNotebook *getCurrentNotebook() const;
signals:
// Emit when editor related configurations were changed by user.
void editorConfigUpdated();
@ -139,7 +141,9 @@ private slots:
void enableImageConstraint(bool p_checked);
void enableImageCaption(bool p_checked);
void printNote();
void exportAsPDF();
// Open export dialog.
void handleExportAct();
// Set the panel view properly.
void enableCompactMode(bool p_enabled);
@ -349,7 +353,7 @@ private:
QAction *m_printAct;
QAction *m_exportAsPDFAct;
QAction *m_exportAct;
QAction *m_findReplaceAct;

View File

@ -10,7 +10,6 @@
#include "vnote.h"
#include "utils/vutils.h"
#include "vconfigmanager.h"
#include "vmainwindow.h"
#include "vorphanfile.h"
#include "vnotefile.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) {
VOrphanFile *file = m_externalFiles[i];
if (!file->isOpened()) {
qDebug() << "release orphan file" << file;
m_externalFiles.removeAt(i);
delete file;
--i;
}
}
freeOrphanFiles();
// Create a VOrphanFile for path.
VOrphanFile *file = new VOrphanFile(this, path, p_modifiable, p_systemFile);
@ -296,3 +287,17 @@ VDirectory *VNote::getInternalDirectory(const QString &p_path)
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;
}
}
}

View File

@ -99,6 +99,8 @@ public:
// Otherwise, returns NULL.
VDirectory *getInternalDirectory(const QString &p_path);
void freeOrphanFiles();
public slots:
void updateTemplate();

View File

@ -621,3 +621,8 @@ VNotebook *VNotebookSelector::getNotebook(const QListWidgetItem *p_item) const
return NULL;
}
VNotebook *VNotebookSelector::currentNotebook() const
{
return getNotebook(currentIndex());
}

View File

@ -27,6 +27,8 @@ public:
// Add notebook on popup if no notebooks currently.
void showPopup() Q_DECL_OVERRIDE;
VNotebook *currentNotebook() const;
// Implementations for VNavigationMode.
void registerNavigation(QChar p_majorKey) Q_DECL_OVERRIDE;
void showNavigation() Q_DECL_OVERRIDE;

View File

@ -8,7 +8,6 @@
#include <QJsonArray>
#include <QDebug>
#include "utils/vutils.h"
#include "vdirectory.h"
VNoteFile::VNoteFile(VDirectory *p_directory,
@ -510,42 +509,12 @@ bool VNoteFile::copyFile(VDirectory *p_destDir,
}
// Copy images.
QDir parentDir(destFile->fetchBasePath());
QSet<QString> processedImages;
for (int i = 0; i < images.size(); ++i) {
const ImageLink &link = 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));
if (!copyInternalImages(images,
destFile->fetchBasePath(),
p_isCut,
&nrImageCopied,
p_errMsg)) {
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.
@ -587,3 +556,53 @@ bool VNoteFile::copyFile(VDirectory *p_destDir,
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;
}

View File

@ -5,6 +5,7 @@
#include <QString>
#include "vfile.h"
#include "utils/vutils.h"
class VDirectory;
class VNotebook;
@ -129,6 +130,13 @@ public:
VNoteFile **p_targetFile,
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:
// Delete internal images of this file.
// Return true only when all internal images were deleted successfully.