New feature to copy properties from one object to all selected objects

This commit is contained in:
Dion Moult
2021-10-25 14:21:11 +11:00
parent e70f675f20
commit 2e6a70b338
17 changed files with 213 additions and 42 deletions
+1 -1
View File
@@ -46,7 +46,7 @@ def draw_attribute(attribute, layout, copy_operator=None):
layout.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="")
if copy_operator:
op = layout.operator(f"{copy_operator}", text="", icon="COPYDOWN")
op.attribute_name = attribute.name
op.name = attribute.name
def import_attributes(ifc_class, props, data, callback=None):
@@ -139,9 +139,9 @@ class GenerateGlobalId(bpy.types.Operator):
class CopyAttributeToSelection(bpy.types.Operator, Operator):
bl_idname = "bim.copy_attribute_to_selection"
bl_label = "Copy Attribute To Selection"
attribute_name: bpy.props.StringProperty()
name: bpy.props.StringProperty()
def _execute(self, context):
value = context.active_object.BIMAttributeProperties.attributes.get(self.attribute_name).get_value()
value = context.active_object.BIMAttributeProperties.attributes.get(self.name).get_value()
for obj in context.selected_objects:
core.copy_attribute_to_selection(tool.Ifc, name=self.attribute_name, value=value, obj=obj)
core.copy_attribute_to_selection(tool.Ifc, name=self.name, value=value, obj=obj)
@@ -20,14 +20,15 @@ import bpy
from . import ui, prop, operator
classes = (
operator.TogglePsetExpansion,
operator.EnablePsetEditing,
operator.DisablePsetEditing,
operator.EditPset,
operator.RemovePset,
operator.AddPset,
operator.AddQto,
operator.CopyPropertyToSelection,
operator.DisablePsetEditing,
operator.EditPset,
operator.EnablePsetEditing,
operator.GuessQuantity,
operator.RemovePset,
operator.TogglePsetExpansion,
prop.PsetProperties,
prop.MaterialPsetProperties,
prop.TaskPsetProperties,
@@ -24,12 +24,20 @@ import ifcopenshell.util.pset
import ifcopenshell.util.attribute
import blenderbim.bim.schema
import blenderbim.tool as tool
import blenderbim.core.pset as core
from blenderbim.bim.ifc import IfcStore
from ifcopenshell.api.pset.data import Data
from ifcopenshell.api.cost.data import Data as CostData
from blenderbim.bim.module.pset.qto_calculator import QtoCalculator
class Operator:
def execute(self, context):
IfcStore.execute_ifc_operator(self, context)
blenderbim.bim.handler.refresh_ui_data()
return {"FINISHED"}
def get_pset_props(context, obj, obj_type):
if obj_type == "Object":
obj = bpy.data.objects.get(obj)
@@ -361,3 +369,17 @@ class GuessQuantity(bpy.types.Operator):
if unit_settings.length_unit == "METERS":
return None, "METRE"
return unit_settings.length_unit[0 : -len("METERS")], "METRE"
class CopyPropertyToSelection(bpy.types.Operator, Operator):
bl_idname = "bim.copy_property_to_selection"
bl_label = "Copy Property To Selection"
name: bpy.props.StringProperty()
def _execute(self, context):
pset_name = context.active_object.PsetProperties.active_pset_name
prop_value = context.active_object.PsetProperties.properties.get(self.name).get_value()
for obj in context.selected_objects:
core.copy_property_to_selection(
tool.Ifc, tool.Pset, obj=obj, pset_name=pset_name, prop_name=self.name, prop_value=prop_value
)
@@ -50,6 +50,8 @@ def getPsetNames(self, context):
obj = context.active_object
if not obj.BIMObjectProperties.ifc_definition_id:
return []
if obj.BIMObjectProperties.ifc_definition_id not in Data.products:
Data.load(IfcStore.get_file(), obj.BIMObjectProperties.ifc_definition_id)
element = IfcStore.get_file().by_id(obj.BIMObjectProperties.ifc_definition_id)
ifc_class = element.is_a()
if ifc_class not in psetnames:
@@ -87,7 +87,7 @@ def draw_psetqto_ui(context, pset_id, pset, props, layout, obj_type):
def draw_psetqto_editable_ui(box, props, prop):
row = box.row(align=True)
draw_attribute(prop, row)
draw_attribute(prop, row, copy_operator="bim.copy_property_to_selection")
if (
"length" in prop.name.lower()
or "width" in prop.name.lower()
-31
View File
@@ -425,37 +425,6 @@ class FetchObjectPassport(bpy.types.Operator):
context.active_object.data = bpy.data.meshes[reference.name]
class CopyPropertyToSelection(bpy.types.Operator):
bl_idname = "bim.copy_property_to_selection"
bl_label = "Copy Property To Selection"
pset_name: bpy.props.StringProperty()
prop_name: bpy.props.StringProperty()
prop_value: bpy.props.StringProperty()
def execute(self, context):
# TODO: this is dead code, awaiting reimplementation. See #1222.
for obj in context.selected_objects:
if "/" not in obj.name:
continue
pset = obj.BIMObjectProperties.psets.get(self.pset_name)
if not pset:
applicable_psets = schema.ifc.psetqto.get_applicable(obj.name.split("/")[0], pset_only=True)
for pset_template in applicable_psets:
if pset_template.Name == self.pset_name:
break
else:
continue
pset = obj.BIMObjectProperties.psets.add()
pset.name = self.pset_name
for template_prop_name in (p.Name for p in pset_template.HasPropertyTemplates):
prop = pset.properties.add()
prop.name = template_prop_name
prop = pset.properties.get(self.prop_name)
if prop:
prop.string_value = self.prop_value
return {"FINISHED"}
class ConfigureVisibility(bpy.types.Operator):
bl_idname = "bim.configure_visibility"
bl_label = "Configure module UI visibility in BlenderBIM"
+27
View File
@@ -0,0 +1,27 @@
# BlenderBIM Add-on - OpenBIM Blender Add-on
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
#
# This file is part of BlenderBIM Add-on.
#
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# BlenderBIM Add-on is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
def copy_property_to_selection(ifc, pset, obj=None, pset_name=None, prop_name=None, prop_value=None):
element = ifc.get_entity(obj)
if not element:
return
ifc_pset = pset.get_element_pset(element, pset_name)
if not ifc_pset:
ifc_pset = ifc.run("pset.add_pset", product=element, name=pset_name)
ifc.run("pset.edit_pset", pset=ifc_pset, properties={prop_name: prop_value})
+5
View File
@@ -139,6 +139,11 @@ class Owner:
def set_user(cls, user): pass
@interface
class Pset:
def get_element_pset(cls, element, pset_name): pass
@interface
class Qto:
def get_radius_of_selected_vertices(cls, obj): pass
@@ -25,6 +25,7 @@ from blenderbim.tool.ifc import Ifc
from blenderbim.tool.material import Material
from blenderbim.tool.misc import Misc
from blenderbim.tool.owner import Owner
from blenderbim.tool.pset import Pset
from blenderbim.tool.qto import Qto
from blenderbim.tool.root import Root
from blenderbim.tool.spatial import Spatial
+31
View File
@@ -0,0 +1,31 @@
# BlenderBIM Add-on - OpenBIM Blender Add-on
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
#
# This file is part of BlenderBIM Add-on.
#
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# BlenderBIM Add-on is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import bpy
import ifcopenshell
import blenderbim.core.tool
import blenderbim.tool as tool
class Pset(blenderbim.core.tool.Pset):
@classmethod
def get_element_pset(cls, element, pset_name):
psets = ifcopenshell.util.element.get_psets(element)
pset = psets.get(pset_name, None)
if pset:
return tool.Ifc.get().by_id(pset["id"])
+1
View File
@@ -11,6 +11,7 @@ markers =
owner
patch
project
pset
pset_template
qto
root
@@ -15,5 +15,5 @@ Scenario: Copy attribute to selected
And additionally the object "IfcWall/Cube.001" is selected
And I press "bim.enable_editing_attributes(obj='IfcWall/Cube.001', obj_type='Object')"
And I set "active_object.BIMAttributeProperties.attributes[2].string_value" to "Foo"
When I press "bim.copy_attribute_to_selection(attribute_name='Description')"
When I press "bim.copy_attribute_to_selection(name='Description')"
Then nothing happens
@@ -0,0 +1,22 @@
@pset
Feature: Pset
Scenario: Copy property to selected
Given an empty IFC project
And I add a cube
And the object "Cube" is selected
And I set "scene.BIMRootProperties.ifc_class" to "IfcWall"
And I press "bim.assign_class"
And I add a cube
And the object "Cube" is selected
And I set "scene.BIMRootProperties.ifc_class" to "IfcWall"
And I press "bim.assign_class"
And the object "IfcWall/Cube" is selected
And additionally the object "IfcWall/Cube.001" is selected
And I set "active_object.PsetProperties.pset_name" to "Pset_BuildingElementCommon"
And I press "bim.add_pset(obj='IfcWall/Cube.001', obj_type='Object')"
And the variable "pset" is "{ifc}.by_type('IfcPropertySet')[-1].id()"
And I press "bim.enable_pset_editing(obj='IfcWall/Cube.001', obj_type='Object', pset_id={pset})"
And I set "active_object.PsetProperties.properties[2].string_value" to "Foo"
When I press "bim.copy_property_to_selection(name='FireRating')"
Then nothing happens
+7
View File
@@ -84,6 +84,13 @@ def owner():
prophet.verify()
@pytest.fixture
def pset():
prophet = Prophecy(blenderbim.core.tool.Pset)
yield prophet
prophet.verify()
@pytest.fixture
def qto():
prophet = Prophecy(blenderbim.core.tool.Qto)
+45
View File
@@ -0,0 +1,45 @@
# BlenderBIM Add-on - OpenBIM Blender Add-on
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
#
# This file is part of BlenderBIM Add-on.
#
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# BlenderBIM Add-on is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import blenderbim.core.pset as subject
from test.core.bootstrap import ifc, pset
class TestCopyPropertyToSelection:
def test_doing_nothing_if_object_is_not_an_element(self, ifc, pset):
ifc.get_entity("obj").should_be_called().will_return(None)
subject.copy_property_to_selection(
ifc, pset, obj="obj", pset_name="pset_name", prop_name="prop_name", prop_value="prop_value"
)
def test_copying_the_property_to_an_existing_pset(self, ifc, pset):
ifc.get_entity("obj").should_be_called().will_return("element")
pset.get_element_pset("element", "pset_name").should_be_called().will_return("pset")
ifc.run("pset.edit_pset", pset="pset", properties={"prop_name": "prop_value"}).should_be_called()
subject.copy_property_to_selection(
ifc, pset, obj="obj", pset_name="pset_name", prop_name="prop_name", prop_value="prop_value"
)
def test_creating_a_new_pset_if_it_doesnt_exist(self, ifc, pset):
ifc.get_entity("obj").should_be_called().will_return("element")
pset.get_element_pset("element", "pset_name").should_be_called().will_return(None)
ifc.run("pset.add_pset", product="element", name="pset_name").should_be_called().will_return("pset")
ifc.run("pset.edit_pset", pset="pset", properties={"prop_name": "prop_value"}).should_be_called()
subject.copy_property_to_selection(
ifc, pset, obj="obj", pset_name="pset_name", prop_name="prop_name", prop_value="prop_value"
)
+38
View File
@@ -0,0 +1,38 @@
# BlenderBIM Add-on - OpenBIM Blender Add-on
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
#
# This file is part of BlenderBIM Add-on.
#
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# BlenderBIM Add-on is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import bpy
import ifcopenshell
import blenderbim.core.tool
import blenderbim.tool as tool
from blenderbim.tool.pset import Pset as subject
from test.bim.bootstrap import NewFile
class TestImplementsTool(NewFile):
def test_run(self):
assert isinstance(subject(), blenderbim.core.tool.Pset)
class TestGetElementPset(NewFile):
def test_run(self):
ifc = ifcopenshell.file()
tool.Ifc.set(ifc)
element = ifc.createIfcWall()
pset = ifcopenshell.api.run("pset.add_pset", ifc, product=element, name="Foo")
assert subject.get_element_pset(element, "Foo") == pset