Fix #1855. Bug where authoring type dropdowns didn't refresh.

This commit is contained in:
Dion Moult
2021-11-08 21:12:27 +11:00
parent 7fbf317ad2
commit de7c54b771
10 changed files with 176 additions and 106 deletions
@@ -0,0 +1,59 @@
# 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 blenderbim.tool as tool
def refresh():
AuthoringData.is_loaded = False
WorkspaceData.is_loaded = False
class AuthoringData:
data = {}
is_loaded = False
@classmethod
def load(cls):
cls.data = {
"ifc_classes": cls.ifc_classes(),
"relating_types": cls.relating_types(),
}
cls.is_loaded = True
@classmethod
def ifc_classes(cls):
results = []
classes = set([e.is_a() for e in tool.Ifc.get().by_type("IfcElementType")])
results.extend([(c, c, "") for c in sorted(classes)])
return results
@classmethod
def relating_types(cls):
results = []
ifc_class = bpy.context.scene.BIMModelProperties.ifc_class
if ifc_class:
elements = [(str(e.id()), e.Name, "") for e in tool.Ifc.get().by_type(ifc_class)]
results.extend(sorted(elements, key=lambda s: s[1]))
return results
return []
class WorkspaceData(AuthoringData):
pass
@@ -63,9 +63,9 @@ class AddTypeInstance(bpy.types.Operator):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
tprops = context.scene.BIMTypeProperties
ifc_class = self.ifc_class or tprops.ifc_class
relating_type_id = self.relating_type or tprops.relating_type
props = context.scene.BIMModelProperties
ifc_class = self.ifc_class or props.ifc_class
relating_type_id = self.relating_type or props.relating_type
if not ifc_class or not relating_type_id:
return {"FINISHED"}
@@ -118,7 +118,7 @@ class AddTypeInstance(bpy.types.Operator):
tool.Ifc,
tool.Type,
element=tool.Ifc.get_entity(obj),
type=tool.Ifc.get().by_id(int(tprops.relating_type)),
type=tool.Ifc.get().by_id(int(props.relating_type)),
)
if building_obj:
@@ -18,6 +18,7 @@
import bpy
import ifcopenshell.util.type
from blenderbim.bim.module.model.data import AuthoringData
from blenderbim.bim.prop import StrProperty, Attribute
from blenderbim.bim.ifc import IfcStore
from bpy.types import PropertyGroup
@@ -32,21 +33,23 @@ from bpy.props import (
CollectionProperty,
)
relating_types_enum = []
def get_ifc_class(self, context):
if not AuthoringData.is_loaded:
AuthoringData.load()
return AuthoringData.data["ifc_classes"]
def purge():
global relating_types_enum
relating_types_enum = []
def get_relating_type(self, context):
if not AuthoringData.is_loaded:
AuthoringData.load()
return AuthoringData.data["relating_types"]
def getRelatingTypes(self, context):
global relating_types_enum
if len(relating_types_enum) < 1:
elements = IfcStore.get_file().by_type("IfcWallType")
relating_types_enum.extend((str(e.id()), e.Name, "") for e in elements)
return relating_types_enum
def update_ifc_class(self, context):
AuthoringData.is_loaded = False
class BIMModelProperties(PropertyGroup):
relating_type: EnumProperty(items=getRelatingTypes, name="Relating Type")
ifc_class: bpy.props.EnumProperty(items=get_ifc_class, name="IFC Class", update=update_ifc_class)
relating_type: bpy.props.EnumProperty(items=get_relating_type, name="Relating Type")
@@ -19,6 +19,7 @@
import blenderbim.bim.module.type.prop as type_prop
from bpy.types import Panel
from blenderbim.bim.ifc import IfcStore
from blenderbim.bim.module.model.data import AuthoringData
class BIM_PT_authoring(Panel):
@@ -33,17 +34,20 @@ class BIM_PT_authoring(Panel):
return IfcStore.get_file()
def draw(self, context):
tprops = context.scene.BIMTypeProperties
if not AuthoringData.is_loaded:
AuthoringData.load()
props = context.scene.BIMModelProperties
col = self.layout.column(align=True)
enabled = True
if type_prop.getIfcTypes(tprops, context):
col.prop(tprops, "ifc_class", text="", icon="FILE_VOLUME")
if AuthoringData.data["ifc_classes"]:
col.prop(props, "ifc_class", text="", icon="FILE_VOLUME")
else:
col.label(text="No IFC Class", icon="FILE_VOLUME")
enabled = False
if type_prop.get_relating_type(tprops, context):
col.prop(tprops, "relating_type", text="", icon="FILE_3D")
if AuthoringData.data["relating_types"]:
col.prop(props, "relating_type", text="", icon="FILE_3D")
else:
col.label(text="No Relating Type", icon="FILE_3D")
enabled = False
@@ -21,6 +21,7 @@ import bpy
import blenderbim.bim.module.type.prop as type_prop
from bpy.types import WorkSpaceTool
from blenderbim.bim.ifc import IfcStore
from blenderbim.bim.module.model.data import WorkspaceData
class BimTool(WorkSpaceTool):
@@ -51,17 +52,19 @@ class BimTool(WorkSpaceTool):
)
def draw_settings(context, layout, tool):
if not WorkspaceData.is_loaded:
WorkspaceData.load()
row = layout.row(align=True)
if not IfcStore.get_file():
row.label(text="No IFC Project", icon="ERROR")
return
props = context.scene.BIMTypeProperties
ifc_classes_is_empty = not bool(type_prop.getIfcTypes(props, context))
if ifc_classes_is_empty:
row.label(text="No IFC Class")
else:
props = context.scene.BIMModelProperties
if WorkspaceData.data["ifc_classes"]:
row.prop(props, "ifc_class", text="")
if type_prop.get_relating_type(props, context):
else:
row.label(text="No IFC Class")
if WorkspaceData.data["relating_types"]:
row.prop(props, "relating_type", text="")
else:
row.label(text="No Relating Type")
@@ -143,8 +146,12 @@ class Hotkey(bpy.types.Operator):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
self.props = context.scene.BIMTypeProperties
self.ifc_classes_is_empty = not bool(type_prop.getIfcTypes(self.props, context))
self.props = context.scene.BIMModelProperties
self.ifc_classes_is_empty = True
try:
self.ifc_classes_is_empty = bool(self.props.ifc_class)
except:
pass
getattr(self, f"hotkey_{self.hotkey}")()
return {"FINISHED"}
@@ -28,16 +28,13 @@ classes = (
operator.SelectTypeObjects,
operator.SelectType,
prop.BIMTypeProperties,
prop.BIMTypeObjectProperties,
ui.BIM_PT_type,
)
def register():
bpy.types.Scene.BIMTypeProperties = bpy.props.PointerProperty(type=prop.BIMTypeProperties)
bpy.types.Object.BIMTypeProperties = bpy.props.PointerProperty(type=prop.BIMTypeObjectProperties)
bpy.types.Object.BIMTypeProperties = bpy.props.PointerProperty(type=prop.BIMTypeProperties)
def unregister():
del bpy.types.Scene.BIMTypeProperties
del bpy.types.Object.BIMTypeProperties
@@ -0,0 +1,53 @@
# 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 blenderbim.tool as tool
def refresh():
TypeData.is_loaded = False
class TypeData:
data = {}
is_loaded = False
@classmethod
def load(cls):
cls.data = {
"relating_type_classes": cls.relating_type_classes(),
"relating_types": cls.relating_types(),
}
cls.is_loaded = True
@classmethod
def relating_type_classes(cls):
results = []
element = tool.Ifc.get_entity(bpy.context.active_object)
types = ifcopenshell.util.type.get_applicable_types(element.is_a(), schema=tool.Ifc.get_schema())
applicable_types_enum.extend((t, t, "") for t in types)
return results
@classmethod
def relating_types(cls):
results = []
elements = tool.Ifc.get().by_type(bpy.context.active_object.BIMTypeProperties.relating_type_class)
elements = [(str(e.id()), e.Name, "") for e in elements]
relating_types_enum.extend(sorted(elements, key=lambda s: s[1]))
return results
@@ -18,6 +18,7 @@
import bpy
import ifcopenshell.util.type
from blenderbim.bim.module.type.data import TypeData
from blenderbim.bim.prop import StrProperty, Attribute
from blenderbim.bim.ifc import IfcStore
from bpy.types import PropertyGroup
@@ -32,78 +33,24 @@ from bpy.props import (
CollectionProperty,
)
applicable_types_enum = []
relating_types_enum = []
type_classes_enum = []
available_types_enum = []
def purge():
global applicable_types_enum
global relating_types_enum
global type_classes_enum
global available_types_enum
applicable_types_enum = []
relating_types_enum = []
type_classes_enum = []
available_types_enum = []
def getIfcTypes(self, context):
global type_classes_enum
file = IfcStore.get_file()
if len(type_classes_enum) < 1 and file:
classes = set([e.is_a() for e in file.by_type("IfcElementType")])
type_classes_enum.extend([(c, c, "") for c in sorted(classes)])
return type_classes_enum
def get_relating_type_class(self, context):
if not TypeData.is_loaded:
TypeData.load()
return TypeData.data["relating_type_classes"]
def get_relating_type(self, context):
global available_types_enum
if len(available_types_enum) < 1 and getIfcTypes(self, context):
elements = [(str(e.id()), e.Name, "") for e in IfcStore.get_file().by_type(self.ifc_class)]
available_types_enum.extend(sorted(elements, key=lambda s: s[1]))
return available_types_enum
if not TypeData.is_loaded:
TypeData.load()
return TypeData.data["relating_types"]
def updateTypeInstanceIfcClass(self, context):
global type_classes_enum
global available_types_enum
type_classes_enum.clear()
available_types_enum.clear()
def getApplicableTypes(self, context):
global applicable_types_enum
if len(applicable_types_enum) < 1:
element = IfcStore.get_file().by_id(context.active_object.BIMObjectProperties.ifc_definition_id)
types = ifcopenshell.util.type.get_applicable_types(element.is_a(), schema=IfcStore.get_file().schema)
applicable_types_enum.extend((t, t, "") for t in types)
return applicable_types_enum
def get_object_relating_type(self, context):
global relating_types_enum
if len(relating_types_enum) < 1:
elements = IfcStore.get_file().by_type(context.active_object.BIMTypeProperties.relating_type_class)
elements = [(str(e.id()), e.Name, "") for e in elements]
relating_types_enum.extend(sorted(elements, key=lambda s: s[1]))
return relating_types_enum
def updateTypeDropdowns(self, context):
global applicable_types_enum
global relating_types_enum
applicable_types_enum.clear()
relating_types_enum.clear()
def update_is_editing_type(self, context):
TypeData.is_loaded = False
class BIMTypeProperties(PropertyGroup):
ifc_class: bpy.props.EnumProperty(items=getIfcTypes, name="IFC Class", update=updateTypeInstanceIfcClass)
relating_type: bpy.props.EnumProperty(items=get_relating_type, name="Relating Type")
class BIMTypeObjectProperties(PropertyGroup):
is_editing_type: BoolProperty(name="Is Editing Type", update=updateTypeDropdowns)
relating_type_class: EnumProperty(items=getApplicableTypes, name="Relating Type Class")
relating_type: EnumProperty(items=get_object_relating_type, name="Relating Type")
is_editing_type: BoolProperty(name="Is Editing Type", update=update_is_editing_type)
relating_type_class: EnumProperty(items=get_relating_type_class, name="Relating Type Class")
relating_type: EnumProperty(items=get_relating_type, name="Relating Type")
@@ -275,9 +275,9 @@ Scenario: Override duplicate move - copying a type instance with a representatio
And I set "scene.BIMRootProperties.ifc_product" to "IfcElementType"
And I set "scene.BIMRootProperties.ifc_class" to "IfcWallType"
And I press "bim.assign_class"
And I set "scene.BIMTypeProperties.ifc_class" to "IfcWallType"
And I set "scene.BIMModelProperties.ifc_class" to "IfcWallType"
And the variable "cube" is "{ifc}.by_type('IfcWallType')[0].id()"
And I set "scene.BIMTypeProperties.relating_type" to "{cube}"
And I set "scene.BIMModelProperties.relating_type" to "{cube}"
And I press "bim.add_type_instance"
And the object "IfcWall/Instance" is selected
When I press "object.duplicate_move"
@@ -8,9 +8,9 @@ Scenario: Add type instance - add from a mesh
And I set "scene.BIMRootProperties.ifc_product" to "IfcElementType"
And I set "scene.BIMRootProperties.ifc_class" to "IfcWallType"
And I press "bim.assign_class"
And I set "scene.BIMTypeProperties.ifc_class" to "IfcWallType"
And I set "scene.BIMModelProperties.ifc_class" to "IfcWallType"
And the variable "cube" is "{ifc}.by_type('IfcWallType')[0].id()"
And I set "scene.BIMTypeProperties.relating_type" to "{cube}"
And I set "scene.BIMModelProperties.relating_type" to "{cube}"
When I press "bim.add_type_instance"
Then the object "IfcWall/Instance" exists
@@ -21,9 +21,9 @@ Scenario: Add type instance - add from an empty
And I set "scene.BIMRootProperties.ifc_product" to "IfcElementType"
And I set "scene.BIMRootProperties.ifc_class" to "IfcWallType"
And I press "bim.assign_class"
And I set "scene.BIMTypeProperties.ifc_class" to "IfcWallType"
And I set "scene.BIMModelProperties.ifc_class" to "IfcWallType"
And the variable "empty" is "{ifc}.by_type('IfcWallType')[0].id()"
And I set "scene.BIMTypeProperties.relating_type" to "{empty}"
And I set "scene.BIMModelProperties.relating_type" to "{empty}"
When I press "bim.add_type_instance"
Then the object "IfcWall/Instance" exists
@@ -34,9 +34,9 @@ Scenario: Add type instance - add a mesh where existing instances have changed c
And I set "scene.BIMRootProperties.ifc_product" to "IfcElementType"
And I set "scene.BIMRootProperties.ifc_class" to "IfcWallType"
And I press "bim.assign_class"
And I set "scene.BIMTypeProperties.ifc_class" to "IfcWallType"
And I set "scene.BIMModelProperties.ifc_class" to "IfcWallType"
And the variable "cube" is "{ifc}.by_type('IfcWallType')[0].id()"
And I set "scene.BIMTypeProperties.relating_type" to "{cube}"
And I set "scene.BIMModelProperties.relating_type" to "{cube}"
And I press "bim.add_type_instance"
And the object "IfcWall/Instance" data is a "Tessellation" representation of "Model/Body/MODEL_VIEW"
And the object "IfcWall/Instance" is selected