SXXXXXXX_ProjectUtility/ProjectUtility.py
2025-04-29 10:09:19 +02:00

164 lines
6.0 KiB
Python

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