#1153 You can now manage assigned products for all annotations

This commit is contained in:
Dion Moult
2022-05-06 15:35:39 +10:00
parent 316a2b7f53
commit 73e048a9a8
11 changed files with 137 additions and 90 deletions
@@ -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)
@@ -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 = {}
@@ -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):
@@ -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)
@@ -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()
@@ -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())
+8 -8
View File
@@ -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):
+4 -4
View File
@@ -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
+10 -10
View File
@@ -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 = {}
+11 -11
View File
@@ -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:
+14 -14
View File
@@ -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):