New Status panel for managing statuses in the costing / scheduling tab.

This commit is contained in:
Dion Moult
2023-08-23 17:08:28 +10:00
parent 098420b858
commit 4217318654
9 changed files with 208 additions and 24 deletions
+4 -1
View File
@@ -146,7 +146,10 @@ classes = [
# Structural analysis
ui.BIM_PT_tab_structural,
# Construction scheduling
ui.BIM_PT_tab_4D5D,
ui.BIM_PT_tab_status,
ui.BIM_PT_tab_resources,
ui.BIM_PT_tab_cost,
ui.BIM_PT_tab_sequence,
# Facility management
ui.BIM_PT_tab_handover,
ui.BIM_PT_tab_operations,
@@ -29,7 +29,8 @@ class BIM_PT_cost_schedules(Panel):
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
bl_parent_id = "BIM_PT_tab_4D5D"
bl_parent_id = "BIM_PT_tab_cost"
bl_options = {"HIDE_HEADER"}
@classmethod
def poll(cls, context):
@@ -38,24 +38,24 @@ class CsvAttribute(PropertyGroup):
sort: EnumProperty(items=[("NONE", "None", ""), ("ASC", "Ascending", ""), ("DESC", "Descending", "")])
group: EnumProperty(
items=[
("NONE", "None", ""),
("GROUP", "Group", "All rows where this value is identical will be merged."),
("CONCAT", "Concatenation", "Concatenate values if values vary within a group."),
("VARIES", "Varies", "Show a custom value if values vary within a group."),
("SUM", "Sum", "Sums the total value of rows in a group."),
("AVERAGE", "Average", "Averages the total value of rows in a group."),
("MIN", "Min", "Gets the minimum value of rows in a group."),
("MAX", "Max", "Gets the maximum value of rows in a group."),
("NONE", "None", "Don't group any rows"),
("GROUP", "Group", "All rows where this value is identical will be merged"),
("CONCAT", "Concatenation", "Concatenate values if values vary within a group"),
("VARIES", "Varies", "Show a custom value if values vary within a group"),
("SUM", "Sum", "Sums the total value of rows in a group"),
("AVERAGE", "Average", "Averages the total value of rows in a group"),
("MIN", "Min", "Gets the minimum value of rows in a group"),
("MAX", "Max", "Gets the maximum value of rows in a group"),
]
)
varies_value: StringProperty(default="Varies", name="Varies Value")
summary: EnumProperty(
items=[
("NONE", "None", ""),
("SUM", "Sum", "Sums the total value of all rows."),
("AVERAGE", "Average", "Averages the total value of all rows."),
("MIN", "Min", "Gets the minimum value of all rows."),
("MAX", "Max", "Gets the maximum value of all rows."),
("NONE", "None", "Don't provide a summary row"),
("SUM", "Sum", "Sums the total value of all rows"),
("AVERAGE", "Average", "Averages the total value of all rows"),
("MIN", "Min", "Gets the minimum value of all rows"),
("MAX", "Max", "Gets the maximum value of all rows"),
]
)
@@ -28,7 +28,8 @@ class BIM_PT_resources(Panel):
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
bl_parent_id = "BIM_PT_tab_4D5D"
bl_parent_id = "BIM_PT_tab_resources"
bl_options = {"HIDE_HEADER"}
@classmethod
def poll(cls, context):
@@ -118,12 +118,18 @@ classes = (
operator.UnassignWorkSchedule,
operator.VisualiseWorkScheduleDate,
operator.VisualiseWorkScheduleDateRange,
operator.EnableStatusFilters,
operator.DisableStatusFilters,
operator.ActivateStatusFilters,
operator.SelectStatusFilter,
prop.WorkPlan,
prop.BIMWorkPlanProperties,
prop.Task,
prop.TaskResource,
prop.TaskProduct,
prop.ISODuration,
prop.IFCStatus,
prop.BIMStatusProperties,
prop.BIMWorkScheduleProperties,
prop.BIMTaskTreeProperties,
prop.BIMTaskTypeColor,
@@ -133,6 +139,7 @@ classes = (
prop.BIMWorkCalendarProperties,
prop.DatePickerProperties,
prop.BIMDateTextProperties,
ui.BIM_PT_status,
ui.BIM_PT_work_plans,
ui.BIM_PT_work_schedules,
ui.BIM_PT_work_calendars,
@@ -165,6 +172,7 @@ def menu_func_import(self, context):
def register():
bpy.types.Scene.BIMStatusProperties = bpy.props.PointerProperty(type=prop.BIMStatusProperties)
bpy.types.Scene.BIMWorkPlanProperties = bpy.props.PointerProperty(type=prop.BIMWorkPlanProperties)
bpy.types.Scene.BIMWorkScheduleProperties = bpy.props.PointerProperty(type=prop.BIMWorkScheduleProperties)
bpy.types.Scene.BIMTaskTreeProperties = bpy.props.PointerProperty(type=prop.BIMTaskTreeProperties)
@@ -177,6 +185,7 @@ def register():
def unregister():
del bpy.types.Scene.BIMStatusProperties
del bpy.types.Scene.BIMWorkPlanProperties
del bpy.types.Scene.BIMWorkScheduleProperties
del bpy.types.Scene.BIMTaskTreeProperties
@@ -27,11 +27,98 @@ import webbrowser
import blenderbim.core.sequence as core
import blenderbim.tool as tool
import blenderbim.bim.module.sequence.helper as helper
import ifcopenshell.util.sequence
import ifcopenshell.util.selector
from datetime import datetime
from dateutil import parser, relativedelta
from blenderbim.bim.ifc import IfcStore
from bpy_extras.io_utils import ImportHelper
import ifcopenshell.util.sequence
class EnableStatusFilters(bpy.types.Operator):
bl_idname = "bim.enable_status_filters"
bl_label = "Enable Status Filters"
def execute(self, context):
props = context.scene.BIMStatusProperties
props.is_enabled = True
props.statuses.clear()
statuses = set()
for element in tool.Ifc.get().by_type("IfcPropertyEnumeratedValue"):
if element.Name == "Status":
pset = element.PartOfPset[0]
if pset.Name.startswith("Pset_") and pset.Name.endswith("Common"):
statuses.update(element.EnumerationValues)
elif pset.Name == "EPset_Status": # Our secret sauce
statuses.update(element.EnumerationValues)
elif element.Name == "UserDefinedStatus":
statuses.add(element.NominalValue)
statuses = ["No Status"] + sorted([s.wrappedValue for s in statuses])
for status in statuses:
new = props.statuses.add()
new.name = status
return {"FINISHED"}
class DisableStatusFilters(bpy.types.Operator):
bl_idname = "bim.disable_status_filters"
bl_label = "Disable Status Filters"
def execute(self, context):
props = context.scene.BIMStatusProperties
props.is_enabled = False
return {"FINISHED"}
class ActivateStatusFilters(bpy.types.Operator):
bl_idname = "bim.activate_status_filters"
bl_label = "Activate Status Filters"
def execute(self, context):
props = context.scene.BIMStatusProperties
query = []
visible_statuses = {s.name for s in props.statuses if s.is_visible}
for name in visible_statuses:
if name == "No Status":
q = f"IfcProduct, /Pset_.*Common/.Status=NULL, EPset_Status.Status=NULL"
else:
q = f"IfcProduct, /Pset_.*Common/.Status={name} + IfcProduct, EPset_Status.Status={name}"
query.append(q)
query = " + ".join(query)
if not query:
return {"FINISHED"}
visible_elements = ifcopenshell.util.selector.filter_elements(tool.Ifc.get(), query)
for obj in bpy.context.view_layer.objects:
element = tool.Ifc.get_entity(obj)
if not element or not element.is_a("IfcProduct"):
continue
obj.hide_set(element not in visible_elements)
return {"FINISHED"}
class SelectStatusFilter(bpy.types.Operator):
bl_idname = "bim.select_status_filter"
bl_label = "Select Status Filter"
name: bpy.props.StringProperty()
def execute(self, context):
props = context.scene.BIMStatusProperties
query = f"IfcProduct, /Pset_.*Common/.Status={self.name} + IfcProduct, EPset_Status.Status={self.name}"
if self.name == "No Status":
query = f"IfcProduct, /Pset_.*Common/.Status=NULL, EPset_Status.Status=NULL"
for element in ifcopenshell.util.selector.filter_elements(tool.Ifc.get(), query):
obj = tool.Ifc.get_object(element)
if obj:
obj.select_set(True)
return {"FINISHED"}
class AddWorkPlan(bpy.types.Operator, tool.Ifc.Operator):
@@ -381,6 +381,16 @@ class ISODuration(PropertyGroup):
seconds: IntProperty(name="Seconds", default=0)
class IFCStatus(PropertyGroup):
name: StringProperty(name="Name")
is_visible: BoolProperty(name="Is Visible", default=True)
class BIMStatusProperties(PropertyGroup):
is_enabled: BoolProperty(name="Is Enabled")
statuses: CollectionProperty(name="Statuses", type=IFCStatus)
class BIMWorkScheduleProperties(PropertyGroup):
work_schedule_predefined_types: EnumProperty(
items=get_schedule_predefined_types, name="Predefined Type", default=None
@@ -30,6 +30,38 @@ from blenderbim.bim.module.sequence.data import (
)
class BIM_PT_status(Panel):
bl_label = "Status"
bl_idname = "BIM_PT_status"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
bl_parent_id = "BIM_PT_tab_status"
bl_options = {"HIDE_HEADER"}
@classmethod
def poll(cls, context):
return IfcStore.get_file()
def draw(self, context):
self.props = context.scene.BIMStatusProperties
if not self.props.is_enabled:
row = self.layout.row()
row.operator("bim.enable_status_filters", icon="GREASEPENCIL")
return
row = self.layout.row(align=True)
row.operator("bim.activate_status_filters", icon="TIME")
row.operator("bim.disable_status_filters", icon="CANCEL", text="")
for status in self.props.statuses:
row = self.layout.row()
row.label(text=status.name)
row.prop(status, "is_visible", text="", emboss=False, icon="HIDE_OFF" if status.is_visible else "HIDE_ON")
row.operator("bim.select_status_filter", icon="RESTRICT_SELECT_OFF", text="").name = status.name
class BIM_PT_work_plans(Panel):
bl_label = "Work Plans"
bl_idname = "BIM_PT_work_plans"
@@ -37,7 +69,7 @@ class BIM_PT_work_plans(Panel):
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
bl_parent_id = "BIM_PT_tab_4D5D"
bl_parent_id = "BIM_PT_tab_sequence"
@classmethod
def poll(cls, context):
@@ -107,7 +139,7 @@ class BIM_PT_work_schedules(Panel):
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
bl_parent_id = "BIM_PT_tab_4D5D"
bl_parent_id = "BIM_PT_tab_sequence"
@classmethod
def poll(cls, context):
@@ -550,7 +582,7 @@ class BIM_PT_animation_Color_Scheme(Panel):
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
bl_parent_id = "BIM_PT_tab_4D5D"
bl_parent_id = "BIM_PT_tab_sequence"
@classmethod
def poll(cls, context):
@@ -888,7 +920,7 @@ class BIM_PT_work_calendars(Panel):
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
bl_parent_id = "BIM_PT_tab_4D5D"
bl_parent_id = "BIM_PT_tab_sequence"
@classmethod
def poll(cls, context):
+44 -3
View File
@@ -408,12 +408,53 @@ class BIM_PT_geometry(Panel):
pass
class BIM_PT_tab_4D5D(Panel):
bl_label = "Costing and Scheduling"
class BIM_PT_tab_status(Panel):
bl_label = "Status"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
@classmethod
def poll(cls, context):
return tool.Blender.is_tab(context, "SCHEDULING") and tool.Ifc.get()
def draw(self, context):
pass
class BIM_PT_tab_resources(Panel):
bl_label = "Resources"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
@classmethod
def poll(cls, context):
return tool.Blender.is_tab(context, "SCHEDULING") and tool.Ifc.get()
def draw(self, context):
pass
class BIM_PT_tab_cost(Panel):
bl_label = "Cost"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
@classmethod
def poll(cls, context):
return tool.Blender.is_tab(context, "SCHEDULING") and tool.Ifc.get()
def draw(self, context):
pass
class BIM_PT_tab_sequence(Panel):
bl_label = "Construction Scheduling"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
bl_options = {"HIDE_HEADER"}
@classmethod
def poll(cls, context):