Add Silo mode toggle, SSL cert browsing, and BOM menu integration
- Silo_ToggleMode: checkable toolbar button that swaps Ctrl+O/S/N between standard FreeCAD file commands and Silo equivalents - _swap_shortcuts() helper stores/restores original QAction shortcuts - SSL settings: add CA certificate file browser (SslCertPath preference) with QFileDialog for .pem/.crt/.cer, loaded in _get_ssl_context() - Integrate Silo_BOM into workbench toolbar (after upstream BOM merge) - Add Silo_ToggleMode to toolbar as first item with separator
This commit is contained in:
@@ -28,6 +28,8 @@ class SiloWorkbench(FreeCADGui.Workbench):
|
||||
import silo_commands
|
||||
|
||||
self.toolbar_commands = [
|
||||
"Silo_ToggleMode",
|
||||
"Separator",
|
||||
"Silo_Open",
|
||||
"Silo_New",
|
||||
"Silo_Save",
|
||||
|
||||
@@ -50,6 +50,16 @@ def _get_ssl_context() -> ssl.SSLContext:
|
||||
"""Build an SSL context based on the current SSL verification preference."""
|
||||
if _get_ssl_verify():
|
||||
ctx = ssl.create_default_context()
|
||||
# Load custom CA certificate if configured (for internal CAs)
|
||||
param = FreeCAD.ParamGet(_PREF_GROUP)
|
||||
custom_cert = param.GetString("SslCertPath", "")
|
||||
if custom_cert and os.path.isfile(custom_cert):
|
||||
try:
|
||||
ctx.load_verify_locations(custom_cert)
|
||||
except Exception as e:
|
||||
FreeCAD.Console.PrintWarning(
|
||||
f"Silo: Failed to load custom cert {custom_cert}: {e}\n"
|
||||
)
|
||||
# The bundled Python may not find the system CA store automatically
|
||||
# (its compiled-in path points to the build environment). Load the
|
||||
# system CA bundle explicitly so internal CAs (e.g. FreeIPA) are trusted.
|
||||
@@ -1970,12 +1980,51 @@ class Silo_Settings:
|
||||
ssl_hint.setStyleSheet("color: #888; font-size: 11px;")
|
||||
layout.addWidget(ssl_hint)
|
||||
|
||||
layout.addSpacing(5)
|
||||
|
||||
# Custom CA certificate
|
||||
cert_label = QtGui.QLabel("Custom CA certificate file:")
|
||||
layout.addWidget(cert_label)
|
||||
|
||||
cert_row = QtGui.QHBoxLayout()
|
||||
cert_input = QtGui.QLineEdit()
|
||||
cert_input.setPlaceholderText("(Use system CA certificates)")
|
||||
current_cert = param.GetString("SslCertPath", "")
|
||||
if current_cert:
|
||||
cert_input.setText(current_cert)
|
||||
cert_browse = QtGui.QPushButton("Browse...")
|
||||
cert_row.addWidget(cert_input)
|
||||
cert_row.addWidget(cert_browse)
|
||||
layout.addLayout(cert_row)
|
||||
|
||||
cert_hint = QtGui.QLabel(
|
||||
"Path to a PEM/CRT file for internal CAs. "
|
||||
"Leave empty for system certificates only."
|
||||
)
|
||||
cert_hint.setWordWrap(True)
|
||||
cert_hint.setStyleSheet("color: #888; font-size: 11px;")
|
||||
layout.addWidget(cert_hint)
|
||||
|
||||
def on_browse_cert():
|
||||
path, _ = QtGui.QFileDialog.getOpenFileName(
|
||||
dialog,
|
||||
"Select CA Certificate",
|
||||
os.path.dirname(cert_input.text()) or "/etc/ssl/certs",
|
||||
"Certificates (*.pem *.crt *.cer);;All Files (*)",
|
||||
)
|
||||
if path:
|
||||
cert_input.setText(path)
|
||||
|
||||
cert_browse.clicked.connect(on_browse_cert)
|
||||
|
||||
layout.addSpacing(10)
|
||||
|
||||
# Current effective values (read-only)
|
||||
cert_display = param.GetString("SslCertPath", "") or "(system defaults)"
|
||||
status_label = QtGui.QLabel(
|
||||
f"<b>Active URL:</b> {_get_api_url()}<br>"
|
||||
f"<b>SSL verification:</b> {'enabled' if _get_ssl_verify() else 'disabled'}"
|
||||
f"<b>SSL verification:</b> {'enabled' if _get_ssl_verify() else 'disabled'}<br>"
|
||||
f"<b>CA certificate:</b> {cert_display}"
|
||||
)
|
||||
status_label.setTextFormat(QtCore.Qt.RichText)
|
||||
layout.addWidget(status_label)
|
||||
@@ -1995,9 +2044,12 @@ class Silo_Settings:
|
||||
url = url_input.text().strip()
|
||||
param.SetString("ApiUrl", url)
|
||||
param.SetBool("SslVerify", ssl_checkbox.isChecked())
|
||||
cert_path = cert_input.text().strip()
|
||||
param.SetString("SslCertPath", cert_path)
|
||||
FreeCAD.Console.PrintMessage(
|
||||
f"Silo settings saved. URL: {_get_api_url()}, "
|
||||
f"SSL verify: {_get_ssl_verify()}\n"
|
||||
f"SSL verify: {_get_ssl_verify()}, "
|
||||
f"Cert: {cert_path or '(system)'}\n"
|
||||
)
|
||||
dialog.accept()
|
||||
|
||||
@@ -2383,6 +2435,85 @@ class Silo_BOM:
|
||||
return FreeCAD.ActiveDocument is not None
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Silo Mode toggle - swap Ctrl+O/S/N between standard and Silo commands
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# Stored original shortcuts so they can be restored on toggle-off
|
||||
_original_shortcuts: Dict[str, Any] = {}
|
||||
|
||||
|
||||
def _swap_shortcuts(mapping, enable_silo):
|
||||
"""Swap keyboard shortcuts between standard and Silo commands.
|
||||
|
||||
mapping: list of (std_cmd, silo_cmd, shortcut) tuples
|
||||
enable_silo: True to assign shortcuts to Silo commands, False to restore.
|
||||
"""
|
||||
from PySide import QtGui
|
||||
|
||||
mw = FreeCADGui.getMainWindow()
|
||||
if mw is None:
|
||||
return
|
||||
|
||||
for std_cmd, silo_cmd, shortcut in mapping:
|
||||
if enable_silo:
|
||||
# Save and clear the standard command's shortcut
|
||||
std_action = mw.findChild(QtGui.QAction, std_cmd)
|
||||
if std_action:
|
||||
_original_shortcuts[std_cmd] = std_action.shortcut().toString()
|
||||
std_action.setShortcut("")
|
||||
# Assign the shortcut to the Silo command
|
||||
silo_action = mw.findChild(QtGui.QAction, silo_cmd)
|
||||
if silo_action:
|
||||
silo_action.setShortcut(shortcut)
|
||||
else:
|
||||
# Clear the Silo command's shortcut
|
||||
silo_action = mw.findChild(QtGui.QAction, silo_cmd)
|
||||
if silo_action:
|
||||
silo_action.setShortcut("")
|
||||
# Restore the standard command's original shortcut
|
||||
std_action = mw.findChild(QtGui.QAction, std_cmd)
|
||||
if std_action and std_cmd in _original_shortcuts:
|
||||
std_action.setShortcut(_original_shortcuts.pop(std_cmd))
|
||||
|
||||
|
||||
_SHORTCUT_MAP = [
|
||||
("Std_Open", "Silo_Open", "Ctrl+O"),
|
||||
("Std_Save", "Silo_Save", "Ctrl+S"),
|
||||
("Std_New", "Silo_New", "Ctrl+N"),
|
||||
]
|
||||
|
||||
|
||||
class Silo_ToggleMode:
|
||||
"""Toggle between standard file operations and Silo equivalents."""
|
||||
|
||||
def GetResources(self):
|
||||
return {
|
||||
"MenuText": "Silo Mode",
|
||||
"ToolTip": (
|
||||
"Toggle between standard file operations and Silo equivalents.\n"
|
||||
"When ON: Ctrl+O/S/N use Silo Open/Save/New.\n"
|
||||
"When OFF: Standard FreeCAD file operations."
|
||||
),
|
||||
"Pixmap": _icon("silo"),
|
||||
"Checkable": True,
|
||||
}
|
||||
|
||||
def Activated(self, checked):
|
||||
param = FreeCAD.ParamGet(_PREF_GROUP)
|
||||
if checked:
|
||||
_swap_shortcuts(_SHORTCUT_MAP, enable_silo=True)
|
||||
param.SetBool("SiloMode", True)
|
||||
FreeCAD.Console.PrintMessage("Silo mode enabled\n")
|
||||
else:
|
||||
_swap_shortcuts(_SHORTCUT_MAP, enable_silo=False)
|
||||
param.SetBool("SiloMode", False)
|
||||
FreeCAD.Console.PrintMessage("Silo mode disabled\n")
|
||||
|
||||
def IsActive(self):
|
||||
return True
|
||||
|
||||
|
||||
# Register commands
|
||||
FreeCADGui.addCommand("Silo_Open", Silo_Open())
|
||||
FreeCADGui.addCommand("Silo_New", Silo_New())
|
||||
@@ -2396,3 +2527,4 @@ FreeCADGui.addCommand("Silo_TagProjects", Silo_TagProjects())
|
||||
FreeCADGui.addCommand("Silo_Rollback", Silo_Rollback())
|
||||
FreeCADGui.addCommand("Silo_SetStatus", Silo_SetStatus())
|
||||
FreeCADGui.addCommand("Silo_Settings", Silo_Settings())
|
||||
FreeCADGui.addCommand("Silo_ToggleMode", Silo_ToggleMode())
|
||||
|
||||
Reference in New Issue
Block a user