v0.5.6
This commit is contained in:
+114
-9
@@ -29,6 +29,7 @@ from .help_content import (
|
||||
load_docs_catalog,
|
||||
load_prompt_catalog,
|
||||
)
|
||||
from .office import DEFAULT_OFFICE_ENGINE, OFFICE_ENGINE_MODES
|
||||
from .pipeline import ConvertRequest, convert, default_output_path, timestamped_output_path
|
||||
from .profiles import (
|
||||
DEFAULT_HEADING_NUMBERING,
|
||||
@@ -64,6 +65,14 @@ TABLE_LABELS = {
|
||||
"legacy": "Резать + «Продолжение»",
|
||||
"caption": "Резать + разрыв страницы + «Продолжение»",
|
||||
}
|
||||
OFFICE_ENGINE_LABELS = {
|
||||
"auto": "Авто: Word → LibreOffice",
|
||||
"word": "Только Microsoft Word",
|
||||
"libre": "LibreOffice Writer (UNO)",
|
||||
}
|
||||
GUI_OFFICE_ENGINE_MODES = tuple(
|
||||
key for key in OFFICE_ENGINE_MODES if key != "openoffice"
|
||||
)
|
||||
FALLBACK_LABELS = {
|
||||
"remote": "Авто: локально, иначе интернет (kroki.io)",
|
||||
"local": "Только этот компьютер (без kroki.io)",
|
||||
@@ -245,6 +254,7 @@ class Md2GostApp:
|
||||
self.toc_var = tk.StringVar()
|
||||
self.table_var = tk.StringVar()
|
||||
self.listing_var = tk.StringVar()
|
||||
self.office_engine_var = tk.StringVar()
|
||||
self.emdash_var = tk.BooleanVar(value=False)
|
||||
self.hr_pagebreak_var = tk.BooleanVar(value=False)
|
||||
self.auto_title_var = tk.BooleanVar(value=False)
|
||||
@@ -1067,10 +1077,18 @@ class Md2GostApp:
|
||||
tip="off — Word сам переносит; word — Split + «Продолжение» после сборки (нужен Word)")
|
||||
self._combo(main, 4, "Продолжение листингов", self.listing_var, _combo_values(TABLE_LABELS, LISTING_CONTINUATION_MODES),
|
||||
tip="То же для листингов; word требует Windows + Word + pywin32")
|
||||
self._combo(
|
||||
main,
|
||||
5,
|
||||
"Движок пост-разрыва",
|
||||
self.office_engine_var,
|
||||
_combo_values(OFFICE_ENGINE_LABELS, GUI_OFFICE_ENGINE_MODES),
|
||||
tip="При режиме word: Word COM или LibreOffice UNO (soffice)",
|
||||
)
|
||||
|
||||
ttk.Label(main, text="Смещение страниц").grid(row=5, column=0, sticky="w", padx=(0, 8), pady=3)
|
||||
ttk.Label(main, text="Смещение страниц").grid(row=6, column=0, sticky="w", padx=(0, 8), pady=3)
|
||||
page_row = ttk.Frame(main)
|
||||
page_row.grid(row=5, column=1, sticky="w", pady=3)
|
||||
page_row.grid(row=6, column=1, sticky="w", pady=3)
|
||||
page_entry = ttk.Entry(page_row, textvariable=self.page_start_var, width=8)
|
||||
page_entry.pack(side=tk.LEFT)
|
||||
_tip(
|
||||
@@ -1085,7 +1103,7 @@ class Md2GostApp:
|
||||
).pack(side=tk.LEFT)
|
||||
|
||||
flags = ttk.Frame(main)
|
||||
flags.grid(row=6, column=0, columnspan=2, sticky="w", pady=(8, 0))
|
||||
flags.grid(row=7, column=0, columnspan=2, sticky="w", pady=(8, 0))
|
||||
checks = [
|
||||
("Заменять «—» на «-»", self.emdash_var, "Типографское тире → дефис (методичка обычно требует «—»)"),
|
||||
("--- → разрыв страницы", self.hr_pagebreak_var, "Строка --- станет page break в Word"),
|
||||
@@ -1139,17 +1157,41 @@ class Md2GostApp:
|
||||
|
||||
log_frame = ttk.LabelFrame(outer, text="Журнал", padding=4)
|
||||
log_frame.pack(fill=tk.BOTH, expand=True, pady=(0, 0))
|
||||
log_toolbar = ttk.Frame(log_frame)
|
||||
log_toolbar.pack(fill=tk.X, pady=(0, 4))
|
||||
ttk.Button(
|
||||
log_toolbar, text="Копировать выделение", command=self._log_copy_selection
|
||||
).pack(side=tk.LEFT)
|
||||
ttk.Button(
|
||||
log_toolbar, text="Копировать весь журнал", command=self._log_copy_all
|
||||
).pack(side=tk.LEFT, padx=(6, 0))
|
||||
log_body = ttk.Frame(log_frame)
|
||||
log_body.pack(fill=tk.BOTH, expand=True)
|
||||
self.log = tk.Text(
|
||||
log_frame, height=7, wrap=tk.WORD, relief=tk.FLAT,
|
||||
log_body, height=7, wrap=tk.WORD, relief=tk.FLAT,
|
||||
bg="#fffdf8", fg=INK, padx=8, pady=6,
|
||||
font=("Consolas", 9) if os.name == "nt" else ("monospace", 9),
|
||||
exportselection=True, undo=False,
|
||||
)
|
||||
scroll = ttk.Scrollbar(log_frame, command=self.log.yview)
|
||||
scroll = ttk.Scrollbar(log_body, command=self.log.yview)
|
||||
self.log.configure(yscrollcommand=scroll.set)
|
||||
self.log.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
|
||||
scroll.pack(side=tk.RIGHT, fill=tk.Y)
|
||||
self.log.insert("1.0", "Готово к работе. Перетащите .md (сборка DOCX) или .docx (импорт в Markdown).\n")
|
||||
self.log.configure(state=tk.DISABLED)
|
||||
self.log.insert(
|
||||
"1.0",
|
||||
"Готово к работе. Перетащите .md (сборка DOCX) или .docx (импорт в Markdown).\n",
|
||||
)
|
||||
self._log_menu = tk.Menu(self.root, tearoff=0)
|
||||
self._log_menu.add_command(
|
||||
label="Копировать", command=self._log_copy_selection
|
||||
)
|
||||
self._log_menu.add_command(
|
||||
label="Копировать весь журнал", command=self._log_copy_all
|
||||
)
|
||||
self.log.bind("<Button-3>", self._log_context_menu)
|
||||
self.log.bind("<Control-Button-1>", self._log_context_menu)
|
||||
self.log.bind("<Key>", self._log_keypress)
|
||||
self.log.bind("<<Copy>>", self._log_copy_event)
|
||||
|
||||
def _build_schemes_tab(self, parent) -> None:
|
||||
ttk.Label(
|
||||
@@ -1697,6 +1739,10 @@ class Md2GostApp:
|
||||
self.toc_var.set(_display(TOC_LABELS, req.toc_mode or DEFAULT_TOC_MODE))
|
||||
self.table_var.set(_display(TABLE_LABELS, req.table_continuation or DEFAULT_TABLE_CONTINUATION))
|
||||
self.listing_var.set(_display(TABLE_LABELS, req.listing_continuation or DEFAULT_LISTING_CONTINUATION))
|
||||
office_engine = req.office_engine or DEFAULT_OFFICE_ENGINE
|
||||
if office_engine not in GUI_OFFICE_ENGINE_MODES:
|
||||
office_engine = DEFAULT_OFFICE_ENGINE
|
||||
self.office_engine_var.set(_display(OFFICE_ENGINE_LABELS, office_engine))
|
||||
self.fallback_var.set(_display(FALLBACK_LABELS, req.diagram_fallback or "remote"))
|
||||
self.format_var.set(_display(FORMAT_LABELS, req.diagram_format or "png"))
|
||||
scale = getattr(req, "diagram_scale", 2.0) or 2.0
|
||||
@@ -1737,6 +1783,11 @@ class Md2GostApp:
|
||||
toc_mode=_combo_key(self.toc_var.get(), TOC_MODES, DEFAULT_TOC_MODE),
|
||||
table_continuation=_combo_key(self.table_var.get(), TABLE_CONTINUATION_MODES, DEFAULT_TABLE_CONTINUATION),
|
||||
listing_continuation=_combo_key(self.listing_var.get(), LISTING_CONTINUATION_MODES, DEFAULT_LISTING_CONTINUATION),
|
||||
office_engine=_combo_key(
|
||||
self.office_engine_var.get(),
|
||||
GUI_OFFICE_ENGINE_MODES,
|
||||
DEFAULT_OFFICE_ENGINE,
|
||||
),
|
||||
emdash_to_hyphen=self.emdash_var.get(),
|
||||
hr_pagebreak=self.hr_pagebreak_var.get(),
|
||||
auto_title=self.auto_title_var.get(),
|
||||
@@ -1860,17 +1911,71 @@ class Md2GostApp:
|
||||
self._append_log(result.message or "Ошибка")
|
||||
messagebox.showerror("md2gost", result.message or "Ошибка конвертации")
|
||||
|
||||
def _log_to_clipboard(self, text: str) -> None:
|
||||
self.root.clipboard_clear()
|
||||
self.root.clipboard_append(text)
|
||||
self.root.update_idletasks()
|
||||
|
||||
def _log_copy_selection(self) -> None:
|
||||
try:
|
||||
if not self.log.tag_ranges(tk.SEL):
|
||||
return
|
||||
text = self.log.get(tk.SEL_FIRST, tk.SEL_LAST)
|
||||
except tk.TclError:
|
||||
return
|
||||
if text:
|
||||
self._log_to_clipboard(text)
|
||||
|
||||
def _log_copy_all(self) -> None:
|
||||
text = self.log.get("1.0", tk.END).strip()
|
||||
if text:
|
||||
self._log_to_clipboard(text)
|
||||
|
||||
def _log_context_menu(self, event) -> str:
|
||||
try:
|
||||
self._log_menu.tk_popup(event.x_root, event.y_root)
|
||||
finally:
|
||||
self._log_menu.grab_release()
|
||||
return "break"
|
||||
|
||||
def _log_copy_event(self, _event=None) -> str | None:
|
||||
self._log_copy_selection()
|
||||
return "break"
|
||||
|
||||
def _log_keypress(self, event) -> str | None:
|
||||
"""Read-only log: allow selection/copy, block edits."""
|
||||
if event.state & 0x4:
|
||||
key = event.keysym.lower()
|
||||
if key == "c":
|
||||
self._log_copy_selection()
|
||||
return "break"
|
||||
if key == "a":
|
||||
self.log.tag_add(tk.SEL, "1.0", tk.END)
|
||||
self.log.mark_set(tk.INSERT, tk.END)
|
||||
self.log.see(tk.INSERT)
|
||||
return "break"
|
||||
if key == "insert":
|
||||
self._log_copy_selection()
|
||||
return "break"
|
||||
if event.keysym in (
|
||||
"Left", "Right", "Up", "Down", "Home", "End",
|
||||
"Prior", "Next", "Shift_L", "Shift_R", "Control_L", "Control_R",
|
||||
"Tab", "ISO_Left_Tab",
|
||||
):
|
||||
return None
|
||||
if not event.char:
|
||||
return None
|
||||
return "break"
|
||||
|
||||
def _append_log(self, text: str) -> None:
|
||||
if not text:
|
||||
return
|
||||
if not hasattr(self, "log"):
|
||||
return
|
||||
self.log.configure(state=tk.NORMAL)
|
||||
if not text.endswith("\n"):
|
||||
text += "\n"
|
||||
self.log.insert(tk.END, text)
|
||||
self.log.see(tk.END)
|
||||
self.log.configure(state=tk.DISABLED)
|
||||
|
||||
def run(self) -> None:
|
||||
self.root.mainloop()
|
||||
|
||||
Reference in New Issue
Block a user