Skip to content
This repository was archived by the owner on Nov 24, 2024. It is now read-only.

Commit a777a55

Browse files
authored
Feature edit work plan (IfcOpenShell#1418)
* ifcopenshell.api modules Persons and Organisations account for IFC4 SCHEMA CHANGE * New Feature to Edit Workplans
1 parent de37aeb commit a777a55

6 files changed

Lines changed: 190 additions & 13 deletions

File tree

src/blenderbim/blenderbim/bim/module/sequence/__init__.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,31 @@
22
from . import ui, prop, operator
33

44
classes = (
5+
operator.LoadWorkPlans,
6+
operator.DisableWorkPlanEditingUI,
57
operator.LoadTasks,
68
operator.DisableTaskEditingUI,
79
operator.AddWorkPlan,
10+
operator.EditWorkPlan,
811
operator.RemoveWorkPlan,
12+
operator.EnableEditingWorkPlan,
13+
operator.DisableEditingWorkPlan,
14+
prop.WorkPlan,
15+
prop.BIMWorkPlanProperties,
916
prop.Task,
1017
prop.BIMTaskProperties,
1118
ui.BIM_PT_work_plans,
19+
ui.BIM_UL_work_plans,
1220
ui.BIM_PT_tasks,
1321
ui.BIM_UL_tasks,
1422
)
1523

1624

1725
def register():
1826
bpy.types.Scene.BIMTaskProperties = bpy.props.PointerProperty(type=prop.BIMTaskProperties)
27+
bpy.types.Scene.BIMWorkPlanProperties = bpy.props.PointerProperty(type=prop.BIMWorkPlanProperties)
1928

2029

2130
def unregister():
2231
del bpy.types.Scene.BIMTaskProperties
32+
del bpy.types.Scene.BIMWorkPlanProperties

src/blenderbim/blenderbim/bim/module/sequence/operator.py

Lines changed: 93 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,119 @@
11
import bpy
2+
import json
23
import ifcopenshell.api
34
from blenderbim.bim.ifc import IfcStore
45
from ifcopenshell.api.sequence.data import Data
56

67

8+
class LoadWorkPlans(bpy.types.Operator):
9+
bl_idname = "bim.load_work_plans"
10+
bl_label = "Load Work Plans"
11+
12+
def execute(self, context):
13+
props = context.scene.BIMWorkPlanProperties
14+
while len(props.work_plans) > 0:
15+
props.work_plans.remove(0)
16+
for ifc_definition_id, work_plan in Data.work_plans.items():
17+
new = props.work_plans.add()
18+
new.ifc_definition_id = ifc_definition_id
19+
new.name = work_plan["Name"] or "Unnamed"
20+
props.is_editing = True
21+
bpy.ops.bim.disable_editing_work_plan()
22+
return {"FINISHED"}
23+
24+
class DisableWorkPlanEditingUI(bpy.types.Operator):
25+
bl_idname = "bim.disable_work_plan_editing_ui"
26+
bl_label = "Disable WorkPlan Editing UI"
27+
28+
def execute(self, context):
29+
context.scene.BIMWorkPlanProperties.is_editing = False
30+
return {"FINISHED"}
31+
32+
733
class AddWorkPlan(bpy.types.Operator):
834
bl_idname = "bim.add_work_plan"
935
bl_label = "Add Work Plan"
1036

1137
def execute(self, context):
1238
ifcopenshell.api.run("sequence.add_work_plan", IfcStore.get_file())
1339
Data.load(IfcStore.get_file())
40+
bpy.ops.bim.load_work_plans()
1441
return {"FINISHED"}
1542

1643

44+
class EditWorkPlan(bpy.types.Operator):
45+
bl_idname = "bim.edit_work_plan"
46+
bl_label = "Edit Work Plan"
47+
48+
def execute(self, context):
49+
props = context.scene.BIMWorkPlanProperties
50+
attributes = {}
51+
for attribute in props.work_plan_attributes:
52+
if attribute.is_null:
53+
attributes[attribute.name] = None
54+
else:
55+
if attribute.data_type == "string":
56+
attributes[attribute.name] = attribute.string_value
57+
elif attribute.data_type == "enum":
58+
attributes[attribute.name] = attribute.enum_value
59+
self.file = IfcStore.get_file()
60+
ifcopenshell.api.run(
61+
"sequence.edit_work_plan", self.file, **{"work_plan": self.file.by_id(props.active_work_plan_id), "attributes": attributes}
62+
)
63+
Data.load(IfcStore.get_file())
64+
bpy.ops.bim.load_work_plans()
65+
return {"FINISHED"}
66+
1767
class RemoveWorkPlan(bpy.types.Operator):
1868
bl_idname = "bim.remove_work_plan"
1969
bl_label = "Remove Work Plan"
2070
work_plan: bpy.props.IntProperty()
2171

2272
def execute(self, context):
23-
ifcopenshell.api.run(
24-
"sequence.remove_work_plan", IfcStore.get_file(), work_plan=IfcStore.get_file().by_id(self.work_plan)
25-
)
73+
props = context.scene.BIMWorkPlanProperties
74+
self.file = IfcStore.get_file()
75+
ifcopenshell.api.run("sequence.remove_work_plan", self.file, **{"work_plan": self.file.by_id(self.work_plan)})
2676
Data.load(IfcStore.get_file())
77+
bpy.ops.bim.load_work_plans()
78+
return {"FINISHED"}
79+
80+
class EnableEditingWorkPlan(bpy.types.Operator):
81+
bl_idname = "bim.enable_editing_work_plan"
82+
bl_label = "Enable Editing Work Plan"
83+
work_plan: bpy.props.IntProperty()
84+
85+
def execute(self, context):
86+
props = context.scene.BIMWorkPlanProperties
87+
while len(props.work_plan_attributes) > 0:
88+
props.work_plan_attributes.remove(0)
89+
90+
data = Data.work_plans[self.work_plan]
91+
92+
for attribute in IfcStore.get_schema().declaration_by_name("IfcWorkPlan").all_attributes():
93+
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
94+
if data_type == "entity":
95+
continue
96+
new = props.work_plan_attributes.add()
97+
new.name = attribute.name()
98+
new.is_null = data[attribute.name()] is None
99+
new.is_optional = attribute.optional()
100+
new.data_type = data_type
101+
if data_type == "string":
102+
new.string_value = "" if new.is_null else data[attribute.name()]
103+
elif data_type == "enum":
104+
new.enum_items = json.dumps(ifcopenshell.util.attribute.get_enum_items(attribute))
105+
if data[attribute.name()]:
106+
new.enum_value = data[attribute.name()]
107+
props.active_work_plan_id = self.work_plan
108+
return {"FINISHED"}
109+
110+
class DisableEditingWorkPlan(bpy.types.Operator):
111+
bl_idname = "bim.disable_editing_work_plan"
112+
bl_label = "Disable Editing Work Plan"
113+
114+
def execute(self, context):
115+
context.scene.BIMWorkPlanProperties.active_work_plan_id = 0
116+
return {"FINISHED"}
27117
return {"FINISHED"}
28118

29119

src/blenderbim/blenderbim/bim/module/sequence/prop.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,16 @@ class BIMTaskProperties(PropertyGroup):
2323
is_editing: BoolProperty(name="Is Editing", default=False)
2424
tasks: CollectionProperty(name="Tasks", type=Task)
2525
active_task_index: IntProperty(name="Active Task Index")
26+
27+
28+
class WorkPlan(PropertyGroup):
29+
name: StringProperty(name="Name")
30+
ifc_definition_id: IntProperty(name="IFC Definition ID")
31+
32+
33+
class BIMWorkPlanProperties(PropertyGroup):
34+
work_plan_attributes: CollectionProperty(name="Work Plan Attributes", type=Attribute)
35+
is_editing: BoolProperty(name="Is Editing", default=False)
36+
work_plans: CollectionProperty(name="Work Plans", type=WorkPlan)
37+
active_work_plan_index: IntProperty(name="Active Work Plan Index")
38+
active_work_plan_id: IntProperty(name="Active Work Plan Id")

src/blenderbim/blenderbim/bim/module/sequence/ui.py

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,50 @@ def poll(cls, context):
1818
def draw(self, context):
1919
if not Data.is_loaded:
2020
Data.load(IfcStore.get_file())
21+
self.props = context.scene.BIMWorkPlanProperties
22+
row = self.layout.row(align=True)
23+
row.label(text="{} Work Plans Found".format(len(Data.work_plans)), icon="TEXT")
24+
if self.props.is_editing:
25+
row.operator("bim.add_work_plan", text="", icon="ADD")
26+
row.operator("bim.disable_work_plan_editing_ui", text="", icon="CHECKMARK")
27+
else:
28+
row.operator("bim.load_work_plans", text="", icon="GREASEPENCIL")
29+
30+
if self.props.is_editing:
31+
self.layout.template_list(
32+
"BIM_UL_work_plans",
33+
"",
34+
self.props,
35+
"work_plans",
36+
self.props,
37+
"active_work_plan_index",
38+
)
39+
40+
if self.props.active_work_plan_id:
41+
self.draw_editable_ui(context)
2142

22-
row = self.layout.row()
23-
row.operator("bim.add_work_plan", icon="ADD")
43+
def draw_editable_ui(self, context):
44+
for attribute in self.props.work_plan_attributes:
45+
row = self.layout.row(align=True)
46+
row.prop(attribute, "string_value", text=attribute.name)
47+
if attribute.is_optional:
48+
row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="")
2449

