mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 17:31:45 +00:00
refactor: Create property group MultipleFileSelect
To easier create and display properties that allow one or more files as input, a `MultipleFileSelect` property group has been extracted, together with an operator for selecting the files and the code for displaying the property.
This commit is contained in:
committed by
Dion Moult
parent
98edb5a34c
commit
95a7ea8dce
@@ -101,6 +101,7 @@ classes = [
|
||||
operator.BIM_OT_remove_section_plane,
|
||||
operator.BIM_OT_select_object,
|
||||
operator.BIM_OT_show_description,
|
||||
operator.BIM_OT_multiple_file_selector,
|
||||
operator.ClippingPlaneCutWithCappings,
|
||||
operator.CloseError,
|
||||
operator.EditBlenderCollection,
|
||||
@@ -132,6 +133,7 @@ classes = [
|
||||
prop.BIMMeshProperties,
|
||||
prop.BIMFacet,
|
||||
prop.BIMFilterGroup,
|
||||
prop.MultipleFileSelect,
|
||||
ui.BIM_UL_clipping_plane,
|
||||
ui.BIM_UL_generic,
|
||||
ui.BIM_UL_topics,
|
||||
|
||||
@@ -22,7 +22,6 @@ from . import ui, prop, operator
|
||||
classes = (
|
||||
operator.ExecuteIfcFM,
|
||||
operator.ExecuteIfcFMFederate,
|
||||
operator.SelectFMIfcFile,
|
||||
operator.SelectFMSpreadsheetFiles,
|
||||
prop.BIMFMProperties,
|
||||
ui.BIM_PT_fm,
|
||||
|
||||
@@ -24,20 +24,6 @@ import logging
|
||||
import tempfile
|
||||
import ifcopenshell
|
||||
import blenderbim.tool as tool
|
||||
from blenderbim.bim.operator import MultipleFileSelector
|
||||
|
||||
|
||||
class SelectFMIfcFile(MultipleFileSelector):
|
||||
bl_idname = "bim.select_fm_ifc_file"
|
||||
bl_label = "Select FM IFC File"
|
||||
filename_ext = ".ifc"
|
||||
filter_glob: bpy.props.StringProperty(default="*.ifc;*.ifczip;*.ifcxml", options={"HIDDEN"})
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMFMProperties
|
||||
|
||||
self.update_props(props, "ifc_file", props.ifc_files)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class ExecuteIfcFM(bpy.types.Operator):
|
||||
@@ -50,7 +36,7 @@ class ExecuteIfcFM(bpy.types.Operator):
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
props = context.scene.BIMFMProperties
|
||||
return props.should_load_from_memory or props.ifc_file
|
||||
return props.should_load_from_memory or props.ifc_files.single_file
|
||||
|
||||
def invoke(self, context, event):
|
||||
props = context.scene.BIMFMProperties
|
||||
@@ -63,14 +49,13 @@ class ExecuteIfcFM(bpy.types.Operator):
|
||||
props = context.scene.BIMFMProperties
|
||||
ifc_file = tool.Ifc.get()
|
||||
filepaths = []
|
||||
if not (ifc_file and props.should_load_from_memory):
|
||||
if len(props.ifc_files):
|
||||
ifc_files = [ifcopenshell.open(f.name) for f in props.ifc_files]
|
||||
filepaths = [f.name for f in props.ifc_files]
|
||||
else:
|
||||
ifc_files = [ifcopenshell.open(props.ifc_file)]
|
||||
else:
|
||||
if ifc_file and props.should_load_from_memory:
|
||||
ifc_files = [ifc_file]
|
||||
else:
|
||||
ifc_files = [ifcopenshell.open(f.name) for f in props.ifc_files.file_list]
|
||||
|
||||
if len(ifc_files) > 1:
|
||||
filepaths = [f.name for f in props.ifc_files.file_list]
|
||||
|
||||
for i, ifc_file in enumerate(ifc_files):
|
||||
if filepaths:
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
import bpy
|
||||
from blenderbim.bim.module.fm.data import FMData
|
||||
from blenderbim.bim.prop import StrProperty
|
||||
from blenderbim.bim.prop import MultipleFileSelect, StrProperty
|
||||
from bpy.types import PropertyGroup
|
||||
from bpy.props import (
|
||||
PointerProperty,
|
||||
@@ -39,8 +39,7 @@ def get_engine(self, context):
|
||||
|
||||
|
||||
class BIMFMProperties(PropertyGroup):
|
||||
ifc_file: StringProperty(default="", name="IFC File")
|
||||
ifc_files: CollectionProperty(name="IFC Files", type=StrProperty)
|
||||
ifc_files: PointerProperty(type=MultipleFileSelect)
|
||||
spreadsheet_files: CollectionProperty(name="Spreadsheets", type=StrProperty)
|
||||
should_load_from_memory: BoolProperty(default=False, name="Load from Memory")
|
||||
engine: EnumProperty(items=get_engine, name="Engine")
|
||||
|
||||
@@ -45,12 +45,8 @@ class BIM_PT_fm(Panel):
|
||||
row.prop(props, "should_load_from_memory")
|
||||
|
||||
if not IfcStore.get_file() or not props.should_load_from_memory:
|
||||
row = layout.row(align=True)
|
||||
if len(props.ifc_files) > 1:
|
||||
row.label(text=f"{len(props.ifc_files)} Files Selected")
|
||||
else:
|
||||
row.prop(props, "ifc_file")
|
||||
row.operator("bim.select_fm_ifc_file", icon="FILE_FOLDER", text="")
|
||||
row = layout.row()
|
||||
props.ifc_files.layout_file_select(row, "*.ifc;*.ifczip;*.ifcxml", "IFC File(s)")
|
||||
|
||||
row = layout.row()
|
||||
row.prop(props, "engine")
|
||||
|
||||
@@ -48,7 +48,6 @@ class BIM_PT_radiance_exporter(bpy.types.Panel):
|
||||
if not tool.Ifc.get() or not props.should_load_from_memory:
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(props, "ifc_file")
|
||||
# row.operator("bim.select_ifctester_ifc_file", icon="FILE_FOLDER", text="")
|
||||
|
||||
row = layout.row()
|
||||
row.prop(props, "output_dir")
|
||||
|
||||
@@ -21,8 +21,6 @@ from . import ui, prop, operator
|
||||
|
||||
classes = (
|
||||
operator.ExecuteIfcTester,
|
||||
operator.SelectSpecs,
|
||||
operator.SelectIfcTesterIfcFile,
|
||||
operator.SelectRequirement,
|
||||
operator.SelectFailedEntities,
|
||||
operator.SelectEntity,
|
||||
|
||||
@@ -27,7 +27,6 @@ import ifctester.reporter
|
||||
import ifcopenshell
|
||||
import blenderbim.tool as tool
|
||||
import blenderbim.bim.handler
|
||||
from blenderbim.bim.operator import MultipleFileSelector
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
@@ -38,7 +37,7 @@ class ExecuteIfcTester(bpy.types.Operator, tool.Ifc.Operator):
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
props = context.scene.IfcTesterProperties
|
||||
return (props.ifc_file or props.should_load_from_memory) and props.specs
|
||||
return (props.ifc_files.single_file or props.should_load_from_memory) and props.specs
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.IfcTesterProperties
|
||||
@@ -49,13 +48,13 @@ class ExecuteIfcTester(bpy.types.Operator, tool.Ifc.Operator):
|
||||
ifc_data = tool.Ifc.get()
|
||||
ifc_path = tool.Ifc.get_path()
|
||||
|
||||
for f in props.specs_files:
|
||||
for f in props.specs.file_list:
|
||||
self.execute_tester(ifc_data, ifc_path, f.name)
|
||||
else:
|
||||
for ifc_file in props.ifc_files:
|
||||
for ifc_file in props.ifc_files.file_list:
|
||||
ifc_data = ifcopenshell.open(ifc_file.name)
|
||||
|
||||
for f in props.specs_files:
|
||||
for f in props.specs.file_list:
|
||||
self.execute_tester(ifc_data, ifc_file.name, f.name)
|
||||
|
||||
blenderbim.bim.handler.refresh_ui_data()
|
||||
@@ -103,33 +102,6 @@ class ExecuteIfcTester(bpy.types.Operator, tool.Ifc.Operator):
|
||||
new_spec.status = spec["status"]
|
||||
|
||||
|
||||
class SelectSpecs(MultipleFileSelector):
|
||||
bl_idname = "bim.select_specs"
|
||||
bl_label = "Select IDS"
|
||||
filename_ext = ".ids"
|
||||
filter_glob: bpy.props.StringProperty(default="*.ids;*.xml", options={"HIDDEN"})
|
||||
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.IfcTesterProperties
|
||||
|
||||
self.update_props(props, "specs", props.specs_files)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class SelectIfcTesterIfcFile(MultipleFileSelector):
|
||||
bl_idname = "bim.select_ifctester_ifc_file"
|
||||
bl_label = "Select IfcTester IFC File"
|
||||
filename_ext = ".ifc"
|
||||
filter_glob: bpy.props.StringProperty(default="*.ifc;*.ifczip;*.ifcxml", options={"HIDDEN"})
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.IfcTesterProperties
|
||||
|
||||
self.update_props(props, "ifc_file", props.ifc_files)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class SelectRequirement(bpy.types.Operator):
|
||||
bl_idname = "bim.select_requirement"
|
||||
bl_label = "Select Specification"
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from blenderbim.bim.module.tester.data import TesterData
|
||||
from blenderbim.bim.prop import StrProperty
|
||||
from blenderbim.bim.prop import StrProperty, MultipleFileSelect
|
||||
from bpy.types import PropertyGroup
|
||||
from bpy.props import (
|
||||
PointerProperty,
|
||||
@@ -48,10 +48,8 @@ class FailedEntities(PropertyGroup):
|
||||
|
||||
|
||||
class IfcTesterProperties(PropertyGroup):
|
||||
specs: StringProperty(default="", name="IDS File(s)")
|
||||
specs_files: CollectionProperty(name="IDS Files", type=StrProperty)
|
||||
ifc_file: StringProperty(default="", name="IFC File(s)")
|
||||
ifc_files: CollectionProperty(name="IFC Files", type=StrProperty)
|
||||
specs: PointerProperty(type=MultipleFileSelect)
|
||||
ifc_files: PointerProperty(type=MultipleFileSelect)
|
||||
should_load_from_memory: BoolProperty(default=False, name="Load from Memory", options=set())
|
||||
generate_html_report: BoolProperty(default=False, name="Generate HTML report", options=set())
|
||||
generate_ods_report: BoolProperty(default=False, name="Generate ODS report", options=set())
|
||||
|
||||
@@ -50,19 +50,10 @@ class BIM_PT_tester(Panel):
|
||||
|
||||
if not tool.Ifc.get() or not props.should_load_from_memory:
|
||||
row = self.layout.row(align=True)
|
||||
if len(props.ifc_files) > 1:
|
||||
row.label(text=f"{len(props.ifc_files)} Files Selected")
|
||||
else:
|
||||
row.prop(props, "ifc_file")
|
||||
|
||||
row.operator("bim.select_ifctester_ifc_file", icon="FILE_FOLDER", text="")
|
||||
props.ifc_files.layout_file_select(row, "*.ifc;*.ifczip;*.ifcxml", "IFC File(s)")
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
if len(props.specs_files) > 1:
|
||||
row.label(text=f"{len(props.specs_files)} Files Selected")
|
||||
else:
|
||||
row.prop(props, "specs")
|
||||
row.operator("bim.select_specs", icon="FILE_FOLDER", text="")
|
||||
props.specs.layout_file_select(row, "*.ids;*.xml", "IDS File(s)")
|
||||
|
||||
row = self.layout.row()
|
||||
row.operator("bim.execute_ifc_tester")
|
||||
|
||||
@@ -143,22 +143,30 @@ class SelectURIAttribute(bpy.types.Operator):
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
|
||||
class MultipleFileSelector(bpy.types.Operator):
|
||||
class BIM_OT_multiple_file_selector(bpy.types.Operator):
|
||||
"""Open Blender's file explorer to select one or multiple files."""
|
||||
|
||||
bl_idname = "bim.multiple_file_selector"
|
||||
bl_label = "Select Multiple Files"
|
||||
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")
|
||||
|
||||
def update_props(self, props, single_file: str, file_list: bpy.types.CollectionProperty):
|
||||
@classmethod
|
||||
def poll(self, context):
|
||||
return getattr(context, "file_props", None) is not None
|
||||
|
||||
def execute(self, context):
|
||||
dirname = os.path.dirname(self.filepath)
|
||||
file_list.clear()
|
||||
self.file_props.single_file = self.filepath
|
||||
self.file_props.set_file_list(dirname, [f.name for f in self.files])
|
||||
|
||||
for f in self.files:
|
||||
new = file_list.add()
|
||||
new.name = os.path.join(dirname, f.name)
|
||||
setattr(props, single_file, self.filepath)
|
||||
return {"FINISHED"}
|
||||
|
||||
def invoke(self, context, event):
|
||||
self.file_props = context.file_props
|
||||
context.window_manager.fileselect_add(self)
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
@@ -458,7 +466,8 @@ class BIM_OT_add_section_plane(bpy.types.Operator):
|
||||
group.interface.new_socket(name="Line Decorator", in_out="OUTPUT", socket_type="NodeSocketFloat")
|
||||
else:
|
||||
group.inputs.new("NodeSocketFloat", "Value")
|
||||
group.inputs["Value"].default_value = 1.0 # Mandatory multiplier for the last node group
|
||||
# Mandatory multiplier for the last node group
|
||||
group.inputs["Value"].default_value = 1.0
|
||||
group.inputs.new("NodeSocketVector", "Vector")
|
||||
group.inputs.new("NodeSocketFloat", "Line Decorator")
|
||||
group.outputs.new("NodeSocketFloat", "Value")
|
||||
@@ -526,12 +535,14 @@ class BIM_OT_add_section_plane(bpy.types.Operator):
|
||||
|
||||
mix_decorator = group.nodes.new(type="ShaderNodeMixShader")
|
||||
mix_decorator.name = "Line Decorator Mix"
|
||||
mix_decorator.inputs[0].default_value = 0 # Directly pass input shader when there is no cutaway
|
||||
# Directly pass input shader when there is no cutaway
|
||||
mix_decorator.inputs[0].default_value = 0
|
||||
mix_decorator.location = group_output.location - Vector((200, 0))
|
||||
|
||||
mix_section = group.nodes.new(type="ShaderNodeMixShader")
|
||||
mix_section.name = "Section Mix"
|
||||
mix_section.inputs[0].default_value = 1 # Directly pass input shader when there is no cutaway
|
||||
# Directly pass input shader when there is no cutaway
|
||||
mix_section.inputs[0].default_value = 1
|
||||
mix_section.location = mix_decorator.location - Vector((200, 200))
|
||||
|
||||
transparent = nodes.new(type="ShaderNodeBsdfTransparent")
|
||||
|
||||
@@ -478,3 +478,31 @@ class BIMFacet(PropertyGroup):
|
||||
|
||||
class BIMFilterGroup(PropertyGroup):
|
||||
filters: CollectionProperty(type=BIMFacet, name="filters")
|
||||
|
||||
|
||||
def update_single_file(self, context):
|
||||
self.file_list.clear()
|
||||
new = self.file_list.add()
|
||||
new.name = self.single_file
|
||||
|
||||
|
||||
class MultipleFileSelect(bpy.types.PropertyGroup):
|
||||
single_file: bpy.props.StringProperty(name="Single File Path", description="", update=update_single_file)
|
||||
file_list: bpy.props.CollectionProperty(type=StrProperty)
|
||||
|
||||
def set_file_list(self, dirname: str, files: list[str]):
|
||||
self.file_list.clear()
|
||||
|
||||
for f in files:
|
||||
new = self.file_list.add()
|
||||
new.name = os.path.join(dirname, f)
|
||||
|
||||
def layout_file_select(self, layout, filter_glob="", text=""):
|
||||
if len(self.file_list) > 1:
|
||||
layout.label(text=f"{len(self.file_list)} Files Selected")
|
||||
else:
|
||||
layout.prop(self, "single_file", text=text)
|
||||
|
||||
layout.context_pointer_set("file_props", self)
|
||||
op = layout.operator("bim.multiple_file_selector", icon="FILE_FOLDER", text="")
|
||||
op.filter_glob = filter_glob
|
||||
|
||||
Reference in New Issue
Block a user