Milestone ultima alpha
This commit is contained in:
118
main.py
118
main.py
@@ -15,29 +15,28 @@ import customtkinter as ctk
|
||||
from tkinter import messagebox
|
||||
|
||||
from async_loop_singleton import get_global_loop
|
||||
from async_msssql_query import AsyncMSSQLClient, make_mssql_dsn
|
||||
from async_msssql_query import AsyncMSSQLClient
|
||||
from audit_log import log_session_event
|
||||
from db_config import build_dsn_from_config, ensure_db_config
|
||||
from gestione_layout import open_layout_window
|
||||
from gestione_pickinglist import open_pickinglist_window
|
||||
from login_window import prompt_login
|
||||
from locale_text import load_locale_catalog, text as loc_text
|
||||
from reset_corsie import open_reset_corsie_window
|
||||
from search_pallets import open_search_window
|
||||
from tooltips import WidgetToolTip, load_tooltip_catalog, tooltip_text
|
||||
from ui_theme import theme_font, theme_section, theme_value
|
||||
from user_session import UserSession, create_user_session
|
||||
from view_celle_multi_udc import open_celle_multiple_window
|
||||
from window_placement import cascade_children_below_parent, place_window_fullsize_below_parent_later
|
||||
|
||||
|
||||
# ---- Config ----
|
||||
SERVER = r"mde3\gesterp"
|
||||
DBNAME = "Mediseawall"
|
||||
USER = "sa"
|
||||
PASSWORD = "1Password1"
|
||||
from window_placement import (
|
||||
cascade_children_below_parent,
|
||||
place_window_below_parent_later,
|
||||
place_window_fullsize_below_parent_later,
|
||||
)
|
||||
|
||||
# Development shortcut: skip the login dialog and boot directly as MAG1.
|
||||
# Set to False when you want to restore normal authentication.
|
||||
BYPASS_LOGIN = True
|
||||
BYPASS_LOGIN = False
|
||||
BYPASS_LOGIN_USER = {
|
||||
"operator_id": 4,
|
||||
"login": "MAG1",
|
||||
@@ -67,8 +66,7 @@ if not hasattr(tk.Toplevel, "block_update_dimensions_event"):
|
||||
if not hasattr(tk.Toplevel, "unblock_update_dimensions_event"):
|
||||
tk.Toplevel.unblock_update_dimensions_event = _noop # type: ignore[attr-defined]
|
||||
|
||||
dsn_app = make_mssql_dsn(server=SERVER, database=DBNAME, user=USER, password=PASSWORD)
|
||||
db_app = AsyncMSSQLClient(dsn_app)
|
||||
db_app: AsyncMSSQLClient | None = None
|
||||
_APP_MUTEX = None
|
||||
_APP_MUTEX_NAME = "Local\\WarehousePythonAppSingleton"
|
||||
|
||||
@@ -114,18 +112,22 @@ class Launcher(ctk.CTk):
|
||||
"pickinglist",
|
||||
]
|
||||
|
||||
def __init__(self, session: UserSession):
|
||||
def __init__(self, session: UserSession, db_client: AsyncMSSQLClient):
|
||||
"""Create the launcher toolbar and wire every button to a feature window."""
|
||||
super().__init__()
|
||||
self.session: UserSession = session
|
||||
self.db_client = db_client
|
||||
self._theme = theme_section("launcher", {})
|
||||
self._locale_catalog = load_locale_catalog()
|
||||
self._tooltip_catalog = load_tooltip_catalog()
|
||||
self._child_windows: list[tk.Misc] = []
|
||||
self._child_windows_by_key: dict[str, tk.Misc] = {}
|
||||
self._is_cascading = False
|
||||
self._focus_restore_pending: set[str] = set()
|
||||
self._restore_suppressed_until = 0.0
|
||||
self.title(f"Warehouse 1.0.0 - {self.session.display_name}")
|
||||
self.title(
|
||||
f"{loc_text('launcher.window_title', catalog=self._locale_catalog, default='Warehouse 1.0.0')} - {self.session.display_name}"
|
||||
)
|
||||
self._apply_dynamic_geometry()
|
||||
|
||||
outer_pady = int(theme_value(self._theme, "outer_pady", 10))
|
||||
@@ -142,58 +144,58 @@ class Launcher(ctk.CTk):
|
||||
actions = [
|
||||
(
|
||||
"reset_corsie",
|
||||
"Gestione Corsie",
|
||||
loc_text("launcher.reset_corsie", catalog=self._locale_catalog, default="Gestione Corsie"),
|
||||
"launcher.open_reset_corsie",
|
||||
lambda: self._open_child_window(
|
||||
"reset_corsie",
|
||||
open_reset_corsie_window(self, db_app, session=self.session),
|
||||
open_reset_corsie_window(self, self.db_client, session=self.session),
|
||||
),
|
||||
),
|
||||
(
|
||||
"layout",
|
||||
"Gestione Layout",
|
||||
loc_text("launcher.layout", catalog=self._locale_catalog, default="Gestione Layout"),
|
||||
"launcher.open_layout",
|
||||
lambda: self._open_child_window(
|
||||
"layout",
|
||||
open_layout_window(self, db_app, session=self.session),
|
||||
open_layout_window(self, self.db_client, session=self.session),
|
||||
),
|
||||
),
|
||||
(
|
||||
"multi_udc",
|
||||
"UDC Fantasma",
|
||||
loc_text("launcher.multi_udc", catalog=self._locale_catalog, default="UDC Fantasma"),
|
||||
"launcher.open_multi_udc",
|
||||
lambda: self._open_child_window(
|
||||
"multi_udc",
|
||||
open_celle_multiple_window(self, db_app, session=self.session),
|
||||
open_celle_multiple_window(self, self.db_client, session=self.session),
|
||||
),
|
||||
),
|
||||
(
|
||||
"search",
|
||||
"Ricerca UDC",
|
||||
loc_text("launcher.search", catalog=self._locale_catalog, default="Ricerca UDC"),
|
||||
"launcher.open_search",
|
||||
lambda: self._open_child_window(
|
||||
"search",
|
||||
open_search_window(self, db_app, session=self.session),
|
||||
open_search_window(self, self.db_client, session=self.session),
|
||||
),
|
||||
),
|
||||
(
|
||||
"pickinglist",
|
||||
"Gestione Picking List",
|
||||
loc_text("launcher.pickinglist", catalog=self._locale_catalog, default="Gestione Picking List"),
|
||||
"launcher.open_pickinglist",
|
||||
lambda: self._open_child_window(
|
||||
"pickinglist",
|
||||
open_pickinglist_window(self, db_app, session=self.session),
|
||||
open_pickinglist_window(self, self.db_client, session=self.session),
|
||||
),
|
||||
),
|
||||
(
|
||||
"arrange",
|
||||
"Ridisponi finestre",
|
||||
loc_text("launcher.arrange", catalog=self._locale_catalog, default="Ridisponi finestre"),
|
||||
"launcher.arrange_windows",
|
||||
self._cascade_open_windows,
|
||||
),
|
||||
(
|
||||
"exit",
|
||||
"Esci",
|
||||
loc_text("launcher.exit", catalog=self._locale_catalog, default="Esci"),
|
||||
"launcher.exit",
|
||||
self._shutdown,
|
||||
),
|
||||
@@ -203,7 +205,11 @@ class Launcher(ctk.CTk):
|
||||
|
||||
info = ctk.CTkLabel(
|
||||
wrap,
|
||||
text=f"Operatore: {self.session.display_name} ({self.session.login})",
|
||||
text=loc_text(
|
||||
"launcher.operator",
|
||||
catalog=self._locale_catalog,
|
||||
default="Operatore: {display_name} ({login})",
|
||||
).format(display_name=self.session.display_name, login=self.session.login),
|
||||
anchor="w",
|
||||
font=theme_font(self._theme, "info_font", default=("Segoe UI", 12, "bold")),
|
||||
)
|
||||
@@ -288,18 +294,6 @@ class Launcher(ctk.CTk):
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
window.bind(
|
||||
"<ButtonPress-1>",
|
||||
lambda event, win=window, win_key=key: self._on_child_activate(win_key, win, event.widget),
|
||||
add="+",
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
window.lift()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def _forget_child_window(self, key: str, window: tk.Misc, event_widget: tk.Misc | None = None) -> None:
|
||||
"""Remove stale references to child windows that have been closed."""
|
||||
@@ -344,7 +338,7 @@ class Launcher(ctk.CTk):
|
||||
return
|
||||
if time.monotonic() < self._restore_suppressed_until:
|
||||
return
|
||||
if not self._widget_belongs_to_window(window, event_widget):
|
||||
if event_widget is not None and event_widget is not window:
|
||||
return
|
||||
tracked = self._child_windows_by_key.get(key)
|
||||
if tracked is not window or not getattr(window, "winfo_exists", lambda: False)():
|
||||
@@ -357,7 +351,11 @@ class Launcher(ctk.CTk):
|
||||
try:
|
||||
tracked_now = self._child_windows_by_key.get(key)
|
||||
if tracked_now is window and getattr(window, "winfo_exists", lambda: False)():
|
||||
place_window_fullsize_below_parent_later(self, window)
|
||||
place_window_below_parent_later(self, window)
|
||||
try:
|
||||
window.lift()
|
||||
except Exception:
|
||||
pass
|
||||
finally:
|
||||
try:
|
||||
self.after(250, lambda: self._focus_restore_pending.discard(key))
|
||||
@@ -396,6 +394,7 @@ class Launcher(ctk.CTk):
|
||||
)
|
||||
def _finish_cascade() -> None:
|
||||
self._is_cascading = False
|
||||
self._restore_suppressed_until = 0.0
|
||||
try:
|
||||
self.lift()
|
||||
self.focus_force()
|
||||
@@ -412,11 +411,12 @@ class Launcher(ctk.CTk):
|
||||
try:
|
||||
if self.session is not None:
|
||||
log_session_event(self.session, action="logout", outcome="ok")
|
||||
fut = asyncio.run_coroutine_threadsafe(db_app.dispose(), _loop)
|
||||
try:
|
||||
fut.result(timeout=2)
|
||||
except Exception:
|
||||
pass
|
||||
if self.db_client is not None:
|
||||
fut = asyncio.run_coroutine_threadsafe(self.db_client.dispose(), _loop)
|
||||
try:
|
||||
fut.result(timeout=2)
|
||||
except Exception:
|
||||
pass
|
||||
finally:
|
||||
self.destroy()
|
||||
|
||||
@@ -428,8 +428,11 @@ if __name__ == "__main__":
|
||||
root = tk.Tk()
|
||||
root.withdraw()
|
||||
messagebox.showwarning(
|
||||
"Warehouse",
|
||||
"L'applicazione e' gia' in esecuzione.\nChiudi l'istanza aperta prima di avviarne un'altra.",
|
||||
loc_text("launcher.already_running_title", default="Warehouse"),
|
||||
loc_text(
|
||||
"launcher.already_running_message",
|
||||
default="L'applicazione e' gia' in esecuzione.\nChiudi l'istanza aperta prima di avviarne un'altra.",
|
||||
),
|
||||
parent=root,
|
||||
)
|
||||
try:
|
||||
@@ -438,6 +441,12 @@ if __name__ == "__main__":
|
||||
pass
|
||||
raise SystemExit(0)
|
||||
|
||||
db_cfg = ensure_db_config(_loop)
|
||||
if db_cfg is None:
|
||||
raise SystemExit(0)
|
||||
|
||||
db_app = AsyncMSSQLClient(build_dsn_from_config(db_cfg))
|
||||
|
||||
if BYPASS_LOGIN:
|
||||
session = _build_bypass_session()
|
||||
log_session_event(
|
||||
@@ -457,11 +466,12 @@ if __name__ == "__main__":
|
||||
session = prompt_login(bootstrap, db_app)
|
||||
|
||||
if session is None:
|
||||
fut = asyncio.run_coroutine_threadsafe(db_app.dispose(), _loop)
|
||||
try:
|
||||
fut.result(timeout=2)
|
||||
except Exception:
|
||||
pass
|
||||
if db_app is not None:
|
||||
fut = asyncio.run_coroutine_threadsafe(db_app.dispose(), _loop)
|
||||
try:
|
||||
fut.result(timeout=2)
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
if bootstrap is not None:
|
||||
bootstrap.destroy()
|
||||
@@ -475,4 +485,4 @@ if __name__ == "__main__":
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
Launcher(session).mainloop()
|
||||
Launcher(session, db_app).mainloop()
|
||||
|
||||
Reference in New Issue
Block a user