From cb89fbfd86cc8dfef45712c1fb2d6c85f5afc04d Mon Sep 17 00:00:00 2001 From: falken10vdl Date: Tue, 4 Nov 2025 14:19:43 +0100 Subject: [PATCH] Add attribute info for relating type --- src/bonsai/bonsai/bim/module/type/__init__.py | 4 + src/bonsai/bonsai/bim/module/type/data.py | 23 ++++++ src/bonsai/bonsai/bim/module/type/operator.py | 78 +++++++++++++++++++ src/bonsai/bonsai/bim/module/type/prop.py | 5 ++ src/bonsai/bonsai/bim/module/type/ui.py | 48 +++++++++++- 5 files changed, 157 insertions(+), 1 deletion(-) diff --git a/src/bonsai/bonsai/bim/module/type/__init__.py b/src/bonsai/bonsai/bim/module/type/__init__.py index 646ab48fcf..b77bcbfb8e 100644 --- a/src/bonsai/bonsai/bim/module/type/__init__.py +++ b/src/bonsai/bonsai/bim/module/type/__init__.py @@ -23,8 +23,11 @@ classes = ( operator.AssignType, operator.AutoRenameOccurrences, operator.DisableEditingType, + operator.DisableEditingTypeAttributes, operator.DuplicateType, + operator.EditTypeAttributes, operator.EnableEditingType, + operator.EnableEditingTypeAttributes, operator.RemoveType, operator.RenameType, operator.SelectSimilarType, @@ -33,6 +36,7 @@ classes = ( operator.UnassignType, prop.BIMTypeProperties, ui.BIM_PT_type, + ui.BIM_PT_type_attributes, ) diff --git a/src/bonsai/bonsai/bim/module/type/data.py b/src/bonsai/bonsai/bim/module/type/data.py index d93b86261d..119456875a 100644 --- a/src/bonsai/bonsai/bim/module/type/data.py +++ b/src/bonsai/bonsai/bim/module/type/data.py @@ -42,6 +42,7 @@ class TypeData: "is_product": cls.is_product(), "total_instances": cls.total_instances(), "relating_type": cls.relating_type(), + "relating_type_attributes": cls.relating_type_attributes(), } ) @@ -92,3 +93,25 @@ class TypeData: element_type = ifcopenshell.util.element.get_type(element) if element_type: return {"id": element_type.id(), "name": f"{element_type.is_a()}/{element_type.Name or 'Unnamed'}"} + + @classmethod + def relating_type_attributes(cls): + results = [] + element = tool.Ifc.get_entity(bpy.context.active_object) + element_type = ifcopenshell.util.element.get_type(element) + if not element_type: + return results + + data = element_type.get_info() + if "GlobalId" in data: + excluded_keys = ["id", "type"] + else: + excluded_keys = ["type"] + exclude_value_types = (tuple, ifcopenshell.entity_instance) + for key, value in data.items(): + if value is None or isinstance(value, exclude_value_types) or key in excluded_keys: + continue + if key == "id": + key = "STEP ID" + results.append({"name": key, "value": str(value)}) + return results diff --git a/src/bonsai/bonsai/bim/module/type/operator.py b/src/bonsai/bonsai/bim/module/type/operator.py index 60a52fdb9b..b09b9fe5a8 100644 --- a/src/bonsai/bonsai/bim/module/type/operator.py +++ b/src/bonsai/bonsai/bim/module/type/operator.py @@ -24,6 +24,7 @@ import ifcopenshell.util.representation import ifcopenshell.util.type import ifcopenshell.util.unit import ifcopenshell.api +import ifcopenshell.api.attribute import ifcopenshell.api.type import bonsai.bim.helper import bonsai.tool as tool @@ -416,3 +417,80 @@ class DuplicateType(bpy.types.Operator, tool.Ifc.Operator): self.layout.prop( self, "assign_selected_objects", text=f"Assign {len(ifc_objects)} Selected Object(s) to New Type" ) + + +class EnableEditingTypeAttributes(bpy.types.Operator): + bl_idname = "bim.enable_editing_type_attributes" + bl_label = "Enable Editing Type Attributes" + bl_description = "Enable editing the attributes of the relating type" + bl_options = {"REGISTER", "UNDO"} + + def execute(self, context): + obj = context.active_object + if not obj: + return {"CANCELLED"} + + element = tool.Ifc.get_entity(obj) + if not element: + return {"CANCELLED"} + + element_type = ifcopenshell.util.element.get_type(element) + if not element_type: + return {"CANCELLED"} + + props = tool.Type.get_object_type_props(obj) + props.type_attributes.clear() + + bonsai.bim.helper.import_attributes(element_type, props.type_attributes) + props.is_editing_type_attributes = True + return {"FINISHED"} + + +class DisableEditingTypeAttributes(bpy.types.Operator): + bl_idname = "bim.disable_editing_type_attributes" + bl_label = "Disable Editing Type Attributes" + bl_description = "Disable editing the attributes of the relating type" + bl_options = {"REGISTER", "UNDO"} + + def execute(self, context): + obj = context.active_object + if not obj: + return {"CANCELLED"} + + props = tool.Type.get_object_type_props(obj) + props.type_attributes.clear() + props.property_unset("is_editing_type_attributes") + return {"FINISHED"} + + +class EditTypeAttributes(bpy.types.Operator, tool.Ifc.Operator): + bl_idname = "bim.edit_type_attributes" + bl_label = "Edit Type Attributes" + bl_description = "Save the changes to the relating type's attributes" + bl_options = {"REGISTER", "UNDO"} + + def _execute(self, context): + obj = context.active_object + if not obj: + return {"CANCELLED"} + + element = tool.Ifc.get_entity(obj) + if not element: + return {"CANCELLED"} + + element_type = ifcopenshell.util.element.get_type(element) + if not element_type: + return {"CANCELLED"} + + props = tool.Type.get_object_type_props(obj) + attributes = bonsai.bim.helper.export_attributes(props.type_attributes) + + ifcopenshell.api.attribute.edit_attributes(tool.Ifc.get(), product=element_type, attributes=attributes) + + type_obj = tool.Ifc.get_object(element_type) + if type_obj: + tool.Root.set_object_name(type_obj, element_type) + + bpy.ops.bim.disable_editing_type_attributes() + + return {"FINISHED"} diff --git a/src/bonsai/bonsai/bim/module/type/prop.py b/src/bonsai/bonsai/bim/module/type/prop.py index 814d678390..2786636404 100644 --- a/src/bonsai/bonsai/bim/module/type/prop.py +++ b/src/bonsai/bonsai/bim/module/type/prop.py @@ -20,6 +20,7 @@ import bpy import ifcopenshell.util.element import ifcopenshell.util.type from bonsai.bim.module.type.data import TypeData +from bonsai.bim.prop import Attribute import bonsai.tool as tool from typing import TYPE_CHECKING, Union from bpy.types import PropertyGroup @@ -90,9 +91,13 @@ class BIMTypeProperties(PropertyGroup): update=update_relating_type_from_object, poll=is_object_class_applicable, ) + is_editing_type_attributes: BoolProperty(name="Is Editing Type Attributes") + type_attributes: CollectionProperty(type=Attribute, name="Type Attributes") if TYPE_CHECKING: is_editing_type: bool relating_type_class: str relating_type: str relating_type_object: Union[bpy.types.Object, None] + is_editing_type_attributes: bool + type_attributes: bpy.types.bpy_prop_collection_idprop[Attribute] diff --git a/src/bonsai/bonsai/bim/module/type/ui.py b/src/bonsai/bonsai/bim/module/type/ui.py index a368f38867..2370782046 100644 --- a/src/bonsai/bonsai/bim/module/type/ui.py +++ b/src/bonsai/bonsai/bim/module/type/ui.py @@ -20,7 +20,7 @@ import bpy import bonsai.tool as tool import bonsai.bim.module.type.prop as type_prop from bpy.types import Panel -from bonsai.bim.helper import prop_with_search +from bonsai.bim.helper import prop_with_search, get_display_value from bonsai.bim.module.type.data import TypeData @@ -107,5 +107,51 @@ class BIM_PT_type(Panel): row.operator("bim.enable_editing_type", icon="GREASEPENCIL", text="") +class BIM_PT_type_attributes(Panel): + bl_label = "Type Attributes" + bl_idname = "BIM_PT_type_attributes" + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "object" + bl_parent_id = "BIM_PT_type" + bl_options = {"DEFAULT_CLOSED"} + + @classmethod + def poll(cls, context): + if not TypeData.is_loaded: + TypeData.load() + return bool(TypeData.data.get("is_product") and TypeData.data.get("relating_type")) + + def draw(self, context): + if not TypeData.is_loaded: + TypeData.load() + + assert (layout := self.layout) + assert (obj := context.active_object) + + if not TypeData.data.get("relating_type"): + layout.label(text="No Relating Type", icon="INFO") + return + + props = tool.Type.get_object_type_props(obj) + + if props.is_editing_type_attributes: + row = layout.row(align=True) + row.operator("bim.edit_type_attributes", icon="CHECKMARK", text="Save Attributes") + row.operator("bim.disable_editing_type_attributes", icon="CANCEL", text="") + + import bonsai.bim.helper + bonsai.bim.helper.draw_attributes(props.type_attributes, layout) + else: + row = layout.row() + row.operator("bim.enable_editing_type_attributes", icon="GREASEPENCIL", text="Edit") + + for attribute in TypeData.data["relating_type_attributes"]: + row = layout.row(align=True) + row.label(text=attribute["name"]) + value = get_display_value(attribute["value"]) + row.label(text=value) + + def add_object_button(self, context): self.layout.operator("bim.add_occurrence", icon="PLUGIN")