diff --git a/src/blenderbim/blenderbim/bim/module/sequence/__init__.py b/src/blenderbim/blenderbim/bim/module/sequence/__init__.py index 15641355a0..26a02991c2 100644 --- a/src/blenderbim/blenderbim/bim/module/sequence/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/sequence/__init__.py @@ -4,8 +4,11 @@ from . import ui, prop, operator classes = ( operator.LoadTasks, operator.DisableTaskEditingUI, + operator.AddWorkPlan, + operator.RemoveWorkPlan, prop.Task, prop.BIMTaskProperties, + ui.BIM_PT_work_plans, ui.BIM_PT_tasks, 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 93f3546407..8fb1570267 100644 --- a/src/blenderbim/blenderbim/bim/module/sequence/operator.py +++ b/src/blenderbim/blenderbim/bim/module/sequence/operator.py @@ -1,8 +1,32 @@ import bpy +import ifcopenshell.api from blenderbim.bim.ifc import IfcStore from ifcopenshell.api.sequence.data import Data +class AddWorkPlan(bpy.types.Operator): + bl_idname = "bim.add_work_plan" + bl_label = "Add Work Plan" + + def execute(self, context): + ifcopenshell.api.run("sequence.add_work_plan", IfcStore.get_file()) + Data.load(IfcStore.get_file()) + return {"FINISHED"} + + +class RemoveWorkPlan(bpy.types.Operator): + bl_idname = "bim.remove_work_plan" + bl_label = "Remove Work Plan" + work_plan: bpy.props.IntProperty() + + def execute(self, context): + ifcopenshell.api.run( + "sequence.remove_work_plan", IfcStore.get_file(), work_plan=IfcStore.get_file().by_id(self.work_plan) + ) + Data.load(IfcStore.get_file()) + return {"FINISHED"} + + class LoadTasks(bpy.types.Operator): bl_idname = "bim.load_tasks" bl_label = "Load Tasks" diff --git a/src/blenderbim/blenderbim/bim/module/sequence/ui.py b/src/blenderbim/blenderbim/bim/module/sequence/ui.py index 1584189940..f38abf8161 100644 --- a/src/blenderbim/blenderbim/bim/module/sequence/ui.py +++ b/src/blenderbim/blenderbim/bim/module/sequence/ui.py @@ -3,6 +3,32 @@ from blenderbim.bim.ifc import IfcStore from ifcopenshell.api.sequence.data import Data +class BIM_PT_work_plans(Panel): + bl_label = "IFC Work Plans" + bl_idname = "BIM_PT_work_plans" + bl_options = {"DEFAULT_CLOSED"} + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "scene" + + @classmethod + def poll(cls, context): + return IfcStore.get_file() + + def draw(self, context): + if not Data.is_loaded: + Data.load(IfcStore.get_file()) + + row = self.layout.row() + row.operator("bim.add_work_plan", icon="ADD") + + for work_plan_id, work_plan in Data.work_plans.items(): + row = self.layout.row(align=True) + row.label(text=work_plan["Name"] or "Unnamed", icon="TEXT") + row.operator("bim.add_work_plan", text="", icon="GREASEPENCIL") + row.operator("bim.remove_work_plan", text="", icon="X").work_plan = work_plan_id + + class BIM_PT_tasks(Panel): bl_label = "IFC Tasks" bl_idname = "BIM_PT_tasks" diff --git a/src/ifcopenshell-python/ifcopenshell/api/sequence/add_work_plan.py b/src/ifcopenshell-python/ifcopenshell/api/sequence/add_work_plan.py new file mode 100644 index 0000000000..f885077333 --- /dev/null +++ b/src/ifcopenshell-python/ifcopenshell/api/sequence/add_work_plan.py @@ -0,0 +1,42 @@ +import ifcopenshell.api +import ifcopenshell.util.date +from datetime import datetime + + +class Usecase: + def __init__(self, file, **settings): + self.file = file + self.settings = {"name": None, "predefined_type": "NOTDEFINED", "start_time": datetime.now()} + for key, value in settings.items(): + self.settings[key] = value + + def execute(self): + work_plan = ifcopenshell.api.run( + "root.create_entity", + self.file, + ifc_class="IfcWorkPlan", + predefined_type=self.settings["predefined_type"], + name=self.settings["name"], + ) + work_plan.CreationDate = ifcopenshell.util.date.datetime2ifc(datetime.now(), "IfcDateTime") + person = ifcopenshell.api.owner.settings.get_person(self.file) + if person: + work_plan.Creators = [person] + work_plan.StartTime = ifcopenshell.util.date.datetime2ifc(self.settings["start_time"], "IfcDateTime") + + context = self.file.by_type("IfcContext")[0] + if context.Declares: + rel_declares = context.Declares[0] + ifcopenshell.api.run("owner.update_owner_history", self.file, element=rel_declares) + else: + rel_declares = self.file.create_entity("IfcRelDeclares", **{ + "GlobalId": ifcopenshell.guid.new(), + "OwnerHistory": ifcopenshell.api.run("owner.create_owner_history", self.file), + "RelatingContext": context + }) + + related_definitions = list(rel_declares.RelatedDefinitions or []) + related_definitions.append(work_plan) + rel_declares.RelatedDefinitions = related_definitions + + return work_plan diff --git a/src/ifcopenshell-python/ifcopenshell/api/sequence/data.py b/src/ifcopenshell-python/ifcopenshell/api/sequence/data.py index 3f36e85843..894a942a40 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/sequence/data.py +++ b/src/ifcopenshell-python/ifcopenshell/api/sequence/data.py @@ -1,15 +1,31 @@ +import ifcopenshell.util.date + + class Data: is_loaded = False + work_plans = {} tasks = {} @classmethod def purge(cls): cls.is_loaded = False + cls.work_plans = {} cls.tasks = {} @classmethod def load(cls, file): + cls.work_plans = {} cls.tasks = {} + for work_plan in file.by_type("IfcWorkPlan"): + data = work_plan.get_info() + del data["OwnerHistory"] + if data["Creators"]: + data["Creators"] = [p.id() for p in data["Creators"]] + data["CreationDate"] = ifcopenshell.util.date.ifc2datetime(data["CreationDate"]) + data["StartTime"] = ifcopenshell.util.date.ifc2datetime(data["StartTime"]) + if data["FinishTime"]: + data["FinishTime"] = ifcopenshell.util.date.ifc2datetime(data["FinishTime"]) + cls.work_plans[work_plan.id()] = data for task in file.by_type("IfcTask"): cls.tasks[task.id()] = {"Name": task.Name, "Identification": task.Identification or ""} cls.is_loaded=True diff --git a/src/ifcopenshell-python/ifcopenshell/api/sequence/remove_work_plan.py b/src/ifcopenshell-python/ifcopenshell/api/sequence/remove_work_plan.py new file mode 100644 index 0000000000..941000f7ff --- /dev/null +++ b/src/ifcopenshell-python/ifcopenshell/api/sequence/remove_work_plan.py @@ -0,0 +1,14 @@ +class Usecase: + def __init__(self, file, **settings): + self.file = file + self.settings = {"work_plan": None} + for key, value in settings.items(): + self.settings[key] = value + + def execute(self): + # TODO: do a deep purge + if self.settings["work_plan"].HasContext: + rel_declares = self.settings["work_plan"].HasContext[0] + if len(rel_declares.RelatedDefinitions) == 1: + self.file.remove(rel_declares) + self.file.remove(self.settings["work_plan"])