25-
for work_plan_id, work_plan in Data.work_plans.items():
50+
51+
class BIM_UL_work_plans(UIList):
52+
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
53+
if item:
54+
row = layout.row(align=True)
55+
row.label(text=item.name)
56+
if context.scene.BIMWorkPlanProperties.active_work_plan_id == item.ifc_definition_id:
57+
row.operator("bim.edit_work_plan", text="", icon="CHECKMARK")
58+
row.operator("bim.disable_editing_work_plan", text="", icon="X")
59+
elif context.scene.BIMWorkPlanProperties.active_work_plan_id:
60+
row.operator("bim.remove_work_plan", text="", icon="X").work_plan = item.ifc_definition_id
61+
else:
62+
op = row.operator("bim.enable_editing_work_plan", text="", icon="GREASEPENCIL")
63+
op.work_plan = item.ifc_definition_id
64+
row.operator("bim.remove_work_plan", text="", icon="X").work_plan = item.ifc_definition_id
2665
row = self.layout.row(align=True)
2766
row.label(text=work_plan["Name"] or "Unnamed", icon="TEXT")
2867
row.operator("bim.add_work_plan", text="", icon="GREASEPENCIL")

src/ifcopenshell-python/ifcopenshell/api/sequence/data.py

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,30 @@ def purge(cls):
1414

