mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-28 11:18:18 +00:00
Implement undo for aggregate operations, with automatic element-obj link undo/redo and improved undo syntax. See #1475.
This commit is contained in:
@@ -13,10 +13,10 @@ endif
|
|||||||
|
|
||||||
# Provides IfcOpenShell Python functionality
|
# Provides IfcOpenShell Python functionality
|
||||||
ifeq ($(PYVERSION), py37)
|
ifeq ($(PYVERSION), py37)
|
||||||
cd dist/working && wget https://s3.amazonaws.com/ifcopenshell-builds/ifcblender-python-37-v0.6.0-81ad689-$(PLATFORM)64.zip
|
cd dist/working && wget https://s3.amazonaws.com/ifcopenshell-builds/ifcblender-python-37-v0.6.0-2fd2b49-$(PLATFORM)64.zip
|
||||||
endif
|
endif
|
||||||
ifeq ($(PYVERSION), py39)
|
ifeq ($(PYVERSION), py39)
|
||||||
cd dist/working && wget https://s3.amazonaws.com/ifcopenshell-builds/ifcblender-python-39-v0.6.0-81ad689-$(PLATFORM)64.zip
|
cd dist/working && wget https://s3.amazonaws.com/ifcopenshell-builds/ifcblender-python-39-v0.6.0-2fd2b49-$(PLATFORM)64.zip
|
||||||
endif
|
endif
|
||||||
cd dist/working && unzip ifcblender*
|
cd dist/working && unzip ifcblender*
|
||||||
cp -r dist/working/io_import_scene_ifc/ifcopenshell dist/blenderbim/libs/site/packages/
|
cp -r dist/working/io_import_scene_ifc/ifcopenshell dist/blenderbim/libs/site/packages/
|
||||||
|
|||||||
@@ -12,7 +12,10 @@ global_subscription_owner = object()
|
|||||||
|
|
||||||
|
|
||||||
def mode_callback(obj, data):
|
def mode_callback(obj, data):
|
||||||
for obj in bpy.context.selected_objects + [bpy.context.active_object]:
|
objects = bpy.context.selected_objects
|
||||||
|
if bpy.context.active_object:
|
||||||
|
objects += [bpy.context.active_object]
|
||||||
|
for obj in objects:
|
||||||
if (
|
if (
|
||||||
obj.mode != "EDIT"
|
obj.mode != "EDIT"
|
||||||
or not obj.data
|
or not obj.data
|
||||||
|
|||||||
@@ -75,7 +75,9 @@ class IfcStore:
|
|||||||
if not file:
|
if not file:
|
||||||
return
|
return
|
||||||
if should_reload_selected:
|
if should_reload_selected:
|
||||||
objects = bpy.context.selected_objects + [bpy.context.active_object]
|
objects = bpy.context.selected_objects
|
||||||
|
if bpy.context.active_object:
|
||||||
|
objects += [bpy.context.active_object]
|
||||||
else:
|
else:
|
||||||
objects = bpy.data.objects
|
objects = bpy.data.objects
|
||||||
[
|
[
|
||||||
@@ -95,6 +97,24 @@ class IfcStore:
|
|||||||
for listener in IfcStore.element_listeners:
|
for listener in IfcStore.element_listeners:
|
||||||
listener(element, obj)
|
listener(element, obj)
|
||||||
|
|
||||||
|
if IfcStore.history:
|
||||||
|
data = {"id": element.id(), "guid": getattr(element, "GlobalId", None), "obj": obj.name}
|
||||||
|
IfcStore.history[-1]["transactions"].append(
|
||||||
|
{"rollback": IfcStore.rollback_link_element, "commit": IfcStore.commit_link_element, "data": data}
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def rollback_link_element(data):
|
||||||
|
del IfcStore.id_map[data["id"]]
|
||||||
|
if data["guid"]:
|
||||||
|
del IfcStore.guid_map[data["guid"]]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def commit_link_element(data):
|
||||||
|
IfcStore.id_map[data["id"]] = bpy.data.objects.get(data["obj"])
|
||||||
|
if data["guid"]:
|
||||||
|
IfcStore.guid_map[data["guid"]] = bpy.data.objects.get(data["obj"])
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def unlink_element(element=None, obj=None):
|
def unlink_element(element=None, obj=None):
|
||||||
if element is None:
|
if element is None:
|
||||||
@@ -120,6 +140,35 @@ class IfcStore:
|
|||||||
if obj:
|
if obj:
|
||||||
obj.BIMObjectProperties.ifc_definition_id = 0
|
obj.BIMObjectProperties.ifc_definition_id = 0
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def execute_ifc_operator(operator, context):
|
||||||
|
is_top_level_operator = not bool(operator.transaction_key)
|
||||||
|
|
||||||
|
if is_top_level_operator:
|
||||||
|
IfcStore.get_file().begin_transaction()
|
||||||
|
# This empty transaction ensures that each operator has at least one transaction
|
||||||
|
IfcStore.add_transaction(operator, rollback=lambda data: True, commit=lambda data: True)
|
||||||
|
|
||||||
|
result = getattr(operator, "_execute")(context)
|
||||||
|
|
||||||
|
if is_top_level_operator:
|
||||||
|
IfcStore.get_file().end_transaction()
|
||||||
|
IfcStore.add_transaction(
|
||||||
|
operator, rollback=IfcStore.rollback_ifc_operator, commit=IfcStore.commit_ifc_operator
|
||||||
|
)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def rollback_ifc_operator(data):
|
||||||
|
IfcStore.get_file().undo()
|
||||||
|
blenderbim.bim.handler.purge_module_data()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def commit_ifc_operator(data):
|
||||||
|
IfcStore.get_file().redo()
|
||||||
|
blenderbim.bim.handler.purge_module_data()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def generate_transaction_key(operator):
|
def generate_transaction_key(operator):
|
||||||
if not getattr(operator, "transaction_key", None):
|
if not getattr(operator, "transaction_key", None):
|
||||||
|
|||||||
@@ -7,10 +7,15 @@ from ifcopenshell.api.aggregate.data import Data
|
|||||||
class AssignObject(bpy.types.Operator):
|
class AssignObject(bpy.types.Operator):
|
||||||
bl_idname = "bim.assign_object"
|
bl_idname = "bim.assign_object"
|
||||||
bl_label = "Assign Object"
|
bl_label = "Assign Object"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
transaction_key: bpy.props.StringProperty()
|
||||||
relating_object: bpy.props.StringProperty()
|
relating_object: bpy.props.StringProperty()
|
||||||
related_object: bpy.props.StringProperty()
|
related_object: 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()
|
||||||
related_objects = (
|
related_objects = (
|
||||||
[bpy.data.objects.get(self.related_object)] if self.related_object else bpy.context.selected_objects
|
[bpy.data.objects.get(self.related_object)] if self.related_object else bpy.context.selected_objects
|
||||||
@@ -29,7 +34,7 @@ class AssignObject(bpy.types.Operator):
|
|||||||
"relating_object": self.file.by_id(relating_object.BIMObjectProperties.ifc_definition_id),
|
"relating_object": self.file.by_id(relating_object.BIMObjectProperties.ifc_definition_id),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
bpy.ops.bim.edit_object_placement(obj=related_object.name)
|
bpy.ops.bim.edit_object_placement(transaction_key=self.transaction_key, obj=related_object.name)
|
||||||
Data.load(IfcStore.get_file(), oprops.ifc_definition_id)
|
Data.load(IfcStore.get_file(), oprops.ifc_definition_id)
|
||||||
bpy.ops.bim.disable_editing_aggregate(obj=related_object.name)
|
bpy.ops.bim.disable_editing_aggregate(obj=related_object.name)
|
||||||
|
|
||||||
@@ -60,6 +65,7 @@ class AssignObject(bpy.types.Operator):
|
|||||||
class EnableEditingAggregate(bpy.types.Operator):
|
class EnableEditingAggregate(bpy.types.Operator):
|
||||||
bl_idname = "bim.enable_editing_aggregate"
|
bl_idname = "bim.enable_editing_aggregate"
|
||||||
bl_label = "Enable Editing Aggregate"
|
bl_label = "Enable Editing Aggregate"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
bpy.context.active_object.BIMObjectProperties.relating_object = None
|
bpy.context.active_object.BIMObjectProperties.relating_object = None
|
||||||
@@ -71,6 +77,7 @@ class DisableEditingAggregate(bpy.types.Operator):
|
|||||||
bl_idname = "bim.disable_editing_aggregate"
|
bl_idname = "bim.disable_editing_aggregate"
|
||||||
bl_label = "Disable Editing Aggregate"
|
bl_label = "Disable Editing Aggregate"
|
||||||
obj: bpy.props.StringProperty()
|
obj: bpy.props.StringProperty()
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
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
|
||||||
@@ -81,14 +88,23 @@ class DisableEditingAggregate(bpy.types.Operator):
|
|||||||
class AddAggregate(bpy.types.Operator):
|
class AddAggregate(bpy.types.Operator):
|
||||||
bl_idname = "bim.add_aggregate"
|
bl_idname = "bim.add_aggregate"
|
||||||
bl_label = "Add Aggregate"
|
bl_label = "Add Aggregate"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
transaction_key: bpy.props.StringProperty()
|
||||||
obj: bpy.props.StringProperty()
|
obj: bpy.props.StringProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
|
return IfcStore.execute_ifc_operator(self, context)
|
||||||
|
|
||||||
|
def _execute(self, context):
|
||||||
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
|
||||||
aggregate_collection = bpy.data.collections.new("IfcElementAssembly/Assembly")
|
aggregate_collection = bpy.data.collections.new("IfcElementAssembly/Assembly")
|
||||||
bpy.context.scene.collection.children.link(aggregate_collection)
|
bpy.context.scene.collection.children.link(aggregate_collection)
|
||||||
aggregate = bpy.data.objects.new("Assembly", None)
|
aggregate = bpy.data.objects.new("Assembly", None)
|
||||||
aggregate_collection.objects.link(aggregate)
|
aggregate_collection.objects.link(aggregate)
|
||||||
bpy.ops.bim.assign_class(obj=aggregate.name, ifc_class="IfcElementAssembly")
|
bpy.ops.bim.assign_class(
|
||||||
bpy.ops.bim.assign_object(related_object=obj.name, relating_object=aggregate.name)
|
transaction_key=self.transaction_key, obj=aggregate.name, ifc_class="IfcElementAssembly"
|
||||||
|
)
|
||||||
|
bpy.ops.bim.assign_object(
|
||||||
|
transaction_key=self.transaction_key, related_object=obj.name, relating_object=aggregate.name
|
||||||
|
)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|||||||
@@ -69,6 +69,9 @@ class EditAttributes(bpy.types.Operator):
|
|||||||
obj_type: bpy.props.StringProperty()
|
obj_type: 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()
|
||||||
if self.obj_type == "Object":
|
if self.obj_type == "Object":
|
||||||
obj = bpy.data.objects.get(self.obj)
|
obj = bpy.data.objects.get(self.obj)
|
||||||
@@ -99,11 +102,9 @@ class EditAttributes(bpy.types.Operator):
|
|||||||
elif attribute["type"] == "enum":
|
elif attribute["type"] == "enum":
|
||||||
attributes[attribute["name"]] = blender_attribute.enum_value
|
attributes[attribute["name"]] = blender_attribute.enum_value
|
||||||
product = self.file.by_id(oprops.ifc_definition_id)
|
product = self.file.by_id(oprops.ifc_definition_id)
|
||||||
self.file.begin_transaction()
|
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"attribute.edit_attributes", self.file, **{"product": product, "attributes": attributes}
|
"attribute.edit_attributes", self.file, **{"product": product, "attributes": attributes}
|
||||||
)
|
)
|
||||||
self.file.end_transaction()
|
|
||||||
if "Name" in attributes:
|
if "Name" in attributes:
|
||||||
new_name = "{}/{}".format(product.is_a(), product.Name or "Unnamed")
|
new_name = "{}/{}".format(product.is_a(), product.Name or "Unnamed")
|
||||||
collection = bpy.data.collections.get(obj.name)
|
collection = bpy.data.collections.get(obj.name)
|
||||||
@@ -112,18 +113,8 @@ class EditAttributes(bpy.types.Operator):
|
|||||||
obj.name = new_name
|
obj.name = new_name
|
||||||
Data.load(IfcStore.get_file(), oprops.ifc_definition_id)
|
Data.load(IfcStore.get_file(), oprops.ifc_definition_id)
|
||||||
bpy.ops.bim.disable_editing_attributes(obj=obj.name, obj_type=self.obj_type)
|
bpy.ops.bim.disable_editing_attributes(obj=obj.name, obj_type=self.obj_type)
|
||||||
self.transaction_data = {"ifc_definition_id": oprops.ifc_definition_id}
|
|
||||||
IfcStore.add_transaction(self)
|
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
def rollback(self, data):
|
|
||||||
IfcStore.get_file().undo()
|
|
||||||
Data.load(IfcStore.get_file(), data["ifc_definition_id"])
|
|
||||||
|
|
||||||
def commit(self, data):
|
|
||||||
IfcStore.get_file().redo()
|
|
||||||
Data.load(IfcStore.get_file(), data["ifc_definition_id"])
|
|
||||||
|
|
||||||
|
|
||||||
class GenerateGlobalId(bpy.types.Operator):
|
class GenerateGlobalId(bpy.types.Operator):
|
||||||
bl_idname = "bim.generate_global_id"
|
bl_idname = "bim.generate_global_id"
|
||||||
|
|||||||
@@ -17,9 +17,14 @@ from mathutils import Vector
|
|||||||
class EditObjectPlacement(bpy.types.Operator):
|
class EditObjectPlacement(bpy.types.Operator):
|
||||||
bl_idname = "bim.edit_object_placement"
|
bl_idname = "bim.edit_object_placement"
|
||||||
bl_label = "Edit Object Placement"
|
bl_label = "Edit Object Placement"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
transaction_key: bpy.props.StringProperty()
|
||||||
obj: bpy.props.StringProperty()
|
obj: bpy.props.StringProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
|
return IfcStore.execute_ifc_operator(self, context)
|
||||||
|
|
||||||
|
def _execute(self, context):
|
||||||
objs = [bpy.data.objects.get(self.obj)] if self.obj else bpy.context.selected_objects
|
objs = [bpy.data.objects.get(self.obj)] if self.obj else bpy.context.selected_objects
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
# TODO: determine how to deal with this module dependency
|
# TODO: determine how to deal with this module dependency
|
||||||
|
|||||||
@@ -16,6 +16,14 @@ class CreateProject(bpy.types.Operator):
|
|||||||
transaction_key: bpy.props.StringProperty()
|
transaction_key: bpy.props.StringProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
|
IfcStore.generate_transaction_key(self)
|
||||||
|
IfcStore.add_transaction(self, rollback=self.rollback, commit=lambda data: True)
|
||||||
|
result = self._execute(context)
|
||||||
|
self.transaction_data = {"file": self.file}
|
||||||
|
IfcStore.add_transaction(self, rollback=lambda data: True, commit=self.commit)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def _execute(self, context):
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
if self.file:
|
if self.file:
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
@@ -25,9 +33,6 @@ class CreateProject(bpy.types.Operator):
|
|||||||
)
|
)
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
|
|
||||||
self.transaction_data = {"file": self.file}
|
|
||||||
IfcStore.add_transaction(self)
|
|
||||||
|
|
||||||
bpy.ops.bim.add_person()
|
bpy.ops.bim.add_person()
|
||||||
bpy.ops.bim.add_organisation()
|
bpy.ops.bim.add_organisation()
|
||||||
|
|
||||||
@@ -53,9 +58,9 @@ class CreateProject(bpy.types.Operator):
|
|||||||
bpy.ops.bim.assign_class(
|
bpy.ops.bim.assign_class(
|
||||||
transaction_key=self.transaction_key, obj=building_storey.name, ifc_class="IfcBuildingStorey"
|
transaction_key=self.transaction_key, obj=building_storey.name, ifc_class="IfcBuildingStorey"
|
||||||
)
|
)
|
||||||
bpy.ops.bim.assign_object(related_object=site.name, relating_object=project.name)
|
bpy.ops.bim.assign_object(transaction_key=self.transaction_key, related_object=site.name, relating_object=project.name)
|
||||||
bpy.ops.bim.assign_object(related_object=building.name, relating_object=site.name)
|
bpy.ops.bim.assign_object(transaction_key=self.transaction_key, related_object=building.name, relating_object=site.name)
|
||||||
bpy.ops.bim.assign_object(related_object=building_storey.name, relating_object=building.name)
|
bpy.ops.bim.assign_object(transaction_key=self.transaction_key, related_object=building_storey.name, relating_object=building.name)
|
||||||
|
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
@@ -75,6 +80,14 @@ class CreateProjectLibrary(bpy.types.Operator):
|
|||||||
transaction_key: bpy.props.StringProperty()
|
transaction_key: bpy.props.StringProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
|
IfcStore.generate_transaction_key(self)
|
||||||
|
IfcStore.add_transaction(self, rollback=self.rollback, commit=lambda data: True)
|
||||||
|
result = self._execute(context)
|
||||||
|
self.transaction_data = {"file": self.file}
|
||||||
|
IfcStore.add_transaction(self, rollback=lambda data: True, commit=self.commit)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def _execute(self, context):
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
if self.file:
|
if self.file:
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
@@ -84,9 +97,6 @@ class CreateProjectLibrary(bpy.types.Operator):
|
|||||||
)
|
)
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
|
|
||||||
self.transaction_data = {"file": self.file}
|
|
||||||
IfcStore.add_transaction(self)
|
|
||||||
|
|
||||||
if self.file.schema == "IFC2X3":
|
if self.file.schema == "IFC2X3":
|
||||||
bpy.ops.bim.add_person()
|
bpy.ops.bim.add_person()
|
||||||
bpy.ops.bim.add_organisation()
|
bpy.ops.bim.add_organisation()
|
||||||
@@ -116,12 +126,15 @@ class SelectLibraryFile(bpy.types.Operator):
|
|||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
old_filepath = IfcStore.library_path
|
old_filepath = IfcStore.library_path
|
||||||
|
result = self._execute(context)
|
||||||
|
self.transaction_data = {"old_filepath": old_filepath, "filepath": self.filepath}
|
||||||
|
IfcStore.add_transaction(self)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def _execute(self, context):
|
||||||
IfcStore.library_path = self.filepath
|
IfcStore.library_path = self.filepath
|
||||||
IfcStore.library_file = ifcopenshell.open(self.filepath)
|
IfcStore.library_file = ifcopenshell.open(self.filepath)
|
||||||
bpy.ops.bim.refresh_library()
|
bpy.ops.bim.refresh_library()
|
||||||
|
|
||||||
self.transaction_data = {"old_filepath": old_filepath, "filepath": self.filepath}
|
|
||||||
IfcStore.add_transaction(self)
|
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
def invoke(self, context, event):
|
def invoke(self, context, event):
|
||||||
@@ -217,23 +230,28 @@ class AssignLibraryDeclaration(bpy.types.Operator):
|
|||||||
bl_idname = "bim.assign_library_declaration"
|
bl_idname = "bim.assign_library_declaration"
|
||||||
bl_label = "Assign Library Declaration"
|
bl_label = "Assign Library Declaration"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
transaction_key: bpy.props.StringProperty()
|
||||||
definition: bpy.props.IntProperty()
|
definition: bpy.props.IntProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
|
IfcStore.library_file.begin_transaction()
|
||||||
|
result = self._execute(context)
|
||||||
|
IfcStore.library_file.end_transaction()
|
||||||
|
IfcStore.add_transaction(self)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def _execute(self, context):
|
||||||
self.props = context.scene.BIMProjectProperties
|
self.props = context.scene.BIMProjectProperties
|
||||||
self.file = IfcStore.library_file
|
self.file = IfcStore.library_file
|
||||||
self.file.begin_transaction()
|
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"project.assign_declaration",
|
"project.assign_declaration",
|
||||||
self.file,
|
self.file,
|
||||||
definition=self.file.by_id(self.definition),
|
definition=self.file.by_id(self.definition),
|
||||||
relating_context=self.file.by_type("IfcProjectLibrary")[0],
|
relating_context=self.file.by_type("IfcProjectLibrary")[0],
|
||||||
)
|
)
|
||||||
self.file.end_transaction()
|
|
||||||
element_name = self.props.active_library_element
|
element_name = self.props.active_library_element
|
||||||
bpy.ops.bim.rewind_library()
|
bpy.ops.bim.rewind_library()
|
||||||
bpy.ops.bim.change_library_element(element_name=element_name)
|
bpy.ops.bim.change_library_element(element_name=element_name)
|
||||||
IfcStore.add_transaction(self)
|
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
def rollback(self, data):
|
def rollback(self, data):
|
||||||
@@ -247,23 +265,28 @@ class UnassignLibraryDeclaration(bpy.types.Operator):
|
|||||||
bl_idname = "bim.unassign_library_declaration"
|
bl_idname = "bim.unassign_library_declaration"
|
||||||
bl_label = "Unassign Library Declaration"
|
bl_label = "Unassign Library Declaration"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
transaction_key: bpy.props.StringProperty()
|
||||||
definition: bpy.props.IntProperty()
|
definition: bpy.props.IntProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
|
IfcStore.library_file.begin_transaction()
|
||||||
|
result = self._execute(context)
|
||||||
|
IfcStore.library_file.end_transaction()
|
||||||
|
IfcStore.add_transaction(self)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def _execute(self, context):
|
||||||
self.props = context.scene.BIMProjectProperties
|
self.props = context.scene.BIMProjectProperties
|
||||||
self.file = IfcStore.library_file
|
self.file = IfcStore.library_file
|
||||||
self.file.begin_transaction()
|
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"project.unassign_declaration",
|
"project.unassign_declaration",
|
||||||
self.file,
|
self.file,
|
||||||
definition=self.file.by_id(self.definition),
|
definition=self.file.by_id(self.definition),
|
||||||
relating_context=self.file.by_type("IfcProjectLibrary")[0],
|
relating_context=self.file.by_type("IfcProjectLibrary")[0],
|
||||||
)
|
)
|
||||||
self.file.end_transaction()
|
|
||||||
element_name = self.props.active_library_element
|
element_name = self.props.active_library_element
|
||||||
bpy.ops.bim.rewind_library()
|
bpy.ops.bim.rewind_library()
|
||||||
bpy.ops.bim.change_library_element(element_name=element_name)
|
bpy.ops.bim.change_library_element(element_name=element_name)
|
||||||
IfcStore.add_transaction(self)
|
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
def rollback(self, data):
|
def rollback(self, data):
|
||||||
@@ -286,21 +309,22 @@ class AppendLibraryElement(bpy.types.Operator):
|
|||||||
bl_idname = "bim.append_library_element"
|
bl_idname = "bim.append_library_element"
|
||||||
bl_label = "Append Library Element"
|
bl_label = "Append Library Element"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
transaction_key: bpy.props.StringProperty()
|
||||||
definition: bpy.props.IntProperty()
|
definition: 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()
|
||||||
self.file.begin_transaction()
|
|
||||||
element = ifcopenshell.api.run(
|
element = ifcopenshell.api.run(
|
||||||
"project.append_asset",
|
"project.append_asset",
|
||||||
self.file,
|
self.file,
|
||||||
library=IfcStore.library_file,
|
library=IfcStore.library_file,
|
||||||
element=IfcStore.library_file.by_id(self.definition),
|
element=IfcStore.library_file.by_id(self.definition),
|
||||||
)
|
)
|
||||||
self.file.end_transaction()
|
|
||||||
self.import_type_from_ifc(element)
|
self.import_type_from_ifc(element)
|
||||||
blenderbim.bim.handler.purge_module_data()
|
blenderbim.bim.handler.purge_module_data()
|
||||||
IfcStore.add_transaction(self)
|
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
def import_type_from_ifc(self, element):
|
def import_type_from_ifc(self, element):
|
||||||
@@ -322,12 +346,6 @@ class AppendLibraryElement(bpy.types.Operator):
|
|||||||
ifc_importer.create_type_product(element)
|
ifc_importer.create_type_product(element)
|
||||||
ifc_importer.place_objects_in_spatial_tree()
|
ifc_importer.place_objects_in_spatial_tree()
|
||||||
|
|
||||||
def rollback(self, data):
|
|
||||||
IfcStore.get_file().undo()
|
|
||||||
|
|
||||||
def commit(self, data):
|
|
||||||
IfcStore.get_file().redo()
|
|
||||||
|
|
||||||
|
|
||||||
class EnableEditingHeader(bpy.types.Operator):
|
class EnableEditingHeader(bpy.types.Operator):
|
||||||
bl_idname = "bim.enable_editing_header"
|
bl_idname = "bim.enable_editing_header"
|
||||||
@@ -367,24 +385,27 @@ class EditHeader(bpy.types.Operator):
|
|||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
|
self.transaction_data = {}
|
||||||
|
self.transaction_data["old"] = self.record_state()
|
||||||
|
result = self._execute(context)
|
||||||
|
self.transaction_data["new"] = self.record_state()
|
||||||
|
IfcStore.add_transaction(self)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def _execute(self, context):
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
props = context.scene.BIMProjectProperties
|
props = context.scene.BIMProjectProperties
|
||||||
props.is_editing = True
|
props.is_editing = True
|
||||||
|
|
||||||
self.transaction_data = {}
|
|
||||||
self.transaction_data["old"] = self.record_state()
|
|
||||||
|
|
||||||
self.file.wrapped_data.header.file_description.description = (f"ViewDefinition[{props.mvd}]",)
|
self.file.wrapped_data.header.file_description.description = (f"ViewDefinition[{props.mvd}]",)
|
||||||
self.file.wrapped_data.header.file_name.author = (props.author_name, props.author_email)
|
self.file.wrapped_data.header.file_name.author = (props.author_name, props.author_email)
|
||||||
self.file.wrapped_data.header.file_name.organization = (props.organisation_name, props.organisation_email)
|
self.file.wrapped_data.header.file_name.organization = (props.organisation_name, props.organisation_email)
|
||||||
self.file.wrapped_data.header.file_name.authorization = props.authorisation
|
self.file.wrapped_data.header.file_name.authorization = props.authorisation
|
||||||
bpy.ops.bim.disable_editing_header()
|
bpy.ops.bim.disable_editing_header()
|
||||||
|
|
||||||
self.transaction_data["new"] = self.record_state()
|
|
||||||
IfcStore.add_transaction(self)
|
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
def record_state(self):
|
def record_state(self):
|
||||||
|
self.file = IfcStore.get_file()
|
||||||
return {
|
return {
|
||||||
"description": self.file.wrapped_data.header.file_description.description,
|
"description": self.file.wrapped_data.header.file_description.description,
|
||||||
"author": self.file.wrapped_data.header.file_name.author,
|
"author": self.file.wrapped_data.header.file_name.author,
|
||||||
|
|||||||
@@ -88,7 +88,9 @@ class AssignClass(bpy.types.Operator):
|
|||||||
ifc_representation_class: bpy.props.StringProperty()
|
ifc_representation_class: bpy.props.StringProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
self.transaction_data = []
|
return IfcStore.execute_ifc_operator(self, context)
|
||||||
|
|
||||||
|
def _execute(self, context):
|
||||||
objects = [bpy.data.objects.get(self.obj)] if self.obj else bpy.context.selected_objects
|
objects = [bpy.data.objects.get(self.obj)] if self.obj else bpy.context.selected_objects
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
self.declaration = IfcStore.get_schema().declaration_by_name(self.ifc_class)
|
self.declaration = IfcStore.get_schema().declaration_by_name(self.ifc_class)
|
||||||
@@ -98,13 +100,11 @@ class AssignClass(bpy.types.Operator):
|
|||||||
predefined_type = None
|
predefined_type = None
|
||||||
for obj in objects:
|
for obj in objects:
|
||||||
self.assign_class(context, obj)
|
self.assign_class(context, obj)
|
||||||
IfcStore.add_transaction(self)
|
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
def assign_class(self, context, obj):
|
def assign_class(self, context, obj):
|
||||||
if obj.BIMObjectProperties.ifc_definition_id:
|
if obj.BIMObjectProperties.ifc_definition_id:
|
||||||
return
|
return
|
||||||
self.file.begin_transaction()
|
|
||||||
product = ifcopenshell.api.run(
|
product = ifcopenshell.api.run(
|
||||||
"root.create_entity",
|
"root.create_entity",
|
||||||
self.file,
|
self.file,
|
||||||
@@ -114,10 +114,8 @@ class AssignClass(bpy.types.Operator):
|
|||||||
"name": obj.name,
|
"name": obj.name,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
self.file.end_transaction()
|
|
||||||
obj.name = "{}/{}".format(product.is_a(), obj.name)
|
obj.name = "{}/{}".format(product.is_a(), obj.name)
|
||||||
IfcStore.link_element(product, obj)
|
IfcStore.link_element(product, obj)
|
||||||
self.transaction_data.append({"element": product.id(), "obj": obj.name})
|
|
||||||
|
|
||||||
if self.should_add_representation:
|
if self.should_add_representation:
|
||||||
bpy.ops.bim.add_representation(
|
bpy.ops.bim.add_representation(
|
||||||
@@ -162,7 +160,9 @@ class AssignClass(bpy.types.Operator):
|
|||||||
collection.objects.link(obj)
|
collection.objects.link(obj)
|
||||||
if parent_collection:
|
if parent_collection:
|
||||||
parent_collection.children.link(collection)
|
parent_collection.children.link(collection)
|
||||||
bpy.ops.bim.assign_object(related_object=obj.name, relating_object=parent_collection.name)
|
bpy.ops.bim.assign_object(
|
||||||
|
transaction_key=self.transaction_key, related_object=obj.name, relating_object=parent_collection.name
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
bpy.context.scene.collection.children.link(collection)
|
bpy.context.scene.collection.children.link(collection)
|
||||||
|
|
||||||
@@ -177,20 +177,6 @@ class AssignClass(bpy.types.Operator):
|
|||||||
)
|
)
|
||||||
break
|
break
|
||||||
|
|
||||||
def rollback(self, data):
|
|
||||||
for linked_element in data:
|
|
||||||
IfcStore.unlink_element(
|
|
||||||
IfcStore.get_file().by_id(linked_element["element"]), bpy.data.objects.get(linked_element["obj"])
|
|
||||||
)
|
|
||||||
IfcStore.get_file().undo()
|
|
||||||
|
|
||||||
def commit(self, data):
|
|
||||||
IfcStore.get_file().redo()
|
|
||||||
for linked_element in data:
|
|
||||||
IfcStore.link_element(
|
|
||||||
IfcStore.get_file().by_id(linked_element["element"]), bpy.data.objects.get(linked_element["obj"])
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class UnassignClass(bpy.types.Operator):
|
class UnassignClass(bpy.types.Operator):
|
||||||
bl_idname = "bim.unassign_class"
|
bl_idname = "bim.unassign_class"
|
||||||
|
|||||||
Reference in New Issue
Block a user