From b7f574fa30da0f49c9e930a8f0cebc2e28108378 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Sat, 23 Jan 2021 11:58:29 +1100 Subject: [PATCH] WIP implement document assign/unassign. See #1222. --- .../bim/module/document/__init__.py | 9 ++ .../bim/module/document/assign_document.py | 42 ++++++++++ .../bim/module/document/operator.py | 64 ++++++++++++++ .../blenderbim/bim/module/document/prop.py | 8 ++ .../blenderbim/bim/module/document/ui.py | 84 ++++++++++++++++++- .../bim/module/document/unassign_document.py | 17 ++++ 6 files changed, 222 insertions(+), 2 deletions(-) create mode 100644 src/ifcblenderexport/blenderbim/bim/module/document/assign_document.py create mode 100644 src/ifcblenderexport/blenderbim/bim/module/document/unassign_document.py diff --git a/src/ifcblenderexport/blenderbim/bim/module/document/__init__.py b/src/ifcblenderexport/blenderbim/bim/module/document/__init__.py index c13ff1879a..8e62e36825 100644 --- a/src/ifcblenderexport/blenderbim/bim/module/document/__init__.py +++ b/src/ifcblenderexport/blenderbim/bim/module/document/__init__.py @@ -12,16 +12,25 @@ classes = ( operator.EditInformation, operator.EditDocumentReference, operator.RemoveDocument, + operator.EnableAssigningDocument, + operator.DisableAssigningDocument, + operator.AssignDocument, + operator.UnassignDocument, prop.Document, prop.BIMDocumentProperties, + prop.BIMObjectDocumentProperties, ui.BIM_PT_documents, + ui.BIM_PT_object_documents, ui.BIM_UL_documents, + ui.BIM_UL_object_documents, ) def register(): bpy.types.Scene.BIMDocumentProperties = bpy.props.PointerProperty(type=prop.BIMDocumentProperties) + bpy.types.Object.BIMObjectDocumentProperties = bpy.props.PointerProperty(type=prop.BIMObjectDocumentProperties) def unregister(): del bpy.types.Scene.BIMDocumentProperties + del bpy.types.Scene.BIMObjectDocumentProperties diff --git a/src/ifcblenderexport/blenderbim/bim/module/document/assign_document.py b/src/ifcblenderexport/blenderbim/bim/module/document/assign_document.py new file mode 100644 index 0000000000..73c744b7e2 --- /dev/null +++ b/src/ifcblenderexport/blenderbim/bim/module/document/assign_document.py @@ -0,0 +1,42 @@ +import ifcopenshell + + +class Usecase: + def __init__(self, file, settings=None): + self.file = file + self.settings = { + "product": None, + "document": None, + } + for key, value in settings.items(): + self.settings[key] = value + + def execute(self): + rel = self.get_document_rel() + related_objects = set(rel.RelatedObjects) if rel.RelatedObjects else set() + related_objects.add(self.settings["product"]) + rel.RelatedObjects = list(related_objects) + + def get_document_rel(self): + rel = None + if self.file.schema == "IFC2X3": + for association in self.file.by_type("IfcRelAssociatesDocument"): + if association.RelatingDocument == self.settings["document"]: + return rel + else: + if ( + hasattr(self.settings["document"], "DocumentRefForObjects") + and self.settings["document"].DocumentRefForObjects + ): + return self.settings["document"].DocumentRefForObjects[0] + elif ( + hasattr(self.settings["document"], "DocumentInfoForObjects") + and self.settings["document"].DocumentInfoForObjects + ): + return self.settings["document"].DocumentInfoForObjects[0] + + return self.file.create_entity("IfcRelAssociatesDocument", **{ + "GlobalId": ifcopenshell.guid.new(), + # TODO: owner history + "RelatingDocument": self.settings["document"] + }) diff --git a/src/ifcblenderexport/blenderbim/bim/module/document/operator.py b/src/ifcblenderexport/blenderbim/bim/module/document/operator.py index 1eaa68882b..21634cbad6 100644 --- a/src/ifcblenderexport/blenderbim/bim/module/document/operator.py +++ b/src/ifcblenderexport/blenderbim/bim/module/document/operator.py @@ -5,6 +5,8 @@ import blenderbim.bim.module.document.add_reference as add_reference import blenderbim.bim.module.document.edit_information as edit_information import blenderbim.bim.module.document.edit_reference as edit_reference import blenderbim.bim.module.document.remove_document as remove_document +import blenderbim.bim.module.document.assign_document as assign_document +import blenderbim.bim.module.document.unassign_document as unassign_document from blenderbim.bim.ifc import IfcStore from blenderbim.bim.module.document.data import Data @@ -184,3 +186,65 @@ class RemoveDocument(bpy.types.Operator): elif props.is_editing == "reference": bpy.ops.bim.load_document_references() return {"FINISHED"} + + +class EnableAssigningDocument(bpy.types.Operator): + bl_idname = "bim.enable_assigning_document" + bl_label = "Enable Assigning Document" + obj: bpy.props.StringProperty() + + def execute(self, context): + obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object + props = obj.BIMObjectDocumentProperties + if props.available_document_types == "IfcDocumentInformation": + bpy.ops.bim.load_information() + elif props.available_document_types == "IfcDocumentReference": + bpy.ops.bim.load_document_references() + props.is_adding = props.available_document_types + return {"FINISHED"} + + +class DisableAssigningDocument(bpy.types.Operator): + bl_idname = "bim.disable_assigning_document" + bl_label = "Disable Assigning Document" + obj: bpy.props.StringProperty() + + def execute(self, context): + obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object + props = obj.BIMObjectDocumentProperties + props.is_adding = "" + return {"FINISHED"} + + +class AssignDocument(bpy.types.Operator): + bl_idname = "bim.assign_document" + bl_label = "Assign Document" + obj: bpy.props.StringProperty() + document: bpy.props.IntProperty() + + def execute(self, context): + obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object + self.file = IfcStore.get_file() + assign_document.Usecase(self.file, { + "product": self.file.by_id(obj.BIMObjectProperties.ifc_definition_id), + "document": self.file.by_id(self.document) + }).execute() + Data.load(obj.BIMObjectProperties.ifc_definition_id) + return {"FINISHED"} + + +class UnassignDocument(bpy.types.Operator): + bl_idname = "bim.unassign_document" + bl_label = "Unassign Document" + obj: bpy.props.StringProperty() + document: bpy.props.IntProperty() + + def execute(self, context): + obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object + self.file = IfcStore.get_file() + unassign_document.Usecase(self.file, { + "product": self.file.by_id(obj.BIMObjectProperties.ifc_definition_id), + "document": self.file.by_id(self.document) + }).execute() + Data.load(obj.BIMObjectProperties.ifc_definition_id) + return {"FINISHED"} diff --git a/src/ifcblenderexport/blenderbim/bim/module/document/prop.py b/src/ifcblenderexport/blenderbim/bim/module/document/prop.py index 3bb6f0dec9..2208551acf 100644 --- a/src/ifcblenderexport/blenderbim/bim/module/document/prop.py +++ b/src/ifcblenderexport/blenderbim/bim/module/document/prop.py @@ -12,6 +12,7 @@ from bpy.props import ( CollectionProperty, ) + class Document(PropertyGroup): name: StringProperty(name="Name") identification: StringProperty(name="Identification") @@ -24,3 +25,10 @@ class BIMDocumentProperties(PropertyGroup): documents: CollectionProperty(name="Documents", type=Document) active_document_index: IntProperty(name="Active Document Index") is_editing: StringProperty(name="Is Editing") + + +class BIMObjectDocumentProperties(PropertyGroup): + is_adding: StringProperty(name="Is Adding") + available_document_types: EnumProperty( + items=[(d, d, "") for d in ["IfcDocumentInformation", "IfcDocumentReference"]], name="Available Document Types" + ) diff --git a/src/ifcblenderexport/blenderbim/bim/module/document/ui.py b/src/ifcblenderexport/blenderbim/bim/module/document/ui.py index db4fec9545..044440f6a1 100644 --- a/src/ifcblenderexport/blenderbim/bim/module/document/ui.py +++ b/src/ifcblenderexport/blenderbim/bim/module/document/ui.py @@ -23,7 +23,7 @@ class BIM_PT_documents(Panel): if not self.props.is_editing or self.props.is_editing == "information": row = self.layout.row(align=True) - row.label(text="{} Documents Found".format(len(Data.information))) + row.label(text="{} Documents Found".format(len(Data.information)), icon="FILE") if self.props.is_editing == "information": row.operator("bim.disable_document_editing_ui", text="", icon="CHECKMARK") row.operator("bim.add_information", text="", icon="ADD") @@ -32,7 +32,7 @@ class BIM_PT_documents(Panel): if not self.props.is_editing or self.props.is_editing == "reference": row = self.layout.row(align=True) - row.label(text="{} References Found".format(len(Data.references))) + row.label(text="{} References Found".format(len(Data.references)), icon="FILE_HIDDEN") if self.props.is_editing == "reference": row.operator("bim.disable_document_editing_ui", text="", icon="CHECKMARK") row.operator("bim.add_document_reference", text="", icon="ADD") @@ -64,6 +64,77 @@ class BIM_PT_documents(Panel): row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="") +class BIM_PT_object_documents(Panel): + bl_label = "IFC Documents" + bl_idname = "BIM_PT_object_documents" + bl_options = {"DEFAULT_CLOSED"} + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "object" + + @classmethod + def poll(cls, context): + return bool(context.active_object.BIMObjectProperties.ifc_definition_id) + + def draw(self, context): + obj = context.active_object + self.oprops = obj.BIMObjectProperties + self.sprops = context.scene.BIMDocumentProperties + self.props = obj.BIMObjectDocumentProperties + self.file = IfcStore.get_file() + if not Data.is_loaded: + Data.load() + if self.oprops.ifc_definition_id not in Data.products: + Data.load(self.oprops.ifc_definition_id) + + self.draw_add_ui() + + document_ids = Data.products[self.oprops.ifc_definition_id] + + if not document_ids: + row = self.layout.row(align=True) + row.label(text="No Documents", icon="FILE") + + for document_id in document_ids: + try: + document = Data.information[document_id] + document_type = "IfcDocumentInformation" + icon = "FILE" + except: + document = Data.references[document_id] + document_type = "IfcDocumentReference" + icon = "FILE_HIDDEN" + row = self.layout.row(align=True) + if self.file.schema == "IFC2X3": + if document_type == "IfcDocumentInformation": + row.label(text=document.get("DocumentId") or "*", icon=icon) + elif document_type == "IfcDocumentReference": + row.label(text=document.get("ItemReference") or "*", icon=icon) + else: + row.label(text=document.get("Identification") or "*", icon=icon) + row.label(text=document.get("Name") or "Unnamed") + row.operator("bim.unassign_document", text="", icon="X").document = document_id + + def draw_add_ui(self): + if self.props.is_adding: + row = self.layout.row(align=True) + icon = "FILE" if self.props.is_adding == "IfcDocumentInformation" else "FILE_HIDDEN" + row.label(text="Adding {}".format(self.props.is_adding), icon=icon) + row.operator("bim.disable_assigning_document", text="", icon="X") + self.layout.template_list( + "BIM_UL_object_documents", + "", + self.sprops, + "documents", + self.sprops, + "active_document_index", + ) + else: + row = self.layout.row(align=True) + row.prop(self.props, "available_document_types", text="") + row.operator("bim.enable_assigning_document", text="", icon="ADD") + + class BIM_UL_documents(UIList): def draw_item(self, context, layout, data, item, icon, active_data, active_propname): if item: @@ -82,3 +153,12 @@ class BIM_UL_documents(UIList): op = row.operator("bim.enable_editing_document", text="", icon="GREASEPENCIL") op.document = item.ifc_definition_id row.operator("bim.remove_document", text="", icon="X").document = item.ifc_definition_id + + +class BIM_UL_object_documents(UIList): + def draw_item(self, context, layout, data, item, icon, active_data, active_propname): + if item: + row = layout.row(align=True) + row.label(text=item.identification) + row.label(text=item.name) + row.operator("bim.assign_document", text="", icon="ADD").document = item.ifc_definition_id diff --git a/src/ifcblenderexport/blenderbim/bim/module/document/unassign_document.py b/src/ifcblenderexport/blenderbim/bim/module/document/unassign_document.py new file mode 100644 index 0000000000..a1bdf6c158 --- /dev/null +++ b/src/ifcblenderexport/blenderbim/bim/module/document/unassign_document.py @@ -0,0 +1,17 @@ +import ifcopenshell + + +class Usecase: + def __init__(self, file, settings=None): + self.file = file + self.settings = { + "product": None, + "document": None, + } + for key, value in settings.items(): + self.settings[key] = value + + def execute(self): + for rel in self.settings["product"].HasAssociations: + if rel.is_a("IfcRelAssociatesDocument") and rel.RelatingDocument == self.settings["document"]: + self.file.remove(rel)