TxT2Docx/gui_style_manager.py

243 lines
9.4 KiB
Python

"""
样式管理GUI模块
提供样式选择、预览、编辑的图形界面。
"""
import tkinter as tk
from tkinter import ttk, filedialog, messagebox, simpledialog
from typing import Optional
from style_manager import style_manager, DocumentStyle
from config import config as config_manager
from advanced_style_editor import open_advanced_editor
def create_style_tab(parent):
"""创建样式管理选项卡"""
style_frame = ttk.Frame(parent)
# 标题
ttk.Label(style_frame, text='文章排版样式管理', font=('', 12, 'bold')).pack(anchor='w', padx=10, pady=(10, 5))
ttk.Separator(style_frame, orient='horizontal').pack(fill='x', padx=10, pady=5)
# 样式选择区域
selection_frame = ttk.LabelFrame(style_frame, text='样式选择', padding="10")
selection_frame.pack(fill='x', padx=10, pady=5)
# 当前样式
current_frame = ttk.Frame(selection_frame)
current_frame.pack(fill='x', pady=2)
ttk.Label(current_frame, text='当前样式:', width=12).pack(side='left')
style_var = tk.StringVar(value=config_manager.current_style)
style_combo = ttk.Combobox(current_frame, textvariable=style_var,
values=style_manager.get_style_names(),
state='readonly', width=25)
style_combo.pack(side='left', padx=(0, 10))
def on_style_change(*args):
config_manager.current_style = style_var.get()
from config import CONFIG_FILE_PATH
config_manager.save_to_file(CONFIG_FILE_PATH)
_update_style_info()
style_var.trace('w', on_style_change)
ttk.Button(current_frame, text='预览', command=lambda: _preview_style(style_var.get(), parent)).pack(side='left', padx=5)
# 样式信息显示
info_frame = ttk.Frame(selection_frame)
info_frame.pack(fill='x', pady=(5, 0))
info_text = tk.Text(info_frame, height=3, wrap=tk.WORD, state='disabled')
info_text.pack(fill='x')
def _update_style_info():
"""更新样式信息显示"""
style = style_manager.get_style(style_var.get())
if style:
info = f"描述: {style.description}\n作者: {style.author} 版本: {style.version}\n"
info += f"正文字体: {style.body_font.name if style.body_font else '默认'} {style.body_font.size if style.body_font else 12}pt"
info_text.config(state='normal')
info_text.delete(1.0, tk.END)
info_text.insert(1.0, info)
info_text.config(state='disabled')
# 样式管理区域
management_frame = ttk.LabelFrame(style_frame, text='样式管理', padding="10")
management_frame.pack(fill='x', padx=10, pady=5)
button_frame = ttk.Frame(management_frame)
button_frame.pack(fill='x')
def _create_new_style():
"""创建新样式"""
name = simpledialog.askstring("新建样式", "请输入样式名称:")
if name and name not in style_manager.get_style_names():
new_style = DocumentStyle(name=name, description="自定义样式", author="用户")
if style_manager.create_custom_style(new_style):
style_combo['values'] = style_manager.get_style_names()
messagebox.showinfo("成功", f"样式 '{name}' 创建成功")
else:
messagebox.showerror("错误", "创建样式失败")
elif name:
messagebox.showerror("错误", "样式名称已存在")
def _duplicate_style():
"""复制样式"""
current_name = style_var.get()
if current_name:
new_name = simpledialog.askstring("复制样式", f"基于 '{current_name}' 创建新样式,请输入新名称:")
if new_name and new_name not in style_manager.get_style_names():
if style_manager.duplicate_style(current_name, new_name):
style_combo['values'] = style_manager.get_style_names()
messagebox.showinfo("成功", f"样式 '{new_name}' 创建成功")
else:
messagebox.showerror("错误", "复制样式失败")
elif new_name:
messagebox.showerror("错误", "样式名称已存在")
def _edit_style_advanced():
"""高级样式编辑"""
current_name = style_var.get()
if not current_name:
messagebox.showwarning("警告", "请先选择一个样式")
return
# 创建高级编辑窗口
try:
edit_window = open_advanced_editor(parent, current_name)
if edit_window:
def on_window_close():
# 更新样式列表
style_combo['values'] = style_manager.get_style_names()
_update_style_info()
# 等待窗口关闭后更新
style_frame.after(1000, on_window_close)
except Exception as e:
messagebox.showerror("错误", f"打开高级编辑器失败: {str(e)}")
def _delete_style():
"""删除样式"""
current_name = style_var.get()
if current_name and current_name not in style_manager.builtin_styles:
if messagebox.askyesno("确认删除", f"确定要删除样式 '{current_name}' 吗?"):
if style_manager.delete_custom_style(current_name):
style_combo['values'] = style_manager.get_style_names()
style_var.set(style_manager.get_style_names()[0] if style_manager.get_style_names() else "")
messagebox.showinfo("成功", "样式删除成功")
else:
messagebox.showerror("错误", "删除样式失败")
else:
messagebox.showerror("错误", "无法删除内置样式")
def _export_style():
"""导出样式"""
current_name = style_var.get()
if current_name:
file_path = filedialog.asksaveasfilename(
title="导出样式",
defaultextension=".json",
filetypes=[("JSON文件", "*.json"), ("所有文件", "*.*")]
)
if file_path:
if style_manager.export_style(current_name, file_path):
messagebox.showinfo("成功", "样式导出成功")
else:
messagebox.showerror("错误", "导出样式失败")
def _import_style():
"""导入样式"""
file_path = filedialog.askopenfilename(
title="导入样式",
filetypes=[("JSON文件", "*.json"), ("所有文件", "*.*")]
)
if file_path:
style_name = style_manager.import_style(file_path)
if style_name:
style_combo['values'] = style_manager.get_style_names()
messagebox.showinfo("成功", f"样式 '{style_name}' 导入成功")
else:
messagebox.showerror("错误", "导入样式失败")
# 管理按钮
ttk.Button(button_frame, text='新建', command=_create_new_style).pack(side='left', padx=5)
ttk.Button(button_frame, text='复制', command=_duplicate_style).pack(side='left', padx=5)
ttk.Button(button_frame, text='高级编辑', command=_edit_style_advanced).pack(side='left', padx=5)
ttk.Button(button_frame, text='删除', command=_delete_style).pack(side='left', padx=5)
ttk.Button(button_frame, text='导出', command=_export_style).pack(side='left', padx=5)
ttk.Button(button_frame, text='导入', command=_import_style).pack(side='left', padx=5)
# 初始化信息显示
_update_style_info()
return style_frame
def _preview_style(style_name: str, parent):
"""预览样式"""
style = style_manager.get_style(style_name)
if not style:
return
preview_text = f"""样式预览: {style.name}
正文示例:
这是正文内容,使用 {style.body_font.name if style.body_font else '默认字体'} 字体,
大小为 {style.body_font.size if style.body_font else 12} 磅,
行距为 {style.body_paragraph.line_spacing if style.body_paragraph else 1.5} 倍。
# 一级标题示例
## 二级标题示例
### 三级标题示例
这是一个包含**粗体**和*斜体*的段落。
> 这是引用块的示例内容。
`这是行内代码`的示例。
- 无序列表项目1
- 无序列表项目2
1. 有序列表项目1
2. 有序列表项目2
"""
# 创建预览窗口
preview_window = tk.Toplevel(parent)
preview_window.title(f'样式预览 - {style_name}')
preview_window.geometry('500x400')
preview_window.transient(parent)
text_widget = tk.Text(preview_window, wrap=tk.WORD, padx=10, pady=10)
text_widget.pack(fill='both', expand=True, padx=10, pady=10)
text_widget.insert(1.0, preview_text)
text_widget.config(state='disabled')
ttk.Button(preview_window, text='关闭',
command=preview_window.destroy).pack(pady=10)
# 兼容性函数
def show_style_manager(parent=None):
"""显示样式管理器窗口"""
if parent is None:
root = tk.Tk()
root.withdraw()
parent = root
window = tk.Toplevel(parent)
window.title('样式管理器')
window.geometry('600x500')
window.transient(parent)
window.grab_set()
style_tab = create_style_tab(window)
style_tab.pack(fill='both', expand=True, padx=10, pady=10)
ttk.Button(window, text='关闭', command=window.destroy).pack(pady=10)