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.bim.module.bcf.prop as bcf_prop
import bonsai.bim.module.bcf.bcfstore as bcfstore
from bpy_extras.io_utils import ImportHelper, ExportHelper
from pathlib import Path
from math import radians, degrees, atan, tan, cos, sin
from mathutils import Vector, Matrix, Euler, geometry
@@ -63,13 +64,14 @@ class NewBcfProject(bpy.types.Operator):
return {"FINISHED"}
class LoadBcfProject(bpy.types.Operator):
class LoadBcfProject(bpy.types.Operator, ImportHelper):
bl_idname = "bim.load_bcf_project"
bl_label = "Load BCF Project"
bl_description = "Load the BCF file."
bl_options = {"REGISTER", "UNDO"}
filepath: bpy.props.StringProperty(subtype="FILE_PATH", options={"SKIP_SAVE"})
filter_glob: bpy.props.StringProperty(default="*.bcf;*.bcfzip", options={"HIDDEN"})
filename_ext = ".bcf"
def execute(self, context):
# 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.")
return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class UnloadBcfProject(bpy.types.Operator):
bl_idname = "bim.unload_bcf_project"
@@ -342,7 +340,7 @@ class EditBcfTopic(bpy.types.Operator):
return {"FINISHED"}
class SaveBcfProject(bpy.types.Operator):
class SaveBcfProject(bpy.types.Operator, ExportHelper):
bl_idname = "bim.save_bcf_project"
bl_label = "Save BCF Project"
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")
filter_glob: bpy.props.StringProperty(default="*.bcf;*.bcfzip", options={"HIDDEN"})
save_current_bcf: bpy.props.BoolProperty(default=False, options={"SKIP_SAVE"})
filename_ext = ".bcf"
def execute(self, context):
bcfxml = bcfstore.BcfStore.get_bcfxml()
@@ -366,8 +365,7 @@ class SaveBcfProject(bpy.types.Operator):
self.filepath = str(path)
return self.execute(context)
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
return ExportHelper.invoke(self, context, event)
class AddBcfTopic(bpy.types.Operator):
@@ -1536,13 +1534,13 @@ class OpenBcfReferenceLink(bpy.types.Operator):
return {"FINISHED"}
class SelectBcfHeaderFile(bpy.types.Operator):
class SelectBcfHeaderFile(bpy.types.Operator, ImportHelper):
bl_idname = "bim.select_bcf_header_file"
bl_label = "Select BCF Header File"
bl_description = "Select filepath for BCF header reference."
bl_options = {"REGISTER", "UNDO"}
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
filter_glob: bpy.props.StringProperty(default="*.ifc;*.ifczip;*.ifcxml;*.ifcjson", options={"HIDDEN"})
filename_ext = ".ifc"
def execute(self, context):
if self.filepath:
@@ -1550,17 +1548,12 @@ class SelectBcfHeaderFile(bpy.types.Operator):
props.file_reference = self.filepath
return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class SelectBcfBimSnippetReference(bpy.types.Operator):
class SelectBcfBimSnippetReference(bpy.types.Operator, ImportHelper):
bl_idname = "bim.select_bcf_bim_snippet_reference"
bl_label = "Select BCF BIM Snippet Reference"
bl_description = "Select filepath for BCF snippet reference."
bl_options = {"REGISTER", "UNDO"}
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
def execute(self, context):
if self.filepath:
@@ -1568,17 +1561,12 @@ class SelectBcfBimSnippetReference(bpy.types.Operator):
props.bim_snippet_reference = self.filepath
return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class SelectBcfDocumentReference(bpy.types.Operator):
class SelectBcfDocumentReference(bpy.types.Operator, ImportHelper):
bl_idname = "bim.select_bcf_document_reference"
bl_label = "Select BCF Document Reference"
bl_description = "Select filepath for BCF document reference."
bl_options = {"REGISTER", "UNDO"}
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
def execute(self, context):
if self.filepath:
@@ -1586,10 +1574,6 @@ class SelectBcfDocumentReference(bpy.types.Operator):
props.document_reference = self.filepath
return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class LoadBcfHeaderIfcFile(bpy.types.Operator):
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.core.brick as core
import bonsai.bim.handler
from bpy_extras.io_utils import ImportHelper, ExportHelper
from bonsai.bim.ifc import IfcStore
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_label = "Load Brickschema Project"
bl_options = {"REGISTER", "UNDO"}
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"})
filename_ext = ".ttl"
def _execute(self, context):
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:
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):
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_label = "Serialize Brick"
# Prevents crash on Blender 4.4.0.
@@ -251,9 +248,7 @@ class SerializeBrick(bpy.types.Operator):
def invoke(self, context, event):
if self.should_save_as or not BrickStore.path:
WindowManager = context.window_manager
WindowManager.fileselect_add(self)
return {"RUNNING_MODAL"}
return ExportHelper.invoke(self, context, event)
else:
return self.execute(context)
+13 -39
View File
@@ -24,26 +24,20 @@ import logging
import numpy as np
import ifcopenshell
import bonsai.tool as tool
from bpy_extras.io_utils import ExportHelper, ImportHelper
from math import radians
from mathutils import Matrix, Vector
from bonsai.bim.ifc import IfcStore
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_label = "Export Clash Sets"
bl_description = "Export clash sets to a selected file"
filename_ext = ".json"
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
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):
self.filepath = bpy.path.ensure_ext(self.filepath, ".json")
clash_sets = tool.Clash.export_clash_sets()
@@ -52,20 +46,17 @@ class ExportClashSets(bpy.types.Operator):
return {"FINISHED"}
class ImportClashSets(bpy.types.Operator):
class ImportClashSets(bpy.types.Operator, ImportHelper):
bl_idname = "bim.import_clash_sets"
bl_label = "Import Clash Sets"
bl_options = {"REGISTER", "UNDO"}
bl_description = "Import clash sets from a selected file"
filename_ext = ".json"
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
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"}
return ImportHelper.invoke(self, context, event)
def execute(self, context):
tool.Clash.load_clash_sets(self.filepath)
@@ -155,15 +146,15 @@ class RemoveClashSource(bpy.types.Operator):
return {"FINISHED"}
class SelectClashSource(bpy.types.Operator):
class SelectClashSource(bpy.types.Operator, ImportHelper):
bl_idname = "bim.select_clash_source"
bl_label = "Select Clash Source"
bl_options = {"REGISTER", "UNDO"}
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"})
index: bpy.props.IntProperty()
group: bpy.props.StringProperty()
filename_ext = ".ifc"
def execute(self, context):
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
return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class SelectClashResults(bpy.types.Operator):
class SelectClashResults(bpy.types.Operator, ImportHelper):
bl_idname = "bim.select_clash_results"
bl_label = "Select Clash Results"
bl_description = "Select filepath for clash results."
bl_options = {"REGISTER", "UNDO"}
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
def execute(self, context):
props = tool.Clash.get_clash_props()
props.clash_results_path = self.filepath
return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class SelectSmartGroupedClashesPath(bpy.types.Operator):
class SelectSmartGroupedClashesPath(bpy.types.Operator, ImportHelper):
bl_idname = "bim.select_smart_grouped_clashes_path"
bl_label = "Select Smart-Grouped Clashes Path"
bl_description = "Select filepath for smart-grouped clashes."
bl_options = {"REGISTER", "UNDO"}
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
def execute(self, context):
props = tool.Clash.get_clash_props()
props.smart_grouped_clashes_path = self.filepath
return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class ExecuteIfcClash(bpy.types.Operator):
class ExecuteIfcClash(bpy.types.Operator, ExportHelper):
bl_idname = "bim.execute_ifc_clash"
bl_label = "Execute IFC Clash"
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):
if self.filepath:
return self.execute(context)
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
return ExportHelper.invoke(self, context, event)
def execute(self, context):
from ifcclash import ifcclash
@@ -294,19 +270,17 @@ class ExecuteIfcClash(bpy.types.Operator):
return {"FINISHED"}
class SelectIfcClashResults(bpy.types.Operator):
class SelectIfcClashResults(bpy.types.Operator, ImportHelper):
bl_idname = "bim.select_ifc_clash_results"
bl_label = "Select IFC Clash Results"
bl_options = {"REGISTER", "UNDO"}
bl_description = "Select the clashing IFC geometry stored in a file"
filter_glob: bpy.props.StringProperty(default="*.json", options={"HIDDEN"})
filename_ext = ".json"
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
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"}
return ImportHelper.invoke(self, context, event)
def execute(self, context):
# TODO refactor into new clash results system
@@ -25,20 +25,16 @@ import ifcopenshell.util.classification
import ifcopenshell.util.element
import bonsai.tool as tool
import bonsai.bim.helper
from bpy_extras.io_utils import ImportHelper
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_label = "Load Classification Library"
bl_description = "Load classification library from the provided filepath."
filename_ext = ".ifc"
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):
IfcStore.classification_file = ifcopenshell.open(self.filepath)
@@ -21,7 +21,7 @@
import bpy
import ifcopenshell.api
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.core.cost as core
from typing import get_args, TYPE_CHECKING
@@ -678,7 +678,7 @@ class CalculateCostItemResourceValue(bpy.types.Operator, tool.Ifc.Operator):
return {"FINISHED"}
class ExportCostSchedules(bpy.types.Operator):
class ExportCostSchedules(bpy.types.Operator, ExportHelper):
bl_idname = "bim.export_cost_schedules"
bl_label = "Export Cost Schedule"
bl_options = {"REGISTER", "UNDO"}
@@ -701,9 +701,7 @@ class ExportCostSchedules(bpy.types.Operator):
return {"FINISHED"}
def invoke(self, context, event):
wm = context.window_manager
wm.fileselect_add(self)
return {"RUNNING_MODAL"}
return ExportHelper.invoke(self, context, event)
def draw(self, context):
self.layout.label(text="Choose a format")
+9 -30
View File
@@ -27,6 +27,7 @@ import ifcopenshell
import ifcopenshell.util.selector
import bonsai.tool as tool
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 typing import TYPE_CHECKING
from collections import Counter
@@ -90,13 +91,13 @@ class ReorderCsvAttribute(bpy.types.Operator):
return {"FINISHED"}
class ImportCsvAttributes(bpy.types.Operator):
class ImportCsvAttributes(bpy.types.Operator, ImportHelper):
bl_idname = "bim.import_csv_attributes"
bl_label = "Load CSV Settings"
bl_description = "Import a json template for CSV export"
bl_options = {"REGISTER", "UNDO"}
filter_glob: bpy.props.StringProperty(default="*.json", options={"HIDDEN"})
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
filename_ext = ".json"
def execute(self, context):
props = tool.Blender.get_csv_props()
@@ -125,19 +126,14 @@ class ImportCsvAttributes(bpy.types.Operator):
setattr(new, prop, attribute[prop])
return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class ExportCsvAttributes(bpy.types.Operator):
class ExportCsvAttributes(bpy.types.Operator, ExportHelper):
bl_idname = "bim.export_csv_attributes"
bl_label = "Save CSV Settings"
bl_options = {"REGISTER", "UNDO"}
bl_description = "Save a json template for CSV export"
filename_ext = ".json"
filter_glob: bpy.props.StringProperty(default="*.json", options={"HIDDEN"})
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
def execute(self, context):
props = tool.Blender.get_csv_props()
@@ -179,14 +175,8 @@ class ExportCsvAttributes(bpy.types.Operator):
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):
class ExportIfcCsv(bpy.types.Operator, ExportHelper):
bl_idname = "bim.export_ifccsv"
bl_label = "Export IFC"
bl_description = "Export IFC data as a spreadsheet."
@@ -212,10 +202,7 @@ class ExportIfcCsv(bpy.types.Operator):
props = tool.Blender.get_csv_props()
if props.format == "web":
return self.execute(context)
self.filepath = bpy.path.ensure_ext(bpy.data.filepath, f".{props.format}")
WindowManager = context.window_manager
WindowManager.fileselect_add(self)
return {"RUNNING_MODAL"}
return ExportHelper.invoke(self, context, event)
def execute(self, context):
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_label = "Import to IFC"
bl_description = "Import IFC data from a spreadsheet."
bl_options = {"REGISTER", "UNDO"}
filter_glob: bpy.props.StringProperty(default="*.csv;*.ods;*.xlsx", options={"HIDDEN"})
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
@classmethod
def poll(cls, context):
@@ -317,9 +303,7 @@ class ImportIfcCsv(bpy.types.Operator, tool.Ifc.Operator):
def invoke(self, context, event):
self.filepath = bpy.path.ensure_ext(bpy.data.filepath, ".csv")
WindowManager = context.window_manager
WindowManager.fileselect_add(self)
return {"RUNNING_MODAL"}
return ImportHelper.invoke(self, context, event)
def _execute(self, context):
import ifccsv
@@ -350,20 +334,15 @@ class ImportIfcCsv(bpy.types.Operator, tool.Ifc.Operator):
return {"FINISHED"}
class SelectCsvIfcFile(bpy.types.Operator):
class SelectCsvIfcFile(bpy.types.Operator, ImportHelper):
bl_idname = "bim.select_csv_ifc_file"
bl_label = "Select CSV IFC File"
bl_description = "Select IFC file for spreadsheet import/export."
bl_options = {"REGISTER", "UNDO"}
filename_ext = ".ifc"
filter_glob: bpy.props.StringProperty(default="*.ifc;*.ifczip;*.ifcxml", options={"HIDDEN"})
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
def execute(self, context):
props = tool.Blender.get_csv_props()
props.csv_ifc_file = self.filepath
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.bim.handler
import bonsai.bim.import_ifc as import_ifc
from bpy_extras.io_utils import ImportHelper, ExportHelper
from pathlib import Path
from bonsai import get_debug_info, format_debug_info
from bonsai.bim.ifc import IfcStore
@@ -446,12 +447,11 @@ class ParseExpress(bpy.types.Operator):
return {"FINISHED"}
class SelectExpressFile(bpy.types.Operator):
class SelectExpressFile(bpy.types.Operator, ImportHelper):
bl_idname = "bim.select_express_file"
bl_label = "Select Express File"
bl_options = {"REGISTER", "UNDO"}
bl_description = "Select an IFC EXPRESS definition"
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
filter_glob: bpy.props.StringProperty(default="*.exp", options={"HIDDEN"})
def execute(self, context):
@@ -460,10 +460,6 @@ class SelectExpressFile(bpy.types.Operator):
props.express_file = self.filepath
return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class PurgeHdf5Cache(bpy.types.Operator):
bl_idname = "bim.purge_hdf5_cache"
@@ -523,7 +519,7 @@ class PrintUnusedElementStats(bpy.types.Operator):
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_label = "Purge Unused Elements By Class"
bl_description = (
@@ -537,7 +533,7 @@ class PurgeUnusedElementsByClass(bpy.types.Operator, tool.Ifc.Operator):
def invoke(self, context, event):
if event.type == "LEFTMOUSE" and event.alt:
context.window_manager.fileselect_add(self)
return ExportHelper.invoke(self, context, event)
return self.execute(context)
@classmethod
+8 -26
View File
@@ -24,26 +24,23 @@ import ifcopenshell
import bonsai.bim.handler
import bonsai.bim.import_ifc
import bonsai.tool as tool
from bpy_extras.io_utils import ImportHelper, ExportHelper
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_label = "Select Diff JSON File"
bl_description = "Select filepath for IFC diff results."
bl_options = {"REGISTER", "UNDO"}
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
filter_glob: bpy.props.StringProperty(default="*.json", options={"HIDDEN"})
filename_ext = ".json"
def execute(self, context):
props = tool.Blender.get_diff_props()
props.diff_json_file = self.filepath
return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class VisualiseDiff(bpy.types.Operator):
bl_idname = "bim.visualise_diff"
@@ -104,56 +101,41 @@ class VisualiseDiff(bpy.types.Operator):
return {"FINISHED"}
class SelectDiffOldFile(bpy.types.Operator):
class SelectDiffOldFile(bpy.types.Operator, ImportHelper):
bl_idname = "bim.select_diff_old_file"
bl_label = "Select Diff Old File"
bl_description = "Select filepath for an old IFC file to compare."
bl_options = {"REGISTER", "UNDO"}
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
filter_glob: bpy.props.StringProperty(default="*.ifc", options={"HIDDEN"})
filename_ext = ".ifc"
def execute(self, context):
props = tool.Blender.get_diff_props()
props.old_file = self.filepath
return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class SelectDiffNewFile(bpy.types.Operator):
class SelectDiffNewFile(bpy.types.Operator, ImportHelper):
bl_idname = "bim.select_diff_new_file"
bl_label = "Select Diff New File"
bl_description = "Select filepath for a new IFC file to compare."
bl_options = {"REGISTER", "UNDO"}
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
filter_glob: bpy.props.StringProperty(default="*.ifc", options={"HIDDEN"})
filename_ext = ".ifc"
def execute(self, context):
props = tool.Blender.get_diff_props()
props.new_file = self.filepath
return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class ExecuteIfcDiff(bpy.types.Operator):
class ExecuteIfcDiff(bpy.types.Operator, ExportHelper):
bl_idname = "bim.execute_ifc_diff"
bl_label = "Execute IFC Diff"
bl_description = "Compare two IFC files and save a json diff report by the provided filepath."
filename_ext = ".json"
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
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):
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.sheeter as sheeter
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.data import DecoratorData, DrawingsData
from typing import NamedTuple, List, Union, Optional, Literal
@@ -2217,12 +2218,12 @@ class ActivateDrawingFromSheet(bpy.types.Operator, ActivateDrawingBase):
# 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_label = "Select Documentation IFC File"
bl_options = {"REGISTER", "UNDO"}
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()
def execute(self, context):
@@ -2230,10 +2231,6 @@ class SelectDocIfcFile(bpy.types.Operator):
props.ifc_files[self.index].name = self.filepath
return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class ResizeText(bpy.types.Operator):
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))
class AddSchedule(bpy.types.Operator, tool.Ifc.Operator):
class AddSchedule(bpy.types.Operator, tool.Ifc.Operator, ImportHelper):
bl_idname = "bim.add_schedule"
bl_label = "Add Schedule"
bl_options = {"REGISTER", "UNDO"}
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"})
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)
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):
bl_idname = "bim.remove_schedule"
@@ -2799,24 +2791,20 @@ class AddReferenceToSheet(bpy.types.Operator, tool.Ifc.Operator):
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_label = "Add Reference"
bl_description = "Import a .svg file to the project as a reference"
bl_options = {"REGISTER", "UNDO"}
filepath: bpy.props.StringProperty(subtype="FILE_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)
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class RemoveReference(bpy.types.Operator, tool.Ifc.Operator):
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)
class AddReferenceImage(bpy.types.Operator, tool.Ifc.Operator):
class AddReferenceImage(bpy.types.Operator, tool.Ifc.Operator, ImportHelper):
bl_idname = "bim.add_reference_image"
bl_label = "Add Reference Image"
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"}
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_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, "use_existing_object_by_name")
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
def _execute(self, context):
abs_path = Path(self.filepath).absolute().resolve()
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 ifcopenshell
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_label = "Execute IfcFM"
bl_description = "Export IfcFM data as a spreadsheet."
file_format: bpy.props.StringProperty()
filter_glob: bpy.props.StringProperty(default="*.csv;*.ods;*.xlsx", options={"HIDDEN"})
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
@classmethod
def poll(cls, context):
@@ -45,9 +45,7 @@ class ExecuteIfcFM(bpy.types.Operator):
def invoke(self, context, event):
props = context.scene.BIMFMProperties
self.filepath = bpy.path.ensure_ext(bpy.data.filepath, f".{props.format}")
WindowManager = context.window_manager
WindowManager.fileselect_add(self)
return {"RUNNING_MODAL"}
return ExportHelper.invoke(self, context, event)
def execute(self, context):
props = context.scene.BIMFMProperties
@@ -83,13 +81,12 @@ class ExecuteIfcFM(bpy.types.Operator):
return {"FINISHED"}
class SelectFMSpreadsheetFiles(bpy.types.Operator):
class SelectFMSpreadsheetFiles(bpy.types.Operator, ImportHelper):
bl_idname = "bim.select_fm_spreadsheet_files"
bl_label = "Select FM Spreadsheet Files"
bl_description = "Select FM spreadsheets to merge."
bl_options = {"REGISTER", "UNDO"}
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)
def execute(self, context):
@@ -101,17 +98,12 @@ class SelectFMSpreadsheetFiles(bpy.types.Operator):
new.name = os.path.join(dirname, f.name)
return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class ExecuteIfcFMFederate(bpy.types.Operator):
class ExecuteIfcFMFederate(bpy.types.Operator, ExportHelper):
bl_idname = "bim.execute_ifcfm_federate"
bl_label = "Merge IfcFM SpreadSheets"
bl_description = "Merge added IfcFM spreadsheets."
filter_glob: bpy.props.StringProperty(default="*.ods;*.xlsx", options={"HIDDEN"})
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
@classmethod
def poll(cls, context):
@@ -124,9 +116,7 @@ class ExecuteIfcFMFederate(bpy.types.Operator):
def invoke(self, context, event):
props = context.scene.BIMFMProperties
self.filepath = bpy.path.ensure_ext(bpy.data.filepath, f".{props.format}")
WindowManager = context.window_manager
WindowManager.fileselect_add(self)
return {"RUNNING_MODAL"}
return ExportHelper.invoke(self, context, event)
def execute(self, context):
props = context.scene.BIMFMProperties
@@ -20,6 +20,7 @@ import bpy
import bonsai.tool as tool
import bonsai.core.georeference as core
from bpy_extras.io_utils import ImportHelper
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)
class ImportPlot(bpy.types.Operator, tool.Ifc.Operator):
class ImportPlot(bpy.types.Operator, tool.Ifc.Operator, ImportHelper):
bl_idname = "bim.import_plot"
bl_label = "Import Plot"
bl_options = {"REGISTER", "UNDO"}
bl_description = "Import plot from a csv file."
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
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)
return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class EnableEditingWCS(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.enable_editing_wcs"
@@ -25,6 +25,7 @@ import bonsai.tool as tool
import json
import zipfile
import os.path
from bpy_extras.io_utils import ImportHelper, ExportHelper
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
# the code was changed to work with ifc sverchok modifier
# 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_label = "Import Sverchok Graph"
bl_description = "Import Sverchok graph from a json file."
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"})
filename_ext = ".json"
def _execute(self, context):
import sverchok
@@ -210,10 +208,6 @@ class ImportSverchokGraph(bpy.types.Operator, tool.Ifc.Operator):
props.node_group = node_group
return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
def draw(self, context):
col = self.layout.column()
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
# the code was changed to work with ifc sverchok modifier
# 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_label = "Export Sverchok Graph"
bl_description = "Export Sverchok graph to a json file."
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"})
filename_ext = ".json"
compact: bpy.props.BoolProperty(default=True, description="Compact representation of the JSON file")
compress: bpy.props.BoolProperty()
@@ -281,10 +272,6 @@ class ExportSverchokGraph(bpy.types.Operator, tool.Ifc.Operator):
return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
def draw(self, context):
graph_name = context.active_object.BIMSverchokProperties.node_group.name
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.core.patch as core
import bonsai.bim.handler
from bpy_extras.io_utils import ImportHelper, ExportHelper
from pathlib import Path
from typing import cast, TYPE_CHECKING
@@ -31,41 +32,33 @@ if TYPE_CHECKING:
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_label = "Select IFC Patch Input"
bl_description = "Select filepath for IFC patch input."
bl_options = {"REGISTER", "UNDO"}
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):
props = tool.Patch.get_patch_props()
props.ifc_patch_input = self.filepath
return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class SelectIfcPatchOutput(bpy.types.Operator):
class SelectIfcPatchOutput(bpy.types.Operator, ExportHelper):
bl_idname = "bim.select_ifc_patch_output"
bl_label = "Select IFC Patch Output"
bl_description = "Select filepath for IFC patch output."
bl_options = {"REGISTER", "UNDO"}
filter_glob: bpy.props.StringProperty(default="*.ifc;*.ifcZIP;*.ifcXML", options={"HIDDEN"})
filename_ext = ".ifc"
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
def execute(self, context):
props = tool.Patch.get_patch_props()
props.ifc_patch_output = self.filepath
return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class ExecuteIfcPatch(bpy.types.Operator):
bl_idname = "bim.execute_ifc_patch"
@@ -47,6 +47,7 @@ import bonsai.bim.helper
import bonsai.bim.schema
import bonsai.tool as tool
import bonsai.core.project as core
from bpy_extras.io_utils import ExportHelper, ImportHelper
from bonsai.bim.ifc import IfcStore
from bonsai.bim.ui import IFCFileSelector
from bonsai.bim import import_ifc
@@ -152,12 +153,11 @@ class CreateProject(bpy.types.Operator):
IfcStore.file = data["file"]
class SelectLibraryFile(bpy.types.Operator, IFCFileSelector):
class SelectLibraryFile(bpy.types.Operator, IFCFileSelector, ImportHelper):
bl_idname = "bim.select_library_file"
bl_label = "Select Library File"
bl_options = {"REGISTER", "UNDO"}
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"})
append_all: bpy.props.BoolProperty(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()
return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
def rollback(self, data):
if data["old_filepath"]:
IfcStore.library_path = data["old_filepath"]
@@ -872,7 +868,7 @@ class DisableEditingHeader(bpy.types.Operator):
return {"FINISHED"}
class LoadProject(bpy.types.Operator, IFCFileSelector):
class LoadProject(bpy.types.Operator, IFCFileSelector, ImportHelper):
bl_idname = "bim.load_project"
bl_label = "Load Project"
bl_options = {"REGISTER", "UNDO"}
@@ -903,6 +899,7 @@ class LoadProject(bpy.types.Operator, IFCFileSelector):
default=False,
)
use_detailed_tooltip: bpy.props.BoolProperty(default=False, options={"HIDDEN"})
filename_ext = ".ifc"
@classmethod
def description(cls, context, properties):
@@ -1014,8 +1011,7 @@ class LoadProject(bpy.types.Operator, IFCFileSelector):
def invoke(self, context, event):
if self.filepath:
return self.execute(context)
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
return ImportHelper.invoke(self, context, event)
def draw(self, context):
if self.use_relative_path:
@@ -1175,12 +1171,12 @@ class ToggleFilterCategories(bpy.types.Operator):
return {"FINISHED"}
class LinkIfc(bpy.types.Operator):
class LinkIfc(bpy.types.Operator, ImportHelper):
bl_idname = "bim.link_ifc"
bl_label = "Link IFC"
bl_options = {"REGISTER", "UNDO"}
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)
directory: bpy.props.StringProperty(subtype="DIR_PATH")
filter_glob: bpy.props.StringProperty(default="*.ifc", options={"HIDDEN"})
@@ -1190,6 +1186,7 @@ class LinkIfc(bpy.types.Operator):
default=False,
)
use_cache: bpy.props.BoolProperty(name="Use Cache", default=True)
filename_ext = ".ifc"
if TYPE_CHECKING:
filepath: str
@@ -1235,10 +1232,6 @@ class LinkIfc(bpy.types.Operator):
print(f"Finished linking {len(files)} IFCs", time.time() - start)
return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class UnlinkIfc(bpy.types.Operator):
bl_idname = "bim.unlink_ifc"
@@ -1544,7 +1537,7 @@ class SelectLinkHandle(bpy.types.Operator):
return {"FINISHED"}
class ExportIFC(bpy.types.Operator):
class ExportIFC(bpy.types.Operator, ExportHelper):
bl_idname = "bim.save_project"
bl_label = "Save IFC"
# Prevents crash on Blender 4.4.0.
@@ -1552,7 +1545,6 @@ class ExportIFC(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"}
filename_ext = ".ifc"
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_compact: bpy.props.BoolProperty(name="Export Compact IFCJSON", default=False)
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:
self.filepath = str(tool.Blender.ensure_blender_path_is_abs(Path(filepath)))
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
WindowManager.fileselect_add(self)
return {"RUNNING_MODAL"}
return ExportHelper.invoke(self, context, event)
def execute(self, context):
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"
class LoadLinkedProject(bpy.types.Operator):
class LoadLinkedProject(bpy.types.Operator, ImportHelper):
bl_idname = "bim.load_linked_project"
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_options = {"REGISTER", "UNDO"}
filepath: bpy.props.StringProperty()
file: ifcopenshell.file
meshes: dict[str, bpy.types.Mesh]
@@ -1682,9 +1666,7 @@ class LoadLinkedProject(bpy.types.Operator):
def invoke(self, context, event):
# Invoke is for debugging purposes, users are not intended to use this method really.
WindowManager = context.window_manager
WindowManager.fileselect_add(self)
return {"RUNNING_MODAL"}
return ImportHelper.invoke(self, context, event)
def execute(self, context):
import ifcpatch
@@ -32,7 +32,7 @@ import ifcopenshell.util.sequence
import ifcopenshell.util.selector
from datetime import datetime
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_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))
class ExportMSP(bpy.types.Operator, ImportHelper):
class ExportMSP(bpy.types.Operator, ExportHelper):
bl_idname = "bim.export_msp"
bl_label = "Export MSP"
bl_options = {"REGISTER", "UNDO"}
@@ -827,7 +827,7 @@ class ExportMSP(bpy.types.Operator, ImportHelper):
return {"FINISHED"}
class ExportP6(bpy.types.Operator, ImportHelper):
class ExportP6(bpy.types.Operator, ExportHelper):
bl_idname = "bim.export_p6"
bl_label = "Export P6"
bl_options = {"REGISTER", "UNDO"}
+4 -15
View File
@@ -25,6 +25,7 @@ import ifcopenshell.api
import ifcopenshell.api.style
import ifcopenshell.util.representation
import ifcopenshell.util.unit
from bpy_extras.io_utils import ImportHelper
from pathlib import Path
from mathutils import Vector
from typing import Any, Union
@@ -273,16 +274,12 @@ class SetAssetMaterialToExternalStyle(bpy.types.Operator):
return {"FINISHED"}
class BrowseExternalStyle(bpy.types.Operator):
class BrowseExternalStyle(bpy.types.Operator, ImportHelper):
bl_idname = "bim.browse_external_style"
bl_label = "Browse External Style"
bl_description = "Select filepath for an external style."
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(
default="*.blend",
options={"HIDDEN"},
@@ -357,8 +354,7 @@ class BrowseExternalStyle(bpy.types.Operator):
if data_block in data_blocks:
self.data_block = data_block
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
return ImportHelper.invoke(self, context, event)
def draw(self, context):
layout = self.layout
@@ -538,7 +534,7 @@ class SelectByStyle(bpy.types.Operator):
return {"FINISHED"}
class ChooseTextureMapPath(bpy.types.Operator):
class ChooseTextureMapPath(bpy.types.Operator, ImportHelper):
bl_idname = "bim.choose_texture_map_path"
bl_label = "Choose Texture Map Path"
bl_description = "Select filepath for a texture map."
@@ -548,9 +544,6 @@ class ChooseTextureMapPath(bpy.types.Operator):
use_relative_path: bpy.props.BoolProperty(
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_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="to use relative paths.")
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
def execute(self, context):
if self.texture_map_index < 0:
self.report({"ERROR"}, "Provide a texture map index")
@@ -28,6 +28,7 @@ import ifctester.reporter
import ifcopenshell
import bonsai.tool as tool
import bonsai.bim.handler
from bpy_extras.io_utils import ExportHelper
from pathlib import Path
from typing import Union
@@ -186,13 +187,13 @@ class SelectFailedEntities(bpy.types.Operator):
return {"FINISHED"}
class ExportBcf(bpy.types.Operator):
class ExportBcf(bpy.types.Operator, ExportHelper):
bl_idname = "bim.export_bcf"
bl_label = "Export BCF"
bl_description = "Save ifctester BCF report by the provided filepath."
bl_options = {"REGISTER", "UNDO"}
filter_glob: bpy.props.StringProperty(default="*.bcf", options={"HIDDEN"})
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
filename_ext = ".bcf"
def execute(self, context):
bcf_reporter = ifctester.reporter.Bcf(tool.Tester.specs)
@@ -200,7 +201,3 @@ class ExportBcf(bpy.types.Operator):
bcf_reporter.to_file(self.filepath)
self.report({"INFO"}, "Finished exporting!")
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.tool as tool
import bonsai.bim.handler
from bpy_extras.io_utils import ImportHelper
from bonsai.bim import import_ifc
from bonsai.bim.prop import StrProperty
from bonsai.bim.ui import IFCFileSelector
@@ -145,12 +146,11 @@ class CloseBlendWarning(bpy.types.Operator):
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_label = "Select URI Attribute"
bl_options = {"REGISTER", "UNDO"}
bl_description = "Select a local file"
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
data_path: bpy.props.StringProperty(name="Data Path")
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)
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):
class BIM_OT_multiple_file_selector(bpy.types.Operator, ImportHelper):
"""Open Blender's file explorer to select one or multiple files."""
bl_idname = "bim.multiple_file_selector"
bl_label = "Select File(s)"
bl_options = {"REGISTER", "UNDO"}
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
files: bpy.props.CollectionProperty(name="File Path", type=bpy.types.OperatorFileListElement)
filter_glob: bpy.props.StringProperty(default="*", options={"HIDDEN"})
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):
self.file_props = context.file_props
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
return ImportHelper.invoke(self, context, event)
class SelectIfcFile(bpy.types.Operator, IFCFileSelector):
class SelectIfcFile(bpy.types.Operator, IFCFileSelector, ImportHelper):
bl_idname = "bim.select_ifc_file"
bl_label = "Select IFC File"
bl_options = {"REGISTER", "UNDO"}
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"})
use_relative_path: bpy.props.BoolProperty(name="Use Relative Path", default=False)
filename_ext = ".ifc"
def execute(self, context):
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)
if res is not None:
return res
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
return ImportHelper.invoke(self, context, event)
class SelectDir(bpy.types.Operator):
class SelectDir(bpy.types.Operator, ImportHelper):
bl_idname = "bim.select_dir"
bl_label = "Select Directory"
bl_options = {"REGISTER", "UNDO"}
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")
def execute(self, context):
@@ -262,8 +253,7 @@ class SelectDir(bpy.types.Operator):
return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
return ImportHelper.invoke(self, context, event)
class FileAssociate(bpy.types.Operator):
@@ -768,13 +758,13 @@ class BIM_OT_remove_section_plane(bpy.types.Operator):
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_label = "Reload IFC File"
bl_options = {"REGISTER", "UNDO"}
bl_description = "Reload an updated IFC file"
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
filter_glob: bpy.props.StringProperty(default="*.ifc", options={"HIDDEN"})
filename_ext = ".ifc"
def _execute(self, context):
import ifcdiff
@@ -842,10 +832,6 @@ class ReloadIfcFile(bpy.types.Operator, tool.Ifc.Operator):
bim_props.ifc_file = self.filepath
return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class AddIfcFile(bpy.types.Operator):
bl_idname = "bim.add_ifc_file"
+3 -6
View File
@@ -32,6 +32,7 @@ import importlib
import logging
import types
import bpy
from bpy_extras.io_utils import ExportHelper
logger = logging.getLogger("sverchok.ifc")
@@ -180,15 +181,15 @@ class IFC_Sv_UpdateCurrent(bpy.types.Operator):
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_label = "Write File"
bl_options = {"REGISTER", "UNDO"}
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"})
node_group: bpy.props.StringProperty(default="")
force_mode: bpy.props.BoolProperty(default=False)
filename_ext = ".ifc"
@classmethod
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}")
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):
bl_idname = "IFC_PT_write_file_panel"