Implement cost identification numbers and big cleanup to cost schedule UI

This commit is contained in:
Dion Moult
2021-08-13 18:01:23 +10:00
parent 26f800331e
commit 2f3c79a0e6
5 changed files with 87 additions and 47 deletions
@@ -103,6 +103,7 @@ class EnableEditingCostItems(bpy.types.Operator):
if context.preferences.addons["blenderbim"].preferences.should_play_chaching_sound: if context.preferences.addons["blenderbim"].preferences.should_play_chaching_sound:
self.play_chaching_sound() # lol self.play_chaching_sound() # lol
self.props = context.scene.BIMCostProperties self.props = context.scene.BIMCostProperties
self.props.is_cost_update_enabled = False
self.props.active_cost_schedule_id = self.cost_schedule self.props.active_cost_schedule_id = self.cost_schedule
while len(self.props.cost_items) > 0: while len(self.props.cost_items) > 0:
self.props.cost_items.remove(0) self.props.cost_items.remove(0)
@@ -111,6 +112,7 @@ class EnableEditingCostItems(bpy.types.Operator):
for related_object_id in Data.cost_schedules[self.cost_schedule]["Controls"]: for related_object_id in Data.cost_schedules[self.cost_schedule]["Controls"]:
self.create_new_cost_item_li(related_object_id, 0) self.create_new_cost_item_li(related_object_id, 0)
self.props.is_editing = "COST_ITEMS" self.props.is_editing = "COST_ITEMS"
self.props.is_cost_update_enabled = True
return {"FINISHED"} return {"FINISHED"}
def play_chaching_sound(self): def play_chaching_sound(self):
@@ -134,6 +136,7 @@ class EnableEditingCostItems(bpy.types.Operator):
new = self.props.cost_items.add() new = self.props.cost_items.add()
new.ifc_definition_id = related_object_id new.ifc_definition_id = related_object_id
new.name = cost_item["Name"] or "Unnamed" new.name = cost_item["Name"] or "Unnamed"
new.identification = cost_item["Identification"] or "XXX"
new.is_expanded = related_object_id not in self.contracted_cost_items new.is_expanded = related_object_id not in self.contracted_cost_items
new.level_index = level_index new.level_index = level_index
if cost_item["IsNestedBy"]: if cost_item["IsNestedBy"]:
@@ -128,11 +128,27 @@ def update_cost_item_index(self, context):
bpy.ops.bim.load_cost_item_quantities() bpy.ops.bim.load_cost_item_quantities()
def updateCostItemName(self, context): def updateCostItemIdentification(self, context):
if self.name == "Unnamed": props = context.scene.BIMCostProperties
if not props.is_cost_update_enabled or self.identification == "XXX":
return return
self.file = IfcStore.get_file() self.file = IfcStore.get_file()
ifcopenshell.api.run(
"cost.edit_cost_item",
self.file,
**{"cost_item": self.file.by_id(self.ifc_definition_id), "attributes": {"Identification": self.identification}},
)
Data.load(self.file)
if props.active_cost_item_id == self.ifc_definition_id:
attribute = props.cost_item_attributes.get("Identification")
attribute.string_value = self.identification
def updateCostItemName(self, context):
props = context.scene.BIMCostProperties props = context.scene.BIMCostProperties
if not props.is_cost_update_enabled or self.name == "Unnamed":
return
self.file = IfcStore.get_file()
ifcopenshell.api.run( ifcopenshell.api.run(
"cost.edit_cost_item", "cost.edit_cost_item",
self.file, self.file,
@@ -146,6 +162,7 @@ def updateCostItemName(self, context):
class CostItem(PropertyGroup): class CostItem(PropertyGroup):
name: StringProperty(name="Name", update=updateCostItemName) name: StringProperty(name="Name", update=updateCostItemName)
identification: StringProperty(name="Identification", update=updateCostItemIdentification)
ifc_definition_id: IntProperty(name="IFC Definition ID") ifc_definition_id: IntProperty(name="IFC Definition ID")
has_children: BoolProperty(name="Has Children") has_children: BoolProperty(name="Has Children")
is_expanded: BoolProperty(name="Is Expanded") is_expanded: BoolProperty(name="Is Expanded")
@@ -159,6 +176,7 @@ class CostItemQuantity(PropertyGroup):
class BIMCostProperties(PropertyGroup): 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) cost_schedule_attributes: CollectionProperty(name="Cost Schedule Attributes", type=Attribute)
is_editing: StringProperty(name="Is Editing") is_editing: StringProperty(name="Is Editing")
active_cost_schedule_id: IntProperty(name="Active Cost Schedule Id") active_cost_schedule_id: IntProperty(name="Active Cost Schedule Id")
+46 -30
View File
@@ -76,6 +76,32 @@ class BIM_PT_cost_schedules(Panel):
row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="") row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="")
def draw_editable_cost_item_ui(self, cost_schedule_id): def draw_editable_cost_item_ui(self, cost_schedule_id):
row = self.layout.row(align=True)
row.alignment = "RIGHT"
ifc_definition_id = None
if self.props.cost_items and self.props.active_cost_item_index < len(self.props.cost_items):
ifc_definition_id = self.props.cost_items[self.props.active_cost_item_index].ifc_definition_id
if ifc_definition_id:
if Data.cost_schedules[self.props.active_cost_schedule_id]["PredefinedType"] != "SCHEDULEOFRATES":
op = row.operator("bim.enable_editing_cost_item_quantities", text="", icon="PROPERTIES")
op.cost_item = ifc_definition_id
op = row.operator("bim.enable_editing_cost_item_values", text="", icon="DISC")
op.cost_item = ifc_definition_id
row.operator("bim.add_cost_item", text="", icon="ADD").cost_item = ifc_definition_id
if self.props.active_cost_item_id == ifc_definition_id:
if self.props.cost_item_editing_type == "ATTRIBUTES":
row.operator("bim.edit_cost_item", text="", icon="CHECKMARK")
row.operator("bim.disable_editing_cost_item", text="", icon="CANCEL")
else:
op = row.operator("bim.enable_editing_cost_item", text="", icon="GREASEPENCIL")
op.cost_item = ifc_definition_id
row.operator("bim.remove_cost_item", text="", icon="X").cost_item = ifc_definition_id
self.layout.template_list( self.layout.template_list(
"BIM_UL_cost_items", "BIM_UL_cost_items",
"", "",
@@ -348,7 +374,7 @@ class BIM_PT_cost_item_quantities(Panel):
class BIM_UL_cost_items(UIList): class BIM_UL_cost_items(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname): def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
if item: if item:
props = context.scene.BIMCostProperties self.props = context.scene.BIMCostProperties
cost_item = Data.cost_items[item.ifc_definition_id] cost_item = Data.cost_items[item.ifc_definition_id]
row = layout.row(align=True) row = layout.row(align=True)
@@ -366,40 +392,30 @@ class BIM_UL_cost_items(UIList):
else: else:
row.label(text="", icon="DOT") row.label(text="", icon="DOT")
split1 = row.split(factor=0.7) split1 = row.split(factor=0.1)
split1.prop(item, "name", emboss=False, text="") split1.prop(item, "identification", emboss=False, text="")
split2 = split1.split(factor=0.5)
split2.alignment = "RIGHT"
split2.prop(item, "name", emboss=False, text="")
if Data.cost_schedules[props.active_cost_schedule_id]["PredefinedType"] != "SCHEDULEOFRATES": if Data.cost_schedules[self.props.active_cost_schedule_id]["PredefinedType"] != "SCHEDULEOFRATES":
op = row.operator("bim.enable_editing_cost_item_quantities", text="", icon="PROPERTIES") split2.label(text="{0:.2f}".format(cost_item["TotalCostQuantity"]) + f" ({cost_item['UnitSymbol'] or '?'})")
op.cost_item = item.ifc_definition_id
row.label(text="{0:.2f}".format(cost_item["TotalCostQuantity"]) + f" ({cost_item['UnitSymbol']})")
op = row.operator("bim.enable_editing_cost_item_values", text="", icon="DISC") split2.label(text="{0:.2f}".format(cost_item["TotalAppliedValue"]))
op.cost_item = item.ifc_definition_id
row.label(text="{0:.2f}".format(cost_item["TotalAppliedValue"]))
for column in props.columns: for column in self.props.columns:
row.label(text=str(cost_item["CategoryValues"].get(column.name, "-"))) split2.label(text=str(cost_item["CategoryValues"].get(column.name, "-")))
row.label(text="{0:.2f}".format(cost_item["TotalCostValue"]), icon="CON_TRANSLIKE") split2.label(text="{0:.2f}".format(cost_item["TotalCostValue"]))
self.draw_buttons(split2, item, cost_item)
if props.active_cost_item_id == item.ifc_definition_id: def draw_buttons(self, row, item, cost_item):
if props.cost_item_editing_type == "ATTRIBUTES": pass # TODO: reimplement somewhere with better UX
row.operator("bim.edit_cost_item", text="", icon="CHECKMARK") # elif self.props.active_cost_item_id:
row.operator("bim.disable_editing_cost_item", text="", icon="CANCEL") # if self.props.cost_item_editing_type == "VALUES":
elif props.active_cost_item_id: # op = row.operator("bim.copy_cost_item_values", text="", icon="COPYDOWN")
if props.cost_item_editing_type == "VALUES": # op.source = self.props.active_cost_item_id
op = row.operator("bim.copy_cost_item_values", text="", icon="COPYDOWN") # op.destination = item.ifc_definition_id
op.source = props.active_cost_item_id
op.destination = item.ifc_definition_id
row.operator("bim.add_cost_item", text="", icon="ADD").cost_item = item.ifc_definition_id
row.operator("bim.remove_cost_item", text="", icon="X").cost_item = item.ifc_definition_id
else:
row.operator(
"bim.enable_editing_cost_item", text="", icon="GREASEPENCIL"
).cost_item = item.ifc_definition_id
row.operator("bim.add_cost_item", text="", icon="ADD").cost_item = item.ifc_definition_id
row.operator("bim.remove_cost_item", text="", icon="X").cost_item = item.ifc_definition_id
class BIM_UL_cost_columns(UIList): class BIM_UL_cost_columns(UIList):
+4 -1
View File
@@ -60,18 +60,20 @@ class Csv2Ifc:
def get_row_cost_data(self, row): def get_row_cost_data(self, row):
name = row[self.headers["Name"]] name = row[self.headers["Name"]]
identification = row[self.headers["Identification"]] if "Identification" in self.headers else None
cost_quantities = row[self.headers["Quantity"]] cost_quantities = row[self.headers["Quantity"]]
cost_quantities_unit = row[self.headers["Unit"]] cost_quantities_unit = row[self.headers["Unit"]]
if self.has_categories: if self.has_categories:
cost_values = { cost_values = {
k: float(row[v]) k: float(row[v])
for k, v in self.headers.items() for k, v in self.headers.items()
if k not in ["Hierarchy", "Name", "Quantity", "Unit", "Subtotal"] and row[v] if k not in ["Hierarchy", "Identification", "Name", "Quantity", "Unit", "Subtotal"] and row[v]
} }
else: else:
cost_values = row[self.headers["Value"]] cost_values = row[self.headers["Value"]]
cost_values = float(cost_values) if cost_values else None cost_values = float(cost_values) if cost_values else None
return { return {
"Identification": str(identification) if identification else None,
"Name": str(name) if name else None, "Name": str(name) if name else None,
"CostQuantities": float(cost_quantities) if cost_quantities else None, "CostQuantities": float(cost_quantities) if cost_quantities else None,
"CostQuantitiesUnit": str(cost_quantities_unit) if cost_quantities_unit else None, "CostQuantitiesUnit": str(cost_quantities_unit) if cost_quantities_unit else None,
@@ -99,6 +101,7 @@ class Csv2Ifc:
cost_item["ifc"] = ifcopenshell.api.run("cost.add_cost_item", self.file, cost_item=parent) cost_item["ifc"] = ifcopenshell.api.run("cost.add_cost_item", self.file, cost_item=parent)
cost_item["ifc"].Name = cost_item["Name"] cost_item["ifc"].Name = cost_item["Name"]
cost_item["ifc"].Identification = cost_item["Identification"]
if not cost_item["CostValues"]: if not cost_item["CostValues"]:
cost_value = ifcopenshell.api.run("cost.add_cost_value", self.file, parent=cost_item["ifc"]) cost_value = ifcopenshell.api.run("cost.add_cost_value", self.file, parent=cost_item["ifc"])
+14 -14
View File
@@ -1,14 +1,14 @@
"Hierarchy","Name","Quantity","Unit","Foo","Bar","Baz","Subtotal" "Hierarchy","Identification","Name","Quantity","Unit","Foo","Bar","Baz","Subtotal"
1,"Demolition",,,,,,301 1,1,"Demolition",,,,,,301
,,,,,,, ,,,,,,,,
2,"Building A",,,,,,96 2,1.1,"Building A",,,,,,96
,,,,,,, ,,,,,,,,
3,"Soft strip",1,"m",5,4,3,12 3,"1.1.1","Soft strip",1,"m",5,4,3,12
3,"Hard Strip",2,"m2",6,5,4,30 3,"1.1.2","Hard Strip",2,"m2",6,5,4,30
3,"Hazmat",3,"m3",7,6,5,54 3,"1.1.3","Hazmat",3,"m3",7,6,5,54
,,,,,,, ,,,,,,,,
2,"Building B",,,,,,205 2,1.2,"Building B",,,,,,205
,,,,,,, ,,,,,,,,
3,"Soft strip",4,"hr",8,7,,60 3,"1.2.1","Soft strip",4,"hr",8,7,,60
3,"Hard Strip",5,,9,,8,85 3,"1.2.2","Hard Strip",5,,9,,8,85
3,"Hazmat",6,"kg",10,,,60 3,"1.2.3","Hazmat",6,"kg",10,,,60
1 Hierarchy Identification Name Quantity Unit Foo Bar Baz Subtotal
2 1 1 Demolition 301
3
4 2 1.1 Building A 96
5
6 3 1.1.1 Soft strip 1 m 5 4 3 12
7 3 1.1.2 Hard Strip 2 m2 6 5 4 30
8 3 1.1.3 Hazmat 3 m3 7 6 5 54
9
10 2 1.2 Building B 205
11
12 3 1.2.1 Soft strip 4 hr 8 7 60
13 3 1.2.2 Hard Strip 5 9 8 85
14 3 1.2.3 Hazmat 6 kg 10 60