185 lines
6.2 KiB
Python
185 lines
6.2 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()
|