mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-11 18:16:40 +00:00
Implement cost identification numbers and big cleanup to cost schedule UI
This commit is contained in:
@@ -103,6 +103,7 @@ class EnableEditingCostItems(bpy.types.Operator):
|
||||
if context.preferences.addons["blenderbim"].preferences.should_play_chaching_sound:
|
||||
self.play_chaching_sound() # lol
|
||||
self.props = context.scene.BIMCostProperties
|
||||
self.props.is_cost_update_enabled = False
|
||||
self.props.active_cost_schedule_id = self.cost_schedule
|
||||
while len(self.props.cost_items) > 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"]:
|
||||
self.create_new_cost_item_li(related_object_id, 0)
|
||||
self.props.is_editing = "COST_ITEMS"
|
||||
self.props.is_cost_update_enabled = True
|
||||
return {"FINISHED"}
|
||||
|
||||
def play_chaching_sound(self):
|
||||
@@ -134,6 +136,7 @@ class EnableEditingCostItems(bpy.types.Operator):
|
||||
new = self.props.cost_items.add()
|
||||
new.ifc_definition_id = related_object_id
|
||||
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.level_index = level_index
|
||||
if cost_item["IsNestedBy"]:
|
||||
|
||||
@@ -128,11 +128,27 @@ def update_cost_item_index(self, context):
|
||||
bpy.ops.bim.load_cost_item_quantities()
|
||||
|
||||
|
||||
def updateCostItemName(self, context):
|
||||
if self.name == "Unnamed":
|
||||
def updateCostItemIdentification(self, context):
|
||||
props = context.scene.BIMCostProperties
|
||||
if not props.is_cost_update_enabled or self.identification == "XXX":
|
||||
return
|
||||
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
|
||||
if not props.is_cost_update_enabled or self.name == "Unnamed":
|
||||
return
|
||||
self.file = IfcStore.get_file()
|
||||
ifcopenshell.api.run(
|
||||
"cost.edit_cost_item",
|
||||
self.file,
|
||||
@@ -146,6 +162,7 @@ def updateCostItemName(self, context):
|
||||
|
||||
class CostItem(PropertyGroup):
|
||||
name: StringProperty(name="Name", update=updateCostItemName)
|
||||
identification: StringProperty(name="Identification", update=updateCostItemIdentification)
|
||||
ifc_definition_id: IntProperty(name="IFC Definition ID")
|
||||
has_children: BoolProperty(name="Has Children")
|
||||
is_expanded: BoolProperty(name="Is Expanded")
|
||||
@@ -159,6 +176,7 @@ class CostItemQuantity(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)
|
||||
is_editing: StringProperty(name="Is Editing")
|
||||
active_cost_schedule_id: IntProperty(name="Active Cost Schedule Id")
|
||||
|
||||
@@ -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="")
|
||||
|
||||
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(
|
||||
"BIM_UL_cost_items",
|
||||
"",
|
||||
@@ -348,7 +374,7 @@ class BIM_PT_cost_item_quantities(Panel):
|
||||
class BIM_UL_cost_items(UIList):
|
||||
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
||||
if item:
|
||||
props = context.scene.BIMCostProperties
|
||||
self.props = context.scene.BIMCostProperties
|
||||
cost_item = Data.cost_items[item.ifc_definition_id]
|
||||
row = layout.row(align=True)
|
||||
|
||||
@@ -366,40 +392,30 @@ class BIM_UL_cost_items(UIList):
|
||||
else:
|
||||
row.label(text="", icon="DOT")
|
||||
|
||||
split1 = row.split(factor=0.7)
|
||||
split1.prop(item, "name", emboss=False, text="")
|
||||
split1 = row.split(factor=0.1)
|
||||
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":
|
||||
op = row.operator("bim.enable_editing_cost_item_quantities", text="", icon="PROPERTIES")
|
||||
op.cost_item = item.ifc_definition_id
|
||||
row.label(text="{0:.2f}".format(cost_item["TotalCostQuantity"]) + f" ({cost_item['UnitSymbol']})")
|
||||
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 '?'})")
|
||||
|
||||
op = row.operator("bim.enable_editing_cost_item_values", text="", icon="DISC")
|
||||
op.cost_item = item.ifc_definition_id
|
||||
row.label(text="{0:.2f}".format(cost_item["TotalAppliedValue"]))
|
||||
split2.label(text="{0:.2f}".format(cost_item["TotalAppliedValue"]))
|
||||
|
||||
for column in props.columns:
|
||||
row.label(text=str(cost_item["CategoryValues"].get(column.name, "-")))
|
||||
for column in self.props.columns:
|
||||
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:
|
||||
if 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")
|
||||
elif props.active_cost_item_id:
|
||||
if props.cost_item_editing_type == "VALUES":
|
||||
op = row.operator("bim.copy_cost_item_values", text="", icon="COPYDOWN")
|
||||
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
|
||||
def draw_buttons(self, row, item, cost_item):
|
||||
pass # TODO: reimplement somewhere with better UX
|
||||
# elif self.props.active_cost_item_id:
|
||||
# if self.props.cost_item_editing_type == "VALUES":
|
||||
# op = row.operator("bim.copy_cost_item_values", text="", icon="COPYDOWN")
|
||||
# op.source = self.props.active_cost_item_id
|
||||
# op.destination = item.ifc_definition_id
|
||||
|
||||
|
||||
class BIM_UL_cost_columns(UIList):
|
||||
|
||||
@@ -60,18 +60,20 @@ class Csv2Ifc:
|
||||
|
||||
def get_row_cost_data(self, row):
|
||||
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_unit = row[self.headers["Unit"]]
|
||||
if self.has_categories:
|
||||
cost_values = {
|
||||
k: float(row[v])
|
||||
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:
|
||||
cost_values = row[self.headers["Value"]]
|
||||
cost_values = float(cost_values) if cost_values else None
|
||||
return {
|
||||
"Identification": str(identification) if identification else None,
|
||||
"Name": str(name) if name else None,
|
||||
"CostQuantities": float(cost_quantities) if cost_quantities 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"].Name = cost_item["Name"]
|
||||
cost_item["ifc"].Identification = cost_item["Identification"]
|
||||
|
||||
if not cost_item["CostValues"]:
|
||||
cost_value = ifcopenshell.api.run("cost.add_cost_value", self.file, parent=cost_item["ifc"])
|
||||
|
||||
+14
-14
@@ -1,14 +1,14 @@
|
||||
"Hierarchy","Name","Quantity","Unit","Foo","Bar","Baz","Subtotal"
|
||||
1,"Demolition",,,,,,301
|
||||
,,,,,,,
|
||||
2,"Building A",,,,,,96
|
||||
,,,,,,,
|
||||
3,"Soft strip",1,"m",5,4,3,12
|
||||
3,"Hard Strip",2,"m2",6,5,4,30
|
||||
3,"Hazmat",3,"m3",7,6,5,54
|
||||
,,,,,,,
|
||||
2,"Building B",,,,,,205
|
||||
,,,,,,,
|
||||
3,"Soft strip",4,"hr",8,7,,60
|
||||
3,"Hard Strip",5,,9,,8,85
|
||||
3,"Hazmat",6,"kg",10,,,60
|
||||
"Hierarchy","Identification","Name","Quantity","Unit","Foo","Bar","Baz","Subtotal"
|
||||
1,1,"Demolition",,,,,,301
|
||||
,,,,,,,,
|
||||
2,1.1,"Building A",,,,,,96
|
||||
,,,,,,,,
|
||||
3,"1.1.1","Soft strip",1,"m",5,4,3,12
|
||||
3,"1.1.2","Hard Strip",2,"m2",6,5,4,30
|
||||
3,"1.1.3","Hazmat",3,"m3",7,6,5,54
|
||||
,,,,,,,,
|
||||
2,1.2,"Building B",,,,,,205
|
||||
,,,,,,,,
|
||||
3,"1.2.1","Soft strip",4,"hr",8,7,,60
|
||||
3,"1.2.2","Hard Strip",5,,9,,8,85
|
||||
3,"1.2.3","Hazmat",6,"kg",10,,,60
|
||||
|
||||
|
Reference in New Issue
Block a user