Reuse ImportHelper/ExportHelper everywhere possible for consistency

This commit is contained in:
Andrej730
2025-03-24 16:30:53 +05:00
parent 4f091af935
commit 4594f596c2
19 changed files with 118 additions and 315 deletions
+10 -26
View File
@@ -42,6 +42,7 @@ import ifcopenshell.util.unit
import bonsai.tool as tool import bonsai.tool as tool
import bonsai.bim.module.bcf.prop as bcf_prop import bonsai.bim.module.bcf.prop as bcf_prop
import bonsai.bim.module.bcf.bcfstore as bcfstore import bonsai.bim.module.bcf.bcfstore as bcfstore
from bpy_extras.io_utils import ImportHelper, ExportHelper
from pathlib import Path from pathlib import Path
from math import radians, degrees, atan, tan, cos, sin from math import radians, degrees, atan, tan, cos, sin
from mathutils import Vector, Matrix, Euler, geometry from mathutils import Vector, Matrix, Euler, geometry
@@ -63,13 +64,14 @@ class NewBcfProject(bpy.types.Operator):
return {"FINISHED"} return {"FINISHED"}
class LoadBcfProject(bpy.types.Operator): class LoadBcfProject(bpy.types.Operator, ImportHelper):
bl_idname = "bim.load_bcf_project" bl_idname = "bim.load_bcf_project"
bl_label = "Load BCF Project" bl_label = "Load BCF Project"
bl_description = "Load the BCF file." bl_description = "Load the BCF file."
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
filepath: bpy.props.StringProperty(subtype="FILE_PATH", options={"SKIP_SAVE"}) filepath: bpy.props.StringProperty(subtype="FILE_PATH", options={"SKIP_SAVE"})
filter_glob: bpy.props.StringProperty(default="*.bcf;*.bcfzip", options={"HIDDEN"}) filter_glob: bpy.props.StringProperty(default="*.bcf;*.bcfzip", options={"HIDDEN"})
filename_ext = ".bcf"
def execute(self, context): def execute(self, context):
# Operator is also used when new project is created by not yet saved. # Operator is also used when new project is created by not yet saved.
@@ -109,10 +111,6 @@ class LoadBcfProject(bpy.types.Operator):
self.report({"INFO"}, f"BCF Project '{Path(self.filepath).name}' is loaded.") self.report({"INFO"}, f"BCF Project '{Path(self.filepath).name}' is loaded.")
return {"FINISHED"} return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class UnloadBcfProject(bpy.types.Operator): class UnloadBcfProject(bpy.types.Operator):
bl_idname = "bim.unload_bcf_project" bl_idname = "bim.unload_bcf_project"
@@ -342,7 +340,7 @@ class EditBcfTopic(bpy.types.Operator):
return {"FINISHED"} return {"FINISHED"}
class SaveBcfProject(bpy.types.Operator): class SaveBcfProject(bpy.types.Operator, ExportHelper):
bl_idname = "bim.save_bcf_project" bl_idname = "bim.save_bcf_project"
bl_label = "Save BCF Project" bl_label = "Save BCF Project"
bl_description = "Save active BCF project by the provided filepath." bl_description = "Save active BCF project by the provided filepath."
@@ -350,6 +348,7 @@ class SaveBcfProject(bpy.types.Operator):
filepath: bpy.props.StringProperty(subtype="FILE_PATH") filepath: bpy.props.StringProperty(subtype="FILE_PATH")
filter_glob: bpy.props.StringProperty(default="*.bcf;*.bcfzip", options={"HIDDEN"}) filter_glob: bpy.props.StringProperty(default="*.bcf;*.bcfzip", options={"HIDDEN"})
save_current_bcf: bpy.props.BoolProperty(default=False, options={"SKIP_SAVE"}) save_current_bcf: bpy.props.BoolProperty(default=False, options={"SKIP_SAVE"})
filename_ext = ".bcf"
def execute(self, context): def execute(self, context):
bcfxml = bcfstore.BcfStore.get_bcfxml() bcfxml = bcfstore.BcfStore.get_bcfxml()
@@ -366,8 +365,7 @@ class SaveBcfProject(bpy.types.Operator):
self.filepath = str(path) self.filepath = str(path)
return self.execute(context) return self.execute(context)
context.window_manager.fileselect_add(self) return ExportHelper.invoke(self, context, event)
return {"RUNNING_MODAL"}
class AddBcfTopic(bpy.types.Operator): class AddBcfTopic(bpy.types.Operator):
@@ -1536,13 +1534,13 @@ class OpenBcfReferenceLink(bpy.types.Operator):
return {"FINISHED"} return {"FINISHED"}
class SelectBcfHeaderFile(bpy.types.Operator): class SelectBcfHeaderFile(bpy.types.Operator, ImportHelper):
bl_idname = "bim.select_bcf_header_file" bl_idname = "bim.select_bcf_header_file"
bl_label = "Select BCF Header File" bl_label = "Select BCF Header File"
bl_description = "Select filepath for BCF header reference." bl_description = "Select filepath for BCF header reference."
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
filter_glob: bpy.props.StringProperty(default="*.ifc;*.ifczip;*.ifcxml;*.ifcjson", options={"HIDDEN"}) filter_glob: bpy.props.StringProperty(default="*.ifc;*.ifczip;*.ifcxml;*.ifcjson", options={"HIDDEN"})
filename_ext = ".ifc"
def execute(self, context): def execute(self, context):
if self.filepath: if self.filepath:
@@ -1550,17 +1548,12 @@ class SelectBcfHeaderFile(bpy.types.Operator):
props.file_reference = self.filepath props.file_reference = self.filepath
return {"FINISHED"} return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class SelectBcfBimSnippetReference(bpy.types.Operator, ImportHelper):
class SelectBcfBimSnippetReference(bpy.types.Operator):
bl_idname = "bim.select_bcf_bim_snippet_reference" bl_idname = "bim.select_bcf_bim_snippet_reference"
bl_label = "Select BCF BIM Snippet Reference" bl_label = "Select BCF BIM Snippet Reference"
bl_description = "Select filepath for BCF snippet reference." bl_description = "Select filepath for BCF snippet reference."
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
def execute(self, context): def execute(self, context):
if self.filepath: if self.filepath:
@@ -1568,17 +1561,12 @@ class SelectBcfBimSnippetReference(bpy.types.Operator):
props.bim_snippet_reference = self.filepath props.bim_snippet_reference = self.filepath
return {"FINISHED"} return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class SelectBcfDocumentReference(bpy.types.Operator, ImportHelper):
class SelectBcfDocumentReference(bpy.types.Operator):
bl_idname = "bim.select_bcf_document_reference" bl_idname = "bim.select_bcf_document_reference"
bl_label = "Select BCF Document Reference" bl_label = "Select BCF Document Reference"
bl_description = "Select filepath for BCF document reference." bl_description = "Select filepath for BCF document reference."
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
def execute(self, context): def execute(self, context):
if self.filepath: if self.filepath:
@@ -1586,10 +1574,6 @@ class SelectBcfDocumentReference(bpy.types.Operator):
props.document_reference = self.filepath props.document_reference = self.filepath
return {"FINISHED"} return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class LoadBcfHeaderIfcFile(bpy.types.Operator): class LoadBcfHeaderIfcFile(bpy.types.Operator):
bl_idname = "bim.load_bcf_header_ifc_file" bl_idname = "bim.load_bcf_header_ifc_file"
+5 -10
View File
@@ -22,17 +22,18 @@ import ifcopenshell.api
import bonsai.tool as tool import bonsai.tool as tool
import bonsai.core.brick as core import bonsai.core.brick as core
import bonsai.bim.handler import bonsai.bim.handler
from bpy_extras.io_utils import ImportHelper, ExportHelper
from bonsai.bim.ifc import IfcStore from bonsai.bim.ifc import IfcStore
from bonsai.tool.brick import BrickStore from bonsai.tool.brick import BrickStore
class LoadBrickProject(bpy.types.Operator, tool.Ifc.Operator): class LoadBrickProject(bpy.types.Operator, tool.Ifc.Operator, ImportHelper):
bl_idname = "bim.load_brick_project" bl_idname = "bim.load_brick_project"
bl_label = "Load Brickschema Project" bl_label = "Load Brickschema Project"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
bl_description = "Load in a Brick project from a file" bl_description = "Load in a Brick project from a file"
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
filter_glob: bpy.props.StringProperty(default="*.ttl", options={"HIDDEN"}) filter_glob: bpy.props.StringProperty(default="*.ttl", options={"HIDDEN"})
filename_ext = ".ttl"
def _execute(self, context): def _execute(self, context):
if os.path.exists(self.filepath) and "ttl" in os.path.splitext(self.filepath)[1].lower(): if os.path.exists(self.filepath) and "ttl" in os.path.splitext(self.filepath)[1].lower():
@@ -41,10 +42,6 @@ class LoadBrickProject(bpy.types.Operator, tool.Ifc.Operator):
else: else:
self.report({"ERROR"}, f"Failed to load {self.filepath}") self.report({"ERROR"}, f"Failed to load {self.filepath}")
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class ViewBrickClass(bpy.types.Operator, tool.Ifc.Operator): class ViewBrickClass(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.view_brick_class" bl_idname = "bim.view_brick_class"
@@ -240,7 +237,7 @@ class RemoveBrick(bpy.types.Operator, tool.Ifc.Operator):
) )
class SerializeBrick(bpy.types.Operator): class SerializeBrick(bpy.types.Operator, ExportHelper):
bl_idname = "bim.serialize_brick" bl_idname = "bim.serialize_brick"
bl_label = "Serialize Brick" bl_label = "Serialize Brick"
# Prevents crash on Blender 4.4.0. # Prevents crash on Blender 4.4.0.
@@ -251,9 +248,7 @@ class SerializeBrick(bpy.types.Operator):
def invoke(self, context, event): def invoke(self, context, event):
if self.should_save_as or not BrickStore.path: if self.should_save_as or not BrickStore.path:
WindowManager = context.window_manager return ExportHelper.invoke(self, context, event)
WindowManager.fileselect_add(self)
return {"RUNNING_MODAL"}
else: else:
return self.execute(context) return self.execute(context)
+13 -39
View File
@@ -24,26 +24,20 @@ import logging
import numpy as np import numpy as np
import ifcopenshell import ifcopenshell
import bonsai.tool as tool import bonsai.tool as tool
from bpy_extras.io_utils import ExportHelper, ImportHelper
from math import radians from math import radians
from mathutils import Matrix, Vector from mathutils import Matrix, Vector
from bonsai.bim.ifc import IfcStore from bonsai.bim.ifc import IfcStore
from bonsai.bim.module.clash.decorator import ClashDecorator from bonsai.bim.module.clash.decorator import ClashDecorator
class ExportClashSets(bpy.types.Operator): class ExportClashSets(bpy.types.Operator, ExportHelper):
bl_idname = "bim.export_clash_sets" bl_idname = "bim.export_clash_sets"
bl_label = "Export Clash Sets" bl_label = "Export Clash Sets"
bl_description = "Export clash sets to a selected file" bl_description = "Export clash sets to a selected file"
filename_ext = ".json" filename_ext = ".json"
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
filter_glob: bpy.props.StringProperty(default="*.json", options={"HIDDEN"}) filter_glob: bpy.props.StringProperty(default="*.json", options={"HIDDEN"})
def invoke(self, context, event):
self.filepath = bpy.path.ensure_ext(bpy.data.filepath, ".json")
WindowManager = context.window_manager
WindowManager.fileselect_add(self)
return {"RUNNING_MODAL"}
def execute(self, context): def execute(self, context):
self.filepath = bpy.path.ensure_ext(self.filepath, ".json") self.filepath = bpy.path.ensure_ext(self.filepath, ".json")
clash_sets = tool.Clash.export_clash_sets() clash_sets = tool.Clash.export_clash_sets()
@@ -52,20 +46,17 @@ class ExportClashSets(bpy.types.Operator):
return {"FINISHED"} return {"FINISHED"}
class ImportClashSets(bpy.types.Operator): class ImportClashSets(bpy.types.Operator, ImportHelper):
bl_idname = "bim.import_clash_sets" bl_idname = "bim.import_clash_sets"
bl_label = "Import Clash Sets" bl_label = "Import Clash Sets"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
bl_description = "Import clash sets from a selected file" bl_description = "Import clash sets from a selected file"
filename_ext = ".json" filename_ext = ".json"
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
filter_glob: bpy.props.StringProperty(default="*.json", options={"HIDDEN"}) filter_glob: bpy.props.StringProperty(default="*.json", options={"HIDDEN"})
def invoke(self, context, event): def invoke(self, context, event):
self.filepath = bpy.path.ensure_ext(bpy.data.filepath, ".json") self.filepath = bpy.path.ensure_ext(bpy.data.filepath, ".json")
WindowManager = context.window_manager return ImportHelper.invoke(self, context, event)
WindowManager.fileselect_add(self)
return {"RUNNING_MODAL"}
def execute(self, context): def execute(self, context):
tool.Clash.load_clash_sets(self.filepath) tool.Clash.load_clash_sets(self.filepath)
@@ -155,15 +146,15 @@ class RemoveClashSource(bpy.types.Operator):
return {"FINISHED"} return {"FINISHED"}
class SelectClashSource(bpy.types.Operator): class SelectClashSource(bpy.types.Operator, ImportHelper):
bl_idname = "bim.select_clash_source" bl_idname = "bim.select_clash_source"
bl_label = "Select Clash Source" bl_label = "Select Clash Source"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
bl_description = "Select an IFC file to add as a clash source" bl_description = "Select an IFC file to add as a clash source"
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
filter_glob: bpy.props.StringProperty(default="*.ifc", options={"HIDDEN"}) filter_glob: bpy.props.StringProperty(default="*.ifc", options={"HIDDEN"})
index: bpy.props.IntProperty() index: bpy.props.IntProperty()
group: bpy.props.StringProperty() group: bpy.props.StringProperty()
filename_ext = ".ifc"
def execute(self, context): def execute(self, context):
props = tool.Clash.get_clash_props() props = tool.Clash.get_clash_props()
@@ -171,46 +162,32 @@ class SelectClashSource(bpy.types.Operator):
getattr(clash_set, self.group)[self.index].name = self.filepath getattr(clash_set, self.group)[self.index].name = self.filepath
return {"FINISHED"} return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class SelectClashResults(bpy.types.Operator, ImportHelper):
class SelectClashResults(bpy.types.Operator):
bl_idname = "bim.select_clash_results" bl_idname = "bim.select_clash_results"
bl_label = "Select Clash Results" bl_label = "Select Clash Results"
bl_description = "Select filepath for clash results." bl_description = "Select filepath for clash results."
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
def execute(self, context): def execute(self, context):
props = tool.Clash.get_clash_props() props = tool.Clash.get_clash_props()
props.clash_results_path = self.filepath props.clash_results_path = self.filepath
return {"FINISHED"} return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class SelectSmartGroupedClashesPath(bpy.types.Operator, ImportHelper):
class SelectSmartGroupedClashesPath(bpy.types.Operator):
bl_idname = "bim.select_smart_grouped_clashes_path" bl_idname = "bim.select_smart_grouped_clashes_path"
bl_label = "Select Smart-Grouped Clashes Path" bl_label = "Select Smart-Grouped Clashes Path"
bl_description = "Select filepath for smart-grouped clashes." bl_description = "Select filepath for smart-grouped clashes."
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
def execute(self, context): def execute(self, context):
props = tool.Clash.get_clash_props() props = tool.Clash.get_clash_props()
props.smart_grouped_clashes_path = self.filepath props.smart_grouped_clashes_path = self.filepath
return {"FINISHED"} return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class ExecuteIfcClash(bpy.types.Operator, ExportHelper):
class ExecuteIfcClash(bpy.types.Operator):
bl_idname = "bim.execute_ifc_clash" bl_idname = "bim.execute_ifc_clash"
bl_label = "Execute IFC Clash" bl_label = "Execute IFC Clash"
bl_description = "Execute clash detection and save the information to a .bcf or .json file" bl_description = "Execute clash detection and save the information to a .bcf or .json file"
@@ -220,8 +197,7 @@ class ExecuteIfcClash(bpy.types.Operator):
def invoke(self, context, event): def invoke(self, context, event):
if self.filepath: if self.filepath:
return self.execute(context) return self.execute(context)
context.window_manager.fileselect_add(self) return ExportHelper.invoke(self, context, event)
return {"RUNNING_MODAL"}
def execute(self, context): def execute(self, context):
from ifcclash import ifcclash from ifcclash import ifcclash
@@ -294,19 +270,17 @@ class ExecuteIfcClash(bpy.types.Operator):
return {"FINISHED"} return {"FINISHED"}
class SelectIfcClashResults(bpy.types.Operator): class SelectIfcClashResults(bpy.types.Operator, ImportHelper):
bl_idname = "bim.select_ifc_clash_results" bl_idname = "bim.select_ifc_clash_results"
bl_label = "Select IFC Clash Results" bl_label = "Select IFC Clash Results"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
bl_description = "Select the clashing IFC geometry stored in a file" bl_description = "Select the clashing IFC geometry stored in a file"
filter_glob: bpy.props.StringProperty(default="*.json", options={"HIDDEN"})
filename_ext = ".json" filename_ext = ".json"
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
def invoke(self, context, event): def invoke(self, context, event):
self.filepath = bpy.path.ensure_ext(bpy.data.filepath, ".json") self.filepath = bpy.path.ensure_ext(bpy.data.filepath, ".json")
WindowManager = context.window_manager return ImportHelper.invoke(self, context, event)
WindowManager.fileselect_add(self)
return {"RUNNING_MODAL"}
def execute(self, context): def execute(self, context):
# TODO refactor into new clash results system # TODO refactor into new clash results system
@@ -25,20 +25,16 @@ import ifcopenshell.util.classification
import ifcopenshell.util.element import ifcopenshell.util.element
import bonsai.tool as tool import bonsai.tool as tool
import bonsai.bim.helper import bonsai.bim.helper
from bpy_extras.io_utils import ImportHelper
from bonsai.bim.ifc import IfcStore from bonsai.bim.ifc import IfcStore
class LoadClassificationLibrary(bpy.types.Operator, tool.Ifc.Operator): class LoadClassificationLibrary(bpy.types.Operator, tool.Ifc.Operator, ImportHelper):
bl_idname = "bim.load_classification_library" bl_idname = "bim.load_classification_library"
bl_label = "Load Classification Library" bl_label = "Load Classification Library"
bl_description = "Load classification library from the provided filepath." bl_description = "Load classification library from the provided filepath."
filename_ext = ".ifc" filename_ext = ".ifc"
filter_glob: bpy.props.StringProperty(default="*.ifc;*.ifczip;*.ifcxml", options={"HIDDEN"}) filter_glob: bpy.props.StringProperty(default="*.ifc;*.ifczip;*.ifcxml", options={"HIDDEN"})
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
def _execute(self, context): def _execute(self, context):
IfcStore.classification_file = ifcopenshell.open(self.filepath) IfcStore.classification_file = ifcopenshell.open(self.filepath)
@@ -21,7 +21,7 @@
import bpy import bpy
import ifcopenshell.api import ifcopenshell.api
import bonsai.tool as tool import bonsai.tool as tool
from bpy_extras.io_utils import ImportHelper from bpy_extras.io_utils import ImportHelper, ExportHelper
import bonsai.tool as tool import bonsai.tool as tool
import bonsai.core.cost as core import bonsai.core.cost as core
from typing import get_args, TYPE_CHECKING from typing import get_args, TYPE_CHECKING
@@ -678,7 +678,7 @@ class CalculateCostItemResourceValue(bpy.types.Operator, tool.Ifc.Operator):
return {"FINISHED"} return {"FINISHED"}
class ExportCostSchedules(bpy.types.Operator): class ExportCostSchedules(bpy.types.Operator, ExportHelper):
bl_idname = "bim.export_cost_schedules" bl_idname = "bim.export_cost_schedules"
bl_label = "Export Cost Schedule" bl_label = "Export Cost Schedule"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
@@ -701,9 +701,7 @@ class ExportCostSchedules(bpy.types.Operator):
return {"FINISHED"} return {"FINISHED"}
def invoke(self, context, event): def invoke(self, context, event):
wm = context.window_manager return ExportHelper.invoke(self, context, event)
wm.fileselect_add(self)
return {"RUNNING_MODAL"}
def draw(self, context): def draw(self, context):
self.layout.label(text="Choose a format") self.layout.label(text="Choose a format")
+9 -30
View File
@@ -27,6 +27,7 @@ import ifcopenshell
import ifcopenshell.util.selector import ifcopenshell.util.selector
import bonsai.tool as tool import bonsai.tool as tool
import bonsai.bim.module.drawing.scheduler as scheduler import bonsai.bim.module.drawing.scheduler as scheduler
from bpy_extras.io_utils import ExportHelper, ImportHelper
from bonsai.bim.handler import refresh_ui_data from bonsai.bim.handler import refresh_ui_data
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from collections import Counter from collections import Counter
@@ -90,13 +91,13 @@ class ReorderCsvAttribute(bpy.types.Operator):
return {"FINISHED"} return {"FINISHED"}
class ImportCsvAttributes(bpy.types.Operator): class ImportCsvAttributes(bpy.types.Operator, ImportHelper):
bl_idname = "bim.import_csv_attributes" bl_idname = "bim.import_csv_attributes"
bl_label = "Load CSV Settings" bl_label = "Load CSV Settings"
bl_description = "Import a json template for CSV export" bl_description = "Import a json template for CSV export"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
filter_glob: bpy.props.StringProperty(default="*.json", options={"HIDDEN"}) filter_glob: bpy.props.StringProperty(default="*.json", options={"HIDDEN"})
filepath: bpy.props.StringProperty(subtype="FILE_PATH") filename_ext = ".json"
def execute(self, context): def execute(self, context):
props = tool.Blender.get_csv_props() props = tool.Blender.get_csv_props()
@@ -125,19 +126,14 @@ class ImportCsvAttributes(bpy.types.Operator):
setattr(new, prop, attribute[prop]) setattr(new, prop, attribute[prop])
return {"FINISHED"} return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class ExportCsvAttributes(bpy.types.Operator, ExportHelper):
class ExportCsvAttributes(bpy.types.Operator):
bl_idname = "bim.export_csv_attributes" bl_idname = "bim.export_csv_attributes"
bl_label = "Save CSV Settings" bl_label = "Save CSV Settings"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
bl_description = "Save a json template for CSV export" bl_description = "Save a json template for CSV export"
filename_ext = ".json" filename_ext = ".json"
filter_glob: bpy.props.StringProperty(default="*.json", options={"HIDDEN"}) filter_glob: bpy.props.StringProperty(default="*.json", options={"HIDDEN"})
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
def execute(self, context): def execute(self, context):
props = tool.Blender.get_csv_props() props = tool.Blender.get_csv_props()
@@ -179,14 +175,8 @@ class ExportCsvAttributes(bpy.types.Operator):
return {"FINISHED"} return {"FINISHED"}
def invoke(self, context, event):
self.filepath = bpy.path.ensure_ext(bpy.data.filepath, ".json")
WindowManager = context.window_manager
WindowManager.fileselect_add(self)
return {"RUNNING_MODAL"}
class ExportIfcCsv(bpy.types.Operator, ExportHelper):
class ExportIfcCsv(bpy.types.Operator):
bl_idname = "bim.export_ifccsv" bl_idname = "bim.export_ifccsv"
bl_label = "Export IFC" bl_label = "Export IFC"
bl_description = "Export IFC data as a spreadsheet." bl_description = "Export IFC data as a spreadsheet."
@@ -212,10 +202,7 @@ class ExportIfcCsv(bpy.types.Operator):
props = tool.Blender.get_csv_props() props = tool.Blender.get_csv_props()
if props.format == "web": if props.format == "web":
return self.execute(context) return self.execute(context)
self.filepath = bpy.path.ensure_ext(bpy.data.filepath, f".{props.format}") return ExportHelper.invoke(self, context, event)
WindowManager = context.window_manager
WindowManager.fileselect_add(self)
return {"RUNNING_MODAL"}
def execute(self, context): def execute(self, context):
import ifccsv import ifccsv
@@ -299,13 +286,12 @@ class ExportIfcCsv(bpy.types.Operator):
] ]
class ImportIfcCsv(bpy.types.Operator, tool.Ifc.Operator): class ImportIfcCsv(bpy.types.Operator, tool.Ifc.Operator, ImportHelper):
bl_idname = "bim.import_ifccsv" bl_idname = "bim.import_ifccsv"
bl_label = "Import to IFC" bl_label = "Import to IFC"
bl_description = "Import IFC data from a spreadsheet." bl_description = "Import IFC data from a spreadsheet."
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
filter_glob: bpy.props.StringProperty(default="*.csv;*.ods;*.xlsx", options={"HIDDEN"}) filter_glob: bpy.props.StringProperty(default="*.csv;*.ods;*.xlsx", options={"HIDDEN"})
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
@classmethod @classmethod
def poll(cls, context): def poll(cls, context):
@@ -317,9 +303,7 @@ class ImportIfcCsv(bpy.types.Operator, tool.Ifc.Operator):
def invoke(self, context, event): def invoke(self, context, event):
self.filepath = bpy.path.ensure_ext(bpy.data.filepath, ".csv") self.filepath = bpy.path.ensure_ext(bpy.data.filepath, ".csv")
WindowManager = context.window_manager return ImportHelper.invoke(self, context, event)
WindowManager.fileselect_add(self)
return {"RUNNING_MODAL"}
def _execute(self, context): def _execute(self, context):
import ifccsv import ifccsv
@@ -350,20 +334,15 @@ class ImportIfcCsv(bpy.types.Operator, tool.Ifc.Operator):
return {"FINISHED"} return {"FINISHED"}
class SelectCsvIfcFile(bpy.types.Operator): class SelectCsvIfcFile(bpy.types.Operator, ImportHelper):
bl_idname = "bim.select_csv_ifc_file" bl_idname = "bim.select_csv_ifc_file"
bl_label = "Select CSV IFC File" bl_label = "Select CSV IFC File"
bl_description = "Select IFC file for spreadsheet import/export." bl_description = "Select IFC file for spreadsheet import/export."
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
filename_ext = ".ifc" filename_ext = ".ifc"
filter_glob: bpy.props.StringProperty(default="*.ifc;*.ifczip;*.ifcxml", options={"HIDDEN"}) filter_glob: bpy.props.StringProperty(default="*.ifc;*.ifczip;*.ifcxml", options={"HIDDEN"})
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
def execute(self, context): def execute(self, context):
props = tool.Blender.get_csv_props() props = tool.Blender.get_csv_props()
props.csv_ifc_file = self.filepath props.csv_ifc_file = self.filepath
return {"FINISHED"} return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
@@ -36,6 +36,7 @@ import bonsai.core.profile
import bonsai.core.type import bonsai.core.type
import bonsai.bim.handler import bonsai.bim.handler
import bonsai.bim.import_ifc as import_ifc import bonsai.bim.import_ifc as import_ifc
from bpy_extras.io_utils import ImportHelper, ExportHelper
from pathlib import Path from pathlib import Path
from bonsai import get_debug_info, format_debug_info from bonsai import get_debug_info, format_debug_info
from bonsai.bim.ifc import IfcStore from bonsai.bim.ifc import IfcStore
@@ -446,12 +447,11 @@ class ParseExpress(bpy.types.Operator):
return {"FINISHED"} return {"FINISHED"}
class SelectExpressFile(bpy.types.Operator): class SelectExpressFile(bpy.types.Operator, ImportHelper):
bl_idname = "bim.select_express_file" bl_idname = "bim.select_express_file"
bl_label = "Select Express File" bl_label = "Select Express File"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
bl_description = "Select an IFC EXPRESS definition" bl_description = "Select an IFC EXPRESS definition"
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
filter_glob: bpy.props.StringProperty(default="*.exp", options={"HIDDEN"}) filter_glob: bpy.props.StringProperty(default="*.exp", options={"HIDDEN"})
def execute(self, context): def execute(self, context):
@@ -460,10 +460,6 @@ class SelectExpressFile(bpy.types.Operator):
props.express_file = self.filepath props.express_file = self.filepath
return {"FINISHED"} return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class PurgeHdf5Cache(bpy.types.Operator): class PurgeHdf5Cache(bpy.types.Operator):
bl_idname = "bim.purge_hdf5_cache" bl_idname = "bim.purge_hdf5_cache"
@@ -523,7 +519,7 @@ class PrintUnusedElementStats(bpy.types.Operator):
return {"FINISHED"} return {"FINISHED"}
class PurgeUnusedElementsByClass(bpy.types.Operator, tool.Ifc.Operator): class PurgeUnusedElementsByClass(bpy.types.Operator, tool.Ifc.Operator, ExportHelper):
bl_idname = "bim.purge_unused_elements_by_class" bl_idname = "bim.purge_unused_elements_by_class"
bl_label = "Purge Unused Elements By Class" bl_label = "Purge Unused Elements By Class"
bl_description = ( bl_description = (
@@ -537,7 +533,7 @@ class PurgeUnusedElementsByClass(bpy.types.Operator, tool.Ifc.Operator):
def invoke(self, context, event): def invoke(self, context, event):
if event.type == "LEFTMOUSE" and event.alt: if event.type == "LEFTMOUSE" and event.alt:
context.window_manager.fileselect_add(self) return ExportHelper.invoke(self, context, event)
return self.execute(context) return self.execute(context)
@classmethod @classmethod
+8 -26
View File
@@ -24,26 +24,23 @@ import ifcopenshell
import bonsai.bim.handler import bonsai.bim.handler
import bonsai.bim.import_ifc import bonsai.bim.import_ifc
import bonsai.tool as tool import bonsai.tool as tool
from bpy_extras.io_utils import ImportHelper, ExportHelper
from bonsai.bim.ifc import IfcStore from bonsai.bim.ifc import IfcStore
class SelectDiffJsonFile(bpy.types.Operator): class SelectDiffJsonFile(bpy.types.Operator, ImportHelper):
bl_idname = "bim.select_diff_json_file" bl_idname = "bim.select_diff_json_file"
bl_label = "Select Diff JSON File" bl_label = "Select Diff JSON File"
bl_description = "Select filepath for IFC diff results." bl_description = "Select filepath for IFC diff results."
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
filter_glob: bpy.props.StringProperty(default="*.json", options={"HIDDEN"}) filter_glob: bpy.props.StringProperty(default="*.json", options={"HIDDEN"})
filename_ext = ".json"
def execute(self, context): def execute(self, context):
props = tool.Blender.get_diff_props() props = tool.Blender.get_diff_props()
props.diff_json_file = self.filepath props.diff_json_file = self.filepath
return {"FINISHED"} return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class VisualiseDiff(bpy.types.Operator): class VisualiseDiff(bpy.types.Operator):
bl_idname = "bim.visualise_diff" bl_idname = "bim.visualise_diff"
@@ -104,56 +101,41 @@ class VisualiseDiff(bpy.types.Operator):
return {"FINISHED"} return {"FINISHED"}
class SelectDiffOldFile(bpy.types.Operator): class SelectDiffOldFile(bpy.types.Operator, ImportHelper):
bl_idname = "bim.select_diff_old_file" bl_idname = "bim.select_diff_old_file"
bl_label = "Select Diff Old File" bl_label = "Select Diff Old File"
bl_description = "Select filepath for an old IFC file to compare." bl_description = "Select filepath for an old IFC file to compare."
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
filter_glob: bpy.props.StringProperty(default="*.ifc", options={"HIDDEN"}) filter_glob: bpy.props.StringProperty(default="*.ifc", options={"HIDDEN"})
filename_ext = ".ifc"
def execute(self, context): def execute(self, context):
props = tool.Blender.get_diff_props() props = tool.Blender.get_diff_props()
props.old_file = self.filepath props.old_file = self.filepath
return {"FINISHED"} return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class SelectDiffNewFile(bpy.types.Operator, ImportHelper):
class SelectDiffNewFile(bpy.types.Operator):
bl_idname = "bim.select_diff_new_file" bl_idname = "bim.select_diff_new_file"
bl_label = "Select Diff New File" bl_label = "Select Diff New File"
bl_description = "Select filepath for a new IFC file to compare." bl_description = "Select filepath for a new IFC file to compare."
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
filter_glob: bpy.props.StringProperty(default="*.ifc", options={"HIDDEN"}) filter_glob: bpy.props.StringProperty(default="*.ifc", options={"HIDDEN"})
filename_ext = ".ifc"
def execute(self, context): def execute(self, context):
props = tool.Blender.get_diff_props() props = tool.Blender.get_diff_props()
props.new_file = self.filepath props.new_file = self.filepath
return {"FINISHED"} return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class ExecuteIfcDiff(bpy.types.Operator, ExportHelper):
class ExecuteIfcDiff(bpy.types.Operator):
bl_idname = "bim.execute_ifc_diff" bl_idname = "bim.execute_ifc_diff"
bl_label = "Execute IFC Diff" bl_label = "Execute IFC Diff"
bl_description = "Compare two IFC files and save a json diff report by the provided filepath." bl_description = "Compare two IFC files and save a json diff report by the provided filepath."
filename_ext = ".json" filename_ext = ".json"
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
filter_glob: bpy.props.StringProperty(default="*.json", options={"HIDDEN"}) filter_glob: bpy.props.StringProperty(default="*.json", options={"HIDDEN"})
def invoke(self, context, event):
self.filepath = bpy.path.ensure_ext(bpy.data.filepath, ".json")
WindowManager = context.window_manager
WindowManager.fileselect_add(self)
return {"RUNNING_MODAL"}
def execute(self, context): def execute(self, context):
import ifcdiff import ifcdiff
@@ -43,6 +43,7 @@ import bonsai.bim.module.drawing.svgwriter as svgwriter
import bonsai.bim.module.drawing.annotation as annotation import bonsai.bim.module.drawing.annotation as annotation
import bonsai.bim.module.drawing.sheeter as sheeter import bonsai.bim.module.drawing.sheeter as sheeter
import bonsai.bim.export_ifc import bonsai.bim.export_ifc
from bpy_extras.io_utils import ImportHelper
from bonsai.bim.module.drawing.decoration import CutDecorator from bonsai.bim.module.drawing.decoration import CutDecorator
from bonsai.bim.module.drawing.data import DecoratorData, DrawingsData from bonsai.bim.module.drawing.data import DecoratorData, DrawingsData
from typing import NamedTuple, List, Union, Optional, Literal from typing import NamedTuple, List, Union, Optional, Literal
@@ -2217,12 +2218,12 @@ class ActivateDrawingFromSheet(bpy.types.Operator, ActivateDrawingBase):
# TODO: not exposed to the UI. # TODO: not exposed to the UI.
class SelectDocIfcFile(bpy.types.Operator): class SelectDocIfcFile(bpy.types.Operator, ImportHelper):
bl_idname = "bim.select_doc_ifc_file" bl_idname = "bim.select_doc_ifc_file"
bl_label = "Select Documentation IFC File" bl_label = "Select Documentation IFC File"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
filter_glob: bpy.props.StringProperty(default="*.ifc;*.ifczip;*.ifcxml", options={"HIDDEN"}) filter_glob: bpy.props.StringProperty(default="*.ifc;*.ifczip;*.ifcxml", options={"HIDDEN"})
filepath: bpy.props.StringProperty(subtype="FILE_PATH") filename_ext = ".ifc"
index: bpy.props.IntProperty() index: bpy.props.IntProperty()
def execute(self, context): def execute(self, context):
@@ -2230,10 +2231,6 @@ class SelectDocIfcFile(bpy.types.Operator):
props.ifc_files[self.index].name = self.filepath props.ifc_files[self.index].name = self.filepath
return {"FINISHED"} return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class ResizeText(bpy.types.Operator): class ResizeText(bpy.types.Operator):
bl_idname = "bim.resize_text" bl_idname = "bim.resize_text"
@@ -2612,13 +2609,12 @@ class RemoveSheet(bpy.types.Operator, tool.Ifc.Operator):
core.remove_sheet(tool.Ifc, tool.Drawing, sheet=tool.Ifc.get().by_id(self.sheet)) core.remove_sheet(tool.Ifc, tool.Drawing, sheet=tool.Ifc.get().by_id(self.sheet))
class AddSchedule(bpy.types.Operator, tool.Ifc.Operator): class AddSchedule(bpy.types.Operator, tool.Ifc.Operator, ImportHelper):
bl_idname = "bim.add_schedule" bl_idname = "bim.add_schedule"
bl_label = "Add Schedule" bl_label = "Add Schedule"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
bl_description = "Add an .ods, .xls or .xlsx file as a schedule" bl_description = "Add an .ods, .xls or .xlsx file as a schedule"
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
filter_glob: bpy.props.StringProperty(default="*.ods;*.xls;*.xlsx", options={"HIDDEN"}) filter_glob: bpy.props.StringProperty(default="*.ods;*.xls;*.xlsx", options={"HIDDEN"})
use_relative_path: bpy.props.BoolProperty(name="Use Relative Path", default=True) use_relative_path: bpy.props.BoolProperty(name="Use Relative Path", default=True)
@@ -2626,10 +2622,6 @@ class AddSchedule(bpy.types.Operator, tool.Ifc.Operator):
filepath = tool.Ifc.get_uri(self.filepath, use_relative_path=self.use_relative_path) filepath = tool.Ifc.get_uri(self.filepath, use_relative_path=self.use_relative_path)
core.add_document(tool.Ifc, tool.Drawing, "SCHEDULE", uri=filepath) core.add_document(tool.Ifc, tool.Drawing, "SCHEDULE", uri=filepath)
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class RemoveSchedule(bpy.types.Operator, tool.Ifc.Operator): class RemoveSchedule(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.remove_schedule" bl_idname = "bim.remove_schedule"
@@ -2799,24 +2791,20 @@ class AddReferenceToSheet(bpy.types.Operator, tool.Ifc.Operator):
tool.Drawing.import_sheets() tool.Drawing.import_sheets()
class AddReference(bpy.types.Operator, tool.Ifc.Operator): class AddReference(bpy.types.Operator, tool.Ifc.Operator, ImportHelper):
bl_idname = "bim.add_reference" bl_idname = "bim.add_reference"
bl_label = "Add Reference" bl_label = "Add Reference"
bl_description = "Import a .svg file to the project as a reference" bl_description = "Import a .svg file to the project as a reference"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
filter_glob: bpy.props.StringProperty(default="*.svg", options={"HIDDEN"}) filter_glob: bpy.props.StringProperty(default="*.svg", options={"HIDDEN"})
use_relative_path: bpy.props.BoolProperty(name="Use Relative Path", default=True) use_relative_path: bpy.props.BoolProperty(name="Use Relative Path", default=True)
filename_ext = ".svg"
def _execute(self, context): def _execute(self, context):
filepath = tool.Ifc.get_uri(self.filepath, use_relative_path=self.use_relative_path) filepath = tool.Ifc.get_uri(self.filepath, use_relative_path=self.use_relative_path)
core.add_document(tool.Ifc, tool.Drawing, "REFERENCE", uri=filepath) core.add_document(tool.Ifc, tool.Drawing, "REFERENCE", uri=filepath)
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class RemoveReference(bpy.types.Operator, tool.Ifc.Operator): class RemoveReference(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.remove_reference" bl_idname = "bim.remove_reference"
@@ -3445,7 +3433,7 @@ class EditElementFilter(bpy.types.Operator, tool.Ifc.Operator):
bpy.ops.bim.activate_drawing(drawing=element.id(), should_view_from_camera=False) bpy.ops.bim.activate_drawing(drawing=element.id(), should_view_from_camera=False)
class AddReferenceImage(bpy.types.Operator, tool.Ifc.Operator): class AddReferenceImage(bpy.types.Operator, tool.Ifc.Operator, ImportHelper):
bl_idname = "bim.add_reference_image" bl_idname = "bim.add_reference_image"
bl_label = "Add Reference Image" bl_label = "Add Reference Image"
bl_description = "Add or import reference image to the IFC project" bl_description = "Add or import reference image to the IFC project"
@@ -3453,9 +3441,6 @@ class AddReferenceImage(bpy.types.Operator, tool.Ifc.Operator):
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
use_relative_path: bpy.props.BoolProperty(name="Use Relative Path", default=True) use_relative_path: bpy.props.BoolProperty(name="Use Relative Path", default=True)
filepath: bpy.props.StringProperty(
name="File Path", description="Filepath used to import from", maxlen=1024, default="", subtype="FILE_PATH"
)
filter_image: bpy.props.BoolProperty(default=True, options={"HIDDEN", "SKIP_SAVE"}) filter_image: bpy.props.BoolProperty(default=True, options={"HIDDEN", "SKIP_SAVE"})
filter_folder: bpy.props.BoolProperty(default=True, options={"HIDDEN", "SKIP_SAVE"}) filter_folder: bpy.props.BoolProperty(default=True, options={"HIDDEN", "SKIP_SAVE"})
@@ -3483,10 +3468,6 @@ class AddReferenceImage(bpy.types.Operator, tool.Ifc.Operator):
layout.prop(self, "override_existing_image") layout.prop(self, "override_existing_image")
layout.prop(self, "use_existing_object_by_name") layout.prop(self, "use_existing_object_by_name")
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
def _execute(self, context): def _execute(self, context):
abs_path = Path(self.filepath).absolute().resolve() abs_path = Path(self.filepath).absolute().resolve()
image_filepath = Path(tool.Ifc.get_uri(self.filepath, use_relative_path=self.use_relative_path)) image_filepath = Path(tool.Ifc.get_uri(self.filepath, use_relative_path=self.use_relative_path))
+6 -16
View File
@@ -24,15 +24,15 @@ import logging
import tempfile import tempfile
import ifcopenshell import ifcopenshell
import bonsai.tool as tool import bonsai.tool as tool
from bpy_extras.io_utils import ExportHelper, ImportHelper
class ExecuteIfcFM(bpy.types.Operator): class ExecuteIfcFM(bpy.types.Operator, ExportHelper):
bl_idname = "bim.execute_ifcfm" bl_idname = "bim.execute_ifcfm"
bl_label = "Execute IfcFM" bl_label = "Execute IfcFM"
bl_description = "Export IfcFM data as a spreadsheet." bl_description = "Export IfcFM data as a spreadsheet."
file_format: bpy.props.StringProperty() file_format: bpy.props.StringProperty()
filter_glob: bpy.props.StringProperty(default="*.csv;*.ods;*.xlsx", options={"HIDDEN"}) filter_glob: bpy.props.StringProperty(default="*.csv;*.ods;*.xlsx", options={"HIDDEN"})
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
@classmethod @classmethod
def poll(cls, context): def poll(cls, context):
@@ -45,9 +45,7 @@ class ExecuteIfcFM(bpy.types.Operator):
def invoke(self, context, event): def invoke(self, context, event):
props = context.scene.BIMFMProperties props = context.scene.BIMFMProperties
self.filepath = bpy.path.ensure_ext(bpy.data.filepath, f".{props.format}") self.filepath = bpy.path.ensure_ext(bpy.data.filepath, f".{props.format}")
WindowManager = context.window_manager return ExportHelper.invoke(self, context, event)
WindowManager.fileselect_add(self)
return {"RUNNING_MODAL"}
def execute(self, context): def execute(self, context):
props = context.scene.BIMFMProperties props = context.scene.BIMFMProperties
@@ -83,13 +81,12 @@ class ExecuteIfcFM(bpy.types.Operator):
return {"FINISHED"} return {"FINISHED"}
class SelectFMSpreadsheetFiles(bpy.types.Operator): class SelectFMSpreadsheetFiles(bpy.types.Operator, ImportHelper):
bl_idname = "bim.select_fm_spreadsheet_files" bl_idname = "bim.select_fm_spreadsheet_files"
bl_label = "Select FM Spreadsheet Files" bl_label = "Select FM Spreadsheet Files"
bl_description = "Select FM spreadsheets to merge." bl_description = "Select FM spreadsheets to merge."
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
filter_glob: bpy.props.StringProperty(default="*.ods;*.xlsx", options={"HIDDEN"}) filter_glob: bpy.props.StringProperty(default="*.ods;*.xlsx", options={"HIDDEN"})
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
files: bpy.props.CollectionProperty(name="File Path", type=bpy.types.OperatorFileListElement) files: bpy.props.CollectionProperty(name="File Path", type=bpy.types.OperatorFileListElement)
def execute(self, context): def execute(self, context):
@@ -101,17 +98,12 @@ class SelectFMSpreadsheetFiles(bpy.types.Operator):
new.name = os.path.join(dirname, f.name) new.name = os.path.join(dirname, f.name)
return {"FINISHED"} return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class ExecuteIfcFMFederate(bpy.types.Operator, ExportHelper):
class ExecuteIfcFMFederate(bpy.types.Operator):
bl_idname = "bim.execute_ifcfm_federate" bl_idname = "bim.execute_ifcfm_federate"
bl_label = "Merge IfcFM SpreadSheets" bl_label = "Merge IfcFM SpreadSheets"
bl_description = "Merge added IfcFM spreadsheets." bl_description = "Merge added IfcFM spreadsheets."
filter_glob: bpy.props.StringProperty(default="*.ods;*.xlsx", options={"HIDDEN"}) filter_glob: bpy.props.StringProperty(default="*.ods;*.xlsx", options={"HIDDEN"})
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
@classmethod @classmethod
def poll(cls, context): def poll(cls, context):
@@ -124,9 +116,7 @@ class ExecuteIfcFMFederate(bpy.types.Operator):
def invoke(self, context, event): def invoke(self, context, event):
props = context.scene.BIMFMProperties props = context.scene.BIMFMProperties
self.filepath = bpy.path.ensure_ext(bpy.data.filepath, f".{props.format}") self.filepath = bpy.path.ensure_ext(bpy.data.filepath, f".{props.format}")
WindowManager = context.window_manager return ExportHelper.invoke(self, context, event)
WindowManager.fileselect_add(self)
return {"RUNNING_MODAL"}
def execute(self, context): def execute(self, context):
props = context.scene.BIMFMProperties props = context.scene.BIMFMProperties
@@ -20,6 +20,7 @@ import bpy
import bonsai.tool as tool import bonsai.tool as tool
import bonsai.core.georeference as core import bonsai.core.georeference as core
from bpy_extras.io_utils import ImportHelper
from bonsai.bim.module.georeference.decorator import GeoreferenceDecorator from bonsai.bim.module.georeference.decorator import GeoreferenceDecorator
@@ -87,22 +88,18 @@ class GetCursorLocation(bpy.types.Operator, tool.Ifc.Operator):
core.get_cursor_location(tool.Georeference) core.get_cursor_location(tool.Georeference)
class ImportPlot(bpy.types.Operator, tool.Ifc.Operator): class ImportPlot(bpy.types.Operator, tool.Ifc.Operator, ImportHelper):
bl_idname = "bim.import_plot" bl_idname = "bim.import_plot"
bl_label = "Import Plot" bl_label = "Import Plot"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
bl_description = "Import plot from a csv file." bl_description = "Import plot from a csv file."
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
filter_glob: bpy.props.StringProperty(default="*.csv", options={"HIDDEN"}) filter_glob: bpy.props.StringProperty(default="*.csv", options={"HIDDEN"})
filename_ext = ".csv"
def execute(self, context): def _execute(self, context):
core.import_plot(tool.Georeference, filepath=self.filepath) core.import_plot(tool.Georeference, filepath=self.filepath)
return {"FINISHED"} return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class EnableEditingWCS(bpy.types.Operator, tool.Ifc.Operator): class EnableEditingWCS(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.enable_editing_wcs" bl_idname = "bim.enable_editing_wcs"
@@ -25,6 +25,7 @@ import bonsai.tool as tool
import json import json
import zipfile import zipfile
import os.path import os.path
from bpy_extras.io_utils import ImportHelper, ExportHelper
def update_sverchok_modifier(context): def update_sverchok_modifier(context):
@@ -181,17 +182,14 @@ class UpdateDataFromSverchok(bpy.types.Operator, tool.Ifc.Operator):
# used code from Sverchok's SvNodeTreeImporter licensed under GPL v3 # used code from Sverchok's SvNodeTreeImporter licensed under GPL v3
# the code was changed to work with ifc sverchok modifier # the code was changed to work with ifc sverchok modifier
# removed the part that was relying on node graph to be opened at execution # removed the part that was relying on node graph to be opened at execution
class ImportSverchokGraph(bpy.types.Operator, tool.Ifc.Operator): class ImportSverchokGraph(bpy.types.Operator, tool.Ifc.Operator, ImportHelper):
bl_idname = "bim.import_sverchok_graph" bl_idname = "bim.import_sverchok_graph"
bl_label = "Import Sverchok Graph" bl_label = "Import Sverchok Graph"
bl_description = "Import Sverchok graph from a json file." bl_description = "Import Sverchok graph from a json file."
bl_options = {"REGISTER"} bl_options = {"REGISTER"}
filepath: bpy.props.StringProperty(
name="File Path", description="Filepath used to import from", maxlen=1024, default="", subtype="FILE_PATH"
)
filter_glob: bpy.props.StringProperty(default="*.json", options={"HIDDEN"}) filter_glob: bpy.props.StringProperty(default="*.json", options={"HIDDEN"})
filename_ext = ".json"
def _execute(self, context): def _execute(self, context):
import sverchok import sverchok
@@ -210,10 +208,6 @@ class ImportSverchokGraph(bpy.types.Operator, tool.Ifc.Operator):
props.node_group = node_group props.node_group = node_group
return {"FINISHED"} return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
def draw(self, context): def draw(self, context):
col = self.layout.column() col = self.layout.column()
col.label(text="Destination tree to import JSON:") col.label(text="Destination tree to import JSON:")
@@ -224,17 +218,14 @@ class ImportSverchokGraph(bpy.types.Operator, tool.Ifc.Operator):
# used code from Sverchok's SvNodeTreeExporter licensed under GPL v3 # used code from Sverchok's SvNodeTreeExporter licensed under GPL v3
# the code was changed to work with ifc sverchok modifier # the code was changed to work with ifc sverchok modifier
# removed the part that was relying on node graph to be opened at execution # removed the part that was relying on node graph to be opened at execution
class ExportSverchokGraph(bpy.types.Operator, tool.Ifc.Operator): class ExportSverchokGraph(bpy.types.Operator, tool.Ifc.Operator, ExportHelper):
bl_idname = "bim.export_sverchok_graph" bl_idname = "bim.export_sverchok_graph"
bl_label = "Export Sverchok Graph" bl_label = "Export Sverchok Graph"
bl_description = "Export Sverchok graph to a json file." bl_description = "Export Sverchok graph to a json file."
bl_options = {"REGISTER"} bl_options = {"REGISTER"}
filepath: bpy.props.StringProperty(
name="File Path", description="Filepath used for exporting to", maxlen=1024, default="", subtype="FILE_PATH"
)
filter_glob: bpy.props.StringProperty(default="*.json", options={"HIDDEN"}) filter_glob: bpy.props.StringProperty(default="*.json", options={"HIDDEN"})
filename_ext = ".json"
compact: bpy.props.BoolProperty(default=True, description="Compact representation of the JSON file") compact: bpy.props.BoolProperty(default=True, description="Compact representation of the JSON file")
compress: bpy.props.BoolProperty() compress: bpy.props.BoolProperty()
@@ -281,10 +272,6 @@ class ExportSverchokGraph(bpy.types.Operator, tool.Ifc.Operator):
return {"FINISHED"} return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
def draw(self, context): def draw(self, context):
graph_name = context.active_object.BIMSverchokProperties.node_group.name graph_name = context.active_object.BIMSverchokProperties.node_group.name
self.layout.label(text=f'Save node tree "{graph_name}" into json:') self.layout.label(text=f'Save node tree "{graph_name}" into json:')
+5 -12
View File
@@ -24,6 +24,7 @@ import ifcpatch
import bonsai.tool as tool import bonsai.tool as tool
import bonsai.core.patch as core import bonsai.core.patch as core
import bonsai.bim.handler import bonsai.bim.handler
from bpy_extras.io_utils import ImportHelper, ExportHelper
from pathlib import Path from pathlib import Path
from typing import cast, TYPE_CHECKING from typing import cast, TYPE_CHECKING
@@ -31,41 +32,33 @@ if TYPE_CHECKING:
from bonsai.bim.prop import AttributeDataType from bonsai.bim.prop import AttributeDataType
class SelectIfcPatchInput(bpy.types.Operator): class SelectIfcPatchInput(bpy.types.Operator, ImportHelper):
bl_idname = "bim.select_ifc_patch_input" bl_idname = "bim.select_ifc_patch_input"
bl_label = "Select IFC Patch Input" bl_label = "Select IFC Patch Input"
bl_description = "Select filepath for IFC patch input." bl_description = "Select filepath for IFC patch input."
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
filter_glob: bpy.props.StringProperty(default="*.ifc;*.ifcZIP;*.ifcXML", options={"HIDDEN"}) filter_glob: bpy.props.StringProperty(default="*.ifc;*.ifcZIP;*.ifcXML", options={"HIDDEN"})
filepath: bpy.props.StringProperty(subtype="FILE_PATH") filename_ext = ".ifc"
def execute(self, context): def execute(self, context):
props = tool.Patch.get_patch_props() props = tool.Patch.get_patch_props()
props.ifc_patch_input = self.filepath props.ifc_patch_input = self.filepath
return {"FINISHED"} return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class SelectIfcPatchOutput(bpy.types.Operator, ExportHelper):
class SelectIfcPatchOutput(bpy.types.Operator):
bl_idname = "bim.select_ifc_patch_output" bl_idname = "bim.select_ifc_patch_output"
bl_label = "Select IFC Patch Output" bl_label = "Select IFC Patch Output"
bl_description = "Select filepath for IFC patch output." bl_description = "Select filepath for IFC patch output."
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
filter_glob: bpy.props.StringProperty(default="*.ifc;*.ifcZIP;*.ifcXML", options={"HIDDEN"})
filename_ext = ".ifc" filename_ext = ".ifc"
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
def execute(self, context): def execute(self, context):
props = tool.Patch.get_patch_props() props = tool.Patch.get_patch_props()
props.ifc_patch_output = self.filepath props.ifc_patch_output = self.filepath
return {"FINISHED"} return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class ExecuteIfcPatch(bpy.types.Operator): class ExecuteIfcPatch(bpy.types.Operator):
bl_idname = "bim.execute_ifc_patch" bl_idname = "bim.execute_ifc_patch"
@@ -47,6 +47,7 @@ import bonsai.bim.helper
import bonsai.bim.schema import bonsai.bim.schema
import bonsai.tool as tool import bonsai.tool as tool
import bonsai.core.project as core import bonsai.core.project as core
from bpy_extras.io_utils import ExportHelper, ImportHelper
from bonsai.bim.ifc import IfcStore from bonsai.bim.ifc import IfcStore
from bonsai.bim.ui import IFCFileSelector from bonsai.bim.ui import IFCFileSelector
from bonsai.bim import import_ifc from bonsai.bim import import_ifc
@@ -152,12 +153,11 @@ class CreateProject(bpy.types.Operator):
IfcStore.file = data["file"] IfcStore.file = data["file"]
class SelectLibraryFile(bpy.types.Operator, IFCFileSelector): class SelectLibraryFile(bpy.types.Operator, IFCFileSelector, ImportHelper):
bl_idname = "bim.select_library_file" bl_idname = "bim.select_library_file"
bl_label = "Select Library File" bl_label = "Select Library File"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
bl_description = "Select an IFC file that can be used as a library" bl_description = "Select an IFC file that can be used as a library"
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
filter_glob: bpy.props.StringProperty(default="*.ifc;*.ifczip;*.ifcxml", options={"HIDDEN"}) filter_glob: bpy.props.StringProperty(default="*.ifc;*.ifczip;*.ifcxml", options={"HIDDEN"})
append_all: bpy.props.BoolProperty(default=False) append_all: bpy.props.BoolProperty(default=False)
use_relative_path: bpy.props.BoolProperty(name="Use Relative Path", default=False) use_relative_path: bpy.props.BoolProperty(name="Use Relative Path", default=False)
@@ -192,10 +192,6 @@ class SelectLibraryFile(bpy.types.Operator, IFCFileSelector):
ProjectLibraryData.load() ProjectLibraryData.load()
return {"FINISHED"} return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
def rollback(self, data): def rollback(self, data):
if data["old_filepath"]: if data["old_filepath"]:
IfcStore.library_path = data["old_filepath"] IfcStore.library_path = data["old_filepath"]
@@ -872,7 +868,7 @@ class DisableEditingHeader(bpy.types.Operator):
return {"FINISHED"} return {"FINISHED"}
class LoadProject(bpy.types.Operator, IFCFileSelector): class LoadProject(bpy.types.Operator, IFCFileSelector, ImportHelper):
bl_idname = "bim.load_project" bl_idname = "bim.load_project"
bl_label = "Load Project" bl_label = "Load Project"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
@@ -903,6 +899,7 @@ class LoadProject(bpy.types.Operator, IFCFileSelector):
default=False, default=False,
) )
use_detailed_tooltip: bpy.props.BoolProperty(default=False, options={"HIDDEN"}) use_detailed_tooltip: bpy.props.BoolProperty(default=False, options={"HIDDEN"})
filename_ext = ".ifc"
@classmethod @classmethod
def description(cls, context, properties): def description(cls, context, properties):
@@ -1014,8 +1011,7 @@ class LoadProject(bpy.types.Operator, IFCFileSelector):
def invoke(self, context, event): def invoke(self, context, event):
if self.filepath: if self.filepath:
return self.execute(context) return self.execute(context)
context.window_manager.fileselect_add(self) return ImportHelper.invoke(self, context, event)
return {"RUNNING_MODAL"}
def draw(self, context): def draw(self, context):
if self.use_relative_path: if self.use_relative_path:
@@ -1175,12 +1171,12 @@ class ToggleFilterCategories(bpy.types.Operator):
return {"FINISHED"} return {"FINISHED"}
class LinkIfc(bpy.types.Operator): class LinkIfc(bpy.types.Operator, ImportHelper):
bl_idname = "bim.link_ifc" bl_idname = "bim.link_ifc"
bl_label = "Link IFC" bl_label = "Link IFC"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
bl_description = "Reference in a read-only IFC model in the background" bl_description = "Reference in a read-only IFC model in the background"
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
files: bpy.props.CollectionProperty(name="Files", type=bpy.types.OperatorFileListElement) files: bpy.props.CollectionProperty(name="Files", type=bpy.types.OperatorFileListElement)
directory: bpy.props.StringProperty(subtype="DIR_PATH") directory: bpy.props.StringProperty(subtype="DIR_PATH")
filter_glob: bpy.props.StringProperty(default="*.ifc", options={"HIDDEN"}) filter_glob: bpy.props.StringProperty(default="*.ifc", options={"HIDDEN"})
@@ -1190,6 +1186,7 @@ class LinkIfc(bpy.types.Operator):
default=False, default=False,
) )
use_cache: bpy.props.BoolProperty(name="Use Cache", default=True) use_cache: bpy.props.BoolProperty(name="Use Cache", default=True)
filename_ext = ".ifc"
if TYPE_CHECKING: if TYPE_CHECKING:
filepath: str filepath: str
@@ -1235,10 +1232,6 @@ class LinkIfc(bpy.types.Operator):
print(f"Finished linking {len(files)} IFCs", time.time() - start) print(f"Finished linking {len(files)} IFCs", time.time() - start)
return {"FINISHED"} return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class UnlinkIfc(bpy.types.Operator): class UnlinkIfc(bpy.types.Operator):
bl_idname = "bim.unlink_ifc" bl_idname = "bim.unlink_ifc"
@@ -1544,7 +1537,7 @@ class SelectLinkHandle(bpy.types.Operator):
return {"FINISHED"} return {"FINISHED"}
class ExportIFC(bpy.types.Operator): class ExportIFC(bpy.types.Operator, ExportHelper):
bl_idname = "bim.save_project" bl_idname = "bim.save_project"
bl_label = "Save IFC" bl_label = "Save IFC"
# Prevents crash on Blender 4.4.0. # Prevents crash on Blender 4.4.0.
@@ -1552,7 +1545,6 @@ class ExportIFC(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
filename_ext = ".ifc" filename_ext = ".ifc"
filter_glob: bpy.props.StringProperty(default="*.ifc;*.ifczip;*.ifcxml;*.ifcjson", options={"HIDDEN"}) filter_glob: bpy.props.StringProperty(default="*.ifc;*.ifczip;*.ifcxml;*.ifcjson", options={"HIDDEN"})
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
json_version: bpy.props.EnumProperty(items=[("4", "4", ""), ("5a", "5a", "")], name="IFC JSON Version") json_version: bpy.props.EnumProperty(items=[("4", "4", ""), ("5a", "5a", "")], name="IFC JSON Version")
json_compact: bpy.props.BoolProperty(name="Export Compact IFCJSON", default=False) json_compact: bpy.props.BoolProperty(name="Export Compact IFCJSON", default=False)
should_save_as: bpy.props.BoolProperty(name="Should Save As", default=False, options={"HIDDEN"}) should_save_as: bpy.props.BoolProperty(name="Should Save As", default=False, options={"HIDDEN"})
@@ -1583,15 +1575,8 @@ class ExportIFC(bpy.types.Operator):
if (filepath := props.ifc_file) and not self.should_save_as: if (filepath := props.ifc_file) and not self.should_save_as:
self.filepath = str(tool.Blender.ensure_blender_path_is_abs(Path(filepath))) self.filepath = str(tool.Blender.ensure_blender_path_is_abs(Path(filepath)))
return self.execute(context) return self.execute(context)
if not self.filepath:
if bpy.data.is_saved:
self.filepath = Path(bpy.data.filepath).with_suffix(".ifc").__str__()
else:
self.filepath = "untitled.ifc"
WindowManager = context.window_manager return ExportHelper.invoke(self, context, event)
WindowManager.fileselect_add(self)
return {"RUNNING_MODAL"}
def execute(self, context): def execute(self, context):
project_props = tool.Project.get_project_props() project_props = tool.Project.get_project_props()
@@ -1668,12 +1653,11 @@ class ExportIFC(bpy.types.Operator):
return "Save the IFC file. Will save both .IFC/.BLEND files if synced together" return "Save the IFC file. Will save both .IFC/.BLEND files if synced together"
class LoadLinkedProject(bpy.types.Operator): class LoadLinkedProject(bpy.types.Operator, ImportHelper):
bl_idname = "bim.load_linked_project" bl_idname = "bim.load_linked_project"
bl_label = "Load Project For Viewing Only" bl_label = "Load Project For Viewing Only"
bl_description = "Operator is used to load a project .cache.blend to then link it to the IFC file." bl_description = "Operator is used to load a project .cache.blend to then link it to the IFC file."
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
filepath: bpy.props.StringProperty()
file: ifcopenshell.file file: ifcopenshell.file
meshes: dict[str, bpy.types.Mesh] meshes: dict[str, bpy.types.Mesh]
@@ -1682,9 +1666,7 @@ class LoadLinkedProject(bpy.types.Operator):
def invoke(self, context, event): def invoke(self, context, event):
# Invoke is for debugging purposes, users are not intended to use this method really. # Invoke is for debugging purposes, users are not intended to use this method really.
WindowManager = context.window_manager return ImportHelper.invoke(self, context, event)
WindowManager.fileselect_add(self)
return {"RUNNING_MODAL"}
def execute(self, context): def execute(self, context):
import ifcpatch import ifcpatch
@@ -32,7 +32,7 @@ import ifcopenshell.util.sequence
import ifcopenshell.util.selector import ifcopenshell.util.selector
from datetime import datetime from datetime import datetime
from dateutil import parser, relativedelta from dateutil import parser, relativedelta
from bpy_extras.io_utils import ImportHelper from bpy_extras.io_utils import ImportHelper, ExportHelper
from typing import get_args, TYPE_CHECKING from typing import get_args, TYPE_CHECKING
from typing_extensions import assert_never from typing_extensions import assert_never
@@ -794,7 +794,7 @@ class ImportMSP(bpy.types.Operator, tool.Ifc.Operator, ImportHelper):
self.report({"INFO"}, "Import finished in {:.2f} seconds".format(time.time() - start)) self.report({"INFO"}, "Import finished in {:.2f} seconds".format(time.time() - start))
class ExportMSP(bpy.types.Operator, ImportHelper): class ExportMSP(bpy.types.Operator, ExportHelper):
bl_idname = "bim.export_msp" bl_idname = "bim.export_msp"
bl_label = "Export MSP" bl_label = "Export MSP"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
@@ -827,7 +827,7 @@ class ExportMSP(bpy.types.Operator, ImportHelper):
return {"FINISHED"} return {"FINISHED"}
class ExportP6(bpy.types.Operator, ImportHelper): class ExportP6(bpy.types.Operator, ExportHelper):
bl_idname = "bim.export_p6" bl_idname = "bim.export_p6"
bl_label = "Export P6" bl_label = "Export P6"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
+4 -15
View File
@@ -25,6 +25,7 @@ import ifcopenshell.api
import ifcopenshell.api.style import ifcopenshell.api.style
import ifcopenshell.util.representation import ifcopenshell.util.representation
import ifcopenshell.util.unit import ifcopenshell.util.unit
from bpy_extras.io_utils import ImportHelper
from pathlib import Path from pathlib import Path
from mathutils import Vector from mathutils import Vector
from typing import Any, Union from typing import Any, Union
@@ -273,16 +274,12 @@ class SetAssetMaterialToExternalStyle(bpy.types.Operator):
return {"FINISHED"} return {"FINISHED"}
class BrowseExternalStyle(bpy.types.Operator): class BrowseExternalStyle(bpy.types.Operator, ImportHelper):
bl_idname = "bim.browse_external_style" bl_idname = "bim.browse_external_style"
bl_label = "Browse External Style" bl_label = "Browse External Style"
bl_description = "Select filepath for an external style." bl_description = "Select filepath for an external style."
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
filepath: bpy.props.StringProperty(
name="File Path", description="Filepath used to import from", maxlen=1024, default="", subtype="FILE_PATH"
)
filter_glob: bpy.props.StringProperty( filter_glob: bpy.props.StringProperty(
default="*.blend", default="*.blend",
options={"HIDDEN"}, options={"HIDDEN"},
@@ -357,8 +354,7 @@ class BrowseExternalStyle(bpy.types.Operator):
if data_block in data_blocks: if data_block in data_blocks:
self.data_block = data_block self.data_block = data_block
context.window_manager.fileselect_add(self) return ImportHelper.invoke(self, context, event)
return {"RUNNING_MODAL"}
def draw(self, context): def draw(self, context):
layout = self.layout layout = self.layout
@@ -538,7 +534,7 @@ class SelectByStyle(bpy.types.Operator):
return {"FINISHED"} return {"FINISHED"}
class ChooseTextureMapPath(bpy.types.Operator): class ChooseTextureMapPath(bpy.types.Operator, ImportHelper):
bl_idname = "bim.choose_texture_map_path" bl_idname = "bim.choose_texture_map_path"
bl_label = "Choose Texture Map Path" bl_label = "Choose Texture Map Path"
bl_description = "Select filepath for a texture map." bl_description = "Select filepath for a texture map."
@@ -548,9 +544,6 @@ class ChooseTextureMapPath(bpy.types.Operator):
use_relative_path: bpy.props.BoolProperty( use_relative_path: bpy.props.BoolProperty(
name="Use Relative Path", description="Save path relative to IFC file", default=True name="Use Relative Path", description="Save path relative to IFC file", default=True
) )
filepath: bpy.props.StringProperty(
name="File Path", description="Filepath used to import from", maxlen=1024, default="", subtype="FILE_PATH"
)
filter_image: bpy.props.BoolProperty(default=True, options={"HIDDEN", "SKIP_SAVE"}) filter_image: bpy.props.BoolProperty(default=True, options={"HIDDEN", "SKIP_SAVE"})
filter_folder: bpy.props.BoolProperty(default=True, options={"HIDDEN", "SKIP_SAVE"}) filter_folder: bpy.props.BoolProperty(default=True, options={"HIDDEN", "SKIP_SAVE"})
@@ -563,10 +556,6 @@ class ChooseTextureMapPath(bpy.types.Operator):
layout.label(text="Save the .ifc file first ") layout.label(text="Save the .ifc file first ")
layout.label(text="to use relative paths.") layout.label(text="to use relative paths.")
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
def execute(self, context): def execute(self, context):
if self.texture_map_index < 0: if self.texture_map_index < 0:
self.report({"ERROR"}, "Provide a texture map index") self.report({"ERROR"}, "Provide a texture map index")
@@ -28,6 +28,7 @@ import ifctester.reporter
import ifcopenshell import ifcopenshell
import bonsai.tool as tool import bonsai.tool as tool
import bonsai.bim.handler import bonsai.bim.handler
from bpy_extras.io_utils import ExportHelper
from pathlib import Path from pathlib import Path
from typing import Union from typing import Union
@@ -186,13 +187,13 @@ class SelectFailedEntities(bpy.types.Operator):
return {"FINISHED"} return {"FINISHED"}
class ExportBcf(bpy.types.Operator): class ExportBcf(bpy.types.Operator, ExportHelper):
bl_idname = "bim.export_bcf" bl_idname = "bim.export_bcf"
bl_label = "Export BCF" bl_label = "Export BCF"
bl_description = "Save ifctester BCF report by the provided filepath." bl_description = "Save ifctester BCF report by the provided filepath."
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
filter_glob: bpy.props.StringProperty(default="*.bcf", options={"HIDDEN"}) filter_glob: bpy.props.StringProperty(default="*.bcf", options={"HIDDEN"})
filepath: bpy.props.StringProperty(subtype="FILE_PATH") filename_ext = ".bcf"
def execute(self, context): def execute(self, context):
bcf_reporter = ifctester.reporter.Bcf(tool.Tester.specs) bcf_reporter = ifctester.reporter.Bcf(tool.Tester.specs)
@@ -200,7 +201,3 @@ class ExportBcf(bpy.types.Operator):
bcf_reporter.to_file(self.filepath) bcf_reporter.to_file(self.filepath)
self.report({"INFO"}, "Finished exporting!") self.report({"INFO"}, "Finished exporting!")
return {"FINISHED"} return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
+11 -25
View File
@@ -31,6 +31,7 @@ import ifcopenshell
import bonsai.bim import bonsai.bim
import bonsai.tool as tool import bonsai.tool as tool
import bonsai.bim.handler import bonsai.bim.handler
from bpy_extras.io_utils import ImportHelper
from bonsai.bim import import_ifc from bonsai.bim import import_ifc
from bonsai.bim.prop import StrProperty from bonsai.bim.prop import StrProperty
from bonsai.bim.ui import IFCFileSelector from bonsai.bim.ui import IFCFileSelector
@@ -145,12 +146,11 @@ class CloseBlendWarning(bpy.types.Operator):
return context.window_manager.invoke_props_dialog(self) return context.window_manager.invoke_props_dialog(self)
class SelectURIAttribute(bpy.types.Operator): class SelectURIAttribute(bpy.types.Operator, ImportHelper):
bl_idname = "bim.select_uri_attribute" bl_idname = "bim.select_uri_attribute"
bl_label = "Select URI Attribute" bl_label = "Select URI Attribute"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
bl_description = "Select a local file" bl_description = "Select a local file"
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
data_path: bpy.props.StringProperty(name="Data Path") data_path: bpy.props.StringProperty(name="Data Path")
use_relative_path: bpy.props.BoolProperty(name="Use Relative Path", default=False) use_relative_path: bpy.props.BoolProperty(name="Use Relative Path", default=False)
@@ -174,18 +174,13 @@ class SelectURIAttribute(bpy.types.Operator):
attribute.string_value = tool.Ifc.get_uri(self.filepath, use_relative_path=self.use_relative_path) attribute.string_value = tool.Ifc.get_uri(self.filepath, use_relative_path=self.use_relative_path)
return {"FINISHED"} return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class BIM_OT_multiple_file_selector(bpy.types.Operator, ImportHelper):
class BIM_OT_multiple_file_selector(bpy.types.Operator):
"""Open Blender's file explorer to select one or multiple files.""" """Open Blender's file explorer to select one or multiple files."""
bl_idname = "bim.multiple_file_selector" bl_idname = "bim.multiple_file_selector"
bl_label = "Select File(s)" bl_label = "Select File(s)"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
files: bpy.props.CollectionProperty(name="File Path", type=bpy.types.OperatorFileListElement) files: bpy.props.CollectionProperty(name="File Path", type=bpy.types.OperatorFileListElement)
filter_glob: bpy.props.StringProperty(default="*", options={"HIDDEN"}) filter_glob: bpy.props.StringProperty(default="*", options={"HIDDEN"})
filepath: bpy.props.StringProperty(subtype="FILE_PATH") filepath: bpy.props.StringProperty(subtype="FILE_PATH")
@@ -206,18 +201,17 @@ class BIM_OT_multiple_file_selector(bpy.types.Operator):
def invoke(self, context, event): def invoke(self, context, event):
self.file_props = context.file_props self.file_props = context.file_props
context.window_manager.fileselect_add(self) return ImportHelper.invoke(self, context, event)
return {"RUNNING_MODAL"}
class SelectIfcFile(bpy.types.Operator, IFCFileSelector): class SelectIfcFile(bpy.types.Operator, IFCFileSelector, ImportHelper):
bl_idname = "bim.select_ifc_file" bl_idname = "bim.select_ifc_file"
bl_label = "Select IFC File" bl_label = "Select IFC File"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
bl_description = f"Select a different IFC file.\n{tool.Blender.operator_invoke_filepath_hotkeys_description}" bl_description = f"Select a different IFC file.\n{tool.Blender.operator_invoke_filepath_hotkeys_description}"
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
filter_glob: bpy.props.StringProperty(default="*.ifc;*.ifczip;*.ifcxml", options={"HIDDEN"}) filter_glob: bpy.props.StringProperty(default="*.ifc;*.ifczip;*.ifcxml", options={"HIDDEN"})
use_relative_path: bpy.props.BoolProperty(name="Use Relative Path", default=False) use_relative_path: bpy.props.BoolProperty(name="Use Relative Path", default=False)
filename_ext = ".ifc"
def execute(self, context): def execute(self, context):
if self.is_existing_ifc_file(): if self.is_existing_ifc_file():
@@ -233,17 +227,14 @@ class SelectIfcFile(bpy.types.Operator, IFCFileSelector):
res = tool.Blender.operator_invoke_filepath_hotkeys(self, context, event, filepath) res = tool.Blender.operator_invoke_filepath_hotkeys(self, context, event, filepath)
if res is not None: if res is not None:
return res return res
return ImportHelper.invoke(self, context, event)
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class SelectDir(bpy.types.Operator): class SelectDir(bpy.types.Operator, ImportHelper):
bl_idname = "bim.select_dir" bl_idname = "bim.select_dir"
bl_label = "Select Directory" bl_label = "Select Directory"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
bl_description = "Open a file browser to choose the directory" bl_description = "Open a file browser to choose the directory"
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
data_path: bpy.props.StringProperty(name="Data Path") data_path: bpy.props.StringProperty(name="Data Path")
def execute(self, context): def execute(self, context):
@@ -262,8 +253,7 @@ class SelectDir(bpy.types.Operator):
return {"FINISHED"} return {"FINISHED"}
def invoke(self, context, event): def invoke(self, context, event):
context.window_manager.fileselect_add(self) return ImportHelper.invoke(self, context, event)
return {"RUNNING_MODAL"}
class FileAssociate(bpy.types.Operator): class FileAssociate(bpy.types.Operator):
@@ -768,13 +758,13 @@ class BIM_OT_remove_section_plane(bpy.types.Operator):
bpy.ops.object.delete() bpy.ops.object.delete()
class ReloadIfcFile(bpy.types.Operator, tool.Ifc.Operator): class ReloadIfcFile(bpy.types.Operator, tool.Ifc.Operator, ImportHelper):
bl_idname = "bim.reload_ifc_file" bl_idname = "bim.reload_ifc_file"
bl_label = "Reload IFC File" bl_label = "Reload IFC File"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
bl_description = "Reload an updated IFC file" bl_description = "Reload an updated IFC file"
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
filter_glob: bpy.props.StringProperty(default="*.ifc", options={"HIDDEN"}) filter_glob: bpy.props.StringProperty(default="*.ifc", options={"HIDDEN"})
filename_ext = ".ifc"
def _execute(self, context): def _execute(self, context):
import ifcdiff import ifcdiff
@@ -842,10 +832,6 @@ class ReloadIfcFile(bpy.types.Operator, tool.Ifc.Operator):
bim_props.ifc_file = self.filepath bim_props.ifc_file = self.filepath
return {"FINISHED"} return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class AddIfcFile(bpy.types.Operator): class AddIfcFile(bpy.types.Operator):
bl_idname = "bim.add_ifc_file" bl_idname = "bim.add_ifc_file"
+3 -6
View File
@@ -32,6 +32,7 @@ import importlib
import logging import logging
import types import types
import bpy import bpy
from bpy_extras.io_utils import ExportHelper
logger = logging.getLogger("sverchok.ifc") logger = logging.getLogger("sverchok.ifc")
@@ -180,15 +181,15 @@ class IFC_Sv_UpdateCurrent(bpy.types.Operator):
return {"FINISHED"} return {"FINISHED"}
class IFC_Sv_write_file(bpy.types.Operator): class IFC_Sv_write_file(bpy.types.Operator, ExportHelper):
bl_idname = "ifc.write_file_panel" bl_idname = "ifc.write_file_panel"
bl_label = "Write File" bl_label = "Write File"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
bl_description = "Save transient IFC file to the provided path." bl_description = "Save transient IFC file to the provided path."
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
filter_glob: bpy.props.StringProperty(default="*.ifc", options={"HIDDEN"}) filter_glob: bpy.props.StringProperty(default="*.ifc", options={"HIDDEN"})
node_group: bpy.props.StringProperty(default="") node_group: bpy.props.StringProperty(default="")
force_mode: bpy.props.BoolProperty(default=False) force_mode: bpy.props.BoolProperty(default=False)
filename_ext = ".ifc"
@classmethod @classmethod
def poll(cls, context): def poll(cls, context):
@@ -264,10 +265,6 @@ class IFC_Sv_write_file(bpy.types.Operator):
self.report({"INFO"}, f"File written to: {self.filepath}") self.report({"INFO"}, f"File written to: {self.filepath}")
return {"FINISHED"} return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class IFC_PT_write_file_panel(bpy.types.Panel): class IFC_PT_write_file_panel(bpy.types.Panel):
bl_idname = "IFC_PT_write_file_panel" bl_idname = "IFC_PT_write_file_panel"