From 312de694b692f29bf7c933fbf4a6900eed0ecf9d Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Wed, 23 Jun 2021 18:17:39 +1000 Subject: [PATCH] Task trees can now be sorted by any attribute independent of the WBS --- .../bim/module/sequence/__init__.py | 1 + .../bim/module/sequence/operator.py | 49 ++++++++++++++++--- .../blenderbim/bim/module/sequence/prop.py | 10 ++++ .../blenderbim/bim/module/sequence/ui.py | 38 ++++++++------ 4 files changed, 74 insertions(+), 24 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/module/sequence/__init__.py b/src/blenderbim/blenderbim/bim/module/sequence/__init__.py index 803e8dfa11..553e9f4d77 100644 --- a/src/blenderbim/blenderbim/bim/module/sequence/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/sequence/__init__.py @@ -75,6 +75,7 @@ classes = ( operator.BlenderBIM_RedrawDatePicker, operator.AddTaskColumn, operator.RemoveTaskColumn, + operator.SetTaskSortColumn, prop.WorkPlan, prop.BIMWorkPlanProperties, prop.Task, diff --git a/src/blenderbim/blenderbim/bim/module/sequence/operator.py b/src/blenderbim/blenderbim/bim/module/sequence/operator.py index fe0d3e8684..5bce3710e1 100644 --- a/src/blenderbim/blenderbim/bim/module/sequence/operator.py +++ b/src/blenderbim/blenderbim/bim/module/sequence/operator.py @@ -244,10 +244,14 @@ class EnableEditingTasks(bpy.types.Operator): self.contracted_tasks = json.loads(self.props.contracted_tasks) self.sort_keys = { - i: Data.tasks[i]["Identification"] or "" for i in Data.work_schedules[self.work_schedule]["RelatedObjects"] + i: self.get_sort_key(Data.tasks[i]) for i in Data.work_schedules[self.work_schedule]["RelatedObjects"] } - for related_object_id in sorted(self.sort_keys, key=self.natural_sort_key): + related_object_ids = sorted(self.sort_keys, key=self.natural_sort_key) + if self.props.is_sort_reversed: + related_object_ids.reverse() + + for related_object_id in related_object_ids: self.create_new_task_li(related_object_id, 0) bpy.ops.bim.load_task_properties() self.props.editing_type = "TASKS" @@ -262,10 +266,27 @@ class EnableEditingTasks(bpy.types.Operator): if task["RelatedObjects"]: new.has_children = True if new.is_expanded: - self.sort_keys = {i: Data.tasks[i]["Identification"] or "" for i in task["RelatedObjects"]} - for related_object_id in sorted(self.sort_keys, key=self.natural_sort_key): + self.sort_keys = {i: self.get_sort_key(Data.tasks[i]) for i in task["RelatedObjects"]} + related_object_ids = sorted(self.sort_keys, key=self.natural_sort_key) + if self.props.is_sort_reversed: + related_object_ids.reverse() + for related_object_id in related_object_ids: self.create_new_task_li(related_object_id, level_index + 1) + def get_sort_key(self, task): + # Sorting only applies to actual tasks, not the WBS + if task["RelatedObjects"]: + # Sorry for the hack + return "0000000000" + (task["Identification"] or "") + if not self.props.sort_column: + return task["Identification"] or "" + column_type, name = self.props.sort_column.split(".") + if column_type == "IfcTask": + return task.get(name) + elif column_type == "IfcTaskTime" and task.get("TaskTime"): + task_time = Data.task_times[task.get("TaskTime")].get(name) + return task["Identification"] or "" + def natural_sort_key(self, i, _nsre=re.compile("([0-9]+)")): s = self.sort_keys[i] return [int(text) if text.isdigit() else text.lower() for text in _nsre.split(s)] @@ -1710,15 +1731,15 @@ class RecalculateSchedule(bpy.types.Operator): class AddTaskColumn(bpy.types.Operator): bl_idname = "bim.add_task_column" bl_label = "Add Task Column" - type: bpy.props.StringProperty() + column_type: bpy.props.StringProperty() name: bpy.props.StringProperty() + data_type: 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 + new.name = f"{self.column_type}.{self.name}" + new.data_type = self.data_type return {"FINISHED"} @@ -1730,3 +1751,15 @@ class RemoveTaskColumn(bpy.types.Operator): self.props = context.scene.BIMWorkScheduleProperties self.props.columns.remove(self.props.active_column_index) return {"FINISHED"} + + +class SetTaskSortColumn(bpy.types.Operator): + bl_idname = "bim.set_task_sort_column" + bl_label = "Set Task Sort Column" + column: bpy.props.StringProperty() + + def execute(self, context): + self.props = context.scene.BIMWorkScheduleProperties + self.props.sort_column = self.column + bpy.ops.bim.enable_editing_tasks(work_schedule=self.props.active_work_schedule_id) + return {"FINISHED"} diff --git a/src/blenderbim/blenderbim/bim/module/sequence/prop.py b/src/blenderbim/blenderbim/bim/module/sequence/prop.py index 0d8f435d1f..ca8ec24d03 100644 --- a/src/blenderbim/blenderbim/bim/module/sequence/prop.py +++ b/src/blenderbim/blenderbim/bim/module/sequence/prop.py @@ -256,6 +256,16 @@ class BIMWorkScheduleProperties(PropertyGroup): 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") + sort_column: StringProperty(name="Sort Column") + is_sort_reversed: BoolProperty(name="Is Sort Reversed") + column_types: EnumProperty( + items=[ + ("IfcTask", "IfcTask", ""), + ("IfcTaskTime", "IfcTaskTime", ""), + ("Special", "Special", ""), + ], + name="Column Types", + ) task_columns: EnumProperty(items=getTaskColumns, name="Task Columns") task_time_columns: EnumProperty(items=getTaskTimeColumns, name="Task Time Columns") other_columns: EnumProperty( diff --git a/src/blenderbim/blenderbim/bim/module/sequence/ui.py b/src/blenderbim/blenderbim/bim/module/sequence/ui.py index 5913f1c303..529d48bd9e 100644 --- a/src/blenderbim/blenderbim/bim/module/sequence/ui.py +++ b/src/blenderbim/blenderbim/bim/module/sequence/ui.py @@ -138,23 +138,26 @@ class BIM_PT_work_schedules(Panel): def draw_column_ui(self): row = self.layout.row(align=True) - row.prop(self.props, "task_columns", text="") + row.prop(self.props, "column_types", text="") + column_type = self.props.column_types + if self.props.column_types == "IfcTask": + row.prop(self.props, "task_columns", text="") + name, data_type = self.props.task_columns.split("/") + elif self.props.column_types == "IfcTaskTime": + row.prop(self.props, "task_time_columns", text="") + name, data_type = self.props.task_time_columns.split("/") + elif self.props.column_types == "Special": + row.prop(self.props, "other_columns", text="") + column_type, name = self.props.other_columns.split(".") + data_type = "string" + row.operator("bim.set_task_sort_column", text="", icon="SORTALPHA").column = f"{column_type}.{name}" + row.prop( + self.props, "is_sort_reversed", text="", icon="SORT_DESC" if self.props.is_sort_reversed else "SORT_ASC" + ) 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" + op.column_type = column_type + op.name = name + op.data_type = data_type self.layout.template_list("BIM_UL_task_columns", "", self.props, "columns", self.props, "active_column_index") @@ -285,9 +288,12 @@ class BIM_PT_work_schedules(Panel): class BIM_UL_task_columns(UIList): def draw_item(self, context, layout, data, item, icon, active_data, active_propname): + props = context.scene.BIMWorkScheduleProperties if item: row = layout.row(align=True) row.prop(item, "name", emboss=False, text="") + if props.sort_column == item.name: + row.label(text="", icon="SORTALPHA") row.operator("bim.remove_task_column", text="", icon="X")