mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 01:41:57 +00:00
Work schedule UI - fix issue with some durations props not loading
E.g. IfcWorkSchedule.Duration wasn't recognized as such or IfcWorkSchedule.TotalFloat wasn't imported properly and was uneditable. Now we also check IfcDuration type on attributes explicitly, instead of relying on hardcoded list
This commit is contained in:
@@ -111,7 +111,7 @@ def draw_attribute(
|
||||
op = layout.operator("bim.attribute_add_subitem", icon="ADD", text="")
|
||||
op.data_path = data_path
|
||||
|
||||
elif attribute.name in ("ScheduleDuration", "ActualDuration", "FreeFloat", "TotalFloat"):
|
||||
elif attribute.special_type == "DURATION":
|
||||
props = tool.Sequence.get_work_schedule_props()
|
||||
for item in props.durations_attributes:
|
||||
if item.name == attribute.name:
|
||||
|
||||
@@ -23,7 +23,7 @@ import bpy
|
||||
from dateutil import parser
|
||||
import ifcopenshell.util.date
|
||||
from datetime import timedelta, datetime
|
||||
from typing import Union
|
||||
from typing import Union, Any
|
||||
|
||||
from bonsai.bim.prop import ISODuration
|
||||
|
||||
@@ -49,8 +49,8 @@ def canonicalise_time(time: Union[datetime, None]) -> str:
|
||||
return time.strftime("%d/%m/%y")
|
||||
|
||||
|
||||
def parse_duration_as_blender_props(dt, simplify=True):
|
||||
if simplify:
|
||||
def parse_duration_as_blender_props(dt: Union[Any, str]) -> dict[str, int]:
|
||||
if True:
|
||||
if isinstance(dt, str):
|
||||
dt = ifcopenshell.util.date.ifc2datetime(dt)
|
||||
|
||||
|
||||
@@ -274,7 +274,18 @@ def get_display_name(self: "Attribute") -> str:
|
||||
|
||||
|
||||
AttributeDataType = Literal["string", "integer", "float", "boolean", "enum", "file", "list[string]"]
|
||||
AttributeSpecialType = Literal["", "DATE", "DATETIME", "LENGTH", "AREA", "VOLUME", "FORCE", "LOGICAL", "URI"]
|
||||
AttributeSpecialType = Literal[
|
||||
"",
|
||||
"DATE",
|
||||
"DATETIME",
|
||||
"LENGTH",
|
||||
"AREA",
|
||||
"VOLUME",
|
||||
"FORCE",
|
||||
"LOGICAL",
|
||||
"URI",
|
||||
"DURATION",
|
||||
]
|
||||
|
||||
|
||||
class Attribute(PropertyGroup):
|
||||
|
||||
@@ -146,12 +146,8 @@ class Sequence(bonsai.core.tool.Sequence):
|
||||
return True
|
||||
attributes[prop.name] = helper.parse_datetime(prop.string_value)
|
||||
return True
|
||||
elif prop.name == "Duration" or prop.name == "TotalFloat":
|
||||
if prop.is_null:
|
||||
attributes[prop.name] = None
|
||||
return True
|
||||
attributes[prop.name] = helper.parse_duration(prop.string_value)
|
||||
return True
|
||||
elif prop.special_type == "DURATION":
|
||||
return cls.export_duration_prop(prop, attributes)
|
||||
return False
|
||||
|
||||
props = cls.get_work_schedule_props()
|
||||
@@ -159,16 +155,58 @@ class Sequence(bonsai.core.tool.Sequence):
|
||||
|
||||
@classmethod
|
||||
def load_work_schedule_attributes(cls, work_schedule: ifcopenshell.entity_instance) -> None:
|
||||
schema = tool.Ifc.schema()
|
||||
entity = schema.declaration_by_name("IfcWorkSchedule").as_entity()
|
||||
assert entity
|
||||
|
||||
def callback(name: str, prop: Union[Attribute, None], data: dict[str, Any]) -> None | Literal[True]:
|
||||
if name in ["CreationDate", "StartTime", "FinishTime"]:
|
||||
assert prop
|
||||
prop.string_value = "" if prop.is_null else data[name]
|
||||
return True
|
||||
else:
|
||||
attr = entity.attribute_by_index(entity.attribute_index(name))
|
||||
if not attr.type_of_attribute()._is("IfcDuration"):
|
||||
return
|
||||
assert prop
|
||||
cls.add_duration_prop(prop, data[name])
|
||||
|
||||
props = cls.get_work_schedule_props()
|
||||
props.work_schedule_attributes.clear()
|
||||
bonsai.bim.helper.import_attributes(work_schedule, props.work_schedule_attributes, callback)
|
||||
|
||||
@classmethod
|
||||
def add_duration_prop(cls, prop: Attribute, duration_value: Union[str, None]) -> None:
|
||||
import bonsai.bim.module.sequence.helper as helper
|
||||
|
||||
props = cls.get_work_schedule_props()
|
||||
prop.special_type = "DURATION"
|
||||
duration_props = props.durations_attributes.add()
|
||||
duration_props.name = prop.name
|
||||
if duration_value is None:
|
||||
return
|
||||
for key, value in helper.parse_duration_as_blender_props(duration_value).items():
|
||||
setattr(duration_props, key, value)
|
||||
|
||||
@classmethod
|
||||
def export_duration_prop(cls, prop: Attribute, out_attributes: dict[str, Any]) -> Literal[True]:
|
||||
import bonsai.bim.module.sequence.helper as helper
|
||||
|
||||
props = cls.get_work_schedule_props()
|
||||
if prop.is_null:
|
||||
out_attributes[prop.name] = None
|
||||
for value in props.durations_attributes.values():
|
||||
value = 0
|
||||
else:
|
||||
duration_type = out_attributes["DurationType"] if "DurationType" in out_attributes else None
|
||||
time_split_iso_duration = helper.blender_props_to_iso_duration(
|
||||
props.durations_attributes, duration_type, prop.name
|
||||
)
|
||||
out_attributes[prop.name] = time_split_iso_duration
|
||||
for value in props.durations_attributes.values():
|
||||
value = 0
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def enable_editing_work_schedule(cls, work_schedule: ifcopenshell.entity_instance) -> None:
|
||||
props = cls.get_work_schedule_props()
|
||||
@@ -401,25 +439,16 @@ class Sequence(bonsai.core.tool.Sequence):
|
||||
|
||||
@classmethod
|
||||
def load_task_time_attributes(cls, task_time: ifcopenshell.entity_instance) -> None:
|
||||
import bonsai.bim.module.sequence.helper as helper
|
||||
|
||||
props = cls.get_work_schedule_props()
|
||||
schema = tool.Ifc.schema()
|
||||
entity = schema.declaration_by_name("IfcTaskTime").as_entity()
|
||||
assert entity
|
||||
|
||||
def callback(name: str, prop: Union[Attribute, None], data: dict[str, Any]) -> Union[bool, None]:
|
||||
if prop and prop.data_type == "string":
|
||||
# TODO: Check actual attribute type instead of providing attribute names.
|
||||
if name in ("ScheduleDuration", "ActualDuration", "FreeFloat", "TotalFloat"):
|
||||
duration_props = props.durations_attributes.add()
|
||||
duration_props.name = name
|
||||
if prop.is_null:
|
||||
for key in duration_props.keys():
|
||||
if key != "name":
|
||||
setattr(duration_props, key, 0)
|
||||
return True
|
||||
if data[name]:
|
||||
for key, value in helper.parse_duration_as_blender_props(data[name]).items():
|
||||
duration_props[key] = value
|
||||
return True
|
||||
attr = entity.attribute_by_index(entity.attribute_index(name))
|
||||
if attr.type_of_attribute()._is("IfcDuration"):
|
||||
assert prop
|
||||
cls.add_duration_prop(prop, data[name])
|
||||
if isinstance(data[name], datetime):
|
||||
assert prop
|
||||
prop.string_value = "" if prop.is_null else data[name].isoformat()
|
||||
@@ -456,21 +485,8 @@ class Sequence(bonsai.core.tool.Sequence):
|
||||
return True
|
||||
attributes[prop.name] = helper.parse_datetime(prop.string_value)
|
||||
return True
|
||||
elif prop.name in ["ScheduleDuration", "ActualDuration", "FreeFloat", "TotalFloat"]:
|
||||
if prop.is_null:
|
||||
attributes[prop.name] = None
|
||||
for value in props.durations_attributes.values():
|
||||
value = 0
|
||||
return True
|
||||
else:
|
||||
duration_type = attributes["DurationType"] if "DurationType" in attributes else None
|
||||
time_split_iso_duration = helper.blender_props_to_iso_duration(
|
||||
props.durations_attributes, duration_type, prop.name
|
||||
)
|
||||
attributes[prop.name] = time_split_iso_duration
|
||||
for value in props.durations_attributes.values():
|
||||
value = 0
|
||||
return True
|
||||
elif prop.special_type == "DURATION":
|
||||
return cls.export_duration_prop(prop, attributes)
|
||||
return False
|
||||
|
||||
return bonsai.bim.helper.export_attributes(props.task_time_attributes, callback)
|
||||
|
||||
Reference in New Issue
Block a user