mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-27 02:31:09 +00:00
#2094. Deleting materials now also deletes Blender material if not used for a style
This commit is contained in:
@@ -41,6 +41,7 @@ classes = (
|
|||||||
operator.RemoveLayer,
|
operator.RemoveLayer,
|
||||||
operator.RemoveListItem,
|
operator.RemoveListItem,
|
||||||
operator.RemoveMaterial,
|
operator.RemoveMaterial,
|
||||||
|
operator.RemoveMaterialSet,
|
||||||
operator.RemoveProfile,
|
operator.RemoveProfile,
|
||||||
operator.ReorderMaterialSetItem,
|
operator.ReorderMaterialSetItem,
|
||||||
operator.UnassignMaterial,
|
operator.UnassignMaterial,
|
||||||
|
|||||||
@@ -104,26 +104,26 @@ class AddMaterialSet(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
material_prop_purge()
|
material_prop_purge()
|
||||||
|
|
||||||
|
|
||||||
class RemoveMaterial(bpy.types.Operator):
|
class RemoveMaterial(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
bl_idname = "bim.remove_material"
|
bl_idname = "bim.remove_material"
|
||||||
bl_label = "Remove Material"
|
bl_label = "Remove Material"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
obj: bpy.props.StringProperty()
|
material: bpy.props.IntProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
|
||||||
return IfcStore.execute_ifc_operator(self, context)
|
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
obj = bpy.data.materials.get(self.obj) if self.obj else context.active_object.active_material
|
core.remove_material(tool.Ifc, tool.Material, tool.Style, material=tool.Ifc.get().by_id(self.material))
|
||||||
self.file = IfcStore.get_file()
|
Data.load(IfcStore.get_file())
|
||||||
result = ifcopenshell.api.run(
|
|
||||||
"material.remove_material",
|
|
||||||
self.file,
|
class RemoveMaterialSet(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
**{"material": self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)},
|
bl_idname = "bim.remove_material_set"
|
||||||
)
|
bl_label = "Remove Material Set"
|
||||||
obj.BIMObjectProperties.ifc_definition_id = 0
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
material: bpy.props.IntProperty()
|
||||||
|
|
||||||
|
def _execute(self, context):
|
||||||
|
core.remove_material_set(tool.Ifc, tool.Material, material=tool.Ifc.get().by_id(self.material))
|
||||||
Data.load(IfcStore.get_file())
|
Data.load(IfcStore.get_file())
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
|
|
||||||
class UnlinkMaterial(bpy.types.Operator, tool.Ifc.Operator):
|
class UnlinkMaterial(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
|
|||||||
@@ -59,8 +59,14 @@ class BIM_PT_materials(Panel):
|
|||||||
|
|
||||||
if self.props.material_type == "IfcMaterial":
|
if self.props.material_type == "IfcMaterial":
|
||||||
row.operator("bim.add_material", text="", icon="ADD")
|
row.operator("bim.add_material", text="", icon="ADD")
|
||||||
|
if self.props.materials and self.props.active_material_index < len(self.props.materials):
|
||||||
|
material = self.props.materials[self.props.active_material_index]
|
||||||
|
row.operator("bim.remove_material", text="", icon="X").material = material.ifc_definition_id
|
||||||
else:
|
else:
|
||||||
row.operator("bim.add_material_set", text="", icon="ADD").set_type = self.props.material_type
|
row.operator("bim.add_material_set", text="", icon="ADD").set_type = self.props.material_type
|
||||||
|
if self.props.materials and self.props.active_material_index < len(self.props.materials):
|
||||||
|
material = self.props.materials[self.props.active_material_index]
|
||||||
|
row.operator("bim.remove_material_set", text="", icon="X").material = material.ifc_definition_id
|
||||||
|
|
||||||
self.layout.template_list("BIM_UL_materials", "", self.props, "materials", self.props, "active_material_index")
|
self.layout.template_list("BIM_UL_materials", "", self.props, "materials", self.props, "active_material_index")
|
||||||
|
|
||||||
@@ -78,8 +84,9 @@ class BIM_PT_material(Panel):
|
|||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
if bool(context.active_object.active_material.BIMObjectProperties.ifc_definition_id):
|
material_id = context.active_object.active_material.BIMObjectProperties.ifc_definition_id
|
||||||
row.operator("bim.remove_material", icon="X", text="Remove IFC Material")
|
if bool(material_id):
|
||||||
|
row.operator("bim.remove_material", icon="X", text="Remove IFC Material").material = material_id
|
||||||
row.operator("bim.unlink_material", icon="UNLINKED", text="")
|
row.operator("bim.unlink_material", icon="UNLINKED", text="")
|
||||||
else:
|
else:
|
||||||
op = row.operator("bim.add_material", icon="ADD", text="Create IFC Material")
|
op = row.operator("bim.add_material", icon="ADD", text="Create IFC Material")
|
||||||
|
|||||||
@@ -43,6 +43,22 @@ def add_material_set(ifc, material, set_type=None):
|
|||||||
return ifc_material
|
return ifc_material
|
||||||
|
|
||||||
|
|
||||||
|
def remove_material(ifc, material_tool, style, material=None):
|
||||||
|
obj = ifc.get_object(material)
|
||||||
|
ifc.unlink(element=material)
|
||||||
|
ifc.run("material.remove_material", material=material)
|
||||||
|
if obj and not style.get_style(obj):
|
||||||
|
material_tool.delete_object(obj)
|
||||||
|
if material_tool.is_editing_materials():
|
||||||
|
material_tool.import_material_definitions(material_tool.get_active_material_type())
|
||||||
|
|
||||||
|
|
||||||
|
def remove_material_set(ifc, material_tool, material=None):
|
||||||
|
ifc.run("material.remove_material_set", material=material)
|
||||||
|
if material_tool.is_editing_materials():
|
||||||
|
material_tool.import_material_definitions(material_tool.get_active_material_type())
|
||||||
|
|
||||||
|
|
||||||
def load_materials(material, material_type):
|
def load_materials(material, material_type):
|
||||||
material.import_material_definitions(material_type)
|
material.import_material_definitions(material_type)
|
||||||
material.enable_editing_materials()
|
material.enable_editing_materials()
|
||||||
|
|||||||
@@ -276,6 +276,7 @@ class Library:
|
|||||||
@interface
|
@interface
|
||||||
class Material:
|
class Material:
|
||||||
def add_default_material_object(cls): pass
|
def add_default_material_object(cls): pass
|
||||||
|
def delete_object(cls, obj): pass
|
||||||
def disable_editing_materials(cls): pass
|
def disable_editing_materials(cls): pass
|
||||||
def enable_editing_materials(cls): pass
|
def enable_editing_materials(cls): pass
|
||||||
def get_active_material_type(cls): pass
|
def get_active_material_type(cls): pass
|
||||||
|
|||||||
@@ -28,6 +28,10 @@ class Material(blenderbim.core.tool.Material):
|
|||||||
def add_default_material_object(cls):
|
def add_default_material_object(cls):
|
||||||
return bpy.data.materials.new("Default")
|
return bpy.data.materials.new("Default")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def delete_object(cls, obj):
|
||||||
|
bpy.data.materials.remove(obj)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def disable_editing_materials(cls):
|
def disable_editing_materials(cls):
|
||||||
bpy.context.scene.BIMMaterialProperties.is_editing = False
|
bpy.context.scene.BIMMaterialProperties.is_editing = False
|
||||||
|
|||||||
@@ -46,8 +46,18 @@ Scenario: Remove material
|
|||||||
And the object "Cube" is selected
|
And the object "Cube" is selected
|
||||||
And I add a material
|
And I add a material
|
||||||
And I press "bim.add_material(obj='Material')"
|
And I press "bim.add_material(obj='Material')"
|
||||||
When I press "bim.remove_material"
|
And the variable "material" is "{ifc}.by_type('IfcMaterial')[0].id()"
|
||||||
Then the material "Material" is not an IFC material
|
When I press "bim.remove_material(material={material})"
|
||||||
|
Then the material "Material" does not exist
|
||||||
|
|
||||||
|
Scenario: Remove material set
|
||||||
|
Given an empty IFC project
|
||||||
|
And I set "scene.BIMMaterialProperties.material_type" to "IfcMaterialLayerSet"
|
||||||
|
And I press "bim.load_materials"
|
||||||
|
And I press "bim.add_material_set(set_type='IfcMaterialLayerSet')"
|
||||||
|
And the variable "material" is "{ifc}.by_type('IfcMaterialLayerSet')[0].id()"
|
||||||
|
When I press "bim.remove_material_set(material={material})"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
Scenario: Unlink material
|
Scenario: Unlink material
|
||||||
Given an empty IFC project
|
Given an empty IFC project
|
||||||
|
|||||||
@@ -297,6 +297,11 @@ def the_material_name_exists(name) -> bpy.types.Material:
|
|||||||
return obj
|
return obj
|
||||||
|
|
||||||
|
|
||||||
|
@then(parsers.parse('the material "{name}" does not exist'))
|
||||||
|
def the_material_name_does_not_exist(name):
|
||||||
|
assert bpy.data.materials.get(name) is None, "Material exists"
|
||||||
|
|
||||||
|
|
||||||
@then("an IFC file does not exist")
|
@then("an IFC file does not exist")
|
||||||
def an_ifc_file_does_not_exist():
|
def an_ifc_file_does_not_exist():
|
||||||
ifc = IfcStore.get_file()
|
ifc = IfcStore.get_file()
|
||||||
|
|||||||
@@ -92,6 +92,50 @@ class TestAddMaterialSet:
|
|||||||
assert subject.add_material_set(ifc, material, set_type="set_type") == "material"
|
assert subject.add_material_set(ifc, material, set_type="set_type") == "material"
|
||||||
|
|
||||||
|
|
||||||
|
class TestRemoveMaterial:
|
||||||
|
def test_removing_a_material(self, ifc, material, style):
|
||||||
|
ifc.get_object("material").should_be_called().will_return(None)
|
||||||
|
ifc.unlink(element="material").should_be_called()
|
||||||
|
ifc.run("material.remove_material", material="material").should_be_called()
|
||||||
|
material.is_editing_materials().should_be_called().will_return(False)
|
||||||
|
subject.remove_material(ifc, material, style, material="material")
|
||||||
|
|
||||||
|
def test_removing_a_material_and_reloading_imported_materials(self, ifc, material, style):
|
||||||
|
ifc.get_object("material").should_be_called().will_return(None)
|
||||||
|
ifc.unlink(element="material").should_be_called()
|
||||||
|
ifc.run("material.remove_material", material="material").should_be_called()
|
||||||
|
material.is_editing_materials().should_be_called().will_return(True)
|
||||||
|
material.get_active_material_type().should_be_called().will_return("material_type")
|
||||||
|
material.import_material_definitions("material_type").should_be_called()
|
||||||
|
subject.remove_material(ifc, material, style, material="material")
|
||||||
|
|
||||||
|
def test_removing_a_material_object_if_it_has_no_style(self, ifc, material, style):
|
||||||
|
ifc.get_object("material").should_be_called().will_return("obj")
|
||||||
|
ifc.unlink(element="material").should_be_called()
|
||||||
|
ifc.run("material.remove_material", material="material").should_be_called()
|
||||||
|
style.get_style("obj").should_be_called().will_return(None)
|
||||||
|
material.delete_object("obj").should_be_called()
|
||||||
|
material.is_editing_materials().should_be_called().will_return(False)
|
||||||
|
subject.remove_material(ifc, material, style, material="material")
|
||||||
|
|
||||||
|
def test_preserving_a_material_object_if_it_is_still_used_as_a_style(self, ifc, material, style):
|
||||||
|
ifc.get_object("material").should_be_called().will_return("obj")
|
||||||
|
ifc.unlink(element="material").should_be_called()
|
||||||
|
ifc.run("material.remove_material", material="material").should_be_called()
|
||||||
|
style.get_style("obj").should_be_called().will_return("style")
|
||||||
|
material.is_editing_materials().should_be_called().will_return(False)
|
||||||
|
subject.remove_material(ifc, material, style, material="material")
|
||||||
|
|
||||||
|
|
||||||
|
class TestRemoveMaterialSet:
|
||||||
|
def test_run(self, ifc, material):
|
||||||
|
ifc.run("material.remove_material_set", material="material").should_be_called()
|
||||||
|
material.is_editing_materials().should_be_called().will_return(True)
|
||||||
|
material.get_active_material_type().should_be_called().will_return("material_type")
|
||||||
|
material.import_material_definitions("material_type").should_be_called()
|
||||||
|
subject.remove_material_set(ifc, material, material="material")
|
||||||
|
|
||||||
|
|
||||||
class TestLoadMaterials:
|
class TestLoadMaterials:
|
||||||
def test_run(self, material):
|
def test_run(self, material):
|
||||||
material.import_material_definitions("material_type").should_be_called()
|
material.import_material_definitions("material_type").should_be_called()
|
||||||
|
|||||||
@@ -36,6 +36,14 @@ class TestAddDefaultMaterialObject(NewFile):
|
|||||||
assert material.name == "Default"
|
assert material.name == "Default"
|
||||||
|
|
||||||
|
|
||||||
|
class TestDeleteObject(NewFile):
|
||||||
|
def test_run(self):
|
||||||
|
material = subject.add_default_material_object()
|
||||||
|
assert bpy.data.materials.get("Default")
|
||||||
|
subject.delete_object(material)
|
||||||
|
assert not bpy.data.materials.get("Default")
|
||||||
|
|
||||||
|
|
||||||
class TestDisableEditingMaterials(NewFile):
|
class TestDisableEditingMaterials(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
bpy.context.scene.BIMMaterialProperties.is_editing = True
|
bpy.context.scene.BIMMaterialProperties.is_editing = True
|
||||||
|
|||||||
Reference in New Issue
Block a user