| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426 |
- #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 "vconfigmanager.h"
- #include "utils/vutils.h"
- #include "vfile.h"
- #include "vwebview.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)
- {
- initMarkdownTemplate();
- setupUI();
- }
- void VExporter::initMarkdownTemplate()
- {
- m_htmlTemplate = VUtils::generateHtmlTemplate(m_mdType, true);
- }
- void VExporter::setupUI()
- {
- m_infoLabel = new QLabel();
- m_infoLabel->setWordWrap(true);
- // 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);
- // 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()) {
- 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,
- const QPageLayout &p_layout)
- {
- int pdfPrinted = 0;
- p_webViewer->page()->printToPdf([&, this](const QByteArray &p_result) {
- if (p_result.isEmpty() || this->m_state == ExportState::Cancelled) {
- pdfPrinted = -1;
- return;
- }
- V_ASSERT(!p_filePath.isEmpty());
- QFile file(p_filePath);
- if (!file.open(QFile::WriteOnly)) {
- pdfPrinted = -1;
- return;
- }
- file.write(p_result.data(), p_result.size());
- file.close();
- pdfPrinted = 1;
- }, p_layout);
- while (pdfPrinted == 0) {
- VUtils::sleepWait(100);
- if (m_state == ExportState::Cancelled) {
- break;
- }
- }
- 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);
- }
|