|
|
|
|
@ -1086,8 +1086,107 @@ class MarkTextMainWindow(QMainWindow):
|
|
|
|
|
self.switch_to_learning_mode(file_path)
|
|
|
|
|
|
|
|
|
|
def export_file(self):
|
|
|
|
|
"""导出文件"""
|
|
|
|
|
QMessageBox.information(self, "提示", "导出功能开发中...")
|
|
|
|
|
"""导出文件 - 支持多种格式"""
|
|
|
|
|
try:
|
|
|
|
|
editor = self.get_current_editor()
|
|
|
|
|
if not editor:
|
|
|
|
|
QMessageBox.warning(self, "提示", "请先打开一个文档")
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
content = editor.get_content()
|
|
|
|
|
if not content.strip():
|
|
|
|
|
QMessageBox.warning(self, "提示", "文档内容为空,无法导出")
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
# 创建导出格式选择对话框
|
|
|
|
|
from PyQt5.QtWidgets import QDialog, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, QDialogButtonBox
|
|
|
|
|
|
|
|
|
|
dialog = QDialog(self)
|
|
|
|
|
dialog.setWindowTitle("选择导出格式")
|
|
|
|
|
dialog.setModal(True)
|
|
|
|
|
dialog.resize(400, 300)
|
|
|
|
|
|
|
|
|
|
# 设置对话框样式
|
|
|
|
|
dialog.setStyleSheet("""
|
|
|
|
|
QDialog {
|
|
|
|
|
background-color: #161b22;
|
|
|
|
|
color: #c9d1d9;
|
|
|
|
|
}
|
|
|
|
|
QLabel {
|
|
|
|
|
color: #c9d1d9;
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
padding: 10px;
|
|
|
|
|
}
|
|
|
|
|
QPushButton {
|
|
|
|
|
background-color: #238636;
|
|
|
|
|
color: white;
|
|
|
|
|
border: none;
|
|
|
|
|
padding: 8px 16px;
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
margin: 5px;
|
|
|
|
|
min-width: 120px;
|
|
|
|
|
}
|
|
|
|
|
QPushButton:hover {
|
|
|
|
|
background-color: #2ea043;
|
|
|
|
|
}
|
|
|
|
|
QPushButton:pressed {
|
|
|
|
|
background-color: #1a5d29;
|
|
|
|
|
}
|
|
|
|
|
""")
|
|
|
|
|
|
|
|
|
|
layout = QVBoxLayout()
|
|
|
|
|
|
|
|
|
|
# 标题
|
|
|
|
|
title_label = QLabel("选择要导出的文件格式:")
|
|
|
|
|
title_label.setStyleSheet("font-size: 16px; font-weight: bold; padding: 15px;")
|
|
|
|
|
layout.addWidget(title_label)
|
|
|
|
|
|
|
|
|
|
# 格式按钮布局
|
|
|
|
|
format_layout = QVBoxLayout()
|
|
|
|
|
|
|
|
|
|
# HTML格式
|
|
|
|
|
html_btn = QPushButton("🌐 导出为 HTML")
|
|
|
|
|
html_btn.clicked.connect(lambda: self.export_as_format(editor, "html", dialog))
|
|
|
|
|
format_layout.addWidget(html_btn)
|
|
|
|
|
|
|
|
|
|
# PDF格式
|
|
|
|
|
pdf_btn = QPushButton("📄 导出为 PDF")
|
|
|
|
|
pdf_btn.clicked.connect(lambda: self.export_as_format(editor, "pdf", dialog))
|
|
|
|
|
format_layout.addWidget(pdf_btn)
|
|
|
|
|
|
|
|
|
|
# TXT格式
|
|
|
|
|
txt_btn = QPushButton("📝 导出为 TXT")
|
|
|
|
|
txt_btn.clicked.connect(lambda: self.export_as_format(editor, "txt", dialog))
|
|
|
|
|
format_layout.addWidget(txt_btn)
|
|
|
|
|
|
|
|
|
|
# Markdown格式
|
|
|
|
|
md_btn = QPushButton("📚 导出为 Markdown")
|
|
|
|
|
md_btn.clicked.connect(lambda: self.export_as_format(editor, "md", dialog))
|
|
|
|
|
format_layout.addWidget(md_btn)
|
|
|
|
|
|
|
|
|
|
layout.addLayout(format_layout)
|
|
|
|
|
|
|
|
|
|
# 取消按钮
|
|
|
|
|
cancel_btn = QPushButton("❌ 取消")
|
|
|
|
|
cancel_btn.setStyleSheet("""
|
|
|
|
|
QPushButton {
|
|
|
|
|
background-color: #21262d;
|
|
|
|
|
color: #c9d1d9;
|
|
|
|
|
}
|
|
|
|
|
QPushButton:hover {
|
|
|
|
|
background-color: #30363d;
|
|
|
|
|
}
|
|
|
|
|
""")
|
|
|
|
|
cancel_btn.clicked.connect(dialog.reject)
|
|
|
|
|
layout.addWidget(cancel_btn)
|
|
|
|
|
|
|
|
|
|
layout.addStretch()
|
|
|
|
|
dialog.setLayout(layout)
|
|
|
|
|
dialog.exec_()
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
QMessageBox.critical(self, "错误", f"导出功能出错: {str(e)}")
|
|
|
|
|
|
|
|
|
|
def switch_mode(self, mode: str):
|
|
|
|
|
"""切换模式"""
|
|
|
|
|
@ -1286,6 +1385,315 @@ class MarkTextMainWindow(QMainWindow):
|
|
|
|
|
QMessageBox.warning(self, "提示", "无法刷新天气信息")
|
|
|
|
|
except Exception as e:
|
|
|
|
|
QMessageBox.critical(self, "错误", f"刷新天气信息失败: {str(e)}")
|
|
|
|
|
|
|
|
|
|
def export_as_format(self, editor, format_type: str, dialog):
|
|
|
|
|
"""导出为指定格式"""
|
|
|
|
|
try:
|
|
|
|
|
content = editor.get_content()
|
|
|
|
|
|
|
|
|
|
# 根据格式设置文件扩展名和过滤器
|
|
|
|
|
if format_type == "html":
|
|
|
|
|
ext = "html"
|
|
|
|
|
filter_str = "HTML文件 (*.html);;所有文件 (*.*)"
|
|
|
|
|
default_name = "document.html"
|
|
|
|
|
elif format_type == "pdf":
|
|
|
|
|
ext = "pdf"
|
|
|
|
|
filter_str = "PDF文件 (*.pdf);;所有文件 (*.*)"
|
|
|
|
|
default_name = "document.pdf"
|
|
|
|
|
elif format_type == "txt":
|
|
|
|
|
ext = "txt"
|
|
|
|
|
filter_str = "文本文档 (*.txt);;所有文件 (*.*)"
|
|
|
|
|
default_name = "document.txt"
|
|
|
|
|
elif format_type == "md":
|
|
|
|
|
ext = "md"
|
|
|
|
|
filter_str = "Markdown文件 (*.md);;所有文件 (*.*)"
|
|
|
|
|
default_name = "document.md"
|
|
|
|
|
else:
|
|
|
|
|
QMessageBox.warning(self, "提示", "不支持的导出格式")
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
# 获取保存路径
|
|
|
|
|
file_path, _ = QFileDialog.getSaveFileName(
|
|
|
|
|
self, f"导出为{format_type.upper()}", default_name, filter_str
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if not file_path:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
dialog.accept() # 关闭选择对话框
|
|
|
|
|
|
|
|
|
|
# 根据格式导出
|
|
|
|
|
if format_type == "html":
|
|
|
|
|
self.export_as_html(content, file_path)
|
|
|
|
|
elif format_type == "pdf":
|
|
|
|
|
self.export_as_pdf(content, file_path)
|
|
|
|
|
elif format_type == "txt":
|
|
|
|
|
self.export_as_txt(content, file_path)
|
|
|
|
|
elif format_type == "md":
|
|
|
|
|
self.export_as_markdown(content, file_path)
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
QMessageBox.critical(self, "错误", f"导出失败: {str(e)}")
|
|
|
|
|
|
|
|
|
|
def export_as_html(self, content: str, file_path: str):
|
|
|
|
|
"""导出为HTML格式"""
|
|
|
|
|
try:
|
|
|
|
|
from datetime import datetime
|
|
|
|
|
|
|
|
|
|
# 创建HTML内容
|
|
|
|
|
html_content = f"""<!DOCTYPE html>
|
|
|
|
|
<html lang="zh-CN">
|
|
|
|
|
<head>
|
|
|
|
|
<meta charset="UTF-8">
|
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
|
|
<title>MagicWord文档</title>
|
|
|
|
|
<style>
|
|
|
|
|
* {{
|
|
|
|
|
margin: 0;
|
|
|
|
|
padding: 0;
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
body {{
|
|
|
|
|
font-family: 'Segoe UI', 'Microsoft YaHei', '微软雅黑', sans-serif;
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
line-height: 1.6;
|
|
|
|
|
background-color: #fafafa;
|
|
|
|
|
color: #333;
|
|
|
|
|
padding: 20px;
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
.container {{
|
|
|
|
|
max-width: 800px;
|
|
|
|
|
margin: 0 auto;
|
|
|
|
|
background-color: #ffffff;
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
|
|
|
|
padding: 40px;
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
h1 {{
|
|
|
|
|
color: #2c3e50;
|
|
|
|
|
border-bottom: 3px solid #3498db;
|
|
|
|
|
padding-bottom: 15px;
|
|
|
|
|
margin-bottom: 30px;
|
|
|
|
|
font-size: 24px;
|
|
|
|
|
font-weight: 300;
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
p {{
|
|
|
|
|
margin: 15px 0;
|
|
|
|
|
white-space: pre-wrap;
|
|
|
|
|
text-align: justify;
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
.document-info {{
|
|
|
|
|
margin-top: 40px;
|
|
|
|
|
padding: 20px;
|
|
|
|
|
background-color: #f8f9fa;
|
|
|
|
|
border-left: 4px solid #3498db;
|
|
|
|
|
border-radius: 0 5px 5px 0;
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
.document-info h3 {{
|
|
|
|
|
color: #495057;
|
|
|
|
|
margin-bottom: 10px;
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
.document-info p {{
|
|
|
|
|
margin: 5px 0;
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
color: #6c757d;
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
br {{
|
|
|
|
|
margin: 10px 0;
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
@media (max-width: 600px) {{
|
|
|
|
|
body {{
|
|
|
|
|
padding: 10px;
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
.container {{
|
|
|
|
|
padding: 20px;
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
h1 {{
|
|
|
|
|
font-size: 20px;
|
|
|
|
|
}}
|
|
|
|
|
}}
|
|
|
|
|
</style>
|
|
|
|
|
</head>
|
|
|
|
|
<body>
|
|
|
|
|
<div class="container">
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
# 获取文件名作为标题
|
|
|
|
|
base_name = os.path.splitext(os.path.basename(file_path))[0]
|
|
|
|
|
html_content += f'<h1>{base_name}</h1>\n\n'
|
|
|
|
|
|
|
|
|
|
# 处理内容
|
|
|
|
|
lines = content.split('\n')
|
|
|
|
|
for line in lines:
|
|
|
|
|
if line.strip():
|
|
|
|
|
# 转义HTML特殊字符
|
|
|
|
|
escaped_line = line.replace("&", "&").replace("<", "<").replace(">", ">")
|
|
|
|
|
html_content += f'<p>{escaped_line}</p>\n'
|
|
|
|
|
else:
|
|
|
|
|
html_content += '<br>\n'
|
|
|
|
|
|
|
|
|
|
# 添加文档信息
|
|
|
|
|
html_content += f'<div class="document-info">\n'
|
|
|
|
|
html_content += f'<h3>文档信息</h3>\n'
|
|
|
|
|
html_content += f'<p><strong>创建时间:</strong> {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}</p>\n'
|
|
|
|
|
html_content += f'<p><strong>字符数:</strong> {len(content)}</p>\n'
|
|
|
|
|
html_content += f'<p><strong>行数:</strong> {len(lines)}</p>\n'
|
|
|
|
|
html_content += f'</div>\n'
|
|
|
|
|
|
|
|
|
|
html_content += """
|
|
|
|
|
</div>
|
|
|
|
|
</body>
|
|
|
|
|
</html>"""
|
|
|
|
|
|
|
|
|
|
# 写入文件
|
|
|
|
|
with open(file_path, 'w', encoding='utf-8') as f:
|
|
|
|
|
f.write(html_content)
|
|
|
|
|
|
|
|
|
|
self.statusBar().showMessage(f"已导出为HTML: {os.path.basename(file_path)}", 3000)
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
QMessageBox.critical(self, "错误", f"导出HTML失败: {str(e)}")
|
|
|
|
|
|
|
|
|
|
def export_as_pdf(self, content: str, file_path: str):
|
|
|
|
|
"""导出为PDF格式"""
|
|
|
|
|
try:
|
|
|
|
|
from PyQt5.QtGui import QTextDocument
|
|
|
|
|
from PyQt5.QtPrintSupport import QPrinter
|
|
|
|
|
|
|
|
|
|
# 创建HTML内容以便更好地处理格式
|
|
|
|
|
html_content = f"""
|
|
|
|
|
<html>
|
|
|
|
|
<head>
|
|
|
|
|
<meta charset='utf-8'>
|
|
|
|
|
<style>
|
|
|
|
|
body {{
|
|
|
|
|
font-family: 'Segoe UI', 'Microsoft YaHei', 微软雅黑, sans-serif;
|
|
|
|
|
font-size: 12pt;
|
|
|
|
|
line-height: 1.6;
|
|
|
|
|
margin: 40px;
|
|
|
|
|
color: #333;
|
|
|
|
|
}}
|
|
|
|
|
p {{ margin: 10px 0; white-space: pre-wrap; }}
|
|
|
|
|
h1 {{ color: #2c3e50; border-bottom: 2px solid #3498db; padding-bottom: 10px; }}
|
|
|
|
|
.document-info {{ margin-top: 30px; padding: 15px; background-color: #f8f9fa; border-left: 3px solid #3498db; }}
|
|
|
|
|
</style>
|
|
|
|
|
</head>
|
|
|
|
|
<body>
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
# 获取文件名作为标题
|
|
|
|
|
base_name = os.path.splitext(os.path.basename(file_path))[0]
|
|
|
|
|
html_content += f'<h1>{base_name}</h1>'
|
|
|
|
|
|
|
|
|
|
# 处理内容
|
|
|
|
|
lines = content.split('\n')
|
|
|
|
|
for line in lines:
|
|
|
|
|
if line.strip():
|
|
|
|
|
# 转义HTML特殊字符
|
|
|
|
|
escaped_line = line.replace("&", "&").replace("<", "<").replace(">", ">")
|
|
|
|
|
html_content += f'<p>{escaped_line}</p>'
|
|
|
|
|
else:
|
|
|
|
|
html_content += '<br>'
|
|
|
|
|
|
|
|
|
|
# 添加文档信息
|
|
|
|
|
from datetime import datetime
|
|
|
|
|
html_content += f'<div class="document-info">'
|
|
|
|
|
html_content += f'<p><strong>创建时间:</strong> {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}</p>'
|
|
|
|
|
html_content += f'<p><strong>字符数:</strong> {len(content)}</p>'
|
|
|
|
|
html_content += f'<p><strong>行数:</strong> {len(lines)}</p>'
|
|
|
|
|
html_content += f'</div>'
|
|
|
|
|
|
|
|
|
|
html_content += "</body></html>"
|
|
|
|
|
|
|
|
|
|
# 创建文本文档
|
|
|
|
|
doc = QTextDocument()
|
|
|
|
|
doc.setHtml(html_content)
|
|
|
|
|
|
|
|
|
|
# 创建PDF打印机
|
|
|
|
|
printer = QPrinter(QPrinter.HighResolution)
|
|
|
|
|
printer.setOutputFormat(QPrinter.PdfFormat)
|
|
|
|
|
printer.setOutputFileName(file_path)
|
|
|
|
|
printer.setPageSize(QPrinter.A4)
|
|
|
|
|
printer.setPageMargins(20, 20, 20, 20, QPrinter.Millimeter)
|
|
|
|
|
|
|
|
|
|
# 打印文档到PDF
|
|
|
|
|
doc.print_(printer)
|
|
|
|
|
|
|
|
|
|
self.statusBar().showMessage(f"已导出为PDF: {os.path.basename(file_path)}", 3000)
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
QMessageBox.critical(self, "错误", f"导出PDF失败: {str(e)}")
|
|
|
|
|
|
|
|
|
|
def export_as_txt(self, content: str, file_path: str):
|
|
|
|
|
"""导出为TXT格式"""
|
|
|
|
|
try:
|
|
|
|
|
from datetime import datetime
|
|
|
|
|
|
|
|
|
|
# 添加文档信息
|
|
|
|
|
txt_content = f"文档标题: {os.path.splitext(os.path.basename(file_path))[0]}\n"
|
|
|
|
|
txt_content += f"创建时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n"
|
|
|
|
|
txt_content += f"字符数: {len(content)}\n"
|
|
|
|
|
txt_content += f"行数: {len(content.split(chr(10)))}\n"
|
|
|
|
|
txt_content += "=" * 50 + "\n\n"
|
|
|
|
|
|
|
|
|
|
# 添加原始内容
|
|
|
|
|
txt_content += content
|
|
|
|
|
|
|
|
|
|
# 写入文件
|
|
|
|
|
with open(file_path, 'w', encoding='utf-8') as f:
|
|
|
|
|
f.write(txt_content)
|
|
|
|
|
|
|
|
|
|
self.statusBar().showMessage(f"已导出为TXT: {os.path.basename(file_path)}", 3000)
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
QMessageBox.critical(self, "错误", f"导出TXT失败: {str(e)}")
|
|
|
|
|
|
|
|
|
|
def export_as_markdown(self, content: str, file_path: str):
|
|
|
|
|
"""导出为Markdown格式"""
|
|
|
|
|
try:
|
|
|
|
|
from datetime import datetime
|
|
|
|
|
|
|
|
|
|
# 创建Markdown内容
|
|
|
|
|
base_name = os.path.splitext(os.path.basename(file_path))[0]
|
|
|
|
|
|
|
|
|
|
md_content = f"# {base_name}\n\n"
|
|
|
|
|
|
|
|
|
|
# 添加文档信息
|
|
|
|
|
md_content += f"**创建时间:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} \n"
|
|
|
|
|
md_content += f"**字符数:** {len(content)} \n"
|
|
|
|
|
md_content += f"**行数:** {len(content.split(chr(10)))} \n\n"
|
|
|
|
|
|
|
|
|
|
md_content += "---\n\n"
|
|
|
|
|
|
|
|
|
|
# 处理内容,将普通文本转换为Markdown格式
|
|
|
|
|
lines = content.split('\n')
|
|
|
|
|
for line in lines:
|
|
|
|
|
if line.strip():
|
|
|
|
|
# 简单的Markdown处理
|
|
|
|
|
md_content += f"{line}\n\n"
|
|
|
|
|
else:
|
|
|
|
|
md_content += "\n"
|
|
|
|
|
|
|
|
|
|
# 写入文件
|
|
|
|
|
with open(file_path, 'w', encoding='utf-8') as f:
|
|
|
|
|
f.write(md_content)
|
|
|
|
|
|
|
|
|
|
self.statusBar().showMessage(f"已导出为Markdown: {os.path.basename(file_path)}", 3000)
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
QMessageBox.critical(self, "错误", f"导出Markdown失败: {str(e)}")
|
|
|
|
|
|
|
|
|
|
def refresh_quote_info(self):
|
|
|
|
|
"""刷新每日名言 - 获取新的名言"""
|
|
|
|
|
|