bcf v3 & bonsai bcf v3 - support adding/removing header files #2790

Also removed unnecessary read in AddBcfDocumentReference.
This commit is contained in:
Andrej730
2024-08-20 14:49:34 +05:00
parent 71ddc6384a
commit 7539404c27
4 changed files with 112 additions and 26 deletions
+5
View File
@@ -63,6 +63,11 @@ class TopicHandler:
"""Return the header of the topic."""
return self.markup.header if self.markup else None
@header.setter
def header(self, header: mdl.Header) -> None:
"""Set the header of the topic."""
self.markup.header = header
@property
def comments(self) -> list[mdl.Comment]:
"""Return the comments of the topic."""
+41
View File
@@ -27,6 +27,7 @@ class TopicHandler:
) -> None:
self._markup: Optional[mdl.Markup] = None
self._viewpoints: Optional[dict[str, VisualizationInfoHandler]] = None
self._reference_files: Optional[dict[str, bytes]] = None
self._bim_snippet: Optional[bytes] = None
self._xml_handler = xml_handler or XmlParserSerializer()
self._topic_dir = topic_dir
@@ -60,6 +61,11 @@ class TopicHandler:
"""Return the header of the topic."""
return self.markup.header
@header.setter
def header(self, header: mdl.Header) -> None:
"""Set the header of the topic."""
self.markup.header = header
@property
def comments(self) -> list[mdl.Comment]:
"""Return the comments of the topic."""
@@ -103,6 +109,27 @@ class TopicHandler:
return bim_snippet_path.read_bytes()
return None
@property
def reference_files(self) -> dict[str, bytes]:
if self._reference_files is not None:
return self._reference_files
self._reference_files = {}
if not self.header:
return self._reference_files
if not self.header.files:
return self._reference_files
for ref in self.header.files.file:
if ref.is_external:
continue
real_path = self._topic_dir
for path_part in ref.reference.split("/"):
real_path = real_path.parent if path_part == ".." else real_path.joinpath(path_part)
self._reference_files[ref.reference] = real_path.read_bytes()
return self._reference_files
@classmethod
def create_new(
cls,
@@ -154,6 +181,7 @@ class TopicHandler:
self._save_xml(destination_zip, self._markup, "markup.bcf")
self._save_viewpoints(destination_zip, topic_dir)
self._save_bim_snippet(destination_zip)
self._save_reference_files(destination_zip)
def _save_viewpoints(self, destination_zip: ZipFileInterface, topic_dir: str) -> None:
if not self.topic.viewpoints or not (viewpoints := self.topic.viewpoints.view_point):
@@ -174,6 +202,19 @@ class TopicHandler:
if self.bim_snippet:
destination_zip.writestr(f"{self.topic.guid}/{ref_filename}", self.bim_snippet)
def _save_reference_files(self, destination_zip: ZipFileInterface) -> None:
if not self.header:
return
if not self.header.files:
return
for ref in self.header.files.file:
if ref.is_external or not ref.reference:
continue
real_path = self._topic_dir
for path_part in ref.reference.split("/"):
real_path = real_path.parent if path_part == ".." else real_path.joinpath(path_part)
destination_zip.writestr(real_path.at, self.reference_files[ref.reference])
def add_viewpoint(self, element: entity_instance) -> VisualizationInfoHandler:
"""
Add a viewpoint tergeting an IFC element to the topic.
+35 -26
View File
@@ -475,31 +475,46 @@ class AddBcfHeaderFile(bpy.types.Operator):
def execute(self, context):
bcfxml = bcfstore.BcfStore.get_bcfxml()
assert bcfxml
if not (version := (bcfxml.version.version_id or "")).startswith("2"):
self.report({"INFO"}, f"BCF {version} is not yet supported: {self.bl_rna.bl_idname}.")
return {"FINISHED"}
bcf_v2 = (bcfxml.version.version_id or "").startswith("2")
props = context.scene.BCFProperties
blender_topic = props.active_topic
topic = bcfxml.topics[blender_topic.name]
is_external = "://" in props.file_reference
filename = Path(props.file_reference).name if os.path.exists(props.file_reference) else None
filepath = Path(props.file_reference)
file_bytes, filename = None, None
if filepath.is_file():
filename = filepath.name
file_bytes = filepath.read_bytes()
if filename:
with open(props.file_reference, "r") as f:
topic.reference_files[filename] = f.read()
header_files = tool.Bcf.get_topic_header_files(topic)
if filename and file_bytes:
topic.reference_files[filename] = file_bytes
if bcf_v2:
header_file = bcf.v2.model.HeaderFile(
filename=filename,
date=XmlDateTime.now(),
reference=props.file_reference if is_external else filename,
ifc_project=props.file_ifc_project,
ifc_spatial_structure_element=props.file_ifc_spatial_structure_element,
is_external=is_external,
)
assert tool.Bcf.is_list_of(header_files, bcf.v2.model.HeaderFile)
header_files.append(header_file)
else:
header_file = bcf.v3.model.File(
filename=filename,
date=XmlDateTime.now(),
reference=props.file_reference if is_external else filename,
ifc_project=props.file_ifc_project,
ifc_spatial_structure_element=props.file_ifc_spatial_structure_element,
is_external=is_external,
)
assert tool.Bcf.is_list_of(header_files, bcf.v3.model.File)
header_files.append(header_file)
header_file = bcf.v2.model.HeaderFile(
filename=filename,
date=XmlDateTime.now(),
reference=props.file_reference if is_external else Path(props.file_reference).name,
ifc_project=props.file_ifc_project,
ifc_spatial_structure_element=props.file_ifc_spatial_structure_element,
is_external=is_external,
)
topic.header.file.append(header_file)
tool.Bcf.set_topic_header_files(topic, header_files)
props.refresh_topic(context)
return {"FINISHED"}
@@ -652,14 +667,12 @@ class RemoveBcfFile(bpy.types.Operator):
bcfxml = bcfstore.BcfStore.get_bcfxml()
assert bcfxml
if not (version := (bcfxml.version.version_id or "")).startswith("2"):
self.report({"INFO"}, f"BCF {version} is not yet supported: {self.bl_rna.bl_idname}.")
return {"FINISHED"}
props = context.scene.BCFProperties
blender_topic = props.active_topic
topic = bcfxml.topics[blender_topic.name]
del topic.header.file[self.index]
header_files = tool.Bcf.get_topic_header_files(topic)
del header_files[self.index]
tool.Bcf.set_topic_header_files(topic, header_files)
props.refresh_topic(context)
return {"FINISHED"}
@@ -734,10 +747,6 @@ class AddBcfDocumentReference(bpy.types.Operator):
filename = document_path.name
document_bytes = document_path.read_bytes()
if filename:
with open(props.document_reference, "rb") as f:
document_bytes = f.read()
document_references = tool.Bcf.get_topic_document_references(topic)
if bcf_v2:
assert isinstance(topic, bcf.v2.topic.TopicHandler)
+31
View File
@@ -112,6 +112,37 @@ class Bcf(bonsai.core.tool.Bcf):
header_files = header_files.file if header_files else []
return header_files
@classmethod
def set_topic_header_files(
cls,
topic: bcf.agnostic.topic.TopicHandler,
files: Union[list[bcf.v2.model.HeaderFile], list[bcf.v3.model.File]],
) -> None:
if isinstance(topic, bcf.v2.topic.TopicHandler):
header = topic.header
if not header:
if not files:
return
topic.header = (header := bcf.v2.model.Header())
if not header.file:
if not files:
return
assert cls.is_list_of(files, bcf.v2.model.HeaderFile)
header.file = files
else:
header = topic.header
if not header:
if not files:
return
header = bcf.v3.model.Header()
header_files = header.files
if not header_files:
if not files:
return
header.files = (header_files := bcf.v3.model.HeaderFiles())
assert cls.is_list_of(files, bcf.v3.model.File)
header_files.file = files
@classmethod
def get_topic_labels(cls, topic: bcf.agnostic.topic.TopicHandler) -> list[str]:
if isinstance(topic, bcf.v2.topic.TopicHandler):