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)
151 lines
4.5 KiB
Python
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)
|