diff --git a/src/bcf/bcf/v2/topic.py b/src/bcf/bcf/v2/topic.py
index 4bcfaa7043..975c9c84b7 100644
--- a/src/bcf/bcf/v2/topic.py
+++ b/src/bcf/bcf/v2/topic.py
@@ -230,7 +230,9 @@ class TopicHandler:
real_path = real_path.parent if path_part == ".." else real_path.joinpath(path_part)
destination_zip.writestr(real_path.at, self.document_references[doc.referenced_document])
- def extract_file(self, entity, outfile: Optional[Path] = None) -> Path:
+ def extract_file(
+ self, entity: Union[mdl.HeaderFile, mdl.BimSnippet, mdl.TopicDocumentReference], outfile: Optional[Path] = None
+ ) -> Union[Path, str, None]:
"""Extracts an element with a file into a temporary directory
These include header files, bim snippets, document references, and
@@ -238,11 +240,9 @@ class TopicHandler:
URI reference is returned.
:param entity: The entity with a file reference to extract
- :type entity: bcf.v2.model.HeaderFile,bcf.v2.model.BimSnippet,bcf.v2.model.TopicDocumentReference
:param outfile: If provided, save the header file to that location.
Otherwise, a temporary directory is created and the filename is
derived from the header's original filename.
- :type outfile: pathlib.Path,optional
:return: The filepath of the extracted file. It may be a URL if the
header file is external.
:rtype: Path
diff --git a/src/bonsai/bonsai/bim/module/bcf/__init__.py b/src/bonsai/bonsai/bim/module/bcf/__init__.py
index 9567879af3..f8e88ede96 100644
--- a/src/bonsai/bonsai/bim/module/bcf/__init__.py
+++ b/src/bonsai/bonsai/bim/module/bcf/__init__.py
@@ -41,6 +41,7 @@ classes = (
operator.EditBcfTopicName,
operator.ExtractBcfFile,
operator.LoadBcfComments,
+ operator.LoadBcfHeaderIfcFile,
operator.LoadBcfProject,
operator.LoadBcfTopic,
operator.LoadBcfTopics,
diff --git a/src/bonsai/bonsai/bim/module/bcf/operator.py b/src/bonsai/bonsai/bim/module/bcf/operator.py
index d4c8e3894e..253f4c9e1b 100644
--- a/src/bonsai/bonsai/bim/module/bcf/operator.py
+++ b/src/bonsai/bonsai/bim/module/bcf/operator.py
@@ -1239,6 +1239,30 @@ class SelectBcfDocumentReference(bpy.types.Operator):
return {"RUNNING_MODAL"}
+class LoadBcfHeaderIfcFile(bpy.types.Operator):
+ bl_idname = "bim.load_bcf_header_ifc_file"
+ bl_label = "Load BCF Header IFC File"
+ bl_description = (
+ "Extract BCF Header IFC file and load it in current session."
+ "\n\nWarning. Current IFC and BCF sessions won't be saved, BCF file will be reloaded (if it's saved on disk)"
+ )
+ bl_options = {"REGISTER", "UNDO"}
+ index: bpy.props.IntProperty()
+
+ def execute(self, context):
+ bcfxml = bcfstore.BcfStore.get_bcfxml()
+ assert bcfxml
+ bcf_path = tool.Bcf.get_path()
+
+ topic = bcfxml.topics[context.scene.BCFProperties.active_topic.name]
+ entity = topic.header.file[self.index]
+ ifc_path = str(topic.extract_file(entity))
+ bpy.ops.bim.load_project(filepath=ifc_path)
+ if bcf_path:
+ bpy.ops.bim.load_bcf_project(filepath=bcf_path)
+ return {"FINISHED"}
+
+
class ExtractBcfFile(bpy.types.Operator):
bl_idname = "bim.extract_bcf_file"
bl_label = "Extract BCF Header File"
diff --git a/src/bonsai/bonsai/bim/module/bcf/ui.py b/src/bonsai/bonsai/bim/module/bcf/ui.py
index 8594944d99..e7c76e849a 100644
--- a/src/bonsai/bonsai/bim/module/bcf/ui.py
+++ b/src/bonsai/bonsai/bim/module/bcf/ui.py
@@ -140,6 +140,8 @@ class BIM_PT_bcf_metadata(Panel):
if f.is_external:
row.operator("bim.open_uri", icon="URL", text="").uri = f.reference
else:
+ op = row.operator("bim.load_bcf_header_ifc_file", icon="FILE_REFRESH", text="")
+ op.index = index
op = row.operator("bim.extract_bcf_file", icon="FILE_FOLDER", text="")
op.index = index
op.entity_type = "HEADER_FILE"
diff --git a/src/bonsai/bonsai/core/tool.py b/src/bonsai/bonsai/core/tool.py
index c58c771832..d7bfe192c5 100644
--- a/src/bonsai/bonsai/core/tool.py
+++ b/src/bonsai/bonsai/core/tool.py
@@ -73,6 +73,11 @@ class Aggregate:
def get_relating_object(cls, related_element): pass
+@interface
+class Bcf:
+ pass
+
+
@interface
class Blender:
def activate_camera(cls, obj): pass
diff --git a/src/bonsai/bonsai/tool/__init__.py b/src/bonsai/bonsai/tool/__init__.py
index 08aad970b7..a7d28cab44 100644
--- a/src/bonsai/bonsai/tool/__init__.py
+++ b/src/bonsai/bonsai/tool/__init__.py
@@ -17,6 +17,7 @@
# along with Bonsai. If not, see .
from bonsai.tool.aggregate import Aggregate
+from bonsai.tool.bcf import Bcf
from bonsai.tool.blender import Blender
from bonsai.tool.boundary import Boundary
from bonsai.tool.brick import Brick
diff --git a/src/bonsai/bonsai/tool/bcf.py b/src/bonsai/bonsai/tool/bcf.py
new file mode 100644
index 0000000000..ec1de193a6
--- /dev/null
+++ b/src/bonsai/bonsai/tool/bcf.py
@@ -0,0 +1,28 @@
+# Bonsai - OpenBIM Blender Add-on
+# Copyright (C) 2022 Dion Moult
+#
+# This file is part of Bonsai.
+#
+# Bonsai is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Bonsai is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Bonsai. If not, see .
+
+import bonsai.core.tool
+import bonsai.tool as tool
+import bpy
+from typing import Any, Union, Optional
+
+
+class Bcf(bonsai.core.tool.Bcf):
+ @classmethod
+ def get_path(cls) -> str:
+ return bpy.context.scene.BCFProperties.bcf_file