Features to re-order cost items in a tree (changing parent & changing nesting order)

This commit is contained in:
Sigma Dimensions
2023-03-29 01:49:55 +00:00
parent 73feadcd66
commit fa261b3281
7 changed files with 145 additions and 23 deletions
@@ -70,10 +70,12 @@ classes = (
operator.ClearCostItemAssignments,
operator.HighlightProductCostItem,
operator.LoadProductCostItems,
operator.ReorderCostItem,
operator.SelectUnassignedProducts,
operator.LoadCostItemElementQuantities,
operator.LoadCostItemTaskQuantities,
operator.LoadCostItemResourceQuantities,
operator.ChangeParentCostItem,
prop.CostItem,
prop.CostItemQuantity,
prop.CostItemType,
@@ -89,9 +89,16 @@ class CostSchedulesData:
data = {}
cls._load_cost_item_quantities(cost_item, data)
cls._load_cost_values(cost_item, data)
cls._load_nesting_index(cost_item, data)
results[cost_item.id()] = data
return results
@classmethod
def _load_nesting_index(cls, cost_item, data):
data["NestingIndex"] = None
for rel in cost_item.Nests or []:
data["NestingIndex"] = rel.RelatedObjects.index(cost_item)
@classmethod
def _load_cost_values(cls, root_element, data):
# data["CostValues"] = []
@@ -119,34 +126,51 @@ class CostSchedulesData:
@classmethod
def _load_cost_item_quantities(cls, cost_item, data):
parametric_quantities = []
for rel in cost_item.Controls:
for related_object in rel.RelatedObjects or []:
quantities = cls._get_object_quantities(cost_item, related_object)
# data["Controls"][related_object.id()] = quantities
parametric_quantities.extend(quantities)
# data["CostQuantities"] = []
# parametric_quantities = []
# for rel in cost_item.Controls:
# for related_object in rel.RelatedObjects or []:
# quantities = cls._get_object_quantities(cost_item, related_object)
# parametric_quantities.extend(quantities)
data["TotalCostQuantity"] = ifcopenshell.util.cost.get_total_quantity(cost_item)
for quantity in cost_item.CostQuantities or []:
if quantity.id() in parametric_quantities:
continue
# quantity_data = quantity.get_info()
# del quantity_data["Unit"]
# cls.physical_quantities[quantity.id()] = quantity_data
# data["CostQuantities"].append(quantity.id())
# data["Unit"] = None
data["UnitSymbol"] = "?"
data["UnitSymbol"] = "-"
if cost_item.CostQuantities:
quantity = cost_item.CostQuantities[0]
unit = ifcopenshell.util.unit.get_property_unit(quantity, tool.Ifc.get())
if unit:
# data["Unit"] = unit.id()
data["UnitSymbol"] = ifcopenshell.util.unit.get_unit_symbol(unit)
else:
# data["Unit"] = None
data["UnitSymbol"] = None
# same_unit_nested_cost_item = set()
# data["DerivedTotalCostQuantity"] = None
# if cost_item.IsNestedBy:
# data["TotalCostQuantity"] = 0.0
# derived_quantity = 0
# derived_unit = None
# should_sum = False
# for rel in cost_item.IsNestedBy:
# for related_object in rel.RelatedObjects or []:
# for quantity in related_object.CostQuantities or []:
# nested_unit = ifcopenshell.util.unit.get_property_unit(quantity, tool.Ifc.get())
# if derived_unit is None:
# derived_unit = nested_unit
# elif nested_unit and nested_unit.id() == derived_unit.id():
# same_unit_nested_cost_item.add(related_object)
# else:
# derived_unit = None
# break
# for cost in same_unit_nested_cost_item:
# qto = ifcopenshell.util.cost.get_total_quantity(cost)
# derived_quantity += qto
# print(derived_quantity)
# if derived_quantity not in [0, None]:
# data["DerivedTotalCostQuantity"] = derived_quantity
# if derived_unit:
# data["DerivedUnitSymbol"] = ifcopenshell.util.unit.get_unit_symbol(derived_unit)
# else:
# data["DerivedUnitSymbol"] = "?"
# print("Total Cost", data["DerivedTotalCostQuantity"], cost_item.Name)
@classmethod
def _get_object_quantities(cls, cost_item, element):
if not element.is_a("IfcObject"):
@@ -236,6 +260,7 @@ class CostSchedulesData:
break
return results
class CostItemRatesData:
data = {}
is_loaded = False
@@ -23,7 +23,6 @@ import time
import ifcopenshell.api
import blenderbim.bim.helper
import blenderbim.tool as tool
from blenderbim.bim.ifc import IfcStore
from bpy_extras.io_utils import ImportHelper
import blenderbim.tool as tool
import blenderbim.core.cost as core
@@ -36,7 +35,7 @@ class AddCostSchedule(bpy.types.Operator, tool.Ifc.Operator):
bl_description = "Add a new cost schedule"
def _execute(self, context):
core.add_cost_schedule(tool.Ifc, predefined_type = context.scene.BIMCostProperties.cost_schedule_predefined_types)
core.add_cost_schedule(tool.Ifc, predefined_type=context.scene.BIMCostProperties.cost_schedule_predefined_types)
class EditCostSchedule(bpy.types.Operator, tool.Ifc.Operator):
@@ -685,6 +684,25 @@ class HighlightProductCostItem(bpy.types.Operator):
return {"FINISHED"}
class ReorderCostItem(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.reorder_cost_item_nesting"
bl_label = "Reorder Nesting"
bl_options = {"REGISTER", "UNDO"}
new_index: bpy.props.IntProperty()
cost_item: bpy.props.IntProperty()
def _execute(self, context):
ifcopenshell.api.run(
"nest.reorder_nesting",
tool.Ifc.get(),
**{
"item": tool.Ifc.get().by_id(self.cost_item),
"new_index": self.new_index,
},
)
tool.Cost.load_cost_schedule_tree()
class SelectUnassignedProducts(bpy.types.Operator):
bl_idname = "bim.select_unassigned_products"
bl_label = "Select Unassigned Products"
@@ -693,3 +711,16 @@ class SelectUnassignedProducts(bpy.types.Operator):
def execute(self, context):
core.select_unassigned_products(tool.Ifc, tool.Cost, tool.Spatial)
return {"FINISHED"}
class ChangeParentCostItem(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.change_parent_cost_item"
bl_label = "Change Parent Cost Item"
bl_options = {"REGISTER", "UNDO"}
new_parent: bpy.props.IntProperty()
def _execute(self, context):
r = core.change_parent_cost_item(tool.Ifc, tool.Cost, new_parent=tool.Ifc.get().by_id(self.new_parent))
if isinstance(r, str):
self.report({"WARNING"}, r)
return {"FINISHED"}
@@ -134,6 +134,12 @@ class CostItemType(PropertyGroup):
name: StringProperty(name="Name")
ifc_definition_id: IntProperty(name="IFC Definition ID")
def update_cost_item_parent(self, context):
cost_item = tool.Cost.get_highlighted_cost_item()
tool.Cost.toggle_cost_item_parent(cost_item=cost_item)
def update_active_cost_item_elements(self, context):
bpy.ops.bim.load_cost_item_element_quantities()
@@ -200,8 +206,10 @@ class BIMCostProperties(PropertyGroup):
contracted_cost_item_rates: StringProperty(name="Contracted Cost Item Rates", default="[]")
product_cost_items: CollectionProperty(name="Product Cost Items", type=CostItem)
active_product_cost_item_index: IntProperty(name="Active Product Cost Item Index")
enable_reorder: BoolProperty(name="Enable Reorder", default=False)
show_nested_elements: BoolProperty(name="Show Nested Tasks", default=False, update=update_active_cost_item_elements)
show_nested_tasks: BoolProperty(name="Show Nested Tasks", default=False, update=update_active_cost_item_tasks)
show_nested_resources: BoolProperty(
name="Show Nested Tasks", default=False, update=update_active_cost_item_resources
)
change_cost_item_parent: BoolProperty(name="Change Cost Item Parent", default=False, update=update_cost_item_parent)
@@ -105,7 +105,8 @@ class BIM_PT_cost_schedules(Panel):
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:
row.prop(self.props, "change_cost_item_parent", text="", icon="LINKED")
row.prop(self.props, "enable_reorder", text="", icon="SORTALPHA")
if not CostSchedulesData.data["is_editing_rates"]:
op = row.operator("bim.enable_editing_cost_item_quantities", text="", icon="PROPERTIES")
op.cost_item = ifc_definition_id
@@ -549,8 +550,23 @@ class BIM_UL_cost_items_trait:
split2.label(text=str(cost_item["CategoryValues"].get(column.name, "-")))
self.draw_total_cost_column(split2, cost_item)
if self.props.enable_reorder:
self.draw_order_operator(row, item.ifc_definition_id, cost_item)
if self.props.change_cost_item_parent:
self.draw_parent_operator(row, item.ifc_definition_id)
# TODO: reimplement "bim.copy_cost_item_values" somewhere with better UX
def draw_parent_operator(self, row, cost_item_id):
if self.props.active_cost_item_id:
if self.props.active_cost_item_id != cost_item_id:
op = row.operator(
"bim.change_parent_cost_item", text="", icon="LINKED", emboss=False
).new_parent = cost_item_id
else:
row.label(text="", icon="BLANK1")
def draw_hierarchy(self, row, item):
for i in range(0, item.level_index):
row.label(text="", icon="BLANK1")
@@ -581,6 +597,17 @@ class BIM_UL_cost_items_trait:
def draw_uom_column(self, layout, cost_item):
layout.label(text=cost_item["UnitBasisUnitSymbol"] or "?" if cost_item["UnitBasisValueComponent"] else "-")
def draw_order_operator(self, row, ifc_definition_id, cost_item):
if cost_item["NestingIndex"] is not None:
if cost_item["NestingIndex"] == 0:
op = row.operator("bim.reorder_cost_item_nesting", icon="TRIA_DOWN", text="")
op.cost_item = ifc_definition_id
op.new_index = cost_item["NestingIndex"] + 1
elif cost_item["NestingIndex"] > 0:
op = row.operator("bim.reorder_cost_item_nesting", icon="TRIA_UP", text="")
op.cost_item = ifc_definition_id
op.new_index = cost_item["NestingIndex"] - 1
def draw_total_quantity_column(self, layout, cost_item):
layout.label(text="{0:.2f}".format(cost_item["TotalCostQuantity"]) + f" {cost_item['UnitSymbol'] or '?'}")
+12 -1
View File
@@ -19,7 +19,6 @@ def remove_cost_schedule(ifc, cost_schedule):
def enable_editing_cost_schedule_attributes(cost, cost_schedule):
cost.load_cost_schedule_attributes(cost_schedule)
cost.enable_editing_cost_schedule_attributes(cost_schedule)
cost.play_sound()
def enable_editing_cost_items(cost, cost_schedule):
cost.enable_editing_cost_items(cost_schedule)
@@ -258,3 +257,15 @@ def highlight_product_cost_item(spatial, cost, cost_item):
cost.highlight_cost_item(cost_item)
else:
return "Cost schedule is not active"
def toggle_cost_item_parent(cost, cost_item):
cost.toggle_cost_item_parent(cost_item)
def change_parent_cost_item(ifc, cost, new_parent):
cost_item = cost.get_active_cost_item()
if cost_item and cost.is_root_cost_item(cost_item):
return "Cannot change root cost item"
if cost_item :
ifc.run("nest.change_nest", item=cost_item, new_parent=new_parent)
cost.disable_editing_cost_item_parent()
cost.load_cost_schedule_tree()
+18
View File
@@ -139,6 +139,7 @@ class Cost(blenderbim.core.tool.Cost):
@classmethod
def disable_editing_cost_item(cls):
bpy.context.scene.BIMCostProperties.active_cost_item_id = 0
bpy.context.scene.BIMCostProperties.change_cost_item_parent = False
@classmethod
def get_cost_item_attributes(cls):
@@ -612,3 +613,20 @@ class Cost(blenderbim.core.tool.Cost):
if rel.is_a("IfcRelAssignsToControl") and rel.RelatingControl.is_a("IfcCostSchedule"):
return True
@classmethod
def toggle_cost_item_parent(cls, cost_item=None):
props = bpy.context.scene.BIMCostProperties
if props.change_cost_item_parent:
props.active_cost_item_id = cost_item.id()
props.cost_item_editing_type = "PARENT"
else:
cls.disable_editing_cost_item_parent()
@classmethod
def change_parent_cost_item(cls, cost_item, new_parent):
ifcopenshell.api.run("nest.change_nest", tool.Ifc.get(), item=cost_item, new_parent=new_parent)
@classmethod
def disable_editing_cost_item_parent(cls):
bpy.context.scene.BIMCostProperties.active_cost_item_id = 0
bpy.context.scene.BIMCostProperties.change_cost_item_parent = False