mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-22 23:02:39 +00:00
Implement undo for context and geometry operators. See #1475.
This commit is contained in:
@@ -7,11 +7,15 @@ from ifcopenshell.api.context.data import Data
|
|||||||
class AddSubcontext(bpy.types.Operator):
|
class AddSubcontext(bpy.types.Operator):
|
||||||
bl_idname = "bim.add_subcontext"
|
bl_idname = "bim.add_subcontext"
|
||||||
bl_label = "Add Subcontext"
|
bl_label = "Add Subcontext"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
context: bpy.props.StringProperty()
|
context: bpy.props.StringProperty()
|
||||||
subcontext: bpy.props.StringProperty()
|
subcontext: bpy.props.StringProperty()
|
||||||
target_view: bpy.props.StringProperty()
|
target_view: bpy.props.StringProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
|
return IfcStore.execute_ifc_operator(self, context)
|
||||||
|
|
||||||
|
def _execute(self, context):
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"context.add_context",
|
"context.add_context",
|
||||||
@@ -29,9 +33,13 @@ class AddSubcontext(bpy.types.Operator):
|
|||||||
class RemoveSubcontext(bpy.types.Operator):
|
class RemoveSubcontext(bpy.types.Operator):
|
||||||
bl_idname = "bim.remove_subcontext"
|
bl_idname = "bim.remove_subcontext"
|
||||||
bl_label = "Remove Context"
|
bl_label = "Remove Context"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
ifc_definition_id: bpy.props.IntProperty()
|
ifc_definition_id: bpy.props.IntProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
|
return IfcStore.execute_ifc_operator(self, context)
|
||||||
|
|
||||||
|
def _execute(self, context):
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"context.remove_context", self.file, **{"context": self.file.by_id(self.ifc_definition_id)}
|
"context.remove_context", self.file, **{"context": self.file.by_id(self.ifc_definition_id)}
|
||||||
|
|||||||
@@ -228,10 +228,14 @@ class SwitchRepresentation(bpy.types.Operator):
|
|||||||
class RemoveRepresentation(bpy.types.Operator):
|
class RemoveRepresentation(bpy.types.Operator):
|
||||||
bl_idname = "bim.remove_representation"
|
bl_idname = "bim.remove_representation"
|
||||||
bl_label = "Remove Representation"
|
bl_label = "Remove Representation"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
obj: bpy.props.StringProperty()
|
obj: bpy.props.StringProperty()
|
||||||
representation_id: bpy.props.IntProperty()
|
representation_id: bpy.props.IntProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
|
return IfcStore.execute_ifc_operator(self, context)
|
||||||
|
|
||||||
|
def _execute(self, context):
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
representation = self.file.by_id(self.representation_id)
|
representation = self.file.by_id(self.representation_id)
|
||||||
obj = bpy.data.objects.get(self.obj) if self.obj else bpy.context.active_object
|
obj = bpy.data.objects.get(self.obj) if self.obj else bpy.context.active_object
|
||||||
@@ -264,10 +268,14 @@ class RemoveRepresentation(bpy.types.Operator):
|
|||||||
class UpdateRepresentation(bpy.types.Operator):
|
class UpdateRepresentation(bpy.types.Operator):
|
||||||
bl_idname = "bim.update_representation"
|
bl_idname = "bim.update_representation"
|
||||||
bl_label = "Update Representation"
|
bl_label = "Update Representation"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
obj: bpy.props.StringProperty()
|
obj: bpy.props.StringProperty()
|
||||||
ifc_representation_class: bpy.props.StringProperty()
|
ifc_representation_class: bpy.props.StringProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
|
return IfcStore.execute_ifc_operator(self, context)
|
||||||
|
|
||||||
|
def _execute(self, context):
|
||||||
if not ContextData.is_loaded:
|
if not ContextData.is_loaded:
|
||||||
ContextData.load(IfcStore.get_file())
|
ContextData.load(IfcStore.get_file())
|
||||||
|
|
||||||
@@ -342,6 +350,7 @@ class UpdateRepresentation(bpy.types.Operator):
|
|||||||
class UpdateParametricRepresentation(bpy.types.Operator):
|
class UpdateParametricRepresentation(bpy.types.Operator):
|
||||||
bl_idname = "bim.update_parametric_representation"
|
bl_idname = "bim.update_parametric_representation"
|
||||||
bl_label = "Update Parametric Representation"
|
bl_label = "Update Parametric Representation"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
index: bpy.props.IntProperty()
|
index: bpy.props.IntProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
@@ -357,6 +366,7 @@ class UpdateParametricRepresentation(bpy.types.Operator):
|
|||||||
class GetRepresentationIfcParameters(bpy.types.Operator):
|
class GetRepresentationIfcParameters(bpy.types.Operator):
|
||||||
bl_idname = "bim.get_representation_ifc_parameters"
|
bl_idname = "bim.get_representation_ifc_parameters"
|
||||||
bl_label = "Get Representation IFC Parameters"
|
bl_label = "Get Representation IFC Parameters"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
|
|||||||
@@ -71,15 +71,19 @@ class Transaction:
|
|||||||
for inverse in self.file.get_inverse(element):
|
for inverse in self.file.get_inverse(element):
|
||||||
inverse_references = []
|
inverse_references = []
|
||||||
for i, attribute in enumerate(inverse):
|
for i, attribute in enumerate(inverse):
|
||||||
if attribute == element:
|
if self.has_element_reference(attribute, element):
|
||||||
inverse_references.append((i, "single"))
|
inverse_references.append((i, self.serialise_value(inverse, attribute)))
|
||||||
elif isinstance(attribute, tuple) and element in attribute:
|
|
||||||
inverse_references.append((i, "multiple"))
|
|
||||||
inverses[inverse.id()] = inverse_references
|
inverses[inverse.id()] = inverse_references
|
||||||
self.operations.append(
|
self.operations.append(
|
||||||
{"action": "delete", "inverses": inverses, "value": self.serialise_entity_instance(element)}
|
{"action": "delete", "inverses": inverses, "value": self.serialise_entity_instance(element)}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def has_element_reference(self, value, element):
|
||||||
|
if isinstance(value, (tuple, list)):
|
||||||
|
for v in value:
|
||||||
|
return self.has_element_reference(v, element)
|
||||||
|
return value == element
|
||||||
|
|
||||||
def rollback(self):
|
def rollback(self):
|
||||||
for operation in self.operations[::-1]:
|
for operation in self.operations[::-1]:
|
||||||
if operation["action"] == "create":
|
if operation["action"] == "create":
|
||||||
@@ -105,16 +109,8 @@ class Transaction:
|
|||||||
pass
|
pass
|
||||||
for inverse_id, data in operation["inverses"].items():
|
for inverse_id, data in operation["inverses"].items():
|
||||||
inverse = self.file.by_id(inverse_id)
|
inverse = self.file.by_id(inverse_id)
|
||||||
for index, data_type in data:
|
for index, value in data:
|
||||||
if data_type == "single":
|
inverse[index] = self.unserialise_value(inverse, value)
|
||||||
inverse[index] = e
|
|
||||||
elif data_type == "multiple":
|
|
||||||
if inverse[index] is None:
|
|
||||||
inverse[index] = e
|
|
||||||
else:
|
|
||||||
new = list(inverse[index])
|
|
||||||
new.append(e)
|
|
||||||
inverse[index] = new
|
|
||||||
|
|
||||||
def commit(self):
|
def commit(self):
|
||||||
for operation in self.operations:
|
for operation in self.operations:
|
||||||
|
|||||||
@@ -91,14 +91,19 @@ def get_aggregate(element):
|
|||||||
|
|
||||||
def replace_attribute(element, old, new):
|
def replace_attribute(element, old, new):
|
||||||
for i, attribute in enumerate(element):
|
for i, attribute in enumerate(element):
|
||||||
if attribute == old:
|
if has_element_reference(attribute, old):
|
||||||
element[i] = new
|
new_attribute = element.walk(lambda v: v == old, lambda v: new, attribute)
|
||||||
elif isinstance(attribute, tuple):
|
# TODO: make this unnecessary
|
||||||
new_attribute = list(attribute)
|
if element.wrapped_data.file.transaction:
|
||||||
for j, item in enumerate(attribute):
|
element.wrapped_data.file.transaction.store_edit(element, i, new_attribute)
|
||||||
if item == old:
|
element[i] = new_attribute
|
||||||
new_attribute[j] = new
|
|
||||||
element[i] = new_attribute
|
|
||||||
|
def has_element_reference(value, element):
|
||||||
|
if isinstance(value, (tuple, list)):
|
||||||
|
for v in value:
|
||||||
|
return has_element_reference(v, element)
|
||||||
|
return value == element
|
||||||
|
|
||||||
|
|
||||||
def remove_deep(ifc_file, element):
|
def remove_deep(ifc_file, element):
|
||||||
|
|||||||
Reference in New Issue
Block a user