Files
silo-mod/freecad/InitGui.py
forbes-0023 a88e104d94 feat(templates): document templating system with Save as Template command
Add a template system that lets users create new items from pre-configured
.kc template files and save existing documents as reusable templates.

Template use (New Item form):
- templates.py: discovery, filtering, TemplateInfo dataclass
- schema_form.py: template combo picker filtered by type/category
- silo_commands.py: SiloSync.create_document_from_template() copies
  template .kc, strips identity, stamps Silo properties

Template creation (Save as Template):
- SaveAsTemplateDialog: captures name, description, item types,
  categories, author, and tags
- Silo_SaveAsTemplate command: copies doc, strips Silo identity,
  injects silo/template.json, optionally uploads to Silo
- Registered in Silo menu via InitGui.py

Template search paths (3-tier, later shadows earlier by name):
1. mods/silo/freecad/templates/ (system)
2. ~/.local/share/FreeCAD/Templates/ (personal, sister to Macro/)
3. ~/projects/templates/ (org-shared)
2026-02-21 09:06:26 -06:00

151 lines
4.5 KiB
Python

"""Kindred Silo Workbench - Item database integration for Kindred Create."""
import os
import FreeCAD
import FreeCADGui
FreeCAD.Console.PrintMessage("Kindred Silo InitGui.py loading...\n")
class SiloWorkbench(FreeCADGui.Workbench):
"""Kindred Silo workbench for item database integration."""
MenuText = "Kindred Silo"
ToolTip = "Item database and part management for Kindred Create"
Icon = ""
def __init__(self):
# Resolve icon relative to this file so it works regardless of install location
icon_path = os.path.join(
os.path.dirname(os.path.abspath(__file__)), "resources", "icons", "silo.svg"
)
if os.path.exists(icon_path):
self.__class__.Icon = icon_path
def Initialize(self):
"""Called when workbench is first activated."""
import silo_commands
# Register Silo as a file origin in the unified origin system
try:
import silo_origin
silo_origin.register_silo_origin()
except Exception as e:
FreeCAD.Console.PrintWarning(f"Could not register Silo origin: {e}\n")
# Silo origin toolbar — shown as an overlay on any context when the
# active document is Silo-tracked. Registered as Unavailable so
# EditingContextResolver controls visibility via the overlay system.
self.silo_toolbar_commands = [
"Silo_Commit",
"Silo_Pull",
"Silo_Push",
"Separator",
"Silo_Info",
"Silo_BOM",
"Silo_Jobs",
]
self.appendToolbar("Silo Origin", self.silo_toolbar_commands, "Unavailable")
# Silo menu provides admin/management commands.
self.menu_commands = [
"Silo_Info",
"Silo_BOM",
"Silo_Jobs",
"Silo_TagProjects",
"Silo_SetStatus",
"Silo_Rollback",
"Silo_SaveAsTemplate",
"Separator",
"Silo_Settings",
"Silo_Auth",
"Silo_Runners",
"Silo_StartPanel",
"Silo_Diag",
]
self.appendMenu("Silo", self.menu_commands)
def Activated(self):
"""Called when workbench is activated."""
FreeCAD.Console.PrintMessage("Kindred Silo workbench activated\n")
FreeCADGui.runCommand("Silo_StartPanel", 0)
def Deactivated(self):
pass
def GetClassName(self):
return "Gui::PythonWorkbench"
FreeCADGui.addWorkbench(SiloWorkbench())
FreeCAD.Console.PrintMessage("Silo workbench registered\n")
# ---------------------------------------------------------------------------
# Silo overlay context — adds "Silo Origin" toolbar to any active context
# when the current document is Silo-tracked.
# ---------------------------------------------------------------------------
def _register_silo_overlay():
"""Register the Silo overlay after the Silo workbench has initialised."""
def _silo_overlay_match():
"""Return True if the active document is Silo-tracked."""
try:
doc = FreeCAD.ActiveDocument
if not doc:
return False
from silo_origin import get_silo_origin
origin = get_silo_origin()
return origin.ownsDocument(doc)
except Exception:
return False
try:
from kindred_sdk import register_overlay
register_overlay(
"silo", # overlay id
["Silo Origin"], # toolbar names to append
_silo_overlay_match, # match function
)
except Exception as e:
FreeCAD.Console.PrintWarning(f"Silo overlay registration failed: {e}\n")
from PySide import QtCore as _QtCore
_QtCore.QTimer.singleShot(2500, _register_silo_overlay)
# Override the Start page with Silo-aware version (must happen before
# the C++ StartLauncher fires at ~100ms after GUI init)
try:
import silo_start
silo_start.register()
except Exception as e:
FreeCAD.Console.PrintWarning(f"Silo Start page override failed: {e}\n")
# Handle kindred:// URLs passed as command-line arguments on cold start.
# Delayed to run after the GUI is fully initialised and the Silo addon has
# loaded its client/sync objects.
def _handle_startup_urls():
"""Process any kindred:// URLs passed as command-line arguments."""
import sys
from silo_commands import handle_kindred_url
for arg in sys.argv[1:]:
if arg.startswith("kindred://"):
handle_kindred_url(arg)
_QtCore.QTimer.singleShot(500, _handle_startup_urls)