# 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()