"""Preferences management for the Robust MCP Bridge workbench. SPDX-License-Identifier: MIT Copyright (c) 2025 Sean P. Kane (GitHub: spkane) This module handles reading and writing workbench preferences using FreeCAD's parameter system. NOTE: Using os.path instead of pathlib throughout this module due to FreeCAD's module loading behavior which can have issues with some Python features at load time. """ from __future__ import annotations from typing import TypedDict import FreeCAD class PreferencesDict(TypedDict): """Type definition for the preferences dictionary.""" auto_start: bool status_bar_enabled: bool xmlrpc_port: int socket_port: int # Parameter path for our workbench preferences PARAM_PATH = "User parameter:BaseApp/Preferences/Mod/RobustMCPBridge" # Default values DEFAULT_AUTO_START = False DEFAULT_STATUS_BAR_ENABLED = True DEFAULT_XMLRPC_PORT = 9875 DEFAULT_SOCKET_PORT = 9876 def get_param() -> FreeCAD.ParameterGrp: """Get the parameter group for our preferences.""" return FreeCAD.ParamGet(PARAM_PATH) def get_auto_start() -> bool: """Get whether the bridge should auto-start when FreeCAD launches. Returns: True if bridge should auto-start, False otherwise. Default: False """ return get_param().GetBool("AutoStart", DEFAULT_AUTO_START) def set_auto_start(enabled: bool) -> None: """Set whether the bridge should auto-start when FreeCAD launches. Args: enabled: True to enable auto-start, False to disable. """ get_param().SetBool("AutoStart", enabled) def get_status_bar_enabled() -> bool: """Get whether the status bar indicator is enabled. Returns: True if status bar indicator should be shown, False otherwise. Default: True """ return get_param().GetBool("StatusBarEnabled", DEFAULT_STATUS_BAR_ENABLED) def set_status_bar_enabled(enabled: bool) -> None: """Set whether the status bar indicator is enabled. Args: enabled: True to show status bar indicator, False to hide. """ get_param().SetBool("StatusBarEnabled", enabled) def get_xmlrpc_port() -> int: """Get the XML-RPC port number. Returns: Port number for XML-RPC server. Default: 9875 """ return get_param().GetInt("XMLRPCPort", DEFAULT_XMLRPC_PORT) def set_xmlrpc_port(port: int) -> None: """Set the XML-RPC port number. Args: port: Port number for XML-RPC server (1024-65535). Raises: ValueError: If port is out of valid range. """ if not 1024 <= port <= 65535: raise ValueError(f"Port must be between 1024 and 65535, got {port}") get_param().SetInt("XMLRPCPort", port) def get_socket_port() -> int: """Get the JSON-RPC socket port number. Returns: Port number for JSON-RPC socket server. Default: 9876 """ return get_param().GetInt("SocketPort", DEFAULT_SOCKET_PORT) def set_socket_port(port: int) -> None: """Set the JSON-RPC socket port number. Args: port: Port number for JSON-RPC socket server (1024-65535). Raises: ValueError: If port is out of valid range. """ if not 1024 <= port <= 65535: raise ValueError(f"Port must be between 1024 and 65535, got {port}") get_param().SetInt("SocketPort", port) def get_all_preferences() -> PreferencesDict: """Get all preferences as a dictionary. Returns: Dictionary with all preference values. """ return { "auto_start": get_auto_start(), "status_bar_enabled": get_status_bar_enabled(), "xmlrpc_port": get_xmlrpc_port(), "socket_port": get_socket_port(), } def reset_to_defaults() -> None: """Reset all preferences to their default values.""" set_auto_start(DEFAULT_AUTO_START) set_status_bar_enabled(DEFAULT_STATUS_BAR_ENABLED) set_xmlrpc_port(DEFAULT_XMLRPC_PORT) set_socket_port(DEFAULT_SOCKET_PORT)