mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 09:48:32 +00:00
Features to re-order cost items in a tree (changing parent & changing nesting order)
This commit is contained in:
@@ -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 '?'}")
|
||||
|
||||
|
||||
@@ -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()
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user