# ProjectUtility/ProjectUtility.py import sys import os import logging import argparse import tkinter as tk from tkinter import messagebox # Importa la finestra principale (che creeremo tra poco) # Assumendo che sia in gui/main_window.py project_root = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, project_root) # Tentativo di importare le classi necessarie try: from gui.main_window import MainWindow except ImportError as e: print(f"Error importing GUI components: {e}") print("Make sure the directory structure is correct.") try: root = tk.Tk() root.withdraw() messagebox.showerror( "Startup Error", f"Error importing GUI components:\n{e}\n\nPlease check the project structure.", ) root.destroy() except tk.TclError: pass sys.exit(1) except tk.TclError as e: print(f"Error initializing Tkinter: {e}") print("Tkinter might not be installed correctly or a display might be unavailable.") sys.exit(1) # --- Constants --- LOGS_DIR = os.path.join(project_root, "logs") DEFAULT_LOG_FILE = os.path.join(LOGS_DIR, "project_utility.log") DEFAULT_LOG_LEVEL = logging.INFO # --- Logging Setup --- def setup_logging( log_level: int = DEFAULT_LOG_LEVEL, log_file: str = DEFAULT_LOG_FILE ) -> None: """ Configures the application's logging. Args: log_level: The minimum logging level (e.g., logging.INFO). log_file: The path to the log file. """ # Ensure log directory exists os.makedirs(os.path.dirname(log_file), exist_ok=True) # Changed comment for clarity log_format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s" logging.basicConfig( level=log_level, format=log_format, handlers=[ logging.FileHandler(log_file, mode="a"), logging.StreamHandler(sys.stdout), ], ) logging.info("Logging configured successfully.") logging.info(f"Log level set to: {logging.getLevelName(log_level)}") logging.info(f"Log file location: {log_file}") # --- Argument Parsing --- def parse_arguments() -> argparse.Namespace: """ Parses command-line arguments. Returns: An object containing the parsed arguments. """ parser = argparse.ArgumentParser( description="Project Utility - A dashboard for project management tools." ) parser.add_argument( "--log-level", type=str, choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"], default=logging.getLevelName(DEFAULT_LOG_LEVEL), help=f"Set the logging level (default: {logging.getLevelName(DEFAULT_LOG_LEVEL)})", ) parser.add_argument( "--log-file", type=str, default=DEFAULT_LOG_FILE, help=f"Specify the log file path (default: {DEFAULT_LOG_FILE})", ) return parser.parse_args() # --- Main Execution --- def main() -> None: """ Main function to initialize and run the application using Tkinter. """ args = parse_arguments() log_level_int = getattr(logging, args.log_level.upper(), DEFAULT_LOG_LEVEL) setup_logging(log_level=log_level_int, log_file=args.log_file) logging.info("Starting ProjectUtility application...") root = None # Initialize root to None for robust error handling try: # Create the main Tkinter window (root) root = tk.Tk() root.withdraw() # Hide the main window temporarily # Create and setup the main application window # MainWindow is responsible for calling root.deiconify() when ready main_app = MainWindow(root) logging.info("Main window initialized.") except Exception as e: logging.exception("Failed to create the main window.") # Use messagebox if Tkinter initialization was at least partially successful try: # Create temporary hidden root if 'root' creation failed earlier # or if messagebox is needed before main root is usable. temp_root = tk.Tk() temp_root.withdraw() messagebox.showerror( "Fatal Error", f"Could not initialize the main application window:\n{e}" ) temp_root.destroy() except tk.TclError: # Fallback if messagebox cannot be shown print( f"CRITICAL ERROR: Could not initialize the main application window: {e}" ) # Attempt to destroy the main root if it was created before the exception if root: try: if root.winfo_exists(): # Check before destroying in error case root.destroy() except tk.TclError: logging.warning( "TclError attempting to destroy root after initialization failure." ) sys.exit(1) # Start the Tkinter event loop logging.info("Starting Tkinter event loop.") try: root.mainloop() except KeyboardInterrupt: logging.info("Application interrupted by user (KeyboardInterrupt).") # If interrupted, the window might still exist, try closing it gracefully if root and root.winfo_exists(): # Trigger the normal close procedure if possible try: main_app._on_close() # Attempt to call the app's close handler except tk.TclError: logging.warning( "TclError calling _on_close during KeyboardInterrupt, forcing destroy." ) root.destroy() # Force destroy if _on_close failed or wasn't fully initialized except AttributeError: # If main_app wasn't fully initialized logging.warning( "main_app not fully initialized during KeyboardInterrupt, forcing destroy." ) root.destroy() finally: # The main window destruction is handled by MainWindow._on_close() # No need to call root.destroy() here again. # Removing the previous block: # if root and root.winfo_exists(): # root.destroy() logging.debug("Mainloop finished.") logging.info("Application finished.") sys.exit(0) if __name__ == "__main__": main()