From 128fe66837f662ea835c207008d3b778436553c9 Mon Sep 17 00:00:00 2001 From: falken10 Date: Tue, 8 Jul 2025 19:45:12 +0200 Subject: [PATCH] cleanup and formatting --- .../bonsai/bim/module/document/__init__.py | 1 - src/bonsai/bonsai/bim/module/document/data.py | 24 ++------ .../bonsai/bim/module/document/operator.py | 32 +++++------ src/bonsai/bonsai/bim/module/document/prop.py | 31 +--------- src/bonsai/bonsai/bim/module/document/ui.py | 56 ++++++++++--------- src/bonsai/bonsai/core/document.py | 6 +- src/bonsai/bonsai/tool/document.py | 44 ++------------- 7 files changed, 64 insertions(+), 130 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/document/__init__.py b/src/bonsai/bonsai/bim/module/document/__init__.py index d2da8285b9..cc71d16306 100644 --- a/src/bonsai/bonsai/bim/module/document/__init__.py +++ b/src/bonsai/bonsai/bim/module/document/__init__.py @@ -37,7 +37,6 @@ classes = ( operator.OpenIFCDocument, prop.Document, prop.DocumentObject, - prop.AssignedDocument, prop.BIMDocumentProperties, ui.BIM_PT_documents, ui.BIM_PT_object_documents, diff --git a/src/bonsai/bonsai/bim/module/document/data.py b/src/bonsai/bonsai/bim/module/document/data.py index 7f788b1388..0ba0106881 100644 --- a/src/bonsai/bonsai/bim/module/document/data.py +++ b/src/bonsai/bonsai/bim/module/document/data.py @@ -23,10 +23,6 @@ import ifcopenshell.util.schema import bonsai.tool as tool from natsort import natsorted -def refresh(): - DocumentData.is_loaded = False - ObjectDocumentData.is_loaded = False - class DocumentData: data = {} @@ -35,24 +31,16 @@ class DocumentData: @classmethod def load(cls): cls.data = { - "total_document_informations": cls.total_document_informations(), - "total_document_references": cls.total_document_references(), + "total_documents": cls.total_documents(), "total_referenced_objects": cls.total_referenced_objects(), "document_objects": cls.document_objects(), } cls.is_loaded = True @classmethod - def total_document_informations(cls): + def total_documents(cls): file = tool.Ifc.get() - info_count = len(file.by_type("IfcDocumentInformation")) - return info_count - - @classmethod - def total_document_references(cls): - file = tool.Ifc.get() - ref_count = len(file.by_type("IfcDocumentReference")) - return ref_count + return len(file.by_type("IfcDocumentInformation")) + len(file.by_type("IfcDocumentReference")) @classmethod def total_referenced_objects(cls): @@ -89,7 +77,7 @@ class DocumentData: def load_document_objects_into_props(cls, document_id): if not cls.is_loaded: cls.load() - + props = tool.Document.get_document_props() props.document_objects.clear() @@ -102,6 +90,7 @@ class DocumentData: item = props.document_objects.add() item.name = obj_data["name"] + class ObjectDocumentData: data = {} is_loaded = False @@ -117,7 +106,7 @@ class ObjectDocumentData: def convert_to_file_uri(location: str) -> str: if not location: return "" - + uri = location if not uri.startswith("file://"): if not os.path.isabs(uri): @@ -125,7 +114,6 @@ class ObjectDocumentData: uri = "file://" + uri return uri - @classmethod def documents(cls): results = [] diff --git a/src/bonsai/bonsai/bim/module/document/operator.py b/src/bonsai/bonsai/bim/module/document/operator.py index 557e2c72af..c2ccd5edc9 100644 --- a/src/bonsai/bonsai/bim/module/document/operator.py +++ b/src/bonsai/bonsai/bim/module/document/operator.py @@ -23,6 +23,7 @@ import bonsai.tool as tool import bonsai.core.document as core from .data import DocumentData, ObjectDocumentData + class LoadProjectDocuments(bpy.types.Operator): bl_idname = "bim.load_project_documents" bl_label = "Load Project Documents" @@ -32,6 +33,7 @@ class LoadProjectDocuments(bpy.types.Operator): core.load_project_documents(tool.Document) return {"FINISHED"} + class DisableDocumentEditingUI(bpy.types.Operator): bl_idname = "bim.disable_document_editing_ui" bl_label = "Disable Document Editing UI" @@ -109,6 +111,7 @@ class AddInformation(bpy.types.Operator, tool.Ifc.Operator): props.json_string = json.dumps(expanded_docs) bpy.ops.bim.load_project_documents() + class AddDocumentReference(bpy.types.Operator, tool.Ifc.Operator): bl_idname = "bim.add_document_reference" bl_label = "Add Document Reference" @@ -154,8 +157,6 @@ class EditDocument(bpy.types.Operator, tool.Ifc.Operator): if props.active_document_id: core.edit_document(tool.Ifc, tool.Document, document=tool.Ifc.get().by_id(props.active_document_id)) props.active_document_id = 0 - props.is_document_editing = False - tool.Document.update_assigned_documents() class RemoveDocument(bpy.types.Operator, tool.Ifc.Operator): @@ -167,6 +168,7 @@ class RemoveDocument(bpy.types.Operator, tool.Ifc.Operator): def _execute(self, context): core.remove_document(tool.Ifc, tool.Document, document=tool.Ifc.get().by_id(self.document)) + class AssignDocument(bpy.types.Operator, tool.Ifc.Operator): bl_idname = "bim.assign_document" bl_label = "Assign Document" @@ -183,11 +185,9 @@ class AssignDocument(bpy.types.Operator, tool.Ifc.Operator): if element: core.assign_document(tool.Ifc, product=element, document=document) - tool.Document.update_document_objects(self.document) ObjectDocumentData.is_loaded = False ObjectDocumentData.load() - tool.Document.update_assigned_documents() return {"FINISHED"} @@ -206,7 +206,7 @@ class UnassignDocument(bpy.types.Operator, tool.Ifc.Operator): element = tool.Ifc.get_entity(obj) if element: core.unassign_document(tool.Ifc, product=element, document=document) - + props = tool.Document.get_document_props() active_document_id = None if props.active_document: @@ -216,11 +216,9 @@ class UnassignDocument(bpy.types.Operator, tool.Ifc.Operator): tool.Document.update_document_objects(active_document_id) else: tool.Document.update_document_objects() - + ObjectDocumentData.is_loaded = False ObjectDocumentData.load() - - tool.Document.update_assigned_documents() return {"FINISHED"} @@ -253,16 +251,12 @@ class LoadObjectDocuments(bpy.types.Operator): bl_options = {"REGISTER", "UNDO"} def execute(self, context): - if not ObjectDocumentData.is_loaded: - ObjectDocumentData.load() - core.load_project_documents(tool.Document) props = tool.Document.get_document_props() props.is_object_editing = True - - tool.Document.update_assigned_documents() - + ObjectDocumentData.is_loaded = False + ObjectDocumentData.load() return {"FINISHED"} @@ -277,19 +271,24 @@ class OpenIFCDocument(bpy.types.Operator): def execute(self, context): import subprocess import os + if not self.uri or not self.uri.lower().startswith("file://"): self.report({"ERROR"}, "Only local file:// URIs are supported") return {"CANCELLED"} filepath = self.uri[7:] # Remove file:// prefix - + if not os.path.exists(filepath): self.report({"ERROR"}, f"File not found: {filepath}") return {"CANCELLED"} try: blender_path = bpy.app.binary_path - args = [blender_path, "--python-expr", "import bpy; bpy.ops.bim.load_project(filepath='{}')".format(filepath)] + args = [ + blender_path, + "--python-expr", + "import bpy; bpy.ops.bim.load_project(filepath='{}')".format(filepath), + ] subprocess.Popen(args) self.report({"INFO"}, f"Opening {filepath} in a new Blender instance") except Exception as e: @@ -325,4 +324,3 @@ class ToggleDocument(bpy.types.Operator): props.json_string = json.dumps(expanded_documents) bpy.ops.bim.load_project_documents() return {"FINISHED"} - diff --git a/src/bonsai/bonsai/bim/module/document/prop.py b/src/bonsai/bonsai/bim/module/document/prop.py index b0964dd5c9..5d9a978c69 100644 --- a/src/bonsai/bonsai/bim/module/document/prop.py +++ b/src/bonsai/bonsai/bim/module/document/prop.py @@ -51,7 +51,7 @@ def update_document_identification(self: "Document", context: bpy.types.Context) def update_active_document(self, context): - if (document := self.active_document): + if document := self.active_document: if document.ifc_definition_id: DocumentData.load_document_objects_into_props(document.ifc_definition_id) @@ -72,7 +72,7 @@ class Document(PropertyGroup): ("INFORMATION", "Information", "IfcDocumentInformation"), ("REFERENCE", "Reference", "IfcDocumentReference"), ], - default="INFORMATION" + default="INFORMATION", ) if TYPE_CHECKING: @@ -96,41 +96,15 @@ class DocumentObject(PropertyGroup): ifc_definition_id: int -class AssignedDocument(PropertyGroup): - name: StringProperty(name="Name") - identification: StringProperty(name="Identification") - description: StringProperty(name="Description", default="") - ifc_definition_id: IntProperty(name="IFC Definition ID") - location: StringProperty(name="Location", default="") - document_type: EnumProperty( - name="Document Type", - items=[ - ("PROJECT", "Project", "Virtual project root node"), - ("INFORMATION", "Information", "IfcDocumentInformation"), - ("REFERENCE", "Reference", "IfcDocumentReference"), - ], - default="INFORMATION" - ) - - if TYPE_CHECKING: - name: str - identification: str - ifc_definition_id: int - location: str - document_type: str - class BIMDocumentProperties(PropertyGroup): document_attributes: CollectionProperty(name="Document Attributes", type=Attribute) active_document_id: IntProperty(name="Active Document Id") documents: CollectionProperty(name="Documents", type=Document) active_document_index: IntProperty(name="Active Document Index", update=update_active_document) is_editing: BoolProperty(name="Is Editing", default=False) - is_document_editing: BoolProperty(name="Is Document Editing", default=False) is_object_editing: BoolProperty(name="Is Object Editing", default=False) document_objects: CollectionProperty(name="Document Objects", type=DocumentObject) active_document_object_index: IntProperty(name="Active Document Object Index") - assigned_documents: CollectionProperty(name="Assigned Documents", type=AssignedDocument) - active_assigned_document_index: IntProperty(name="Active Assigned Document Index") json_string: StringProperty(name="JSON String", default="[]") if TYPE_CHECKING: @@ -139,7 +113,6 @@ class BIMDocumentProperties(PropertyGroup): documents: bpy.types.bpy_prop_collection_idprop[Document] active_document_index: int is_editing: bool - is_document_editing: bool is_object_editing: bool document_objects: bpy.types.bpy_prop_collection_idprop[DocumentObject] active_document_object_index: int diff --git a/src/bonsai/bonsai/bim/module/document/ui.py b/src/bonsai/bonsai/bim/module/document/ui.py index a742130f94..84f7d04632 100644 --- a/src/bonsai/bonsai/bim/module/document/ui.py +++ b/src/bonsai/bonsai/bim/module/document/ui.py @@ -22,6 +22,7 @@ from bpy.types import Panel, UIList from bonsai.bim.helper import draw_attributes from .data import DocumentData, ObjectDocumentData + class BIM_PT_documents(Panel): bl_label = "Documents" bl_idname = "BIM_PT_documents" @@ -45,9 +46,7 @@ class BIM_PT_documents(Panel): split = row.split(factor=0.55) left_row = split.row(align=True) - total_documents = DocumentData.data["total_document_informations"] + DocumentData.data["total_document_references"] - left_row.label(text="{} Documents".format(total_documents), icon="FILE") - + left_row.label(text="{} Documents".format(DocumentData.data["total_documents"]), icon="FILE") right_row = split.row(align=True) right_row.label( text="{} Objects Referenced".format(DocumentData.data["total_referenced_objects"]), icon="OBJECT_DATA" @@ -63,7 +62,7 @@ class BIM_PT_documents(Panel): row = self.layout.row(align=True) row.alignment = "RIGHT" - if self.props.is_document_editing: + if self.props.active_document_id > 0: row.operator("bim.edit_document", text="", icon="CHECKMARK") row.operator("bim.disable_editing_document", text="", icon="CANCEL") else: @@ -71,25 +70,27 @@ class BIM_PT_documents(Panel): row.operator("bim.add_information", text="", icon="ADD") if self.props.active_document and ( - self.props.active_document.document_type == "INFORMATION" and - self.props.active_document.document_type != "PROJECT" + self.props.active_document.document_type == "INFORMATION" + and self.props.active_document.document_type != "PROJECT" ): row.operator("bim.add_document_reference", text="", icon="FILE_HIDDEN") active_document = self.props.active_document if active_document: ifc_definition_id = active_document.ifc_definition_id - + if active_document.document_type != "PROJECT": row.operator("bim.select_document_objects", text="", icon="RESTRICT_SELECT_OFF").document = ( ifc_definition_id ) row.operator("bim.assign_document", text="", icon="BRUSH_DATA").document = ifc_definition_id - row.operator("bim.enable_editing_document", text="", icon="GREASEPENCIL").document = ifc_definition_id - row.operator("bim.remove_document", text="", icon="X").document = ifc_definition_id + row.operator("bim.enable_editing_document", text="", icon="GREASEPENCIL").document = ( + ifc_definition_id + ) + row.operator("bim.remove_document", text="", icon="X").document = ifc_definition_id self.layout.template_list("BIM_UL_documents", "", self.props, "documents", self.props, "active_document_index") - if self.props.is_document_editing: + if self.props.active_document_id > 0: active_document = self.props.active_document draw_attributes(self.props.document_attributes, self.layout) @@ -107,6 +108,7 @@ class BIM_PT_documents(Panel): "active_document_object_index", ) + class BIM_PT_object_documents(Panel): bl_label = "Documents" bl_idname = "BIM_PT_object_documents" @@ -161,25 +163,27 @@ class BIM_PT_object_documents(Panel): col = box.column(align=True) for document in ObjectDocumentData.data["documents"]: row = col.row(align=True) - + # Create a split layout to separate left and right sides split = row.split(factor=0.7) # Adjust factor as needed (0.7 = 70% left, 30% right) - + # Left side - Document identification and name left_side = split.row(align=True) - left_side.alignment = 'LEFT' + left_side.alignment = "LEFT" left_side.label(text=document["identification"] or "*", icon="FILE") left_side.label(text=document["name"] or "Unnamed") - + # Right side - Action buttons right_side = split.row(align=True) - right_side.alignment = 'RIGHT' # Align buttons to the right - + right_side.alignment = "RIGHT" # Align buttons to the right + if document["location"]: if document["location"].lower().endswith(".ifc"): - right_side.operator("bim.open_ifc_document", icon="HIDE_OFF", text="").uri = document["location"] + right_side.operator("bim.open_ifc_document", icon="HIDE_OFF", text="").uri = document[ + "location" + ] right_side.operator("bim.open_uri", icon="URL", text="").uri = document["location"] - + right_side.operator("bim.unassign_document", text="", icon="X").document = document["id"] def draw_add_ui(self): @@ -194,9 +198,11 @@ class BIM_PT_object_documents(Panel): for doc in ObjectDocumentData.data["documents"]: assigned_doc_ids.append(doc["id"]) - if (document.document_type == "INFORMATION" and - document.document_type != "PROJECT" and - document.ifc_definition_id not in assigned_doc_ids): + if ( + document.document_type == "INFORMATION" + and document.document_type != "PROJECT" + and document.ifc_definition_id not in assigned_doc_ids + ): doc_op = row.operator("bim.assign_document", text="", icon="BRUSH_DATA") doc_op.document = document.ifc_definition_id elif document.ifc_definition_id in assigned_doc_ids: @@ -215,15 +221,15 @@ class BIM_UL_documents(UIList): if item.document_type != "PROJECT": if item.tree_depth > 1: indent_depth = item.tree_depth - 1 - + for i in range(indent_depth): row.label(text="", icon="BLANK1") - + if item.document_type == "PROJECT": row.label(text="", icon="OUTLINER_COLLECTION") row.label(text=item.name) return - + if item.document_type == "INFORMATION" and item.has_children: op = row.operator( "bim.toggle_document", icon="TRIA_DOWN" if item.is_expanded else "TRIA_RIGHT", text="", emboss=False @@ -232,7 +238,7 @@ class BIM_UL_documents(UIList): op.option = "Collapse" if item.is_expanded else "Expand" elif item.document_type == "INFORMATION": row.label(text="", icon="BLANK1") - + if item.document_type == "INFORMATION": row.label(text="", icon="FILE") text = " - ".join([x for x in [item.name, item.location] if x]) diff --git a/src/bonsai/bonsai/core/document.py b/src/bonsai/bonsai/core/document.py index e55c077022..07a167c785 100644 --- a/src/bonsai/bonsai/core/document.py +++ b/src/bonsai/bonsai/core/document.py @@ -29,27 +29,29 @@ def load_project_documents(document: tool.Document) -> None: document.import_project_documents() document.enable_editing_ui() + def disable_document_editing_ui(document: tool.Document) -> None: document.disable_editing_ui() document.disable_editing_document() + def disable_object_document_editing_ui(document: tool.Document) -> None: props = document.get_document_props() props.is_object_editing = False + def enable_editing_document(document_tool: tool.Document, document: ifcopenshell.entity_instance) -> None: props = document_tool.get_document_props() - props.is_document_editing = True document_tool.set_active_document(document) document_tool.import_document_attributes(document) def disable_editing_document(document: tool.Document) -> None: props = document.get_document_props() - props.is_document_editing = False document.clear_active_document() document.clear_document_attributes() + def add_information(ifc: tool.Ifc, document_tool: tool.Document, parent=None) -> ifcopenshell.entity_instance: document_tool.clear_document_tree() diff --git a/src/bonsai/bonsai/tool/document.py b/src/bonsai/bonsai/tool/document.py index cd51f35e8d..bbc20663dc 100644 --- a/src/bonsai/bonsai/tool/document.py +++ b/src/bonsai/bonsai/tool/document.py @@ -153,8 +153,7 @@ class Document(bonsai.core.tool.Document): if root.is_expanded: root_documents = natsorted( - root_documents, - key=lambda doc: (cls.get_document_information_id(doc) or "", doc.Name or "") + root_documents, key=lambda doc: (cls.get_document_information_id(doc) or "", doc.Name or "") ) for doc in root_documents: @@ -204,21 +203,17 @@ class Document(bonsai.core.tool.Document): ref_children = [d for d in children if not d.is_a("IfcDocumentInformation")] info_children = natsorted( - info_children, - key=lambda doc: (cls.get_document_information_id(doc) or "", doc.Name or "") + info_children, key=lambda doc: (cls.get_document_information_id(doc) or "", doc.Name or "") ) ref_children = natsorted( ref_children, - key=lambda doc: ( - cls.get_external_reference_id(doc) or "", - doc.Description or doc.Name or "" - ) + key=lambda doc: (cls.get_external_reference_id(doc) or "", doc.Description or doc.Name or ""), ) for child in info_children + ref_children: cls._process_document(child, props, document_children, expanded_documents, depth + 1) - + @classmethod def is_document_information(cls, document: ifcopenshell.entity_instance) -> bool: return document.is_a("IfcDocumentInformation") @@ -295,12 +290,14 @@ class Document(bonsai.core.tool.Document): @classmethod def refresh_document_data(cls) -> None: import bonsai.bim.module.document.data as document_data + document_data.DocumentData.is_loaded = False document_data.DocumentData.load() @classmethod def load_document_objects_into_props(cls, document_id: int) -> None: import bonsai.bim.module.document.data as document_data + document_data.DocumentData.load_document_objects_into_props(document_id) @classmethod @@ -314,32 +311,3 @@ class Document(bonsai.core.tool.Document): if document_id: cls.load_document_objects_into_props(document_id) - - @classmethod - def update_assigned_documents(cls) -> None: - from bonsai.bim.module.document.data import ObjectDocumentData - - ObjectDocumentData.is_loaded = False - - props = cls.get_document_props() - props.assigned_documents.clear() - - if not ObjectDocumentData.is_loaded: - ObjectDocumentData.load() - - if not ObjectDocumentData.data.get("documents"): - return - - sorted_docs = sorted( - ObjectDocumentData.data["documents"], - key=lambda doc: ((doc.get("identification") or "").lower(), (doc.get("name") or "").lower()), - ) - - for document in sorted_docs: - new = props.assigned_documents.add() - new.name = document["name"] or "Unnamed" - new.identification = document["identification"] or "*" - new.document_type = "INFORMATION" if document.get("is_information", False) else "REFERENCE" - new.ifc_definition_id = document["id"] - new.location = document.get("location") or "" - new.description = document.get("description") or "" \ No newline at end of file