diff --git a/src/blenderbim/blenderbim/bim/module/sequence/__init__.py b/src/blenderbim/blenderbim/bim/module/sequence/__init__.py index 9184ae5ab8..83777c9476 100644 --- a/src/blenderbim/blenderbim/bim/module/sequence/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/sequence/__init__.py @@ -42,10 +42,12 @@ classes = ( operator.UnassignProduct, operator.GenerateGanttChart, operator.ImportP6, + operator.LoadTaskProperties, prop.WorkPlan, prop.BIMWorkPlanProperties, prop.Task, prop.BIMWorkScheduleProperties, + prop.BIMTaskTreeProperties, prop.WorkCalendar, prop.BIMWorkCalendarProperties, ui.BIM_PT_work_plans, @@ -64,6 +66,7 @@ def menu_func_import(self, context): def register(): 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) bpy.types.Scene.BIMWorkCalendarProperties = bpy.props.PointerProperty(type=prop.BIMWorkCalendarProperties) bpy.types.TOPBAR_MT_file_import.append(menu_func_import) @@ -71,5 +74,6 @@ def register(): def unregister(): del bpy.types.Scene.BIMWorkPlanProperties del bpy.types.Scene.BIMWorkScheduleProperties + del bpy.types.Scene.BIMTaskTreeProperties del bpy.types.Scene.BIMWorkCalendarProperties bpy.types.TOPBAR_MT_file_import.remove(menu_func_import) diff --git a/src/blenderbim/blenderbim/bim/module/sequence/operator.py b/src/blenderbim/blenderbim/bim/module/sequence/operator.py index 3e49d5a28e..68e5659948 100644 --- a/src/blenderbim/blenderbim/bim/module/sequence/operator.py +++ b/src/blenderbim/blenderbim/bim/module/sequence/operator.py @@ -223,32 +223,22 @@ class EnableEditingTasks(bpy.types.Operator): def execute(self, context): self.props = context.scene.BIMWorkScheduleProperties + self.tprops = context.scene.BIMTaskTreeProperties self.props.active_work_schedule_id = self.work_schedule - while len(self.props.tasks) > 0: - self.props.tasks.remove(0) + while len(self.tprops.tasks) > 0: + self.tprops.tasks.remove(0) self.contracted_tasks = json.loads(self.props.contracted_tasks) for related_object_id in Data.work_schedules[self.work_schedule]["RelatedObjects"]: self.create_new_task_li(related_object_id, 0) + bpy.ops.bim.load_task_properties() self.props.is_editing = "TASKS" return {"FINISHED"} def create_new_task_li(self, related_object_id, level_index): task = Data.tasks[related_object_id] - new = self.props.tasks.add() + new = self.tprops.tasks.add() new.ifc_definition_id = related_object_id - new.name = task["Name"] or "Unnamed" - new.identification = task["Identification"] or "XXX" - if task["TaskTime"]: - task_time = Data.task_times[task["TaskTime"]] - new.start = self.canonicalise_time(task_time["ScheduleStart"]) - new.finish = self.canonicalise_time(task_time["ScheduleFinish"]) - # TODO: duration - new.duration = "-" - else: - new.start = "-" - new.finish = "-" - new.duration = "-" new.is_expanded = related_object_id not in self.contracted_tasks new.level_index = level_index if task["RelatedObjects"]: @@ -258,6 +248,38 @@ class EnableEditingTasks(bpy.types.Operator): self.create_new_task_li(related_object_id, level_index + 1) return {"FINISHED"} + +class LoadTaskProperties(bpy.types.Operator): + bl_idname = "bim.load_task_properties" + bl_label = "Load Task Properties" + task: bpy.props.IntProperty() + + def execute(self, context): + self.props = context.scene.BIMWorkScheduleProperties + self.tprops = context.scene.BIMTaskTreeProperties + self.props.is_task_update_enabled = False + for item in self.tprops.tasks: + if self.task and item.ifc_definition_id != self.task: + continue + task = Data.tasks[item.ifc_definition_id] + item.name = task["Name"] or "Unnamed" + item.identification = task["Identification"] or "XXX" + if self.props.active_task_id: + item.is_predecessor = self.props.active_task_id in task["IsPredecessorTo"] + item.is_successor = self.props.active_task_id in task["IsSuccessorFrom"] + if task["TaskTime"]: + task_time = Data.task_times[task["TaskTime"]] + item.start = self.canonicalise_time(task_time["ScheduleStart"]) + item.finish = self.canonicalise_time(task_time["ScheduleFinish"]) + # TODO: duration + item.duration = "-" + else: + item.start = "-" + item.finish = "-" + item.duration = "-" + self.props.is_task_update_enabled = True + return {"FINISHED"} + def canonicalise_time(self, time): if not time: return "-" @@ -400,6 +422,7 @@ class EnableEditingTaskTime(bpy.types.Operator): new.enum_value = data[attribute.name()] props.active_task_time_id = task_time_id props.active_task_id = self.task + bpy.ops.bim.load_task_properties() return {"FINISHED"} def add_task_time(self): @@ -448,7 +471,7 @@ class EditTaskTime(bpy.types.Operator): ) Data.load(IfcStore.get_file()) bpy.ops.bim.disable_editing_task_time() - bpy.ops.bim.enable_editing_tasks(work_schedule=props.active_work_schedule_id) + bpy.ops.bim.load_task_properties(task=props.active_task_id) return {"FINISHED"} def convert_strings_to_date_times(self, attributes): @@ -498,6 +521,7 @@ class EnableEditingTask(bpy.types.Operator): if data[attribute.name()]: new.enum_value = data[attribute.name()] props.active_task_id = self.task + bpy.ops.bim.load_task_properties() return {"FINISHED"} @@ -535,7 +559,7 @@ class EditTask(bpy.types.Operator): ) Data.load(IfcStore.get_file()) bpy.ops.bim.disable_editing_task() - bpy.ops.bim.enable_editing_tasks(work_schedule=props.active_work_schedule_id) + bpy.ops.bim.load_task_properties(task=props.active_task_id) return {"FINISHED"} @@ -554,6 +578,7 @@ class AssignPredecessor(bpy.types.Operator): related_process=IfcStore.get_file().by_id(props.active_task_id), ) Data.load(self.file) + bpy.ops.bim.load_task_properties(task=self.task) return {"FINISHED"} @@ -572,6 +597,7 @@ class AssignSuccessor(bpy.types.Operator): related_process=IfcStore.get_file().by_id(self.task), ) Data.load(self.file) + bpy.ops.bim.load_task_properties(task=self.task) return {"FINISHED"} @@ -590,6 +616,7 @@ class UnassignPredecessor(bpy.types.Operator): related_process=IfcStore.get_file().by_id(props.active_task_id), ) Data.load(self.file) + bpy.ops.bim.load_task_properties(task=self.task) return {"FINISHED"} @@ -608,6 +635,7 @@ class UnassignSuccessor(bpy.types.Operator): related_process=self.file.by_id(self.task), ) Data.load(self.file) + bpy.ops.bim.load_task_properties(task=self.task) return {"FINISHED"} diff --git a/src/blenderbim/blenderbim/bim/module/sequence/prop.py b/src/blenderbim/blenderbim/bim/module/sequence/prop.py index ebf065ac39..7416ae88a7 100644 --- a/src/blenderbim/blenderbim/bim/module/sequence/prop.py +++ b/src/blenderbim/blenderbim/bim/module/sequence/prop.py @@ -18,10 +18,10 @@ from bpy.props import ( def updateTaskName(self, context): - if self.name == "Unnamed": + props = context.scene.BIMWorkScheduleProperties + if not props.is_task_update_enabled or self.name == "Unnamed": return self.file = IfcStore.get_file() - props = context.scene.BIMWorkScheduleProperties ifcopenshell.api.run( "sequence.edit_task", self.file, @@ -34,10 +34,10 @@ def updateTaskName(self, context): def updateTaskIdentification(self, context): - if self.identification == "X": + props = context.scene.BIMWorkScheduleProperties + if not props.is_task_update_enabled or self.identification == "XXX": return self.file = IfcStore.get_file() - props = context.scene.BIMWorkScheduleProperties ifcopenshell.api.run( "sequence.edit_task", self.file, @@ -58,6 +58,11 @@ def updateTaskTimeFinish(self, context): def updateTaskTimeDateTime(self, context, startfinish): + props = context.scene.BIMWorkScheduleProperties + + if not props.is_task_update_enabled: + return + def canonicalise_time(time): if not time: return "-" @@ -112,6 +117,8 @@ class Task(PropertyGroup): duration: StringProperty(name="Duration") start: StringProperty(name="Start", update=updateTaskTimeStart) finish: StringProperty(name="Finish", update=updateTaskTimeFinish) + is_predecessor: BoolProperty(name="Is Predecessor") + is_successor: BoolProperty(name="Is Successor") class WorkPlan(PropertyGroup): @@ -132,7 +139,6 @@ class BIMWorkScheduleProperties(PropertyGroup): is_editing: StringProperty(name="Is Editing") active_work_schedule_index: IntProperty(name="Active Work Schedules Index") active_work_schedule_id: IntProperty(name="Active Work Schedules Id") - tasks: CollectionProperty(name="Tasks", type=Task) active_task_index: IntProperty(name="Active Task Index") active_task_id: IntProperty(name="Active Task Id") task_attributes: CollectionProperty(name="Task Attributes", type=Attribute) @@ -140,6 +146,13 @@ class BIMWorkScheduleProperties(PropertyGroup): 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="[]") + is_task_update_enabled: BoolProperty(name="Is Task Update Enabled", default=True) + + +class BIMTaskTreeProperties(PropertyGroup): + # This belongs by itself for performance reasons. + # In Blender if you add thousands of tasks it makes other property access in the same group really slow. + tasks: CollectionProperty(name="Tasks", type=Task) class WorkCalendar(PropertyGroup): diff --git a/src/blenderbim/blenderbim/bim/module/sequence/ui.py b/src/blenderbim/blenderbim/bim/module/sequence/ui.py index 1cc813390d..e09e356ec1 100644 --- a/src/blenderbim/blenderbim/bim/module/sequence/ui.py +++ b/src/blenderbim/blenderbim/bim/module/sequence/ui.py @@ -81,6 +81,7 @@ class BIM_PT_work_schedules(Panel): def draw(self, context): self.props = context.scene.BIMWorkScheduleProperties + self.tprops = context.scene.BIMTaskTreeProperties if not Data.is_loaded: Data.load(IfcStore.get_file()) @@ -130,7 +131,7 @@ class BIM_PT_work_schedules(Panel): self.layout.template_list( "BIM_UL_tasks", "", - self.props, + self.tprops, "tasks", self.props, "active_task_index", @@ -214,7 +215,7 @@ class BIM_UL_tasks(UIList): row.operator("bim.edit_task", text="", icon="CHECKMARK") row.operator("bim.disable_editing_task", text="", icon="CANCEL") elif props.active_task_id: - if props.active_task_id in Data.tasks[item.ifc_definition_id]["IsPredecessorTo"]: + if item.is_predecessor: row.operator( "bim.unassign_predecessor", text="", icon="BACK", emboss=False ).task = item.ifc_definition_id @@ -223,7 +224,7 @@ class BIM_UL_tasks(UIList): "bim.assign_predecessor", text="", icon="TRACKING_BACKWARDS", emboss=False ).task = item.ifc_definition_id - if props.active_task_id in Data.tasks[item.ifc_definition_id]["IsSuccessorFrom"]: + if item.is_successor: row.operator( "bim.unassign_successor", text="", icon="FORWARD", emboss=False ).task = item.ifc_definition_id