mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 09:48:32 +00:00
BBIM Feature - expand and contract all tasks in a work schedule
This commit is contained in:
@@ -20,6 +20,8 @@ import bpy
|
||||
from . import ui, prop, operator
|
||||
|
||||
classes = (
|
||||
operator.ExpandAllTasks,
|
||||
operator.ContractAllTasks,
|
||||
operator.AddSummaryTask,
|
||||
operator.AddTask,
|
||||
operator.AddTaskColumn,
|
||||
|
||||
@@ -1507,3 +1507,23 @@ class CalculateTaskDuration(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
def _execute(self, context):
|
||||
core.calculate_task_duration(tool.Ifc, tool.Sequence, task=tool.Ifc.get().by_id(self.task))
|
||||
class ExpandAllTasks(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.expand_all_tasks"
|
||||
bl_label = "Expands all tasks"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
bl_description = "Finds the related Task"
|
||||
product_type: bpy.props.StringProperty()
|
||||
|
||||
def _execute(self, context):
|
||||
core.expand_all_tasks(tool.Sequence)
|
||||
|
||||
|
||||
class ContractAllTasks(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.contract_all_tasks"
|
||||
bl_label = "Expands all tasks"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
bl_description = "Finds the related Task"
|
||||
product_type: bpy.props.StringProperty()
|
||||
|
||||
def _execute(self, context):
|
||||
core.contract_all_tasks(tool.Sequence)
|
||||
|
||||
@@ -252,6 +252,9 @@ class BIM_PT_work_schedules(Panel):
|
||||
self.props,
|
||||
"active_task_index",
|
||||
)
|
||||
row = self.layout.row()
|
||||
row.operator("bim.expand_all_tasks", text="Expand All Tasks")
|
||||
row.operator("bim.contract_all_tasks", text="Contract All Tasks")
|
||||
if self.props.active_task_id and self.props.editing_task_type == "ATTRIBUTES":
|
||||
self.draw_editable_task_attributes_ui()
|
||||
elif self.props.active_task_id and self.props.editing_task_type == "CALENDAR":
|
||||
|
||||
@@ -90,6 +90,13 @@ def expand_task(sequence, task=None):
|
||||
sequence.load_task_properties()
|
||||
|
||||
|
||||
def expand_all_tasks(sequence):
|
||||
sequence.expand_all_tasks()
|
||||
work_schedule = sequence.get_active_work_schedule()
|
||||
sequence.create_task_tree(work_schedule)
|
||||
sequence.load_task_properties()
|
||||
|
||||
|
||||
def contract_task(sequence, task=None):
|
||||
sequence.contract_task(task)
|
||||
work_schedule = sequence.get_active_work_schedule()
|
||||
@@ -97,6 +104,12 @@ def contract_task(sequence, task=None):
|
||||
sequence.load_task_properties()
|
||||
|
||||
|
||||
def contract_all_tasks(sequence):
|
||||
sequence.contract_all_tasks()
|
||||
work_schedule = sequence.get_active_work_schedule()
|
||||
sequence.create_task_tree(work_schedule)
|
||||
sequence.load_task_properties()
|
||||
|
||||
def remove_task(ifc, sequence, task=None):
|
||||
ifc.run("sequence.remove_task", task=task)
|
||||
work_schedule = sequence.get_active_work_schedule()
|
||||
|
||||
@@ -489,8 +489,7 @@ class Sequence:
|
||||
def remove_task_column(cls, name): pass
|
||||
def set_task_sort_column(cls, column): pass
|
||||
def find_related_output_tasks(cls, column): pass
|
||||
def get_root_task(cls, task): pass
|
||||
def get_task_work_schedule(cls, task): pass
|
||||
def get_work_schedule(cls, task): pass
|
||||
def is_work_schedule_active(cls, work_schedule): pass
|
||||
def highlight_task(cls, task): pass
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@ class Sequence(blenderbim.core.tool.Sequence):
|
||||
|
||||
@classmethod
|
||||
def create_task_tree(cls, work_schedule):
|
||||
def get_work_schedule_root_tasks(work_schedule):
|
||||
def get_root_tasks_ids(work_schedule):
|
||||
related_objects_ids = []
|
||||
if work_schedule.Controls:
|
||||
for rel in work_schedule.Controls:
|
||||
@@ -136,7 +136,7 @@ class Sequence(blenderbim.core.tool.Sequence):
|
||||
props = bpy.context.scene.BIMWorkScheduleProperties
|
||||
cls.contracted_tasks = json.loads(props.contracted_tasks)
|
||||
|
||||
related_objects_ids = get_work_schedule_root_tasks(work_schedule)
|
||||
related_objects_ids = get_root_tasks_ids(work_schedule)
|
||||
if not related_objects_ids:
|
||||
return
|
||||
cls.sort_keys = {i: cls.get_sort_key(tool.Ifc.get().by_id(i)) for i in related_objects_ids}
|
||||
@@ -268,6 +268,19 @@ class Sequence(blenderbim.core.tool.Sequence):
|
||||
contracted_tasks.remove(task.id())
|
||||
props.contracted_tasks = json.dumps(contracted_tasks)
|
||||
|
||||
@classmethod
|
||||
def expand_all_tasks(cls):
|
||||
bpy.context.scene.BIMWorkScheduleProperties.contracted_tasks = json.dumps([])
|
||||
|
||||
@classmethod
|
||||
def contract_all_tasks(cls):
|
||||
props = bpy.context.scene.BIMWorkScheduleProperties
|
||||
contracted_tasks = json.loads(props.contracted_tasks)
|
||||
for task_item in bpy.context.scene.BIMTaskTreeProperties.tasks:
|
||||
if task_item.is_expanded:
|
||||
contracted_tasks.append(task_item.ifc_definition_id)
|
||||
props.contracted_tasks = json.dumps(contracted_tasks)
|
||||
|
||||
@classmethod
|
||||
def contract_task(cls, task):
|
||||
props = bpy.context.scene.BIMWorkScheduleProperties
|
||||
@@ -310,7 +323,7 @@ class Sequence(blenderbim.core.tool.Sequence):
|
||||
|
||||
@classmethod
|
||||
def get_task_time(cls, task):
|
||||
return task.TaskTime if task.TaskTime else None
|
||||
return task.TaskTime if task.TaskTime else None
|
||||
|
||||
@classmethod
|
||||
def load_task_attributes(cls, task):
|
||||
@@ -342,17 +355,19 @@ class Sequence(blenderbim.core.tool.Sequence):
|
||||
if prop.data_type == "string":
|
||||
if name == "ScheduleDuration" and data[name] and isinstance(data[name], str):
|
||||
time_object = ifcopenshell.util.date.ifc2datetime(data[name])
|
||||
minutes = int(round(time_object.seconds/60 % 60))
|
||||
hours = (time_object.seconds - minutes*60)/60/60
|
||||
minutes = int(round(time_object.seconds / 60 % 60))
|
||||
hours = (time_object.seconds - minutes * 60) / 60 / 60
|
||||
bpy.context.scene.BIMDuration.duration_days = int(time_object.days)
|
||||
bpy.context.scene.BIMDuration.duration_hours = round(hours)
|
||||
bpy.context.scene.BIMDuration.duration_minutes = minutes # should consider years, months and seconds.
|
||||
bpy.context.scene.BIMDuration.duration_minutes = (
|
||||
minutes # should consider years, months and seconds.
|
||||
)
|
||||
if isinstance(data[name], datetime):
|
||||
prop.string_value = "" if prop.is_null else data[name].isoformat()
|
||||
if name == "ScheduleDuration":
|
||||
bpy.context.scene.BIMDuration.duration_days = data[name].days
|
||||
bpy.context.scene.BIMDuration.duration_hours = round(data[name].seconds / 60 / 60)
|
||||
bpy.context.scene.BIMDuration.duration_minutes = data[name].seconds/60 % 60
|
||||
bpy.context.scene.BIMDuration.duration_minutes = data[name].seconds / 60 % 60
|
||||
return True
|
||||
elif isinstance(data[name], isodate.Duration):
|
||||
prop.string_value = (
|
||||
@@ -390,7 +405,7 @@ class Sequence(blenderbim.core.tool.Sequence):
|
||||
return True
|
||||
# TODO make this parse PT32 as P4D
|
||||
attributes[prop.name] = helper.parse_duration(prop.string_value)
|
||||
dprops= bpy.context.scene.BIMDuration
|
||||
dprops = bpy.context.scene.BIMDuration
|
||||
duration_days = dprops.duration_days if dprops.duration_days else 0
|
||||
duration_hours = dprops.duration_hours if dprops.duration_hours else 0
|
||||
duration_minutes = dprops.duration_minutes if dprops.duration_minutes else 0
|
||||
@@ -638,7 +653,6 @@ class Sequence(blenderbim.core.tool.Sequence):
|
||||
props.active_sequence_id = rel_sequence.id()
|
||||
props.editing_sequence_type = "ATTRIBUTES"
|
||||
|
||||
|
||||
@classmethod
|
||||
def load_lag_time_attributes(cls, lag_time):
|
||||
def callback(name, prop, data):
|
||||
@@ -716,19 +730,12 @@ class Sequence(blenderbim.core.tool.Sequence):
|
||||
return related_tasks
|
||||
|
||||
@classmethod
|
||||
def get_root_task(cls, task):
|
||||
return (
|
||||
task
|
||||
if not task.Nests or not task.Nests[0].RelatingObject.is_a("IfcTask")
|
||||
else cls.get_root_task(task.Nests[0].RelatingObject)
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_task_work_schedule(cls, task):
|
||||
if task.HasAssignments:
|
||||
for rel in task.HasAssignments:
|
||||
if rel.is_a("IfcRelAssignsToControl") and rel.RelatingControl.is_a("IfcWorkSchedule"):
|
||||
return rel.RelatingControl
|
||||
def get_work_schedule(cls, task):
|
||||
for rel in task.HasAssignments or []:
|
||||
if rel.is_a("IfcRelAssignsToControl") and rel.RelatingControl.is_a("IfcWorkSchedule"):
|
||||
return rel.RelatingControl
|
||||
for rel in task.Nests or []:
|
||||
return cls.get_work_schedule(rel.RelatingObject)
|
||||
|
||||
@classmethod
|
||||
def is_work_schedule_active(cls, work_schedule):
|
||||
@@ -736,11 +743,42 @@ class Sequence(blenderbim.core.tool.Sequence):
|
||||
True if work_schedule.id() == bpy.context.scene.BIMWorkScheduleProperties.active_work_schedule_id else False
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_work_schedule(cls, task):
|
||||
for rel in task.HasAssignments or []:
|
||||
if rel.is_a("IfcRelAssignsToControl") and rel.RelatingControl.is_a("IfcWorkSchedule"):
|
||||
return rel.RelatingControl
|
||||
for rel in task.Nests or []:
|
||||
return cls.get_work_schedule(rel.RelatingObject)
|
||||
|
||||
@classmethod
|
||||
def expand_ancestors(cls, task):
|
||||
for rel in task.Nests or []:
|
||||
parent_task = rel.RelatingObject if rel.RelatingObject.is_a("IfcTask") else None
|
||||
print(parent_task)
|
||||
contracted_tasks = json.loads(bpy.context.scene.BIMWorkScheduleProperties.contracted_tasks)
|
||||
if parent_task and parent_task.id() in contracted_tasks:
|
||||
contracted_tasks.remove(parent_task.id())
|
||||
bpy.context.scene.BIMWorkScheduleProperties.contracted_tasks = json.dumps(contracted_tasks)
|
||||
cls.expand_ancestors(parent_task)
|
||||
|
||||
@classmethod
|
||||
def highlight_task(cls, task):
|
||||
props = bpy.context.scene.BIMWorkScheduleProperties
|
||||
def expand_ancestors(task):
|
||||
for rel in task.Nests or []:
|
||||
parent_task = rel.RelatingObject if rel.RelatingObject.is_a("IfcTask") else None
|
||||
contracted_tasks = json.loads(bpy.context.scene.BIMWorkScheduleProperties.contracted_tasks)
|
||||
if parent_task and parent_task.id() in contracted_tasks:
|
||||
contracted_tasks.remove(parent_task.id())
|
||||
bpy.context.scene.BIMWorkScheduleProperties.contracted_tasks = json.dumps(contracted_tasks)
|
||||
expand_ancestors(parent_task)
|
||||
work_schedule = cls.get_active_work_schedule()
|
||||
cls.create_task_tree(work_schedule)
|
||||
cls.load_task_properties()
|
||||
|
||||
task_props = bpy.context.scene.BIMTaskTreeProperties
|
||||
task_id = task.id()
|
||||
task_index = [task.ifc_definition_id for task in task_props.tasks].index(task_id)
|
||||
if task_index:
|
||||
props.active_task_index = task_index
|
||||
displayed_tasks = [item.ifc_definition_id for item in task_props.tasks]
|
||||
if not task.id() in displayed_tasks:
|
||||
expand_ancestors(task)
|
||||
task_index = [item.ifc_definition_id for item in task_props.tasks].index(task.id()) or 0
|
||||
bpy.context.scene.BIMWorkScheduleProperties.active_task_index = task_index
|
||||
|
||||
@@ -661,4 +661,56 @@ Scenario: Assign task calendar with no working time
|
||||
And I set "scene.BIMWorkScheduleProperties.task_time_attributes.get('ScheduleStart').string_value" to "2021-01-02"
|
||||
And I set "scene.BIMWorkScheduleProperties.task_time_attributes.get('ScheduleFinish').string_value" to "2021-01-06"
|
||||
And I press "bim.edit_task_time"
|
||||
Then nothing happens
|
||||
|
||||
Scenario: Contract Task
|
||||
Given an empty IFC project
|
||||
When I press "bim.add_work_schedule"
|
||||
And the variable "work_schedule" is "IfcStore.get_file().by_type('IfcWorkSchedule')[0].id()"
|
||||
And I press "bim.enable_editing_work_schedule_tasks(work_schedule={work_schedule})"
|
||||
And I press "bim.add_summary_task(work_schedule={work_schedule})"
|
||||
And the variable "summary_task" is "IfcStore.get_file().by_type('IfcTask')[0].id()"
|
||||
When I press "bim.add_task(task={summary_task})"
|
||||
And I press "bim.contract_task(task={summary_task})"
|
||||
Then nothing happens
|
||||
|
||||
Scenario: Expand Task
|
||||
Given an empty IFC project
|
||||
When I press "bim.add_work_schedule"
|
||||
And the variable "work_schedule" is "IfcStore.get_file().by_type('IfcWorkSchedule')[0].id()"
|
||||
And I press "bim.enable_editing_work_schedule_tasks(work_schedule={work_schedule})"
|
||||
And I press "bim.add_summary_task(work_schedule={work_schedule})"
|
||||
And the variable "summary_task" is "IfcStore.get_file().by_type('IfcTask')[0].id()"
|
||||
When I press "bim.add_task(task={summary_task})"
|
||||
And I press "bim.contract_task(task={summary_task})"
|
||||
And I press "bim.expand_task(task={summary_task})"
|
||||
Then nothing happens
|
||||
|
||||
Scenario: Contract All Tasks
|
||||
Given an empty IFC project
|
||||
When I press "bim.add_work_schedule"
|
||||
And the variable "work_schedule" is "IfcStore.get_file().by_type('IfcWorkSchedule')[0].id()"
|
||||
And I press "bim.enable_editing_work_schedule_tasks(work_schedule={work_schedule})"
|
||||
And I press "bim.add_summary_task(work_schedule={work_schedule})"
|
||||
And the variable "summary_task" is "IfcStore.get_file().by_type('IfcTask')[0].id()"
|
||||
When I press "bim.add_task(task={summary_task})"
|
||||
And the variable "nested_task_one" is "IfcStore.get_file().by_type('IfcTask')[1].id()"
|
||||
When I press "bim.add_task(task={summary_task})"
|
||||
And the variable "nested_task_two" is "IfcStore.get_file().by_type('IfcTask')[1].id()"
|
||||
When I press "bim.contract_all_tasks()"
|
||||
Then nothing happens
|
||||
|
||||
Scenario: Expand All Tasks
|
||||
Given an empty IFC project
|
||||
When I press "bim.add_work_schedule"
|
||||
And the variable "work_schedule" is "IfcStore.get_file().by_type('IfcWorkSchedule')[0].id()"
|
||||
And I press "bim.enable_editing_work_schedule_tasks(work_schedule={work_schedule})"
|
||||
And I press "bim.add_summary_task(work_schedule={work_schedule})"
|
||||
And the variable "summary_task" is "IfcStore.get_file().by_type('IfcTask')[0].id()"
|
||||
When I press "bim.add_task(task={summary_task})"
|
||||
And the variable "nested_task_one" is "IfcStore.get_file().by_type('IfcTask')[1].id()"
|
||||
When I press "bim.add_task(task={summary_task})"
|
||||
And the variable "nested_task_two" is "IfcStore.get_file().by_type('IfcTask')[1].id()"
|
||||
And I press "bim.contract_all_tasks()"
|
||||
When I press "bim.expand_all_tasks()"
|
||||
Then nothing happens
|
||||
Reference in New Issue
Block a user