diff --git a/src/blenderbim/blenderbim/bim/module/sequence/__init__.py b/src/blenderbim/blenderbim/bim/module/sequence/__init__.py index 9d08abf0da..803e8dfa11 100644 --- a/src/blenderbim/blenderbim/bim/module/sequence/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/sequence/__init__.py @@ -73,6 +73,8 @@ classes = ( operator.BlenderBIM_DatePicker, operator.BlenderBIM_DatePickerSetDate, operator.BlenderBIM_RedrawDatePicker, + operator.AddTaskColumn, + operator.RemoveTaskColumn, prop.WorkPlan, prop.BIMWorkPlanProperties, prop.Task, @@ -85,6 +87,7 @@ classes = ( ui.BIM_PT_work_plans, ui.BIM_PT_work_schedules, ui.BIM_PT_work_calendars, + ui.BIM_UL_task_columns, ui.BIM_UL_tasks, ) diff --git a/src/blenderbim/blenderbim/bim/module/sequence/operator.py b/src/blenderbim/blenderbim/bim/module/sequence/operator.py index 8da8d671a2..fe0d3e8684 100644 --- a/src/blenderbim/blenderbim/bim/module/sequence/operator.py +++ b/src/blenderbim/blenderbim/bim/module/sequence/operator.py @@ -1705,3 +1705,28 @@ class RecalculateSchedule(bpy.types.Operator): ) Data.load(self.file) return {"FINISHED"} + + +class AddTaskColumn(bpy.types.Operator): + bl_idname = "bim.add_task_column" + bl_label = "Add Task Column" + type: bpy.props.StringProperty() + name: bpy.props.StringProperty() + + def execute(self, context): + self.props = context.scene.BIMWorkScheduleProperties + new = self.props.columns.add() + name, data_type = self.name.split("/") + new.name = f"{self.type}.{name}" + new.data_type = data_type + return {"FINISHED"} + + +class RemoveTaskColumn(bpy.types.Operator): + bl_idname = "bim.remove_task_column" + bl_label = "Remove Task Column" + + def execute(self, context): + self.props = context.scene.BIMWorkScheduleProperties + self.props.columns.remove(self.props.active_column_index) + return {"FINISHED"} diff --git a/src/blenderbim/blenderbim/bim/module/sequence/prop.py b/src/blenderbim/blenderbim/bim/module/sequence/prop.py index 9c75f55d24..0d8f435d1f 100644 --- a/src/blenderbim/blenderbim/bim/module/sequence/prop.py +++ b/src/blenderbim/blenderbim/bim/module/sequence/prop.py @@ -1,5 +1,6 @@ import bpy import ifcopenshell.api +import ifcopenshell.util.attribute from blenderbim.bim.ifc import IfcStore from ifcopenshell.api.sequence.data import Data from blenderbim.bim.prop import StrProperty, Attribute @@ -17,6 +18,53 @@ from bpy.props import ( ) +taskcolumns_enum = [] +tasktimecolumns_enum = [] + + +def purge(): + global taskcolumns_enum + global tasktimecolumns_enum + taskcolumns_enum = [] + tasktimecolumns_enum = [] + + +def getTaskColumns(self, context): + global taskcolumns_enum + if not len(taskcolumns_enum) and IfcStore.get_schema(): + taskcolumns_enum.extend( + [ + (a.name() + "/" + ifcopenshell.util.attribute.get_primitive_type(a), a.name(), "") + for a in IfcStore.get_schema().declaration_by_name("IfcTask").all_attributes() + if ifcopenshell.util.attribute.get_primitive_type(a) + in ["string", "float", "integer", "boolean", "enum"] + ] + ) + return taskcolumns_enum + + +def getTaskTimeColumns(self, context): + global tasktimecolumns_enum + if not len(tasktimecolumns_enum) and IfcStore.get_schema(): + tasktimecolumns_enum.extend( + [ + (a.name() + "/" + ifcopenshell.util.attribute.get_primitive_type(a), a.name(), "") + for a in IfcStore.get_schema().declaration_by_name("IfcTaskTime").all_attributes() + if ifcopenshell.util.attribute.get_primitive_type(a) + in ["string", "float", "integer", "boolean", "enum"] + ] + ) + return tasktimecolumns_enum + + +def getWorkSchedules(self, context): + return [(str(k), v["Name"], "") for k, v in Data.work_schedules.items()] + + +def getWorkCalendars(self, context): + return [(str(k), v["Name"], "") for k, v in Data.work_calendars.items()] + + def updateTaskName(self, context): props = context.scene.BIMWorkScheduleProperties if not props.is_task_update_enabled or self.name == "Unnamed": @@ -160,17 +208,6 @@ def updateVisualisationStartFinish(self, context, startfinish): setattr(self, startfinish, canonical_value) -workschedule_enum = [] - - -def getWorkSchedules(self, context): - return [(str(k), v["Name"], "") for k, v in Data.work_schedules.items()] - - -def getWorkCalendars(self, context): - return [(str(k), v["Name"], "") for k, v in Data.work_calendars.items()] - - class Task(PropertyGroup): name: StringProperty(name="Name", update=updateTaskName) identification: StringProperty(name="Identification", update=updateTaskIdentification) @@ -216,8 +253,17 @@ class BIMWorkScheduleProperties(PropertyGroup): active_task_id: IntProperty(name="Active Task Id") task_attributes: CollectionProperty(name="Task Attributes", type=Attribute) should_show_visualisation_ui: BoolProperty(name="Should Show Visualisation UI", default=False) - should_show_times: BoolProperty(name="Should Show Times", default=False) - should_show_calendars: BoolProperty(name="Should Show Calendars", default=False) + should_show_column_ui: BoolProperty(name="Should Show Column UI", default=False) + columns: CollectionProperty(name="Columns", type=Attribute) + active_column_index: IntProperty(name="Active Column Index") + task_columns: EnumProperty(items=getTaskColumns, name="Task Columns") + task_time_columns: EnumProperty(items=getTaskTimeColumns, name="Task Time Columns") + other_columns: EnumProperty( + items=[ + ("Controls.Calendar", "Calendar", ""), + ], + name="Special Columns", + ) active_task_time_id: IntProperty(name="Active Task Id") task_time_attributes: CollectionProperty(name="Task Time Attributes", type=Attribute) contracted_tasks: StringProperty(name="Contracted Task Items", default="[]") diff --git a/src/blenderbim/blenderbim/bim/module/sequence/ui.py b/src/blenderbim/blenderbim/bim/module/sequence/ui.py index c47a409217..5913f1c303 100644 --- a/src/blenderbim/blenderbim/bim/module/sequence/ui.py +++ b/src/blenderbim/blenderbim/bim/module/sequence/ui.py @@ -111,8 +111,7 @@ class BIM_PT_work_schedules(Panel): if self.props.editing_type == "WORK_SCHEDULE": row.operator("bim.edit_work_schedule", text="", icon="CHECKMARK") elif self.props.editing_type == "TASKS": - row.prop(self.props, "should_show_times", text="", icon="TIME") - row.prop(self.props, "should_show_calendars", text="", icon="VIEW_ORTHO") + row.prop(self.props, "should_show_column_ui", text="", icon="SHORTDISPLAY") row.prop(self.props, "should_show_visualisation_ui", text="", icon="CAMERA_STEREO") row.operator("bim.generate_gantt_chart", text="", icon="NLA").work_schedule = work_schedule_id row.operator("bim.recalculate_schedule", text="", icon="FILE_REFRESH").work_schedule = work_schedule_id @@ -128,6 +127,8 @@ class BIM_PT_work_schedules(Panel): row.operator("bim.remove_work_schedule", text="", icon="X").work_schedule = work_schedule_id if self.props.active_work_schedule_id == work_schedule_id: + if self.props.should_show_column_ui: + self.draw_column_ui() if self.props.should_show_visualisation_ui: self.draw_visualisation_ui() if self.props.editing_type == "WORK_SCHEDULE": @@ -135,6 +136,28 @@ class BIM_PT_work_schedules(Panel): elif self.props.editing_type == "TASKS": self.draw_editable_task_ui(work_schedule_id) + def draw_column_ui(self): + row = self.layout.row(align=True) + row.prop(self.props, "task_columns", text="") + op = row.operator("bim.add_task_column", text="", icon="ADD") + op.type = "IfcTask" + op.name = self.props.task_columns + + row = self.layout.row(align=True) + row.prop(self.props, "task_time_columns", text="") + op = row.operator("bim.add_task_column", text="", icon="ADD") + op.type = "IfcTaskTime" + op.name = self.props.task_time_columns + + row = self.layout.row(align=True) + row.prop(self.props, "other_columns", text="") + op = row.operator("bim.add_task_column", text="", icon="ADD") + type, name = self.props.other_columns.split(".") + op.type = type + op.name = f"{name}/string" + + self.layout.template_list("BIM_UL_task_columns", "", self.props, "columns", self.props, "active_column_index") + def draw_visualisation_ui(self): row = self.layout.row(align=True) target_prop = "BIMWorkScheduleProperties.visualisation_start" @@ -260,10 +283,19 @@ class BIM_PT_work_schedules(Panel): blenderbim.bim.helper.draw_attributes(self.props.task_time_attributes, self.layout) +class BIM_UL_task_columns(UIList): + def draw_item(self, context, layout, data, item, icon, active_data, active_propname): + if item: + row = layout.row(align=True) + row.prop(item, "name", emboss=False, text="") + row.operator("bim.remove_task_column", text="", icon="X") + + class BIM_UL_tasks(UIList): def draw_item(self, context, layout, data, item, icon, active_data, active_propname): if item: props = context.scene.BIMWorkScheduleProperties + task = IfcStore.get_file().by_id(item.ifc_definition_id) row = layout.row(align=True) for i in range(0, item.level_index): row.label(text="", icon="BLANK1") @@ -281,27 +313,36 @@ class BIM_UL_tasks(UIList): row.prop(item, "identification", emboss=False, text="") row.prop(item, "name", emboss=False, text="") - if props.should_show_times: - if item.derived_start: - row.label(text=item.derived_start + "*") + for column in props.columns: + if column.name == "IfcTaskTime.ScheduleStart": + if item.derived_start: + row.label(text=item.derived_start + "*") + else: + row.prop(item, "start", emboss=False, text="") + elif column.name == "IfcTaskTime.ScheduleFinish": + if item.derived_finish: + row.label(text=item.derived_finish + "*") + else: + row.prop(item, "finish", emboss=False, text="") + elif column.name == "IfcTaskTime.ScheduleDuration": + if item.derived_duration: + row.label(text=item.derived_duration + "*") + else: + row.prop(item, "duration", emboss=False, text="") + elif column.name == "Controls.Calendar": + if item.derived_calendar: + row.label(text=item.derived_calendar + "*") + else: + row.label(text=item.calendar or "-") else: - row.prop(item, "start", emboss=False, text="") - - if item.derived_finish: - row.label(text=item.derived_finish + "*") - else: - row.prop(item, "finish", emboss=False, text="") - - if item.derived_duration: - row.label(text=item.derived_duration + "*") - else: - row.prop(item, "duration", emboss=False, text="") - - if props.should_show_calendars: - if item.derived_calendar: - row.label(text=item.derived_calendar + "*") - else: - row.label(text=item.calendar or "-") + ifc_class, name = column.name.split(".") + if ifc_class == "IfcTask": + value = getattr(task, name) + elif ifc_class == "IfcTaskTime": + value = getattr(task.TaskTime, name) if task.TaskTime else None + if value is None: + value = "-" + row.label(text=str(value)) if context.active_object: oprops = context.active_object.BIMObjectProperties