diff --git a/src/blenderbim/blenderbim/bim/module/cost/__init__.py b/src/blenderbim/blenderbim/bim/module/cost/__init__.py index fa370240d8..885fcb2060 100644 --- a/src/blenderbim/blenderbim/bim/module/cost/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/cost/__init__.py @@ -26,6 +26,8 @@ classes = ( operator.ExpandCostItem, operator.ContractCostItem, operator.RemoveCostItem, + operator.AssignCostItemType, + operator.UnassignCostItemType, operator.AssignCostItemQuantity, operator.UnassignCostItemQuantity, operator.AddCostItemQuantity, @@ -37,14 +39,18 @@ classes = ( operator.SelectCostScheduleProducts, operator.ImportCostScheduleCsv, operator.LoadCostItemQuantities, + operator.LoadCostItemTypes, prop.CostItem, prop.CostItemQuantity, + prop.CostItemType, prop.BIMCostProperties, ui.BIM_PT_cost_schedules, ui.BIM_PT_cost_item_quantities, + ui.BIM_PT_cost_item_types, ui.BIM_UL_cost_items, ui.BIM_UL_cost_columns, ui.BIM_UL_cost_item_quantities, + ui.BIM_UL_cost_item_types, ) diff --git a/src/blenderbim/blenderbim/bim/module/cost/operator.py b/src/blenderbim/blenderbim/bim/module/cost/operator.py index 08563d8c14..be7248a4e6 100644 --- a/src/blenderbim/blenderbim/bim/module/cost/operator.py +++ b/src/blenderbim/blenderbim/bim/module/cost/operator.py @@ -303,6 +303,63 @@ class EditCostItem(bpy.types.Operator): return {"FINISHED"} +class AssignCostItemType(bpy.types.Operator): + bl_idname = "bim.assign_cost_item_type" + bl_label = "Assign Cost Item Type Product" + bl_options = {"REGISTER", "UNDO"} + cost_item: bpy.props.IntProperty() + prop_name: bpy.props.StringProperty() + + def execute(self, context): + return IfcStore.execute_ifc_operator(self, context) + + def _execute(self, context): + self.file = IfcStore.get_file() + cost_item = self.file.by_id(self.cost_item) + for obj in context.selected_objects: + if not obj.BIMObjectProperties.ifc_definition_id: + continue + product = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id) + if product.is_a("IfcTypeProduct"): + ifcopenshell.api.run( + "control.assign_control", self.file, relating_control=cost_item, related_object=product + ) + Data.load(self.file) + bpy.ops.bim.load_cost_item_types() + return {"FINISHED"} + + +class UnassignCostItemType(bpy.types.Operator): + bl_idname = "bim.unassign_cost_item_type" + bl_label = "Unassign Cost Item Type" + bl_options = {"REGISTER", "UNDO"} + cost_item: bpy.props.IntProperty() + related_object: bpy.props.IntProperty() + + def execute(self, context): + return IfcStore.execute_ifc_operator(self, context) + + def _execute(self, context): + self.file = IfcStore.get_file() + cost_item = self.file.by_id(self.cost_item) + if self.related_object: + products = [self.file.by_id(self.related_object)] + else: + for obj in context.selected_objects: + if not obj.BIMObjectProperties.ifc_definition_id: + continue + product = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id) + if product.is_a("IfcTypeProduct"): + products.append(product) + for product in products: + ifcopenshell.api.run( + "control.unassign_control", self.file, relating_control=cost_item, related_object=product + ) + Data.load(self.file) + bpy.ops.bim.load_cost_item_types() + return {"FINISHED"} + + class AssignCostItemQuantity(bpy.types.Operator): bl_idname = "bim.assign_cost_item_quantity" bl_label = "Assign Cost Item Quantity" @@ -806,3 +863,33 @@ class LoadCostItemQuantities(bpy.types.Operator): total_quantity += self.file.by_id(quantity_id)[3] new.total_quantity = total_quantity return {"FINISHED"} + + +class LoadCostItemTypes(bpy.types.Operator): + bl_idname = "bim.load_cost_item_types" + bl_label = "Load Cost Item Types" + bl_options = {"REGISTER", "UNDO"} + + def execute(self, context): + self.props = context.scene.BIMCostProperties + self.file = IfcStore.get_file() + while len(self.props.cost_item_type_products) > 0: + self.props.cost_item_type_products.remove(0) + # TODO implement process and resource types + #while len(self.props.cost_item_processes) > 0: + # self.props.cost_item_processes.remove(0) + #while len(self.props.cost_item_resources) > 0: + # self.props.cost_item_resources.remove(0) + ifc_definition_id = self.props.cost_items[self.props.active_cost_item_index].ifc_definition_id + for control_id, quantity_ids in Data.cost_items[ifc_definition_id]["Controls"].items(): + related_object = self.file.by_id(control_id) + if related_object.is_a("IfcTypeProduct"): + new = self.props.cost_item_type_products.add() + # TODO implement process and resource types + #elif related_object.is_a("IfcProcess"): + # new = self.props.cost_item_processes.add() + #elif related_object.is_a("IfcResource"): + # new = self.props.cost_item_resources.add() + new.ifc_definition_id = control_id + new.name = related_object.Name or "Unnamed" + return {"FINISHED"} diff --git a/src/blenderbim/blenderbim/bim/module/cost/prop.py b/src/blenderbim/blenderbim/bim/module/cost/prop.py index d57d373960..63253a4fe6 100644 --- a/src/blenderbim/blenderbim/bim/module/cost/prop.py +++ b/src/blenderbim/blenderbim/bim/module/cost/prop.py @@ -175,6 +175,11 @@ class CostItemQuantity(PropertyGroup): total_quantity: FloatProperty(name="Total Quantity") +class CostItemType(PropertyGroup): + name: StringProperty(name="Name") + ifc_definition_id: IntProperty(name="IFC Definition ID") + + class BIMCostProperties(PropertyGroup): is_cost_update_enabled: BoolProperty(name="Is Cost Update Enabled", default=True) cost_schedule_attributes: CollectionProperty(name="Cost Schedule Attributes", type=Attribute) @@ -213,3 +218,5 @@ class BIMCostProperties(PropertyGroup): active_cost_item_process_index: IntProperty(name="Active Cost Item Process Index") cost_item_resources: CollectionProperty(name="Cost Item Resources", type=CostItemQuantity) active_cost_item_resource_index: IntProperty(name="Active Cost Item Resource Index") + cost_item_type_products: CollectionProperty(name="Cost Item Type Products", type=CostItemType) + active_cost_item_type_product_index: IntProperty(name="Active Cost Item TYpe Product Index") diff --git a/src/blenderbim/blenderbim/bim/module/cost/ui.py b/src/blenderbim/blenderbim/bim/module/cost/ui.py index 4170f025b9..9a87d0dd24 100644 --- a/src/blenderbim/blenderbim/bim/module/cost/ui.py +++ b/src/blenderbim/blenderbim/bim/module/cost/ui.py @@ -225,6 +225,93 @@ class BIM_PT_cost_schedules(Panel): def draw_editable_cost_value_ui(self, layout, cost_value): draw_attributes(self.props.cost_value_attributes, layout) + +class BIM_PT_cost_item_types(Panel): + bl_label = "IFC Cost Item Types" + bl_idname = "BIM_PT_cost_item_types" + bl_options = {"DEFAULT_CLOSED"} + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "scene" + bl_parent_id = "BIM_PT_cost_schedules" + + @classmethod + def poll(cls, context): + props = context.scene.BIMCostProperties + total_cost_items = len(props.cost_items) + if not props.active_cost_schedule_id: + return False + if Data.cost_schedules[props.active_cost_schedule_id]["PredefinedType"] != "SCHEDULEOFRATES": + return False + if total_cost_items > 0 and props.active_cost_item_index < total_cost_items: + return True + return False + + def draw(self, context): + self.props = context.scene.BIMCostProperties + + cost_item = self.props.cost_items[self.props.active_cost_item_index] + + grid = self.layout.grid_flow(columns=3, even_columns=True) + + # Column1 + col = grid.column() + + row2 = col.row(align=True) + row2.label(text="Elements") + op = row2.operator("bim.assign_cost_item_type", text="", icon="ADD") + op.cost_item = cost_item.ifc_definition_id + op = row2.operator("bim.unassign_cost_item_type", text="", icon="REMOVE") + op.cost_item = cost_item.ifc_definition_id + op.related_object = 0 + op = row2.operator("bim.select_cost_item_products", icon="RESTRICT_SELECT_OFF", text="") + op.cost_item = cost_item.ifc_definition_id + + row2 = col.row() + row2.template_list( + "BIM_UL_cost_item_types", + "", + self.props, + "cost_item_type_products", + self.props, + "active_cost_item_type_product_index", + ) + + # Column2 + # TODO + col = grid.column() + + row2 = col.row(align=True) + row2.label(text="Tasks") + + row2 = col.row() + row2.template_list( + "BIM_UL_cost_item_quantities", + "", + self.props, + "cost_item_processes", + self.props, + "active_cost_item_process_index", + ) + + # Column3 + # TODO + col = grid.column() + + row2 = col.row(align=True) + row2.label(text="Resources") + + row2 = col.row() + row2.template_list( + "BIM_UL_cost_item_quantities", + "", + self.props, + "cost_item_resources", + self.props, + "active_cost_item_resource_index", + ) + + class BIM_PT_cost_item_quantities(Panel): bl_label = "IFC Cost Item Quantities" bl_idname = "BIM_PT_cost_item_quantities" @@ -238,6 +325,10 @@ class BIM_PT_cost_item_quantities(Panel): def poll(cls, context): props = context.scene.BIMCostProperties total_cost_items = len(props.cost_items) + if not props.active_cost_schedule_id: + return False + if Data.cost_schedules[props.active_cost_schedule_id]["PredefinedType"] == "SCHEDULEOFRATES": + return False if total_cost_items > 0 and props.active_cost_item_index < total_cost_items: return True return False @@ -355,7 +446,9 @@ class BIM_UL_cost_items(UIList): split2.prop(item, "name", emboss=False, text="") if Data.cost_schedules[self.props.active_cost_schedule_id]["PredefinedType"] != "SCHEDULEOFRATES": - split2.label(text="{0:.2f}".format(cost_item["TotalCostQuantity"]) + f" ({cost_item['UnitSymbol'] or '?'})") + split2.label( + text="{0:.2f}".format(cost_item["TotalCostQuantity"]) + f" ({cost_item['UnitSymbol'] or '?'})" + ) split2.label(text="{0:.2f}".format(cost_item["TotalAppliedValue"])) @@ -383,6 +476,19 @@ class BIM_UL_cost_columns(UIList): row.operator("bim.remove_cost_column", text="", icon="X").name = item.name +class BIM_UL_cost_item_types(UIList): + def draw_item(self, context, layout, data, item, icon, active_data, active_propname): + props = context.scene.BIMCostProperties + cost_item = props.cost_items[props.active_cost_item_index] + + if item: + row = layout.row(align=True) + row.label(text=item.name) + op = row.operator("bim.unassign_cost_item_type", text="", icon="X") + op.cost_item = cost_item.ifc_definition_id + op.related_object = item.ifc_definition_id + + class BIM_UL_cost_item_quantities(UIList): def draw_item(self, context, layout, data, item, icon, active_data, active_propname): props = context.scene.BIMCostProperties