1515
@classmethod
1616
def load(cls, file):
17+
cls._file = file
18+
if not cls._file:
19+
return
20+
cls.load_work_plans()
21+
cls.load_work_schedules()
22+
cls.load_tasks()
23+
cls.is_loaded=True
24+
25+
@classmethod
26+
def load_work_plans(cls):
1727
cls.work_plans = {}
18-
cls.tasks = {}
19-
for work_plan in file.by_type("IfcWorkPlan"):
28+
for work_plan in cls._file.by_type("IfcWorkPlan"):
2029
data = work_plan.get_info()
2130
del data["OwnerHistory"]
2231
if data["Creators"]:
2332
data["Creators"] = [p.id() for p in data["Creators"]]
24-
data["CreationDate"] = ifcopenshell.util.date.ifc2datetime(data["CreationDate"])
25-
data["StartTime"] = ifcopenshell.util.date.ifc2datetime(data["StartTime"])
33+
data["CreationDate"] = ifcopenshell.util.date.ifc2datetime(data["CreationDate"]).isoformat()
34+
data["StartTime"] = ifcopenshell.util.date.ifc2datetime(data["StartTime"]).isoformat()
2635
if data["FinishTime"]:
27-
data["FinishTime"] = ifcopenshell.util.date.ifc2datetime(data["FinishTime"])
36+
data["FinishTime"] = ifcopenshell.util.date.ifc2datetime(data["FinishTime"]).isoformat()
2837
cls.work_plans[work_plan.id()] = data
29-
for task in file.by_type("IfcTask"):
38+
39+
@classmethod
40+
def load_tasks(cls):
41+
cls.tasks = {}
42+
for task in cls._file.by_type("IfcTask"):
3043
cls.tasks[task.id()] = {"Name": task.Name, "Identification": task.Identification or ""}
31-
cls.is_loaded=True
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
class Usecase:
2+
def __init__(self, file, **settings):
3+
self.file = file
4+
self.settings = {
5+
"work_plan": None,
6+
"attributes": {}
7+
}
8+
for key, value in settings.items():
9+
self.settings[key] = value
10+
11+
def execute(self):
12+
for name, value in self.settings["attributes"].items():
13+
setattr(self.settings["work_plan"], name, value)

0 commit comments

Comments
 (0)