mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-22 12:07:59 +00:00
Bonsai: uniquify drawing name on rename so SVGs don't overwrite (#5635)
A drawing's SVG filename is derived from its Name (get_default_drawing_path -> drawings/<name>.svg). New drawings are de-duplicated by ensure_unique_drawing_name in core.add_drawing, but the rename path core.update_drawing_name applied the raw name with no uniqueness check. Renaming one drawing to another's name then made both resolve to the same SVG path: update_drawing_name moved one SVG onto the other and pointed both IfcDocumentReference.Location values at the same file, overwriting the drawing and crossing the sheet references. Give ensure_unique_drawing_name an optional `ignore` entity (so a drawing can keep its own name) and call it from update_drawing_name with ignore=drawing, mirroring add_drawing. Default stays None, so existing callers are unchanged. Verified live in headless Blender: renaming a second drawing to a taken name now yields "<name>-X" and a distinct SVG path (paths no longer collide). Core test_drawing.py::TestUpdateDrawingName passes; the tool ensure_unique_drawing_name ignore case is confirmed live. Generated with the assistance of an AI coding tool. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -475,6 +475,11 @@ def remove_drawing(
|
|||||||
def update_drawing_name(
|
def update_drawing_name(
|
||||||
ifc: type[tool.Ifc], drawing_tool: type[tool.Drawing], drawing: ifcopenshell.entity_instance, name: str
|
ifc: type[tool.Ifc], drawing_tool: type[tool.Drawing], drawing: ifcopenshell.entity_instance, name: str
|
||||||
) -> None:
|
) -> None:
|
||||||
|
# A drawing's Name is used to derive its SVG filename, so two drawings
|
||||||
|
# sharing a name would resolve to the same file and overwrite each other
|
||||||
|
# (and tangle the sheet references). Uniquify the name on rename, just like
|
||||||
|
# new drawings do, ignoring this drawing's own current name.
|
||||||
|
name = drawing_tool.ensure_unique_drawing_name(name, ignore=drawing)
|
||||||
if drawing_tool.get_name(drawing) != name:
|
if drawing_tool.get_name(drawing) != name:
|
||||||
ifc.run("attribute.edit_attributes", product=drawing, attributes={"Name": name})
|
ifc.run("attribute.edit_attributes", product=drawing, attributes={"Name": name})
|
||||||
|
|
||||||
|
|||||||
@@ -357,7 +357,7 @@ class Drawing:
|
|||||||
def ensure_annotation_in_drawing_plane(cls, obj, camera=None): pass
|
def ensure_annotation_in_drawing_plane(cls, obj, camera=None): pass
|
||||||
def ensure_drawings_parent_document(cls): pass
|
def ensure_drawings_parent_document(cls): pass
|
||||||
def ensure_drawings_parent_group(cls): pass
|
def ensure_drawings_parent_group(cls): pass
|
||||||
def ensure_unique_drawing_name(cls, name): pass
|
def ensure_unique_drawing_name(cls, name, ignore=None): pass
|
||||||
def ensure_unique_identification(cls, identification): pass
|
def ensure_unique_identification(cls, identification): pass
|
||||||
def export_font_size(cls, obj): pass
|
def export_font_size(cls, obj): pass
|
||||||
def export_symbol(cls, obj): pass
|
def export_symbol(cls, obj): pass
|
||||||
|
|||||||
@@ -617,8 +617,14 @@ class Drawing(bonsai.core.tool.Drawing):
|
|||||||
props.is_editing_product = True
|
props.is_editing_product = True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def ensure_unique_drawing_name(cls, name: str) -> str:
|
def ensure_unique_drawing_name(
|
||||||
names = [e.Name for e in tool.Ifc.get().by_type("IfcAnnotation") if e.ObjectType == "DRAWING"]
|
cls, name: str, ignore: Optional[ifcopenshell.entity_instance] = None
|
||||||
|
) -> str:
|
||||||
|
names = [
|
||||||
|
e.Name
|
||||||
|
for e in tool.Ifc.get().by_type("IfcAnnotation")
|
||||||
|
if e.ObjectType == "DRAWING" and e != ignore
|
||||||
|
]
|
||||||
while name in names:
|
while name in names:
|
||||||
name += "-X"
|
name += "-X"
|
||||||
return name
|
return name
|
||||||
|
|||||||
@@ -533,6 +533,7 @@ class TestRemoveDrawing:
|
|||||||
|
|
||||||
class TestUpdateDrawingName:
|
class TestUpdateDrawingName:
|
||||||
def test_do_not_update_if_name_unchanged(self, ifc, drawing):
|
def test_do_not_update_if_name_unchanged(self, ifc, drawing):
|
||||||
|
drawing.ensure_unique_drawing_name("name", ignore="drawing").should_be_called().will_return("name")
|
||||||
drawing.get_name("drawing").should_be_called().will_return("name")
|
drawing.get_name("drawing").should_be_called().will_return("name")
|
||||||
drawing.set_camera_name("drawing", "name").should_be_called()
|
drawing.set_camera_name("drawing", "name").should_be_called()
|
||||||
drawing.get_drawing_group("drawing").should_be_called().will_return("group")
|
drawing.get_drawing_group("drawing").should_be_called().will_return("group")
|
||||||
@@ -549,6 +550,7 @@ class TestUpdateDrawingName:
|
|||||||
subject.update_drawing_name(ifc, drawing, drawing="drawing", name="name")
|
subject.update_drawing_name(ifc, drawing, drawing="drawing", name="name")
|
||||||
|
|
||||||
def test_run(self, ifc, drawing):
|
def test_run(self, ifc, drawing):
|
||||||
|
drawing.ensure_unique_drawing_name("name", ignore="drawing").should_be_called().will_return("name")
|
||||||
drawing.get_name("drawing").should_be_called().will_return("oldname")
|
drawing.get_name("drawing").should_be_called().will_return("oldname")
|
||||||
ifc.run("attribute.edit_attributes", product="drawing", attributes={"Name": "name"}).should_be_called()
|
ifc.run("attribute.edit_attributes", product="drawing", attributes={"Name": "name"}).should_be_called()
|
||||||
drawing.set_camera_name("drawing", "name").should_be_called()
|
drawing.set_camera_name("drawing", "name").should_be_called()
|
||||||
|
|||||||
@@ -385,10 +385,12 @@ class TestEnsureUniqueDrawingName(NewFile):
|
|||||||
ifc = ifcopenshell.file()
|
ifc = ifcopenshell.file()
|
||||||
tool.Ifc.set(ifc)
|
tool.Ifc.set(ifc)
|
||||||
assert subject.ensure_unique_drawing_name("FOOBAR") == "FOOBAR"
|
assert subject.ensure_unique_drawing_name("FOOBAR") == "FOOBAR"
|
||||||
ifc.createIfcAnnotation(Name="FOOBAR", ObjectType="DRAWING")
|
foobar = ifc.createIfcAnnotation(Name="FOOBAR", ObjectType="DRAWING")
|
||||||
assert subject.ensure_unique_drawing_name("FOOBAR") == "FOOBAR-X"
|
assert subject.ensure_unique_drawing_name("FOOBAR") == "FOOBAR-X"
|
||||||
ifc.createIfcAnnotation(Name="FOOBAR-X", ObjectType="DRAWING")
|
ifc.createIfcAnnotation(Name="FOOBAR-X", ObjectType="DRAWING")
|
||||||
assert subject.ensure_unique_drawing_name("FOOBAR") == "FOOBAR-X-X"
|
assert subject.ensure_unique_drawing_name("FOOBAR") == "FOOBAR-X-X"
|
||||||
|
# A drawing may keep its own name (e.g. when re-applying it on rename).
|
||||||
|
assert subject.ensure_unique_drawing_name("FOOBAR", ignore=foobar) == "FOOBAR"
|
||||||
|
|
||||||
|
|
||||||
class TestEnsureUniqueIdentification(NewFile):
|
class TestEnsureUniqueIdentification(NewFile):
|
||||||
|
|||||||
Reference in New Issue
Block a user