All checks were successful
Build and Test / build (pull_request) Successful in 30m48s
Add SiloMetadataEditor widget that opens in an MDI subwindow when the user double-clicks the Metadata node in the Silo tree. Supports editing lifecycle state, tags (add/remove chips), and schema-defined fields with type-inferred widgets (QCheckBox, QDoubleSpinBox, QLineEdit). Changes: - silo_viewers.py: SiloMetadataEditor with dirty tracking, Save/Reset buttons, unsaved-changes close guard, and tag chip management - silo_objects.py: mark_dirty()/is_dirty()/clear_dirty() on proxy - kc_format.py: fix entries=None before hooks; _metadata_save_hook writes dirty RawContent back to silo/ cache on document save Closes #39
71 lines
1.9 KiB
Python
71 lines
1.9 KiB
Python
"""
|
|
silo_objects.py - Create FeaturePython proxy for Silo tree leaf nodes.
|
|
|
|
Each silo/ ZIP entry in a .kc file gets one SiloViewerObject in the
|
|
FreeCAD document tree. All properties are Transient so they are never
|
|
persisted in Document.xml.
|
|
"""
|
|
|
|
import FreeCAD
|
|
|
|
|
|
class SiloViewerObject:
|
|
"""Proxy for App::FeaturePython silo viewer nodes.
|
|
|
|
Properties (all Transient):
|
|
SiloPath - ZIP entry path, e.g. "silo/manifest.json"
|
|
ContentType - "json", "yaml", or "py"
|
|
RawContent - decoded UTF-8 content of the entry
|
|
"""
|
|
|
|
def __init__(self, obj):
|
|
obj.Proxy = self
|
|
|
|
obj.addProperty(
|
|
"App::PropertyString",
|
|
"SiloPath",
|
|
"Silo",
|
|
"ZIP entry path of this silo item",
|
|
)
|
|
obj.addProperty(
|
|
"App::PropertyString",
|
|
"ContentType",
|
|
"Silo",
|
|
"Content type of this silo item",
|
|
)
|
|
obj.addProperty(
|
|
"App::PropertyString",
|
|
"RawContent",
|
|
"Silo",
|
|
"Raw text content of this silo entry",
|
|
)
|
|
|
|
obj.setPropertyStatus("SiloPath", "Transient")
|
|
obj.setPropertyStatus("ContentType", "Transient")
|
|
obj.setPropertyStatus("RawContent", "Transient")
|
|
|
|
obj.setEditorMode("SiloPath", 1) # read-only in property panel
|
|
obj.setEditorMode("ContentType", 1)
|
|
obj.setEditorMode("RawContent", 2) # hidden in property panel
|
|
|
|
def execute(self, obj):
|
|
pass
|
|
|
|
def mark_dirty(self):
|
|
"""Flag this object's content as modified by a viewer widget."""
|
|
self._dirty = True
|
|
|
|
def is_dirty(self):
|
|
"""Return True if content has been modified since last save."""
|
|
return getattr(self, "_dirty", False)
|
|
|
|
def clear_dirty(self):
|
|
"""Clear the dirty flag after saving."""
|
|
self._dirty = False
|
|
|
|
def __getstate__(self):
|
|
return None
|
|
|
|
def __setstate__(self, state):
|
|
pass
|