feat: v0.5.0 —— 导出 PDF(带预览窗口)
导出 - 文件 → 导出 PDF…(Ctrl+E)先弹出预览窗口,确认后点「保存 PDF…」选路径 - A4 纸、16mm 页边距;预览和导出共用同一个 QTextDocument,页宽一致 - 只用 Qt 自带的 QPrinter / QTextDocument,没有引入外部 PDF 库 排版 - 新增 MarkdownRenderer:把 Markdown 解析成排版好的富文本文档 - 支持标题、列表 / 任务列表、引用、围栏代码块、行内代码、 粗体 / 斜体 / 删除线、链接;图片输出 alt 文字,表格暂按原文 - 代码块带底色、引用带竖线、分隔线画成横线 其它 - 用用户更新后的 logo.png 重新生成了 ico / icns / png - docs/screenshot-export.png 与 README 同步
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
#include "ExportDialog.h"
|
||||
|
||||
#include "MarkdownRenderer.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QFileDialog>
|
||||
#include <QFileInfo>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QMessageBox>
|
||||
#include <QPageSize>
|
||||
#include <QPrinter>
|
||||
#include <QPushButton>
|
||||
#include <QTextBrowser>
|
||||
#include <QTextDocument>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
ExportDialog::ExportDialog(const QString &markdown, const QString &documentName,
|
||||
const QString &startDirectory, QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, m_documentName(documentName)
|
||||
, m_startDirectory(startDirectory)
|
||||
{
|
||||
setWindowTitle(tr("导出 PDF — %1")
|
||||
.arg(documentName.isEmpty() ? tr("未命名") : documentName));
|
||||
resize(900, 840);
|
||||
|
||||
QVBoxLayout *layout = new QVBoxLayout(this);
|
||||
layout->setContentsMargins(16, 16, 16, 12);
|
||||
layout->setSpacing(10);
|
||||
|
||||
m_document = new QTextDocument(this);
|
||||
MarkdownRenderer::render(markdown, m_document);
|
||||
// A4 去掉 16mm 页边距后的正文宽度(96dpi 下的像素):
|
||||
// 预览和打印用同一个页宽,看到的就是导出的样子。
|
||||
m_document->setPageSize(QSizeF(672.76, 1001.57));
|
||||
|
||||
m_preview = new QTextBrowser(this);
|
||||
m_preview->setFrameShape(QFrame::NoFrame);
|
||||
m_preview->setOpenExternalLinks(true);
|
||||
m_preview->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
m_preview->setFixedWidth(700);
|
||||
m_preview->setDocument(m_document);
|
||||
m_preview->setStyleSheet(QStringLiteral(
|
||||
"QTextBrowser { background: #ffffff; color: #1f2328;"
|
||||
" border: 1px solid #d8dde3; border-radius: 4px; }"));
|
||||
|
||||
QHBoxLayout *center = new QHBoxLayout;
|
||||
center->addStretch(1);
|
||||
center->addWidget(m_preview);
|
||||
center->addStretch(1);
|
||||
layout->addLayout(center, 1);
|
||||
|
||||
QLabel *hint = new QLabel(tr("A4 纸、16mm 页边距,内容和预览一致。"), this);
|
||||
hint->setForegroundRole(QPalette::PlaceholderText);
|
||||
|
||||
QPushButton *saveButton = new QPushButton(tr("保存 PDF…"), this);
|
||||
saveButton->setDefault(true);
|
||||
QPushButton *closeButton = new QPushButton(tr("关闭"), this);
|
||||
|
||||
QHBoxLayout *buttons = new QHBoxLayout;
|
||||
buttons->addWidget(hint);
|
||||
buttons->addStretch(1);
|
||||
buttons->addWidget(closeButton);
|
||||
buttons->addWidget(saveButton);
|
||||
layout->addLayout(buttons);
|
||||
|
||||
connect(closeButton, &QPushButton::clicked, this, &QDialog::reject);
|
||||
connect(saveButton, &QPushButton::clicked, this, &ExportDialog::savePdf);
|
||||
}
|
||||
|
||||
void ExportDialog::savePdf()
|
||||
{
|
||||
QString suggested = m_documentName.isEmpty()
|
||||
? tr("未命名")
|
||||
: QFileInfo(m_documentName).completeBaseName();
|
||||
suggested += QStringLiteral(".pdf");
|
||||
|
||||
QString target = QFileDialog::getSaveFileName(
|
||||
this, tr("保存 PDF"), QDir(m_startDirectory).filePath(suggested),
|
||||
tr("PDF 文件 (*.pdf)"));
|
||||
if (target.isEmpty())
|
||||
return;
|
||||
|
||||
if (!target.endsWith(QStringLiteral(".pdf"), Qt::CaseInsensitive))
|
||||
target += QStringLiteral(".pdf");
|
||||
|
||||
QPrinter printer(QPrinter::HighResolution);
|
||||
printer.setOutputFormat(QPrinter::PdfFormat);
|
||||
printer.setOutputFileName(target);
|
||||
printer.setPageSize(QPageSize(QPageSize::A4));
|
||||
printer.setPageMargins(QMarginsF(16, 16, 16, 16), QPageLayout::Millimeter);
|
||||
printer.setDocName(QFileInfo(target).completeBaseName());
|
||||
|
||||
m_document->print(&printer);
|
||||
|
||||
if (!QFileInfo::exists(target) || QFileInfo(target).size() <= 0) {
|
||||
QMessageBox::warning(this, tr("导出失败"),
|
||||
tr("没能写出「%1」,换个位置再试一次。")
|
||||
.arg(QDir::toNativeSeparators(target)));
|
||||
return;
|
||||
}
|
||||
|
||||
QMessageBox::information(this, tr("导出完成"),
|
||||
tr("已保存到\n%1").arg(QDir::toNativeSeparators(target)));
|
||||
accept();
|
||||
}
|
||||
Reference in New Issue
Block a user