Merge pull request #7316 from falken10vdl/Show-attributes-for-relating-type

Add attribute info for relating type
This commit is contained in:
falken10vdl
2025-12-16 09:48:50 +01:00
committed by GitHub
5 changed files with 157 additions and 1 deletions
@@ -23,8 +23,11 @@ classes = (
operator.AssignType, operator.AssignType,
operator.AutoRenameOccurrences, operator.AutoRenameOccurrences,
operator.DisableEditingType, operator.DisableEditingType,
operator.DisableEditingTypeAttributes,
operator.DuplicateType, operator.DuplicateType,
operator.EditTypeAttributes,
operator.EnableEditingType, operator.EnableEditingType,
operator.EnableEditingTypeAttributes,
operator.RemoveType, operator.RemoveType,
operator.RenameType, operator.RenameType,
operator.SelectSimilarType, operator.SelectSimilarType,
@@ -33,6 +36,7 @@ classes = (
operator.UnassignType, operator.UnassignType,
prop.BIMTypeProperties, prop.BIMTypeProperties,
ui.BIM_PT_type, ui.BIM_PT_type,
ui.BIM_PT_type_attributes,
) )
+23
View File
@@ -42,6 +42,7 @@ class TypeData:
"is_product": cls.is_product(), "is_product": cls.is_product(),
"total_instances": cls.total_instances(), "total_instances": cls.total_instances(),
"relating_type": cls.relating_type(), "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) element_type = ifcopenshell.util.element.get_type(element)
if element_type: if element_type:
return {"id": element_type.id(), "name": f"{element_type.is_a()}/{element_type.Name or 'Unnamed'}"} 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
@@ -24,6 +24,7 @@ import ifcopenshell.util.representation
import ifcopenshell.util.type import ifcopenshell.util.type
import ifcopenshell.util.unit import ifcopenshell.util.unit
import ifcopenshell.api import ifcopenshell.api
import ifcopenshell.api.attribute
import ifcopenshell.api.type import ifcopenshell.api.type
import bonsai.bim.helper import bonsai.bim.helper
import bonsai.tool as tool import bonsai.tool as tool
@@ -416,3 +417,80 @@ class DuplicateType(bpy.types.Operator, tool.Ifc.Operator):
self.layout.prop( self.layout.prop(
self, "assign_selected_objects", text=f"Assign {len(ifc_objects)} Selected Object(s) to New Type" 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"}
@@ -20,6 +20,7 @@ import bpy
import ifcopenshell.util.element import ifcopenshell.util.element
import ifcopenshell.util.type import ifcopenshell.util.type
from bonsai.bim.module.type.data import TypeData from bonsai.bim.module.type.data import TypeData
from bonsai.bim.prop import Attribute
import bonsai.tool as tool import bonsai.tool as tool
from typing import TYPE_CHECKING, Union from typing import TYPE_CHECKING, Union
from bpy.types import PropertyGroup from bpy.types import PropertyGroup
@@ -90,9 +91,13 @@ class BIMTypeProperties(PropertyGroup):
update=update_relating_type_from_object, update=update_relating_type_from_object,
poll=is_object_class_applicable, 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: if TYPE_CHECKING:
is_editing_type: bool is_editing_type: bool
relating_type_class: str relating_type_class: str
relating_type: str relating_type: str
relating_type_object: Union[bpy.types.Object, None] relating_type_object: Union[bpy.types.Object, None]
is_editing_type_attributes: bool
type_attributes: bpy.types.bpy_prop_collection_idprop[Attribute]
+47 -1
View File
@@ -20,7 +20,7 @@ import bpy
import bonsai.tool as tool import bonsai.tool as tool
import bonsai.bim.module.type.prop as type_prop import bonsai.bim.module.type.prop as type_prop
from bpy.types import Panel 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 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="") 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): def add_object_button(self, context):
self.layout.operator("bim.add_occurrence", icon="PLUGIN") self.layout.operator("bim.add_occurrence", icon="PLUGIN")