All checks were successful
Build and Test / build (pull_request) Successful in 29m13s
Add SiloManifestViewer widget that opens in an MDI subwindow when the user double-clicks the Manifest node in the Silo tree. Displays all manifest.json fields in a read-only QFormLayout with copy buttons for Part UUID and Silo Instance. New files: - silo_viewers.py: SiloManifestViewer widget + create_viewer_widget() factory with _VIEWER_REGISTRY for future viewer classes Modified files: - silo_viewproviders.py: doubleClicked() wired to open MDI subwindow with deduplication via widget objectName() - CMakeLists.txt: add silo_viewers.py to install list Closes #38
114 lines
3.3 KiB
Python
114 lines
3.3 KiB
Python
"""
|
|
silo_viewproviders.py - ViewProvider proxy for Silo tree leaf nodes.
|
|
|
|
Controls tree icon, double-click behavior, and context menu for
|
|
SiloViewerObject nodes in the document tree.
|
|
"""
|
|
|
|
import os
|
|
|
|
# Icon directory — Phase 6 will add SVGs here.
|
|
_ICON_DIR = os.path.join(
|
|
os.path.dirname(os.path.abspath(__file__)),
|
|
"resources",
|
|
"icons",
|
|
)
|
|
|
|
# Map silo/ paths to icon basenames (without .svg extension).
|
|
_SILO_PATH_ICONS = {
|
|
"silo/manifest.json": "silo-manifest",
|
|
"silo/metadata.json": "silo-metadata",
|
|
"silo/history.json": "silo-history",
|
|
"silo/approvals.json": "silo-approvals",
|
|
"silo/dependencies.json": "silo-dependencies",
|
|
}
|
|
|
|
# Prefix-based fallbacks for subdirectory entries.
|
|
_SILO_PREFIX_ICONS = {
|
|
"silo/jobs/": "silo-job",
|
|
"silo/macros/": "silo-macro",
|
|
}
|
|
|
|
|
|
def _icon_for_path(silo_path):
|
|
"""Return absolute icon path for a silo/ entry, or '' if not found."""
|
|
name = _SILO_PATH_ICONS.get(silo_path)
|
|
if name is None:
|
|
for prefix, icon_name in _SILO_PREFIX_ICONS.items():
|
|
if silo_path.startswith(prefix):
|
|
name = icon_name
|
|
break
|
|
if name is None:
|
|
return ""
|
|
path = os.path.join(_ICON_DIR, f"{name}.svg")
|
|
return path if os.path.exists(path) else ""
|
|
|
|
|
|
class SiloViewerViewProvider:
|
|
"""ViewProvider proxy for SiloViewerObject leaf nodes."""
|
|
|
|
def __init__(self, vobj):
|
|
vobj.Proxy = self
|
|
self.Object = vobj.Object
|
|
|
|
def attach(self, vobj):
|
|
"""Store back-reference; called on document restore."""
|
|
self.Object = vobj.Object
|
|
|
|
def getIcon(self):
|
|
"""Return icon path based on SiloPath; '' uses FreeCAD default."""
|
|
try:
|
|
return _icon_for_path(self.Object.SiloPath)
|
|
except Exception:
|
|
return ""
|
|
|
|
def doubleClicked(self, vobj):
|
|
"""Open a read-only MDI viewer for this silo node."""
|
|
try:
|
|
import FreeCADGui
|
|
from PySide import QtWidgets
|
|
from silo_viewers import create_viewer_widget
|
|
|
|
obj = vobj.Object
|
|
widget = create_viewer_widget(obj)
|
|
if widget is None:
|
|
return False
|
|
|
|
mw = FreeCADGui.getMainWindow()
|
|
mdi = mw.findChild(QtWidgets.QMdiArea)
|
|
if mdi is None:
|
|
return False
|
|
|
|
# Reuse existing subwindow if already open for this object
|
|
target_name = widget.objectName()
|
|
for sw in mdi.subWindowList():
|
|
if sw.widget() and sw.widget().objectName() == target_name:
|
|
widget.deleteLater()
|
|
mdi.setActiveSubWindow(sw)
|
|
sw.show()
|
|
return True
|
|
|
|
sw = mdi.addSubWindow(widget)
|
|
sw.setWindowTitle(getattr(widget, "WINDOW_TITLE", "Silo Viewer"))
|
|
sw.show()
|
|
mdi.setActiveSubWindow(sw)
|
|
return True
|
|
|
|
except Exception as exc:
|
|
import FreeCAD
|
|
|
|
FreeCAD.Console.PrintWarning(
|
|
f"silo_viewproviders: doubleClicked failed: {exc}\n"
|
|
)
|
|
return False
|
|
|
|
def setupContextMenu(self, vobj, menu):
|
|
"""Phase 1: no context menu items."""
|
|
pass
|
|
|
|
def __getstate__(self):
|
|
return None
|
|
|
|
def __setstate__(self, state):
|
|
pass
|