diff --git a/src/bonsai/bonsai/bim/module/drawing/operator.py b/src/bonsai/bonsai/bim/module/drawing/operator.py index abc6bbfb5c..f92f7e0085 100644 --- a/src/bonsai/bonsai/bim/module/drawing/operator.py +++ b/src/bonsai/bonsai/bim/module/drawing/operator.py @@ -2896,12 +2896,16 @@ class AddSchedule(bpy.types.Operator, tool.Ifc.Operator, ImportHelper): bl_options = {"REGISTER", "UNDO"} bl_description = "Add an .ods, .xls or .xlsx file as a schedule" + files: bpy.props.CollectionProperty(name="Files", type=bpy.types.OperatorFileListElement) + directory: bpy.props.StringProperty(subtype="DIR_PATH") filter_glob: bpy.props.StringProperty(default="*.ods;*.xls;*.xlsx", options={"HIDDEN"}) use_relative_path: bpy.props.BoolProperty(name="Use Relative Path", default=True) def _execute(self, context): - filepath = tool.Ifc.get_uri(self.filepath, use_relative_path=self.use_relative_path) - core.add_document(tool.Ifc, tool.Drawing, "SCHEDULE", uri=filepath) + for filepath in tool.Blender.get_selected_files( + self.directory, self.files, use_relative_path=self.use_relative_path + ): + core.add_document(tool.Ifc, tool.Drawing, "SCHEDULE", uri=filepath) class RemoveSchedule(bpy.types.Operator, tool.Ifc.Operator): @@ -3090,13 +3094,17 @@ class AddReference(bpy.types.Operator, tool.Ifc.Operator, ImportHelper): bl_description = "Import a .svg file to the project as a reference" bl_options = {"REGISTER", "UNDO"} + files: bpy.props.CollectionProperty(name="Files", type=bpy.types.OperatorFileListElement) + directory: bpy.props.StringProperty(subtype="DIR_PATH") filter_glob: bpy.props.StringProperty(default="*.svg", options={"HIDDEN"}) use_relative_path: bpy.props.BoolProperty(name="Use Relative Path", default=True) filename_ext = ".svg" def _execute(self, context): - filepath = tool.Ifc.get_uri(self.filepath, use_relative_path=self.use_relative_path) - core.add_document(tool.Ifc, tool.Drawing, "REFERENCE", uri=filepath) + for filepath in tool.Blender.get_selected_files( + self.directory, self.files, use_relative_path=self.use_relative_path + ): + core.add_document(tool.Ifc, tool.Drawing, "REFERENCE", uri=filepath) class RemoveReference(bpy.types.Operator, tool.Ifc.Operator): diff --git a/src/bonsai/bonsai/tool/blender.py b/src/bonsai/bonsai/tool/blender.py index e499f35106..a2a0f09ed8 100644 --- a/src/bonsai/bonsai/tool/blender.py +++ b/src/bonsai/bonsai/tool/blender.py @@ -2165,3 +2165,13 @@ class Blender(bonsai.core.tool.Blender): if cls.BLENDER_5: return np.array(mathutils_type) return np.array(mathutils_type, dtype=np.float32) + + @classmethod + def get_selected_files( + cls, directory: str, files: bpy.types.OperatorFileListElement, use_relative_path=False + ) -> list[Path]: + return [ + tool.Ifc.get_uri(Path(directory) / f.name, use_relative_path=use_relative_path) + for f in files + if (Path(directory) / f.name).is_file() + ] diff --git a/src/bonsai/test/tool/test_blender.py b/src/bonsai/test/tool/test_blender.py index 43d04c7c19..97e68b9d08 100644 --- a/src/bonsai/test/tool/test_blender.py +++ b/src/bonsai/test/tool/test_blender.py @@ -24,8 +24,10 @@ import pytest import bonsai.core.tool import bonsai.tool as tool +import tempfile from bonsai.tool.blender import Blender as subject from test.bim.bootstrap import NewFile +from pathlib import Path if TYPE_CHECKING: import bpy.stub_internal.rna_enums as rna_enums @@ -110,3 +112,35 @@ class TestBlenderErrorMessageExtraction(NewFile): assert error_reports == [] bpy.utils.unregister_class(OBJECT_OT_test_fail_operator) + + +class TestGetSelectedFiles(NewFile): + def test_get_a_single_file(self) -> None: + with tempfile.NamedTemporaryFile() as f: + file = type("", (object,), {"name": f.name})() + assert subject.get_selected_files(Path(f.name).parent, [file]) == [f.name] + + def test_get_multiple_files(self) -> None: + with tempfile.NamedTemporaryFile() as f: + with tempfile.NamedTemporaryFile() as g: + file = type("", (object,), {"name": f.name})() + file2 = type("", (object,), {"name": g.name})() + assert subject.get_selected_files(Path(f.name).parent, [file, file2]) == [f.name, g.name] + + def test_exclude_directories(self) -> None: + with tempfile.NamedTemporaryFile() as f: + with tempfile.TemporaryDirectory() as d: + file = type("", (object,), {"name": f.name})() + directory = type("", (object,), {"name": d})() + assert subject.get_selected_files(Path(f.name).parent, [file, directory]) == [f.name] + + def test_get_relative_paths(self) -> None: + with tempfile.TemporaryDirectory() as tmp_dir: + base_path = Path(tmp_dir) + with tempfile.NamedTemporaryFile(dir=tmp_dir, suffix=".ifc") as f: + tool.Ifc.set_path(str(f.name)) + with tempfile.NamedTemporaryFile(dir=tmp_dir) as g: + file = type("", (object,), {"name": g.name}) + assert subject.get_selected_files(Path(g.name).parent, [file], use_relative_path=True) == [ + Path(g.name).name + ]