You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
659 lines
24 KiB
659 lines
24 KiB
#!/usr/bin/env python3
|
|
"""
|
|
vzug-e-hinge Main Application
|
|
==============================
|
|
Entry point for the integrated test and control system.
|
|
|
|
Integrates:
|
|
- Session management
|
|
- UART control
|
|
- I2C control
|
|
- UART Logger
|
|
- I2C Logger
|
|
- Graph visualization
|
|
- Test profile execution
|
|
|
|
Author: Kynsight
|
|
Version: 1.0.0
|
|
"""
|
|
|
|
import sys
|
|
import os
|
|
from pathlib import Path
|
|
|
|
# Force X11 backend for Qt (Wayland workaround)
|
|
# os.environ['QT_QPA_PLATFORM'] = 'xcb'
|
|
|
|
from PyQt6.QtWidgets import (
|
|
QApplication, QMainWindow, QTabWidget, QWidget, QVBoxLayout,
|
|
QHBoxLayout, QLabel, QMenuBar, QMenu, QMessageBox, QStatusBar
|
|
)
|
|
from PyQt6.QtCore import Qt, QTimer
|
|
from PyQt6.QtGui import QAction
|
|
|
|
# Import database
|
|
from database.init_database import DatabaseManager
|
|
|
|
# Import widgets (will be created next)
|
|
# from session_widget import SessionWidget
|
|
# from uart_widget import UARTWidget
|
|
# from uart_logger_widget import UARTLoggerWidget
|
|
# from i2c_widget import I2CWidget
|
|
# from i2c_logger_widget import I2CLoggerWidget
|
|
# from graph_widget import GraphWidget
|
|
|
|
# Import session manager (will be created next)
|
|
# from session_manager import SessionManager
|
|
|
|
|
|
class MainWindow(QMainWindow):
|
|
"""
|
|
Main application window with tabbed interface.
|
|
|
|
Tabs:
|
|
- Session: Control panel, command execution, profile management
|
|
- UART: Direct UART control
|
|
- UART Logger: UART logging interface
|
|
- I2C: Direct I2C control
|
|
- I2C Logger: I2C logging interface
|
|
- Graph: Data visualization
|
|
"""
|
|
|
|
def __init__(self, db_path: str = "./database/ehinge.db"):
|
|
super().__init__()
|
|
|
|
self.db_path = db_path
|
|
self.db_manager = None
|
|
|
|
# Initialize database
|
|
self._init_database()
|
|
|
|
# Setup UI
|
|
self._init_ui()
|
|
|
|
# Setup session manager
|
|
self._init_session_manager()
|
|
|
|
# Setup connections
|
|
self._setup_connections()
|
|
|
|
# Status update timer
|
|
self.status_timer = QTimer()
|
|
self.status_timer.timeout.connect(self._update_status)
|
|
self.status_timer.start(1000) # Update every second
|
|
|
|
def _init_database(self):
|
|
"""Initialize database connection."""
|
|
self.db_manager = DatabaseManager(self.db_path)
|
|
|
|
# Check if database exists
|
|
if not os.path.exists(self.db_path):
|
|
reply = QMessageBox.question(
|
|
self,
|
|
"Database Not Found",
|
|
f"Database not found at:\n{self.db_path}\n\nCreate new database?",
|
|
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
|
|
)
|
|
|
|
if reply == QMessageBox.StandardButton.Yes:
|
|
success = self.db_manager.initialize_database()
|
|
if not success:
|
|
QMessageBox.critical(
|
|
self,
|
|
"Database Error",
|
|
"Failed to create database. Application cannot continue."
|
|
)
|
|
sys.exit(1)
|
|
else:
|
|
sys.exit(0)
|
|
else:
|
|
# Connect to existing database
|
|
if not self.db_manager.connect():
|
|
QMessageBox.critical(
|
|
self,
|
|
"Database Error",
|
|
"Failed to connect to database. Application cannot continue."
|
|
)
|
|
sys.exit(1)
|
|
|
|
def _init_ui(self):
|
|
"""Initialize user interface."""
|
|
self.setWindowTitle("vzug-e-hinge Test & Control System")
|
|
self.setGeometry(100, 100, 1400, 900)
|
|
|
|
# Central widget with tabs
|
|
central_widget = QWidget()
|
|
self.setCentralWidget(central_widget)
|
|
|
|
layout = QVBoxLayout()
|
|
central_widget.setLayout(layout)
|
|
|
|
# Session info bar (shows current session)
|
|
self.session_info_bar = self._create_session_info_bar()
|
|
layout.addWidget(self.session_info_bar)
|
|
|
|
# Tab widget
|
|
self.tabs = QTabWidget()
|
|
layout.addWidget(self.tabs)
|
|
|
|
# Create placeholder tabs (will be replaced with actual widgets)
|
|
self._create_tabs()
|
|
|
|
# Connect tab change to refresh profiles
|
|
self.tabs.currentChanged.connect(self._on_tab_changed)
|
|
|
|
# Menu bar
|
|
self._create_menu_bar()
|
|
|
|
# Status bar
|
|
self.status_bar = QStatusBar()
|
|
self.setStatusBar(self.status_bar)
|
|
self.status_bar.showMessage("Ready")
|
|
|
|
def _create_session_info_bar(self) -> QWidget:
|
|
"""Create session information bar at top."""
|
|
widget = QWidget()
|
|
widget.setStyleSheet("background-color: #1e1e1e; padding: 5px;")
|
|
|
|
layout = QHBoxLayout()
|
|
widget.setLayout(layout)
|
|
|
|
# Session info
|
|
self.lbl_session_name = QLabel("Session: None")
|
|
self.lbl_session_name.setStyleSheet("color: #ffffff; font-weight: bold;")
|
|
layout.addWidget(self.lbl_session_name)
|
|
|
|
layout.addStretch()
|
|
|
|
# Status indicator
|
|
self.lbl_session_status = QLabel("Status: Idle")
|
|
self.lbl_session_status.setStyleSheet("color: #00ff00;")
|
|
layout.addWidget(self.lbl_session_status)
|
|
|
|
# Run counter
|
|
self.lbl_run_count = QLabel("Runs: 0")
|
|
self.lbl_run_count.setStyleSheet("color: #ffffff;")
|
|
layout.addWidget(self.lbl_run_count)
|
|
|
|
# Database size
|
|
self.lbl_db_size = QLabel("DB: 0%")
|
|
self.lbl_db_size.setStyleSheet("color: #00ff00;")
|
|
layout.addWidget(self.lbl_db_size)
|
|
|
|
return widget
|
|
|
|
def _create_tabs(self):
|
|
"""Create tab widgets."""
|
|
# Tab 1: Session Control (integrate SessionWidget)
|
|
try:
|
|
from session_widget import SessionWidget
|
|
self.session_widget = SessionWidget(self.db_manager)
|
|
self.tabs.addTab(self.session_widget, "Session")
|
|
except ImportError as e:
|
|
# Fallback to placeholder if SessionWidget not available
|
|
print(f"Warning: SessionWidget not available: {e}")
|
|
self.tab_session = self._create_placeholder_tab("Session Control")
|
|
self.tabs.addTab(self.tab_session, "Session")
|
|
self.session_widget = None
|
|
|
|
# Tab 2: Configure Session Profiles
|
|
try:
|
|
from configure_session_widget import ConfigureSessionWidget
|
|
self.configure_session_widget = ConfigureSessionWidget(self.db_manager)
|
|
self.tabs.addTab(self.configure_session_widget, "Configure Session")
|
|
except ImportError as e:
|
|
print(f"Warning: ConfigureSessionWidget not available: {e}")
|
|
self.tab_configure_session = self._create_placeholder_tab("Configure Session")
|
|
self.tabs.addTab(self.tab_configure_session, "Configure Session")
|
|
self.configure_session_widget = None
|
|
|
|
# Tab 3: Configure Interface Profiles
|
|
try:
|
|
from configure_interface_widget import ConfigureInterfaceWidget
|
|
self.configure_interface_widget = ConfigureInterfaceWidget(self.db_manager)
|
|
self.tabs.addTab(self.configure_interface_widget, "Configure Interface")
|
|
except ImportError as e:
|
|
print(f"Warning: ConfigureInterfaceWidget not available: {e}")
|
|
self.tab_configure_interface = self._create_placeholder_tab("Configure Interface")
|
|
self.tabs.addTab(self.tab_configure_interface, "Configure Interface")
|
|
self.configure_interface_widget = None
|
|
|
|
# Tab 4: UART (integrated: table + core)
|
|
try:
|
|
from uart.uart_integrated_widget import UARTControlWidget
|
|
self.uart_widget = UARTControlWidget(self.db_manager.get_connection())
|
|
self.tabs.addTab(self.uart_widget, "UART")
|
|
except ImportError as e:
|
|
print(f"UART widget import error: {e}")
|
|
self.tab_uart = self._create_placeholder_tab("UART Control")
|
|
self.tabs.addTab(self.tab_uart, "UART")
|
|
self.uart_widget = None
|
|
|
|
|
|
# Tab 5: I2C (integrated: table + core)
|
|
try:
|
|
from i2c.i2c_integrated_widget import I2CControlWidget
|
|
self.i2c_widget = I2CControlWidget(self.db_manager.get_connection())
|
|
self.tabs.addTab(self.i2c_widget, "I2C")
|
|
except ImportError as e:
|
|
print(f"I2C widget import error: {e}")
|
|
self.tab_i2c = self._create_placeholder_tab("I2C Control")
|
|
self.tabs.addTab(self.tab_i2c, "I2C")
|
|
self.i2c_widget = None
|
|
|
|
# Tab 6: Graph
|
|
self.tab_graph = self._create_placeholder_tab("Graph Visualization")
|
|
self.tabs.addTab(self.tab_graph, "Graph")
|
|
|
|
def _create_placeholder_tab(self, title: str) -> QWidget:
|
|
"""Create placeholder tab widget."""
|
|
widget = QWidget()
|
|
layout = QVBoxLayout()
|
|
widget.setLayout(layout)
|
|
|
|
label = QLabel(f"{title}\n\n(Coming soon...)")
|
|
label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
|
label.setStyleSheet("font-size: 16pt; color: #888888;")
|
|
layout.addWidget(label)
|
|
|
|
return widget
|
|
|
|
def _create_menu_bar(self):
|
|
"""Create menu bar."""
|
|
menubar = self.menuBar()
|
|
|
|
# File menu
|
|
file_menu = menubar.addMenu("&File")
|
|
|
|
action_new_session = QAction("&New Session", self)
|
|
action_new_session.setShortcut("Ctrl+N")
|
|
action_new_session.triggered.connect(self._on_new_session)
|
|
file_menu.addAction(action_new_session)
|
|
|
|
action_end_session = QAction("&End Session", self)
|
|
action_end_session.setShortcut("Ctrl+E")
|
|
action_end_session.triggered.connect(self._on_end_session)
|
|
file_menu.addAction(action_end_session)
|
|
|
|
file_menu.addSeparator()
|
|
|
|
action_export_session = QAction("E&xport Session...", self)
|
|
action_export_session.triggered.connect(self._on_export_session)
|
|
file_menu.addAction(action_export_session)
|
|
|
|
file_menu.addSeparator()
|
|
|
|
action_exit = QAction("E&xit", self)
|
|
action_exit.setShortcut("Ctrl+Q")
|
|
action_exit.triggered.connect(self.close)
|
|
file_menu.addAction(action_exit)
|
|
|
|
# Config menu
|
|
config_menu = menubar.addMenu("&Config")
|
|
|
|
action_uart_config = QAction("&UART Configuration...", self)
|
|
action_uart_config.triggered.connect(self._on_uart_config)
|
|
config_menu.addAction(action_uart_config)
|
|
|
|
action_i2c_config = QAction("&I2C Configuration...", self)
|
|
action_i2c_config.triggered.connect(self._on_i2c_config)
|
|
config_menu.addAction(action_i2c_config)
|
|
|
|
action_debugger_config = QAction("&Debugger Configuration...", self)
|
|
action_debugger_config.triggered.connect(self._on_debugger_config)
|
|
config_menu.addAction(action_debugger_config)
|
|
|
|
config_menu.addSeparator()
|
|
|
|
action_gui_profile = QAction("&GUI Profile...", self)
|
|
action_gui_profile.triggered.connect(self._on_gui_profile)
|
|
config_menu.addAction(action_gui_profile)
|
|
|
|
# Profiles menu
|
|
profiles_menu = menubar.addMenu("&Profiles")
|
|
|
|
action_manage_profiles = QAction("&Manage Test Profiles...", self)
|
|
action_manage_profiles.triggered.connect(self._on_manage_profiles)
|
|
profiles_menu.addAction(action_manage_profiles)
|
|
|
|
action_new_profile = QAction("&New Profile...", self)
|
|
action_new_profile.triggered.connect(self._on_new_profile)
|
|
profiles_menu.addAction(action_new_profile)
|
|
|
|
# Database menu
|
|
database_menu = menubar.addMenu("&Database")
|
|
|
|
action_vacuum = QAction("&Vacuum Database", self)
|
|
action_vacuum.triggered.connect(self._on_vacuum_database)
|
|
database_menu.addAction(action_vacuum)
|
|
|
|
action_db_info = QAction("Database &Info...", self)
|
|
action_db_info.triggered.connect(self._on_database_info)
|
|
database_menu.addAction(action_db_info)
|
|
|
|
database_menu.addSeparator()
|
|
|
|
action_cleanup = QAction("&Cleanup Old Data...", self)
|
|
action_cleanup.triggered.connect(self._on_cleanup_data)
|
|
database_menu.addAction(action_cleanup)
|
|
|
|
# Help menu
|
|
help_menu = menubar.addMenu("&Help")
|
|
|
|
action_about = QAction("&About", self)
|
|
action_about.triggered.connect(self._on_about)
|
|
help_menu.addAction(action_about)
|
|
|
|
action_docs = QAction("&Documentation", self)
|
|
action_docs.triggered.connect(self._on_documentation)
|
|
help_menu.addAction(action_docs)
|
|
|
|
def _init_session_manager(self):
|
|
"""Initialize session manager (coordination logic)."""
|
|
# NOTE: Session management is now integrated into SessionWidget
|
|
# The Session class is instantiated by SessionWidget internally
|
|
# No need for separate SessionManager anymore
|
|
self.session_manager = None
|
|
|
|
def _setup_connections(self):
|
|
"""Setup signal/slot connections between components."""
|
|
# NOTE: Session management is now self-contained in SessionWidget
|
|
# All signals/slots are handled internally by the widget
|
|
# Main window just needs to monitor session state if desired
|
|
|
|
if self.session_widget:
|
|
# Connect to session widget's session object signals for monitoring
|
|
try:
|
|
self.session_widget.session.session_started.connect(self._on_session_started_internal)
|
|
self.session_widget.session.session_finished.connect(self._on_session_finished_internal)
|
|
self.session_widget.session.status_changed.connect(self._on_session_status_changed_internal)
|
|
except Exception as e:
|
|
print(f"Warning: Could not connect to session signals: {e}")
|
|
|
|
# Connect UART widget TX/RX to Session widget's data monitor
|
|
if hasattr(self, 'uart_widget') and self.uart_widget and self.session_widget:
|
|
try:
|
|
# Connect TX signal (bytes) → convert to hex string → display
|
|
self.uart_widget.uart_core.data_sent.connect(
|
|
lambda data: self.session_widget._on_raw_data_received("TX", data.hex(' ').upper())
|
|
)
|
|
# Connect RX signal (bytes, info) → convert to hex string → display
|
|
self.uart_widget.uart_core.data_received_display.connect(
|
|
lambda data, info: self.session_widget._on_raw_data_received("RX", data.hex(' ').upper())
|
|
)
|
|
print("[Main] Connected UART widget TX/RX to Session data monitor")
|
|
except Exception as e:
|
|
print(f"Warning: Could not connect UART signals to data monitor: {e}")
|
|
|
|
# =========================================================================
|
|
# Signal Handlers - Session Widget Actions
|
|
# =========================================================================
|
|
|
|
# =========================================================================
|
|
# OLD Signal Handlers - NO LONGER USED (kept for reference)
|
|
# Session management is now self-contained in SessionWidget
|
|
# =========================================================================
|
|
|
|
# def _on_execute_command_requested(self, command_type: str, command_id: int):
|
|
# """Handle execute command request from session widget."""
|
|
# # NO LONGER USED
|
|
# pass
|
|
|
|
# def _on_execute_profile_requested(self, profile_id: int):
|
|
# """Handle execute profile request from session widget."""
|
|
# # NO LONGER USED
|
|
# pass
|
|
|
|
# def _on_pause_profile_requested(self):
|
|
# """Handle pause profile request."""
|
|
# # NO LONGER USED
|
|
# pass
|
|
|
|
# def _on_resume_profile_requested(self):
|
|
# """Handle resume profile request."""
|
|
# # NO LONGER USED
|
|
# pass
|
|
|
|
# def _on_abort_profile_requested(self):
|
|
# """Handle abort profile request."""
|
|
# # NO LONGER USED
|
|
# pass
|
|
|
|
# def _on_session_created(self, session_id: str):
|
|
# """Handle session created."""
|
|
# # NO LONGER USED
|
|
# pass
|
|
|
|
# def _on_session_ended(self, session_id: str, status: str):
|
|
# """Handle session ended."""
|
|
# # NO LONGER USED
|
|
# pass
|
|
self.lbl_session_status.setText("Status: Idle")
|
|
self.lbl_session_status.setStyleSheet("color: #888888;")
|
|
|
|
# def _on_run_started(self, session_id: str, run_no: int):
|
|
# """Handle run started."""
|
|
# # NO LONGER USED
|
|
# pass
|
|
|
|
# def _on_run_completed(self, session_id: str, run_no: int, status: str):
|
|
# """Handle run completed."""
|
|
# # NO LONGER USED
|
|
# pass
|
|
|
|
# def _on_profile_step_changed(self, current_repeat: int, current_step: int):
|
|
# """Handle profile step changed."""
|
|
# # NO LONGER USED
|
|
# pass
|
|
|
|
# =========================================================================
|
|
# Internal Session Monitoring (from new Session class)
|
|
# =========================================================================
|
|
|
|
def _on_session_started_internal(self, session_id: str):
|
|
"""Handle session started (internal monitoring)."""
|
|
if self.session_widget:
|
|
session_name = self.session_widget.session.get_session_name()
|
|
self.lbl_session_name.setText(f"Session: {session_name}")
|
|
self.lbl_session_status.setText("Status: Running")
|
|
self.lbl_session_status.setStyleSheet("color: #00ff00;")
|
|
self.status_bar.showMessage(f"Session started: {session_id}")
|
|
|
|
def _on_session_finished_internal(self):
|
|
"""Handle session finished (internal monitoring)."""
|
|
self.lbl_session_status.setText("Status: Finished")
|
|
self.lbl_session_status.setStyleSheet("color: #00ff00;")
|
|
self.status_bar.showMessage("Session completed successfully")
|
|
|
|
def _on_session_status_changed_internal(self, status_text: str):
|
|
"""Handle session status changes (internal monitoring)."""
|
|
# Update status bar with session status
|
|
self.status_bar.showMessage(status_text)
|
|
|
|
def _update_status(self):
|
|
"""Update status bar and session info (called every second)."""
|
|
# Update database size
|
|
try:
|
|
size_bytes, percentage, status = self.db_manager.check_size()
|
|
|
|
color = "#00ff00" # Green
|
|
if status == "warning":
|
|
color = "#ffaa00" # Orange
|
|
elif status == "critical":
|
|
color = "#ff0000" # Red
|
|
|
|
self.lbl_db_size.setText(f"DB: {percentage:.1f}%")
|
|
self.lbl_db_size.setStyleSheet(f"color: {color};")
|
|
except:
|
|
pass
|
|
|
|
# Update run count from session widget
|
|
if self.session_widget and self.session_widget.session:
|
|
try:
|
|
# Get current session from widget
|
|
session_id = self.session_widget.session.get_current_session_id()
|
|
if session_id:
|
|
# Query database for run count
|
|
cursor = self.db_manager.get_connection().execute("""
|
|
SELECT total_runs FROM sessions WHERE session_id = ?
|
|
""", (session_id,))
|
|
row = cursor.fetchone()
|
|
if row:
|
|
self.lbl_run_count.setText(f"Runs: {row[0]}")
|
|
except:
|
|
pass
|
|
|
|
# =========================================================================
|
|
# Menu Actions
|
|
# =========================================================================
|
|
|
|
def _on_new_session(self):
|
|
"""Start new session."""
|
|
# TODO: Implement
|
|
QMessageBox.information(self, "New Session", "New session dialog (coming soon)")
|
|
|
|
def _on_end_session(self):
|
|
"""End current session."""
|
|
# TODO: Implement
|
|
QMessageBox.information(self, "End Session", "End session (coming soon)")
|
|
|
|
def _on_export_session(self):
|
|
"""Export session data."""
|
|
# TODO: Implement
|
|
QMessageBox.information(self, "Export", "Export session (coming soon)")
|
|
|
|
def _on_uart_config(self):
|
|
"""Configure UART."""
|
|
# TODO: Implement
|
|
QMessageBox.information(self, "UART Config", "UART configuration dialog (coming soon)")
|
|
|
|
def _on_i2c_config(self):
|
|
"""Configure I2C."""
|
|
# TODO: Implement
|
|
QMessageBox.information(self, "I2C Config", "I2C configuration dialog (coming soon)")
|
|
|
|
def _on_debugger_config(self):
|
|
"""Configure debugger."""
|
|
# TODO: Implement
|
|
QMessageBox.information(self, "Debugger Config", "Debugger configuration dialog (coming soon)")
|
|
|
|
def _on_gui_profile(self):
|
|
"""Manage GUI profile."""
|
|
# TODO: Implement
|
|
QMessageBox.information(self, "GUI Profile", "GUI profile settings (coming soon)")
|
|
|
|
def _on_manage_profiles(self):
|
|
"""Manage test profiles."""
|
|
# TODO: Implement
|
|
QMessageBox.information(self, "Manage Profiles", "Test profile manager (coming soon)")
|
|
|
|
def _on_new_profile(self):
|
|
"""Create new test profile."""
|
|
# TODO: Implement
|
|
QMessageBox.information(self, "New Profile", "Create test profile (coming soon)")
|
|
|
|
def _on_vacuum_database(self):
|
|
"""Vacuum database."""
|
|
reply = QMessageBox.question(
|
|
self,
|
|
"Vacuum Database",
|
|
"Vacuum database to reclaim space?\n\nThis may take a few seconds.",
|
|
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
|
|
)
|
|
|
|
if reply == QMessageBox.StandardButton.Yes:
|
|
self.db_manager.vacuum()
|
|
QMessageBox.information(self, "Success", "Database vacuumed successfully!")
|
|
|
|
def _on_database_info(self):
|
|
"""Show database information."""
|
|
size_bytes, percentage, status = self.db_manager.check_size()
|
|
info = self.db_manager.get_table_info()
|
|
|
|
msg = f"Database: {self.db_path}\n\n"
|
|
msg += f"Size: {self.db_manager.format_size(size_bytes)} ({percentage:.1f}% of 2 GB)\n"
|
|
msg += f"Status: {status}\n\n"
|
|
msg += "Table Row Counts:\n"
|
|
|
|
for table, count in info.items():
|
|
msg += f" {table}: {count}\n"
|
|
|
|
QMessageBox.information(self, "Database Info", msg)
|
|
|
|
def _on_cleanup_data(self):
|
|
"""Cleanup old data."""
|
|
# TODO: Implement
|
|
QMessageBox.information(self, "Cleanup", "Data cleanup dialog (coming soon)")
|
|
|
|
def _on_about(self):
|
|
"""Show about dialog."""
|
|
msg = "vzug-e-hinge Test & Control System\n\n"
|
|
msg += "Version 1.0.0\n\n"
|
|
msg += "Integrated test and control system for e-hinge devices.\n\n"
|
|
msg += "Author: Kynsight\n"
|
|
msg += "© 2025"
|
|
|
|
QMessageBox.about(self, "About", msg)
|
|
|
|
def _on_documentation(self):
|
|
"""Show documentation."""
|
|
# TODO: Open documentation
|
|
QMessageBox.information(self, "Documentation", "Documentation (coming soon)")
|
|
|
|
def _on_tab_changed(self, index: int):
|
|
"""
|
|
Handle tab change event.
|
|
Refresh profiles when Session tab becomes active.
|
|
|
|
Args:
|
|
index: Index of newly selected tab
|
|
"""
|
|
# Check if Session tab (index 0) is now active
|
|
if index == 0 and hasattr(self, 'session_widget') and self.session_widget:
|
|
self.session_widget.refresh_profiles()
|
|
|
|
def closeEvent(self, event):
|
|
"""Handle application close."""
|
|
reply = QMessageBox.question(
|
|
self,
|
|
"Exit",
|
|
"Are you sure you want to exit?",
|
|
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
|
|
)
|
|
|
|
if reply == QMessageBox.StandardButton.Yes:
|
|
# Close database
|
|
if self.db_manager:
|
|
self.db_manager.close()
|
|
event.accept()
|
|
else:
|
|
event.ignore()
|
|
|
|
|
|
def main():
|
|
"""Main entry point."""
|
|
# Parse command line arguments
|
|
db_path = "./database/ehinge.db"
|
|
|
|
if len(sys.argv) > 1:
|
|
db_path = sys.argv[1]
|
|
|
|
# Create application
|
|
app = QApplication(sys.argv)
|
|
|
|
# Set application metadata
|
|
app.setApplicationName("vzug-e-hinge")
|
|
app.setOrganizationName("Kynsight")
|
|
app.setOrganizationDomain("kynsight.com")
|
|
|
|
# Create main window
|
|
window = MainWindow(db_path)
|
|
window.show()
|
|
|
|
# Run application
|
|
sys.exit(app.exec())
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|