SXXXXXXX_MarkdownConverter/markdownconverter/gui/gui.py
2025-06-17 15:18:44 +02:00

198 lines
9.0 KiB
Python

# markdownconverter/gui/gui.py
import os
import sys
import logging
import subprocess
import tkinter as tk
import ttkbootstrap as tb
from tkinter.scrolledtext import ScrolledText
from ttkbootstrap.constants import *
from tkinter import filedialog, messagebox, StringVar, BooleanVar
from ..core.core import convert_markdown
from ..utils.config import save_configuration, load_configuration
from ..utils.logger import (
setup_basic_logging,
add_tkinter_handler,
shutdown_logging_system,
get_logger
)
from .editor import EditorWindow
log = get_logger(__name__)
def open_with_default_app(filepath):
if not filepath:
log.warning("Open file/folder requested, but no path was provided.")
messagebox.showwarning("Warning", "No output file or folder to open.")
return
try:
log.info(f"Opening '{filepath}' with default application.")
if sys.platform == "win32":
os.startfile(filepath)
elif sys.platform == "darwin":
subprocess.run(["open", filepath], check=True)
else:
subprocess.run(["xdg-open", filepath], check=True)
except Exception as e:
log.error(f"Failed to open '{filepath}': {e}", exc_info=True)
messagebox.showerror("Error", f"Could not open the file/folder:\n{str(e)}")
def open_output_folder(filepath):
if not filepath:
log.warning("Open folder requested, but no output file has been generated yet.")
messagebox.showwarning("Warning", "No output file has been generated yet.")
return
folder = os.path.dirname(filepath)
open_with_default_app(folder)
def run_app():
app = tb.Window(themename="sandstone")
app.title("Markdown Converter")
app.geometry("800x750")
app.resizable(True, True)
log_config = {
"default_root_level": logging.DEBUG,
"format": "%(asctime)s [%(levelname)-8s] %(name)-20s: %(message)s",
"date_format": "%H:%M:%S",
"enable_console": True, "enable_file": True,
"file_path": "markdown_converter.log",
"colors": {
logging.DEBUG: "gray", logging.INFO: "black", logging.WARNING: "orange",
logging.ERROR: "red", logging.CRITICAL: "purple",
},
}
setup_basic_logging(root_tk_instance_for_processor=app, logging_config_dict=log_config)
config = load_configuration()
metadata_config = config.get("metadata", {})
selected_file = StringVar(value=config.get("last_markdown_file", ""))
selected_template = StringVar(value=config.get("last_template_file", ""))
add_toc_var = BooleanVar(value=config.get("add_toc", True))
output_path = StringVar()
doc_security_var = StringVar(value=metadata_config.get("DOC_SECURITY", ""))
doc_number_var = StringVar(value=metadata_config.get("DOC_NUMBER", ""))
doc_rev_var = StringVar(value=metadata_config.get("DOC_REV", ""))
doc_project_var = StringVar(value=metadata_config.get("DOC_PROJECT", ""))
customer_var = StringVar(value=metadata_config.get("CUSTOMER", ""))
def open_editor():
file_path = selected_file.get()
if not file_path or not os.path.exists(file_path):
messagebox.showerror("Error", "Please select a valid Markdown file first.")
return
EditorWindow(parent=app, file_path=file_path)
def browse_markdown():
path = filedialog.askopenfilename(filetypes=[("Markdown files", "*.md"), ("All files", "*.*")])
if path:
selected_file.set(path)
def browse_template():
# --- CORREZIONE: Cerca prima i file .docx ---
path = filedialog.askopenfilename(
title="Select a Template Document",
filetypes=[("Word Documents", "*.docx"), ("All files", "*.*")]
)
if path:
selected_template.set(path)
def convert(fmt):
file_path = selected_file.get()
if not file_path:
messagebox.showerror("Error", "Please select a Markdown file.")
return
template = selected_template.get()
if fmt == "DOCX" and not template:
messagebox.showwarning("Warning", "A DOCX template is required.")
return
metadata_to_pass = {
'DOC_SECURITY': doc_security_var.get(),
'DOC_NUMBER': doc_number_var.get(),
'DOC_REV': doc_rev_var.get(),
'DOC_PROJECT': doc_project_var.get(),
'DOC_CUSTOMER': customer_var.get(),
}
try:
output = convert_markdown(
input_file=file_path, output_format=fmt, add_toc=add_toc_var.get(),
template_path=template, metadata=metadata_to_pass
)
output_path.set(output)
messagebox.showinfo("Success", f"File converted successfully:\n{output}")
save_configuration(
last_markdown=file_path, last_template=template,
add_toc=add_toc_var.get(), metadata=metadata_to_pass
)
except Exception as e:
log.critical(f"An error occurred during conversion: {e}", exc_info=True)
messagebox.showerror("Error", f"An error occurred during conversion:\n{str(e)}")
container = tb.Frame(app, padding=10)
container.pack(fill=tk.BOTH, expand=True)
top_frame = tb.Frame(container)
top_frame.pack(fill=tk.X, side=tk.TOP, pady=(0, 10))
tb.Label(top_frame, text="Markdown File:").grid(row=0, column=0, padx=(0, 10), pady=5, sticky="w")
tb.Entry(top_frame, textvariable=selected_file, width=70).grid(row=0, column=1, padx=5, sticky="ew")
file_button_frame = tb.Frame(top_frame)
file_button_frame.grid(row=0, column=2, sticky="w")
tb.Button(file_button_frame, text="Browse...", command=browse_markdown, bootstyle=PRIMARY).pack(side=tk.LEFT, padx=(0, 5))
tb.Button(file_button_frame, text="Edit...", command=open_editor, bootstyle=INFO).pack(side=tk.LEFT)
tb.Label(top_frame, text="Template File:").grid(row=1, column=0, padx=(0, 10), pady=5, sticky="w")
tb.Entry(top_frame, textvariable=selected_template, width=70).grid(row=1, column=1, padx=5, sticky="ew")
tb.Button(top_frame, text="Browse...", command=browse_template, bootstyle=SECONDARY).grid(row=1, column=2, padx=5)
metadata_frame = tb.Labelframe(top_frame, text="Template Placeholders", padding=10)
metadata_frame.grid(row=2, column=0, columnspan=3, padx=0, pady=10, sticky="ew")
tb.Label(metadata_frame, text="Document Number:").grid(row=0, column=0, padx=5, pady=3, sticky="w")
tb.Entry(metadata_frame, textvariable=doc_number_var).grid(row=0, column=1, padx=5, pady=3, sticky="ew")
tb.Label(metadata_frame, text="Revision:").grid(row=0, column=2, padx=(10, 5), pady=3, sticky="w")
tb.Entry(metadata_frame, textvariable=doc_rev_var).grid(row=0, column=3, padx=5, pady=3, sticky="ew")
tb.Label(metadata_frame, text="Project Name:").grid(row=1, column=0, padx=5, pady=3, sticky="w")
tb.Entry(metadata_frame, textvariable=doc_project_var).grid(row=1, column=1, padx=5, pady=3, sticky="ew")
tb.Label(metadata_frame, text="Customer:").grid(row=1, column=2, padx=(10, 5), pady=3, sticky="w")
tb.Entry(metadata_frame, textvariable=customer_var).grid(row=1, column=3, padx=5, pady=3, sticky="ew")
tb.Label(metadata_frame, text="Security Class:").grid(row=2, column=0, padx=5, pady=3, sticky="w")
tb.Entry(metadata_frame, textvariable=doc_security_var).grid(row=2, column=1, padx=5, pady=3, sticky="ew")
options_frame = tb.Frame(top_frame)
options_frame.grid(row=3, column=0, columnspan=3, pady=10, sticky="ew")
tb.Checkbutton(options_frame, text="Add Table of Contents", variable=add_toc_var, bootstyle="primary-round-toggle").pack(side=tk.LEFT, padx=(0, 20))
action_frame = tb.Frame(options_frame)
action_frame.pack(side=tk.LEFT)
tb.Button(action_frame, text="Convert to DOCX", command=lambda: convert("DOCX"), bootstyle=SUCCESS).pack(side=tk.LEFT, padx=5)
tb.Button(action_frame, text="Convert to PDF", command=lambda: convert("PDF"), bootstyle=SUCCESS).pack(side=tk.LEFT, padx=5)
tb.Button(action_frame, text="Open File", command=lambda: open_with_default_app(output_path.get()), bootstyle=WARNING).pack(side=tk.LEFT, padx=(20, 5))
tb.Button(action_frame, text="Open Folder", command=lambda: open_output_folder(output_path.get()), bootstyle=WARNING).pack(side=tk.LEFT, padx=5)
top_frame.columnconfigure(1, weight=1)
metadata_frame.columnconfigure(1, weight=1)
metadata_frame.columnconfigure(3, weight=1)
log_frame = tb.Labelframe(container, text="Log Viewer", padding=10)
log_frame.pack(fill=tk.BOTH, expand=True, side=tk.BOTTOM)
log_text_widget = ScrolledText(log_frame, wrap=tk.WORD, state=tk.DISABLED, height=10)
log_text_widget.pack(fill=tk.BOTH, expand=True)
add_tkinter_handler(gui_log_widget=log_text_widget, root_tk_instance_for_gui_handler=app, logging_config_dict=log_config)
def on_closing():
shutdown_logging_system()
app.destroy()
app.protocol("WM_DELETE_WINDOW", on_closing)
log.info("Application GUI initialized successfully.")
app.mainloop()