mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-24 17:29:57 +00:00
Fix #1857. Fix bug where deleting from the outliner was not tracked.
This commit is contained in:
@@ -25,6 +25,7 @@ classes = (
|
|||||||
operator.EditObjectPlacement,
|
operator.EditObjectPlacement,
|
||||||
operator.GetRepresentationIfcParameters,
|
operator.GetRepresentationIfcParameters,
|
||||||
operator.OverrideDelete,
|
operator.OverrideDelete,
|
||||||
|
operator.OverrideOutlinerDelete,
|
||||||
operator.OverrideDuplicateMove,
|
operator.OverrideDuplicateMove,
|
||||||
operator.OverrideDuplicateMoveLinked,
|
operator.OverrideDuplicateMoveLinked,
|
||||||
operator.OverridePasteBuffer,
|
operator.OverridePasteBuffer,
|
||||||
|
|||||||
@@ -311,7 +311,32 @@ class CopyRepresentation(bpy.types.Operator, Operator):
|
|||||||
return r.MappedRepresentation
|
return r.MappedRepresentation
|
||||||
|
|
||||||
|
|
||||||
class OverrideDelete(bpy.types.Operator):
|
class OverrideDeleteTrait:
|
||||||
|
def delete_ifc_object(self, obj):
|
||||||
|
if obj.BIMObjectProperties.ifc_definition_id:
|
||||||
|
element = IfcStore.get_file().by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||||
|
IfcStore.deleted_ids.add(element.id())
|
||||||
|
if getattr(element, "FillsVoids", None):
|
||||||
|
self.remove_filling(element)
|
||||||
|
if element.is_a("IfcOpeningElement"):
|
||||||
|
for rel in element.HasFillings:
|
||||||
|
self.remove_filling(rel.RelatedBuildingElement)
|
||||||
|
if element.VoidsElements:
|
||||||
|
self.delete_opening_element(element)
|
||||||
|
elif getattr(element, "HasOpenings", None):
|
||||||
|
for rel in element.HasOpenings:
|
||||||
|
self.delete_opening_element(rel.RelatedOpeningElement)
|
||||||
|
|
||||||
|
def delete_opening_element(self, element):
|
||||||
|
obj = IfcStore.get_element(element.VoidsElements[0].RelatingBuildingElement.id())
|
||||||
|
bpy.ops.bim.remove_opening(opening_id=element.id(), obj=obj.name)
|
||||||
|
|
||||||
|
def remove_filling(self, element):
|
||||||
|
obj = IfcStore.get_element(element.id())
|
||||||
|
bpy.ops.bim.remove_filling(obj=obj.name)
|
||||||
|
|
||||||
|
|
||||||
|
class OverrideDelete(bpy.types.Operator, OverrideDeleteTrait):
|
||||||
bl_idname = "object.delete"
|
bl_idname = "object.delete"
|
||||||
bl_label = "Delete"
|
bl_label = "Delete"
|
||||||
use_global: bpy.props.BoolProperty(default=False)
|
use_global: bpy.props.BoolProperty(default=False)
|
||||||
@@ -333,31 +358,56 @@ class OverrideDelete(bpy.types.Operator):
|
|||||||
return context.window_manager.invoke_confirm(self, event)
|
return context.window_manager.invoke_confirm(self, event)
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
file = IfcStore.get_file()
|
|
||||||
for obj in context.selected_objects:
|
for obj in context.selected_objects:
|
||||||
if obj.BIMObjectProperties.ifc_definition_id:
|
self.delete_ifc_object(obj)
|
||||||
element = file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
|
||||||
IfcStore.deleted_ids.add(element.id())
|
|
||||||
if getattr(element, "FillsVoids", None):
|
|
||||||
self.remove_filling(element)
|
|
||||||
if element.is_a("IfcOpeningElement"):
|
|
||||||
for rel in element.HasFillings:
|
|
||||||
self.remove_filling(rel.RelatedBuildingElement)
|
|
||||||
if element.VoidsElements:
|
|
||||||
self.delete_opening_element(element)
|
|
||||||
elif getattr(element, "HasOpenings", None):
|
|
||||||
for rel in element.HasOpenings:
|
|
||||||
self.delete_opening_element(rel.RelatedOpeningElement)
|
|
||||||
bpy.data.objects.remove(obj)
|
bpy.data.objects.remove(obj)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
def delete_opening_element(self, element):
|
|
||||||
obj = IfcStore.get_element(element.VoidsElements[0].RelatingBuildingElement.id())
|
|
||||||
bpy.ops.bim.remove_opening(opening_id=element.id(), obj=obj.name)
|
|
||||||
|
|
||||||
def remove_filling(self, element):
|
class OverrideOutlinerDelete(bpy.types.Operator, OverrideDeleteTrait):
|
||||||
obj = IfcStore.get_element(element.id())
|
bl_idname = "outliner.delete"
|
||||||
bpy.ops.bim.remove_filling(obj=obj.name)
|
bl_label = "Delete"
|
||||||
|
hierarchy: bpy.props.BoolProperty(default=False)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
return len(context.selected_ids) > 0
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
# Deep magick from the dawn of time
|
||||||
|
if IfcStore.get_file():
|
||||||
|
return IfcStore.execute_ifc_operator(self, context)
|
||||||
|
# https://blender.stackexchange.com/questions/203729/python-get-selected-objects-in-outliner
|
||||||
|
objects_to_delete = set()
|
||||||
|
for item in context.selected_ids:
|
||||||
|
if item.bl_rna.identifier == "Collection":
|
||||||
|
collection = bpy.data.collections.get(item.name)
|
||||||
|
if self.hierarchy:
|
||||||
|
for obj in collection.objects:
|
||||||
|
objects_to_delete.add(bpy.data.objects.get(item.name))
|
||||||
|
bpy.data.collections.remove(collection)
|
||||||
|
elif item.bl_rna.identifier == "Object":
|
||||||
|
objects_to_delete.add(bpy.data.objects.get(item.name))
|
||||||
|
for obj in objects_to_delete:
|
||||||
|
bpy.data.objects.remove(obj)
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
def _execute(self, context):
|
||||||
|
objects_to_delete = set()
|
||||||
|
for item in context.selected_ids:
|
||||||
|
if item.bl_rna.identifier == "Collection":
|
||||||
|
collection = bpy.data.collections.get(item.name)
|
||||||
|
if self.hierarchy:
|
||||||
|
for obj in collection.objects:
|
||||||
|
objects_to_delete.add(bpy.data.objects.get(item.name))
|
||||||
|
bpy.data.collections.remove(collection)
|
||||||
|
elif item.bl_rna.identifier == "Object":
|
||||||
|
objects_to_delete.add(bpy.data.objects.get(item.name))
|
||||||
|
for obj in objects_to_delete:
|
||||||
|
# This is the only difference
|
||||||
|
self.delete_ifc_object(obj)
|
||||||
|
bpy.data.objects.remove(obj)
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class OverrideDuplicateMove(bpy.types.Operator):
|
class OverrideDuplicateMove(bpy.types.Operator):
|
||||||
|
|||||||
@@ -282,6 +282,10 @@ Scenario: Override delete - with active IFC data
|
|||||||
When I press "object.delete"
|
When I press "object.delete"
|
||||||
Then the object "IfcWall/Cube" does not exist
|
Then the object "IfcWall/Cube" does not exist
|
||||||
|
|
||||||
|
Scenario: Override outliner delete
|
||||||
|
Given an untestable scenario
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
Scenario: Override duplicate move - without active IFC data
|
Scenario: Override duplicate move - without active IFC data
|
||||||
Given an empty Blender session
|
Given an empty Blender session
|
||||||
And I add a cube
|
And I add a cube
|
||||||
|
|||||||
@@ -40,6 +40,11 @@ def replace_variables(value):
|
|||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
@given("an untestable scenario")
|
||||||
|
def an_untestable_scenario():
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
@given("an empty Blender session")
|
@given("an empty Blender session")
|
||||||
@when("an empty Blender session is started")
|
@when("an empty Blender session is started")
|
||||||
def an_empty_ifc_project():
|
def an_empty_ifc_project():
|
||||||
|
|||||||
Reference in New Issue
Block a user