diff --git a/src/blenderbim/blenderbim/bim/module/drawing/__init__.py b/src/blenderbim/blenderbim/bim/module/drawing/__init__.py index 62f56ae128..87caeeb83e 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/__init__.py @@ -37,16 +37,16 @@ classes = ( operator.CopyGrid, operator.CreateDrawing, operator.CreateSheets, + operator.DisableEditingAssignedProduct, operator.DisableEditingDrawings, operator.DisableEditingSchedules, operator.DisableEditingSheets, operator.DisableEditingText, - operator.DisableEditingTextProduct, + operator.EditAssignedProduct, operator.EditText, - operator.EditTextProduct, operator.EditVectorStyle, + operator.EnableEditingAssignedProduct, operator.EnableEditingText, - operator.EnableEditingTextProduct, operator.ExpandSheet, operator.LoadDrawings, operator.LoadSchedules, @@ -71,12 +71,14 @@ classes = ( prop.DocProperties, prop.BIMCameraProperties, prop.BIMTextProperties, + prop.BIMAssignedProductProperties, ui.BIM_PT_camera, ui.BIM_PT_drawing_underlay, ui.BIM_PT_annotation_utilities, ui.BIM_PT_sheets, ui.BIM_PT_drawings, ui.BIM_PT_schedules, + ui.BIM_PT_product_assignments, ui.BIM_PT_text, ui.BIM_UL_drawinglist, ui.BIM_UL_sheets, @@ -91,6 +93,7 @@ classes = ( def register(): bpy.types.Scene.DocProperties = bpy.props.PointerProperty(type=prop.DocProperties) bpy.types.Camera.BIMCameraProperties = bpy.props.PointerProperty(type=prop.BIMCameraProperties) + bpy.types.Object.BIMAssignedProductProperties = bpy.props.PointerProperty(type=prop.BIMAssignedProductProperties) bpy.types.Object.BIMTextProperties = bpy.props.PointerProperty(type=prop.BIMTextProperties) bpy.types.TextCurve.BIMTextProperties = bpy.props.PointerProperty(type=prop.BIMTextProperties) bpy.app.handlers.load_post.append(handler.toggleDecorationsOnLoad) @@ -100,6 +103,8 @@ def register(): def unregister(): del bpy.types.Scene.DocProperties del bpy.types.Camera.BIMCameraProperties + del bpy.types.Object.BIMAssignedProductProperties + del bpy.types.Object.BIMTextProperties del bpy.types.TextCurve.BIMTextProperties bpy.app.handlers.load_post.remove(handler.toggleDecorationsOnLoad) bpy.app.handlers.depsgraph_update_pre.remove(handler.depsgraph_update_pre_handler) diff --git a/src/blenderbim/blenderbim/bim/module/drawing/data.py b/src/blenderbim/blenderbim/bim/module/drawing/data.py index 049f8874a8..a91f7690eb 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/data.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/data.py @@ -22,19 +22,40 @@ import blenderbim.tool as tool def refresh(): + ProductAssignmentsData.is_loaded = False TextData.is_loaded = False SheetsData.is_loaded = False SchedulesData.is_loaded = False DrawingsData.is_loaded = False +class ProductAssignmentsData: + data = {} + is_loaded = False + + @classmethod + def load(cls): + cls.data = {"relating_product": cls.relating_product()} + cls.is_loaded = True + + @classmethod + def relating_product(cls): + element = tool.Ifc.get_entity(bpy.context.active_object) + if not element or not element.is_a("IfcAnnotation"): + return + for rel in element.HasAssignments: + if rel.is_a("IfcRelAssignsToProduct"): + name = rel.RelatingProduct.Name or "Unnamed" + return f"{rel.RelatingProduct.is_a()}/{name}" + + class TextData: data = {} is_loaded = False @classmethod def load(cls): - cls.data = {"attributes": cls.attributes(), "relating_product": cls.relating_product()} + cls.data = {"attributes": cls.attributes()} cls.is_loaded = True @classmethod @@ -49,15 +70,6 @@ class TextData: {"name": "BoxAlignment", "value": text_literal.BoxAlignment}, ] - @classmethod - def relating_product(cls): - element = tool.Ifc.get_entity(bpy.context.active_object) - if not element or not element.is_a("IfcAnnotation") or element.ObjectType not in ["TEXT", "TEXT_LEADER"]: - return - for rel in element.HasAssignments: - if rel.is_a("IfcRelAssignsToProduct"): - return rel.RelatingProduct.Name or "Unnamed" - class SheetsData: data = {} diff --git a/src/blenderbim/blenderbim/bim/module/drawing/operator.py b/src/blenderbim/blenderbim/bim/module/drawing/operator.py index d377c7a922..a16dd25f2a 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/operator.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/operator.py @@ -1246,34 +1246,34 @@ class DisableEditingText(bpy.types.Operator, Operator): core.disable_editing_text(tool.Drawing, obj=context.active_object) -class EditTextProduct(bpy.types.Operator, Operator): - bl_idname = "bim.edit_text_product" +class EditAssignedProduct(bpy.types.Operator, Operator): + bl_idname = "bim.edit_assigned_product" bl_label = "Edit Text Product" bl_options = {"REGISTER", "UNDO"} def _execute(self, context): product = None - if context.active_object.BIMTextProperties.relating_product: - product = tool.Ifc.get_entity(context.active_object.BIMTextProperties.relating_product) - core.edit_text_product(tool.Ifc, tool.Drawing, obj=context.active_object, product=product) + if context.active_object.BIMAssignedProductProperties.relating_product: + product = tool.Ifc.get_entity(context.active_object.BIMAssignedProductProperties.relating_product) + core.edit_assigned_product(tool.Ifc, tool.Drawing, obj=context.active_object, product=product) -class EnableEditingTextProduct(bpy.types.Operator, Operator): - bl_idname = "bim.enable_editing_text_product" +class EnableEditingAssignedProduct(bpy.types.Operator, Operator): + bl_idname = "bim.enable_editing_assigned_product" bl_label = "Enable Editing Text Product" bl_options = {"REGISTER", "UNDO"} def _execute(self, context): - core.enable_editing_text_product(tool.Drawing, obj=context.active_object) + core.enable_editing_assigned_product(tool.Drawing, obj=context.active_object) -class DisableEditingTextProduct(bpy.types.Operator, Operator): - bl_idname = "bim.disable_editing_text_product" +class DisableEditingAssignedProduct(bpy.types.Operator, Operator): + bl_idname = "bim.disable_editing_assigned_product" bl_label = "Disable Editing Text Product" bl_options = {"REGISTER", "UNDO"} def _execute(self, context): - core.disable_editing_text_product(tool.Drawing, obj=context.active_object) + core.disable_editing_assigned_product(tool.Drawing, obj=context.active_object) class LoadSheets(bpy.types.Operator, Operator): diff --git a/src/blenderbim/blenderbim/bim/module/drawing/prop.py b/src/blenderbim/blenderbim/bim/module/drawing/prop.py index 1105869828..2016f23dd2 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/prop.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/prop.py @@ -377,7 +377,6 @@ class BIMCameraProperties(PropertyGroup): class BIMTextProperties(PropertyGroup): is_editing: BoolProperty(name="Is Editing", default=False) - is_editing_product: BoolProperty(name="Is Editing Product", default=False) attributes: CollectionProperty(name="Attributes", type=Attribute) value: StringProperty(name="Value", default="TEXT") font_size: EnumProperty( @@ -392,4 +391,7 @@ class BIMTextProperties(PropertyGroup): update=refreshFontSize, name="Font Size", ) + +class BIMAssignedProductProperties(PropertyGroup): + is_editing_product: BoolProperty(name="Is Editing Product", default=False) relating_product: PointerProperty(name="Relating Product", type=bpy.types.Object) diff --git a/src/blenderbim/blenderbim/bim/module/drawing/ui.py b/src/blenderbim/blenderbim/bim/module/drawing/ui.py index 558e0f30a0..0b8f719a1b 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/ui.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/ui.py @@ -20,7 +20,7 @@ import bpy import blenderbim.bim.helper import blenderbim.tool as tool from bpy.types import Panel -from blenderbim.bim.module.drawing.data import TextData, SheetsData, SchedulesData, DrawingsData +from blenderbim.bim.module.drawing.data import ProductAssignmentsData, TextData, SheetsData, SchedulesData, DrawingsData class BIM_PT_camera(Panel): @@ -225,10 +225,14 @@ class BIM_PT_schedules(Panel): row = self.layout.row(align=True) row.alignment = "RIGHT" row.operator("bim.open_schedule", icon="URL", text="").schedule = active_schedule.ifc_definition_id - row.operator("bim.build_schedule", icon="LINENUMBERS_ON", text="").schedule = active_schedule.ifc_definition_id + row.operator( + "bim.build_schedule", icon="LINENUMBERS_ON", text="" + ).schedule = active_schedule.ifc_definition_id row.operator("bim.remove_schedule", icon="X", text="").schedule = active_schedule.ifc_definition_id - self.layout.template_list("BIM_UL_generic", "", self.props, "schedules", self.props, "active_schedule_index") + self.layout.template_list( + "BIM_UL_generic", "", self.props, "schedules", self.props, "active_schedule_index" + ) class BIM_PT_sheets(Panel): @@ -276,6 +280,39 @@ class BIM_PT_sheets(Panel): self.layout.template_list("BIM_UL_sheets", "", self.props, "sheets", self.props, "active_sheet_index") +class BIM_PT_product_assignments(Panel): + bl_label = "IFC Product Assignments" + bl_idname = "BIM_PT_product_assignments" + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "object" + + @classmethod + def poll(cls, context): + if not tool.Ifc.get() or not context.active_object: + return + element = tool.Ifc.get_entity(context.active_object) + if not element: + return + return element.is_a("IfcAnnotation") + + def draw(self, context): + if not ProductAssignmentsData.is_loaded: + ProductAssignmentsData.load() + + props = context.active_object.BIMAssignedProductProperties + + if props.is_editing_product: + row = self.layout.row(align=True) + row.prop(props, "relating_product", text="") + row.operator("bim.edit_assigned_product", icon="CHECKMARK", text="") + row.operator("bim.disable_editing_assigned_product", icon="CANCEL", text="") + else: + row = self.layout.row(align=True) + row.label(text=ProductAssignmentsData.data["relating_product"] or "No Relating Product", icon="OBJECT_DATA") + row.operator("bim.enable_editing_assigned_product", icon="GREASEPENCIL", text="") + + class BIM_PT_text(Panel): bl_label = "IFC Text" bl_idname = "BIM_PT_text" @@ -312,16 +349,6 @@ class BIM_PT_text(Panel): row.label(text=attribute["name"]) row.label(text=attribute["value"]) - if props.is_editing_product: - row = self.layout.row(align=True) - row.prop(props, "relating_product", text="") - row.operator("bim.edit_text_product", icon="CHECKMARK", text="") - row.operator("bim.disable_editing_text_product", icon="CANCEL", text="") - else: - row = self.layout.row(align=True) - row.label(text=TextData.data["relating_product"] or "No Relating Product", icon="OBJECT_DATA") - row.operator("bim.enable_editing_text_product", icon="GREASEPENCIL", text="") - row = self.layout.row() row.prop(props, "font_size") row = self.layout.row() diff --git a/src/blenderbim/blenderbim/bim/module/geometry/operator.py b/src/blenderbim/blenderbim/bim/module/geometry/operator.py index 83c19d4a5e..541cb0a92d 100644 --- a/src/blenderbim/blenderbim/bim/module/geometry/operator.py +++ b/src/blenderbim/blenderbim/bim/module/geometry/operator.py @@ -331,11 +331,12 @@ class OverrideDeleteTrait: self.remove_filling(rel.RelatedBuildingElement) if element.VoidsElements: self.delete_opening_element(element) - elif getattr(element, "HasOpenings", None): - for rel in element.HasOpenings: - self.delete_opening_element(rel.RelatedOpeningElement) - for port in ifcopenshell.util.system.get_ports(element): - self.remove_port(port) + else: + if getattr(element, "HasOpenings", None): + for rel in element.HasOpenings: + self.delete_opening_element(rel.RelatedOpeningElement) + for port in ifcopenshell.util.system.get_ports(element): + self.remove_port(port) def delete_opening_element(self, element): obj = IfcStore.get_element(element.VoidsElements[0].RelatingBuildingElement.id()) diff --git a/src/blenderbim/blenderbim/core/drawing.py b/src/blenderbim/blenderbim/core/drawing.py index 10b02438cf..fe82d49ade 100644 --- a/src/blenderbim/blenderbim/core/drawing.py +++ b/src/blenderbim/blenderbim/core/drawing.py @@ -36,18 +36,18 @@ def edit_text(ifc, drawing, obj=None): drawing.disable_editing_text(obj) -def enable_editing_text_product(drawing, obj=None): - drawing.enable_editing_text_product(obj) - drawing.import_text_product(obj) +def enable_editing_assigned_product(drawing, obj=None): + drawing.enable_editing_assigned_product(obj) + drawing.import_assigned_product(obj) -def disable_editing_text_product(drawing, obj=None): - drawing.disable_editing_text_product(obj) +def disable_editing_assigned_product(drawing, obj=None): + drawing.disable_editing_assigned_product(obj) -def edit_text_product(ifc, drawing, obj=None, product=None): +def edit_assigned_product(ifc, drawing, obj=None, product=None): element = ifc.get_entity(obj) - existing_product = drawing.get_text_product(element) + existing_product = drawing.get_assigned_product(element) if existing_product == product: return if existing_product: @@ -55,7 +55,7 @@ def edit_text_product(ifc, drawing, obj=None, product=None): if product: ifc.run("drawing.assign_product", relating_product=product, related_object=element) drawing.update_text_value(obj) - drawing.disable_editing_text_product(obj) + drawing.disable_editing_assigned_product(obj) def load_sheets(drawing): diff --git a/src/blenderbim/blenderbim/core/tool.py b/src/blenderbim/blenderbim/core/tool.py index 790b702ea3..123bc1e5f5 100644 --- a/src/blenderbim/blenderbim/core/tool.py +++ b/src/blenderbim/blenderbim/core/tool.py @@ -161,17 +161,17 @@ class Drawing: def delete_collection(cls, collection): pass def delete_drawing_elements(cls, elements): pass def delete_object(cls, obj): pass + def disable_editing_assigned_product(cls, obj): pass def disable_editing_drawings(cls): pass def disable_editing_schedules(cls): pass def disable_editing_sheets(cls): pass def disable_editing_text(cls, obj): pass - def disable_editing_text_product(cls, obj): pass def enable_editing(cls, obj): pass + def enable_editing_assigned_product(cls, obj): pass def enable_editing_drawings(cls): pass def enable_editing_schedules(cls): pass def enable_editing_sheets(cls): pass def enable_editing_text(cls, obj): pass - def enable_editing_text_product(cls, obj): pass def ensure_unique_drawing_name(cls, name): pass def ensure_unique_identification(cls, identification): pass def export_text_literal_attributes(cls, obj): pass @@ -179,6 +179,7 @@ class Drawing: def generate_drawing_name(cls, target_view, location_hint): pass def generate_sheet_identification(cls): pass def get_annotation_context(cls, target_view): pass + def get_assigned_product(cls, element): pass def get_body_context(cls): pass def get_document_uri(cls, document): pass def get_drawing_collection(cls, drawing): pass @@ -189,12 +190,11 @@ class Drawing: def get_name(cls, element): pass def get_schedule_location(cls, schedule): pass def get_text_literal(cls, obj): pass - def get_text_product(cls, element): pass + def import_assigned_product(cls, obj): pass def import_drawings(cls): pass def import_schedules(cls): pass def import_sheets(cls): pass def import_text_attributes(cls, obj): pass - def import_text_product(cls, obj): pass def open_spreadsheet(cls, uri): pass def open_svg(cls, filepath): pass def run_root_assign_class(cls, obj=None, ifc_class=None, predefined_type=None, should_add_representation=True, context=None, ifc_representation_class=None): pass diff --git a/src/blenderbim/blenderbim/tool/drawing.py b/src/blenderbim/blenderbim/tool/drawing.py index 168f0e9fa8..a0099e9ccb 100644 --- a/src/blenderbim/blenderbim/tool/drawing.py +++ b/src/blenderbim/blenderbim/tool/drawing.py @@ -118,8 +118,8 @@ class Drawing(blenderbim.core.tool.Drawing): obj.BIMTextProperties.is_editing = False @classmethod - def disable_editing_text_product(cls, obj): - obj.BIMTextProperties.is_editing_product = False + def disable_editing_assigned_product(cls, obj): + obj.BIMAssignedProductProperties.is_editing_product = False @classmethod def enable_editing(cls, obj): @@ -146,8 +146,8 @@ class Drawing(blenderbim.core.tool.Drawing): obj.BIMTextProperties.is_editing = True @classmethod - def enable_editing_text_product(cls, obj): - obj.BIMTextProperties.is_editing_product = True + def enable_editing_assigned_product(cls, obj): + obj.BIMAssignedProductProperties.is_editing_product = True @classmethod def ensure_unique_drawing_name(cls, name): @@ -282,7 +282,7 @@ class Drawing(blenderbim.core.tool.Drawing): return items[0] @classmethod - def get_text_product(cls, element): + def get_assigned_product(cls, element): for rel in element.HasAssignments: if rel.is_a("IfcRelAssignsToProduct"): return rel.RelatingProduct @@ -356,13 +356,13 @@ class Drawing(blenderbim.core.tool.Drawing): blenderbim.bim.helper.import_attributes2(text, props.attributes) @classmethod - def import_text_product(cls, obj): + def import_assigned_product(cls, obj): element = tool.Ifc.get_entity(obj) - product = cls.get_text_product(element) + product = cls.get_assigned_product(element) if product: - obj.BIMTextProperties.relating_product = tool.Ifc.get_object(product) + obj.BIMAssignedProductProperties.relating_product = tool.Ifc.get_object(product) else: - obj.BIMTextProperties.relating_product = None + obj.BIMAssignedProductProperties.relating_product = None @classmethod def open_with_user_command(cls, user_command, path): @@ -421,7 +421,7 @@ class Drawing(blenderbim.core.tool.Drawing): if not element: return value = element.Literal - product = cls.get_text_product(tool.Ifc.get_entity(obj)) + product = cls.get_assigned_product(tool.Ifc.get_entity(obj)) if product: selector = ifcopenshell.util.selector.Selector() variables = {} diff --git a/src/blenderbim/test/core/test_drawing.py b/src/blenderbim/test/core/test_drawing.py index 19e69f1f97..290c4f8ca3 100644 --- a/src/blenderbim/test/core/test_drawing.py +++ b/src/blenderbim/test/core/test_drawing.py @@ -43,30 +43,30 @@ class TestEditText: subject.edit_text(ifc, drawing, obj="obj") -class TestEnableEditingTextProduct: +class TestEnableEditingAssignedProduct: def test_run(self, drawing): - drawing.enable_editing_text_product("obj").should_be_called() - drawing.import_text_product("obj").should_be_called() - subject.enable_editing_text_product(drawing, obj="obj") + drawing.enable_editing_assigned_product("obj").should_be_called() + drawing.import_assigned_product("obj").should_be_called() + subject.enable_editing_assigned_product(drawing, obj="obj") -class TestDisableEditingTextProduct: +class TestDisableEditingAssignedProduct: def test_run(self, drawing): - drawing.disable_editing_text_product("obj").should_be_called() - subject.disable_editing_text_product(drawing, obj="obj") + drawing.disable_editing_assigned_product("obj").should_be_called() + subject.disable_editing_assigned_product(drawing, obj="obj") -class TestEditTextProduct: +class TestEditAssignedProduct: def test_run(self, ifc, drawing): ifc.get_entity("obj").should_be_called().will_return("element") - drawing.get_text_product("element").should_be_called().will_return("existing_product") + drawing.get_assigned_product("element").should_be_called().will_return("existing_product") ifc.run( "drawing.unassign_product", relating_product="existing_product", related_object="element" ).should_be_called() ifc.run("drawing.assign_product", relating_product="product", related_object="element").should_be_called() drawing.update_text_value("obj").should_be_called() - drawing.disable_editing_text_product("obj").should_be_called() - subject.edit_text_product(ifc, drawing, obj="obj", product="product") + drawing.disable_editing_assigned_product("obj").should_be_called() + subject.edit_assigned_product(ifc, drawing, obj="obj", product="product") class TestLoadSheets: diff --git a/src/blenderbim/test/tool/test_drawing.py b/src/blenderbim/test/tool/test_drawing.py index fbe28d318d..64048c8192 100644 --- a/src/blenderbim/test/tool/test_drawing.py +++ b/src/blenderbim/test/tool/test_drawing.py @@ -109,12 +109,12 @@ class TestDisableEditingText(NewFile): assert obj.BIMTextProperties.is_editing == False -class TestDisableEditingTextProduct(NewFile): +class TestDisableEditingAssignedProduct(NewFile): def test_run(self): obj = bpy.data.objects.new("Object", None) - obj.BIMTextProperties.is_editing_product = True - subject.disable_editing_text_product(obj) - assert obj.BIMTextProperties.is_editing_product == False + obj.BIMAssignedProductProperties.is_editing_product = True + subject.disable_editing_assigned_product(obj) + assert obj.BIMAssignedProductProperties.is_editing_product == False class TestEnableEditing(NewFile): @@ -153,11 +153,11 @@ class TestEnableEditingText(NewFile): assert obj.BIMTextProperties.is_editing == True -class TestEnableEditingTextProduct(NewFile): +class TestEnableEditingAssignedProduct(NewFile): def test_run(self): obj = bpy.data.objects.new("Object", None) - subject.enable_editing_text_product(obj) - assert obj.BIMTextProperties.is_editing_product == True + subject.enable_editing_assigned_product(obj) + assert obj.BIMAssignedProductProperties.is_editing_product == True class TestEnsureUniqueDrawingName(NewFile): @@ -423,14 +423,14 @@ class TestGetTextLiteral(NewFile): assert subject.get_text_literal(obj) == item -class TestGetTextProduct(NewFile): +class TestGetAssignedProduct(NewFile): def test_run(self): ifc = ifcopenshell.file() tool.Ifc.set(ifc) wall = ifc.createIfcWall() label = ifc.createIfcAnnotation() ifcopenshell.api.run("drawing.assign_product", ifc, relating_product=wall, related_object=label) - assert subject.get_text_product(label) == wall + assert subject.get_assigned_product(label) == wall class TestImportDrawings(NewFile): @@ -514,7 +514,7 @@ class TestImportTextAttributes(NewFile): assert props.attributes.get("BoxAlignment").string_value == "BoxAlignment" -class TestImportTextProduct(NewFile): +class TestImportAssignedProduct(NewFile): def test_run(self): ifc = ifcopenshell.file() tool.Ifc.set(ifc) @@ -525,8 +525,8 @@ class TestImportTextProduct(NewFile): label_obj = bpy.data.objects.new("Object", None) tool.Ifc.link(wall, wall_obj) tool.Ifc.link(label, label_obj) - subject.import_text_product(label_obj) - assert label_obj.BIMTextProperties.relating_product == wall_obj + subject.import_assigned_product(label_obj) + assert label_obj.BIMAssignedProductProperties.relating_product == wall_obj def test_doing_nothing_if_no_product_to_import(self): ifc = ifcopenshell.file() @@ -534,8 +534,8 @@ class TestImportTextProduct(NewFile): label = ifc.createIfcAnnotation() label_obj = bpy.data.objects.new("Object", None) tool.Ifc.link(label, label_obj) - subject.import_text_product(label_obj) - assert label_obj.BIMTextProperties.relating_product is None + subject.import_assigned_product(label_obj) + assert label_obj.BIMAssignedProductProperties.relating_product is None class TestOpenSchedule(NewFile):