Merge pull request #2544 from Gorgious56/Tooltips

Blenderbim : Implement tooltips and online docs in the interface
This commit is contained in:
Dion Moult
2022-11-01 08:46:51 +11:00
committed by GitHub
22 changed files with 326 additions and 151 deletions
@@ -95,6 +95,7 @@ classes = [
operator.SelectURIAttribute, operator.SelectURIAttribute,
operator.EditBlenderCollection, operator.EditBlenderCollection,
operator.BIM_OT_open_webbrowser, operator.BIM_OT_open_webbrowser,
operator.BIM_OT_show_description,
prop.StrProperty, prop.StrProperty,
operator.BIM_OT_enum_property_search, # /!\ Register AFTER prop.StrProperty operator.BIM_OT_enum_property_search, # /!\ Register AFTER prop.StrProperty
prop.ObjProperty, prop.ObjProperty,
+43 -8
View File
@@ -23,8 +23,10 @@ import math
import zipfile import zipfile
import ifcopenshell import ifcopenshell
import ifcopenshell.util.attribute import ifcopenshell.util.attribute
from ifcopenshell.util.doc import get_attribute_doc, get_predefined_type_doc, get_property_doc
from mathutils import geometry from mathutils import geometry
from mathutils import Vector from mathutils import Vector
import blenderbim.tool as tool
from blenderbim.bim.ifc import IfcStore from blenderbim.bim.ifc import IfcStore
@@ -83,6 +85,7 @@ def import_attribute(attribute, props, data, callback=None):
new.is_null = data[attribute.name()] is None new.is_null = data[attribute.name()] is None
new.is_optional = attribute.optional() new.is_optional = attribute.optional()
new.data_type = data_type if isinstance(data_type, str) else "" new.data_type = data_type if isinstance(data_type, str) else ""
new.ifc_class = data["type"]
is_handled_by_callback = callback(attribute.name(), new, data) if callback else None is_handled_by_callback = callback(attribute.name(), new, data) if callback else None
if is_handled_by_callback: if is_handled_by_callback:
@@ -100,9 +103,38 @@ def import_attribute(attribute, props, data, callback=None):
elif data_type == "float": elif data_type == "float":
new.float_value = 0.0 if new.is_null else data[attribute.name()] new.float_value = 0.0 if new.is_null else data[attribute.name()]
elif data_type == "enum": elif data_type == "enum":
new.enum_items = json.dumps(ifcopenshell.util.attribute.get_enum_items(attribute)) enum_items = ifcopenshell.util.attribute.get_enum_items(attribute)
if data[attribute.name()]: new.enum_items = json.dumps(enum_items)
new.enum_value = data[attribute.name()] add_attribute_enum_items_descriptions(new, enum_items)
if data[new.name]:
new.enum_value = data[new.name]
add_attribute_description(new)
def add_attribute_enum_items_descriptions(attribute_blender, enum_items):
attribute_blender.enum_descriptions.clear()
if isinstance(enum_items, dict):
enum_items = enum_items.keys()
version = tool.Ifc.get_schema()
for enum_item in enum_items:
new_enum_description = attribute_blender.enum_descriptions.add()
try:
description = get_predefined_type_doc(version, attribute_blender.ifc_class, enum_item)
except KeyError: # TODO this only supports predefined type enums. Add support for other types of enums ?
description = ""
new_enum_description.name = description
def add_attribute_description(attribute_blender):
if not attribute_blender.name:
return
version = tool.Ifc.get_schema()
try:
description = get_attribute_doc(version, attribute_blender.ifc_class, attribute_blender.name)
except RuntimeError: # It's not an Entity Attribute. Let's try a Property Set attribute.
description = get_property_doc(version, attribute_blender.ifc_class, attribute_blender.name).get("description")
if description:
attribute_blender.description = description
def export_attributes(props, callback=None): def export_attributes(props, callback=None):
@@ -119,11 +151,14 @@ def prop_with_search(layout, data, prop_name, **kwargs):
# kwargs are layout.prop arguments (text, icon, etc.) # kwargs are layout.prop arguments (text, icon, etc.)
row = layout.row(align=True) row = layout.row(align=True)
row.prop(data, prop_name, **kwargs) row.prop(data, prop_name, **kwargs)
if len(get_enum_items(data, prop_name)) > 10: try:
# Magick courtesy of https://blender.stackexchange.com/a/203443/86891 if len(get_enum_items(data, prop_name)) > 10:
row.context_pointer_set(name="data", data=data) # Magick courtesy of https://blender.stackexchange.com/a/203443/86891
op = row.operator("bim.enum_property_search", text="", icon="VIEWZOOM") row.context_pointer_set(name="data", data=data)
op.prop_name = prop_name op = row.operator("bim.enum_property_search", text="", icon="VIEWZOOM")
op.prop_name = prop_name
except TypeError: # Prop is not iterable
pass
def get_enum_items(data, prop_name, context=None): def get_enum_items(data, prop_name, context=None):
@@ -17,7 +17,9 @@
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>. # along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import bpy import bpy
from blenderbim.bim.prop import StrProperty, Attribute, get_ifc_entity_description from ifcopenshell.util.doc import get_entity_doc
import blenderbim.tool as tool
from blenderbim.bim.prop import Attribute
from bpy.types import PropertyGroup from bpy.types import PropertyGroup
from bpy.props import ( from bpy.props import (
PointerProperty, PointerProperty,
@@ -32,7 +34,8 @@ from bpy.props import (
def get_available_constraint_types(self, context): def get_available_constraint_types(self, context):
return [(c, c, get_ifc_entity_description(c)) for c in ["IfcObjective"]] version = tool.Ifc.get_schema()
return [(c, c, get_entity_doc(version, c).get("description", "")) for c in ["IfcObjective"]]
class Constraint(PropertyGroup): class Constraint(PropertyGroup):
@@ -21,7 +21,6 @@ import bpy
import ifcopenshell import ifcopenshell
import ifcopenshell.util.schema import ifcopenshell.util.schema
import blenderbim.tool as tool import blenderbim.tool as tool
from blenderbim.bim.prop import get_ifc_entity_description
def refresh(): def refresh():
@@ -66,9 +65,12 @@ class MaterialsData:
"IfcMaterialProfileSet", "IfcMaterialProfileSet",
"IfcMaterialList", "IfcMaterialList",
] ]
if tool.Ifc.get_schema() == "IFC2X3": version = tool.Ifc.get_schema()
if version == "IFC2X3":
material_types = ["IfcMaterial", "IfcMaterialLayerSet", "IfcMaterialList"] material_types = ["IfcMaterial", "IfcMaterialLayerSet", "IfcMaterialList"]
return [(m, m, get_ifc_entity_description(m)) for m in material_types] return [
(m, m, ifcopenshell.util.doc.get_entity_doc(version, m).get("description", "")) for m in material_types
]
class ObjectMaterialData: class ObjectMaterialData:
@@ -617,6 +617,7 @@ class EnableEditingMaterialSetItem(bpy.types.Operator):
continue continue
if attribute.name() in material_set_item_data: if attribute.name() in material_set_item_data:
new = self.props.material_set_item_attributes.add() new = self.props.material_set_item_attributes.add()
new.ifc_class = material_set_item.is_a()
new.name = attribute.name() new.name = attribute.name()
new.is_null = material_set_item_data[attribute.name()] is None new.is_null = material_set_item_data[attribute.name()] is None
new.data_type = data_type new.data_type = data_type
@@ -628,7 +629,8 @@ class EnableEditingMaterialSetItem(bpy.types.Operator):
new.int_value = 0 if new.is_null else material_set_item_data[attribute.name()] new.int_value = 0 if new.is_null else material_set_item_data[attribute.name()]
elif data_type == "boolean": elif data_type == "boolean":
new.bool_value = False if new.is_null else material_set_item_data[attribute.name()] new.bool_value = False if new.is_null else material_set_item_data[attribute.name()]
blenderbim.bim.helper.add_attribute_description(new)
def load_profile_attributes(self, material_set_item, material_set_item_data): def load_profile_attributes(self, material_set_item, material_set_item_data):
self.props.material_set_item_profile_attributes.clear() self.props.material_set_item_profile_attributes.clear()
@@ -645,6 +647,7 @@ class EnableEditingMaterialSetItem(bpy.types.Operator):
if attribute.name() in profile_data: if attribute.name() in profile_data:
new = self.props.material_set_item_profile_attributes.add() new = self.props.material_set_item_profile_attributes.add()
new.name = attribute.name() new.name = attribute.name()
new.ifc_class = profile.is_a()
new.is_null = profile_data[attribute.name()] is None new.is_null = profile_data[attribute.name()] is None
new.is_optional = attribute.optional() new.is_optional = attribute.optional()
new.data_type = data_type new.data_type = data_type
@@ -661,6 +664,8 @@ class EnableEditingMaterialSetItem(bpy.types.Operator):
if profile_data[attribute.name()]: if profile_data[attribute.name()]:
new.enum_value = profile_data[attribute.name()] new.enum_value = profile_data[attribute.name()]
blenderbim.bim.helper.add_attribute_description(new)
# Force null to be false if the attribute is mandatory because when we first assign a profile, all of # Force null to be false if the attribute is mandatory because when we first assign a profile, all of
# its fields are null (which is illegal). # its fields are null (which is illegal).
# TODO: find a better solution. # TODO: find a better solution.
@@ -17,10 +17,12 @@
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>. # along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import bpy import bpy
from ifcopenshell.util.doc import get_entity_doc
from ifcopenshell.api.material.data import Data from ifcopenshell.api.material.data import Data
import blenderbim.tool as tool
from blenderbim.bim.module.material.data import MaterialsData, ObjectMaterialData from blenderbim.bim.module.material.data import MaterialsData, ObjectMaterialData
from blenderbim.bim.ifc import IfcStore from blenderbim.bim.ifc import IfcStore
from blenderbim.bim.prop import StrProperty, Attribute, get_ifc_entity_description from blenderbim.bim.prop import StrProperty, Attribute
from bpy.types import PropertyGroup from bpy.types import PropertyGroup
from bpy.props import ( from bpy.props import (
PointerProperty, PointerProperty,
@@ -47,28 +49,31 @@ def purge():
parameterizedprofileclasses_enum = [] parameterizedprofileclasses_enum = []
def getProfileClasses(self, context): def get_profile_classes(self, context):
global profileclasses_enum global profileclasses_enum
if len(profileclasses_enum) == 0 and IfcStore.get_schema(): if len(profileclasses_enum) == 0 and IfcStore.get_schema():
version = tool.Ifc.get_schema()
profileclasses_enum.clear() profileclasses_enum.clear()
profileclasses_enum = [ profileclasses_enum = [
(t.name(), t.name(), "") for t in IfcStore.get_schema().declaration_by_name("IfcProfileDef").subtypes() (t.name(), t.name(), get_entity_doc(version, t.name()).get("description", ""))
for t in IfcStore.get_schema().declaration_by_name("IfcProfileDef").subtypes()
] ]
return profileclasses_enum return profileclasses_enum
def getParameterizedProfileClasses(self, context): def get_parameterized_profile_classes(self, context):
global parameterizedprofileclasses_enum global parameterizedprofileclasses_enum
if len(parameterizedprofileclasses_enum) == 0 and IfcStore.get_schema(): if len(parameterizedprofileclasses_enum) == 0 and IfcStore.get_schema():
version = tool.Ifc.get_schema()
parameterizedprofileclasses_enum.clear() parameterizedprofileclasses_enum.clear()
parameterizedprofileclasses_enum = [ parameterizedprofileclasses_enum = [
(t.name(), t.name(), "") (t.name(), t.name(), get_entity_doc(version, t.name()).get("description", ""))
for t in IfcStore.get_schema().declaration_by_name("IfcParameterizedProfileDef").subtypes() for t in IfcStore.get_schema().declaration_by_name("IfcParameterizedProfileDef").subtypes()
] ]
for ifc_class in parameterizedprofileclasses_enum: for ifc_class in parameterizedprofileclasses_enum:
parameterizedprofileclasses_enum.extend( parameterizedprofileclasses_enum.extend(
[ [
(t.name(), t.name(), "") (t.name(), t.name(), get_entity_doc(version, t.name()).get("description", ""))
for t in IfcStore.get_schema().declaration_by_name(ifc_class[0]).subtypes() or [] for t in IfcStore.get_schema().declaration_by_name(ifc_class[0]).subtypes() or []
] ]
) )
@@ -93,10 +98,11 @@ def get_object_material_types(self, context):
"IfcMaterialProfileSetUsage", "IfcMaterialProfileSetUsage",
"IfcMaterialList", "IfcMaterialList",
] ]
if IfcStore.get_file().schema == "IFC2X3": version = tool.Ifc.get_schema()
if version == "IFC2X3":
material_types = ["IfcMaterial", "IfcMaterialLayerSet", "IfcMaterialLayerSetUsage", "IfcMaterialList"] material_types = ["IfcMaterial", "IfcMaterialLayerSet", "IfcMaterialLayerSetUsage", "IfcMaterialList"]
materialtypes_enum.clear() materialtypes_enum.clear()
materialtypes_enum = [(m, m, get_ifc_entity_description(m)) for m in material_types] materialtypes_enum = [(m, m, get_entity_doc(version, m).get("description", "")) for m in material_types]
return materialtypes_enum return materialtypes_enum
@@ -133,7 +139,7 @@ class BIMObjectMaterialProperties(PropertyGroup):
name="Material Set Item Profile Attributes", type=Attribute name="Material Set Item Profile Attributes", type=Attribute
) )
material_set_item_material: EnumProperty(items=get_materials, name="Material") material_set_item_material: EnumProperty(items=get_materials, name="Material")
profile_classes: EnumProperty(items=getProfileClasses, name="Profile Classes") profile_classes: EnumProperty(items=get_profile_classes, name="Profile Classes")
parameterized_profile_classes: EnumProperty( parameterized_profile_classes: EnumProperty(
items=getParameterizedProfileClasses, name="Parameterized Profile Classes" items=get_parameterized_profile_classes, name="Parameterized Profile Classes"
) )
@@ -22,11 +22,10 @@ import json
import functools import functools
import ifcopenshell import ifcopenshell
import ifcopenshell.util.element import ifcopenshell.util.element
from ifcopenshell.util.doc import get_entity_doc, get_predefined_type_doc
import blenderbim.tool as tool import blenderbim.tool as tool
from blenderbim.bim.ifc import IfcStore from blenderbim.bim.ifc import IfcStore
from blenderbim.bim.module.model.root import ConstrTypeEntityNotFound from blenderbim.bim.module.model.root import ConstrTypeEntityNotFound
from blenderbim.bim.prop import get_ifc_entity_description, get_predefined_type_description
def refresh(): def refresh():
AuthoringData.is_loaded = False AuthoringData.is_loaded = False
@@ -64,17 +63,19 @@ class AuthoringData:
declarations = ifcopenshell.util.schema.get_subtypes(declaration) declarations = ifcopenshell.util.schema.get_subtypes(declaration)
names = [d.name() for d in declarations] names = [d.name() for d in declarations]
names.extend(("IfcDoorStyle", "IfcWindowStyle")) names.extend(("IfcDoorStyle", "IfcWindowStyle"))
return [(c, c, get_ifc_entity_description(c)) for c in sorted(names)] version = tool.Ifc.get_schema()
return [(c, c, get_entity_doc(version, c).get("description", "")) for c in sorted(names)]
@classmethod @classmethod
def type_predefined_type(cls): def type_predefined_type(cls):
results = [] results = []
declaration = tool.Ifc().schema().declaration_by_name(cls.props.type_class) declaration = tool.Ifc().schema().declaration_by_name(cls.props.type_class)
version = tool.Ifc.get_schema()
for attribute in declaration.attributes(): for attribute in declaration.attributes():
if attribute.name() == "PredefinedType": if attribute.name() == "PredefinedType":
results.extend( results.extend(
[ [
(e, e, get_predefined_type_description(cls.props.type_class, e)) (e, e, get_predefined_type_doc(version, cls.props.type_class, e))
for e in attribute.type_of_attribute().declared_type().enumeration_items() for e in attribute.type_of_attribute().declared_type().enumeration_items()
] ]
) )
@@ -17,7 +17,9 @@
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>. # along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import bpy import bpy
from blenderbim.bim.prop import StrProperty, Attribute, get_ifc_entity_description from ifcopenshell.util.doc import get_entity_doc
import blenderbim.tool as tool
from blenderbim.bim.prop import StrProperty, Attribute
from blenderbim.bim.module.owner.data import OwnerData, ActorData, ObjectActorData from blenderbim.bim.module.owner.data import OwnerData, ActorData, ObjectActorData
from bpy.types import PropertyGroup from bpy.types import PropertyGroup
from bpy.props import ( from bpy.props import (
@@ -65,17 +67,19 @@ def update_actor_class(self, context):
def get_actor_class_enum(self, context): def get_actor_class_enum(self, context):
version = tool.Ifc.get_schema()
return [ return [
("IfcActor", "Actor", get_ifc_entity_description("IfcActor")), ("IfcActor", "Actor", get_entity_doc(version, "IfcActor").get("description", "")),
("IfcOccupant", "Occupant", get_ifc_entity_description("IfcOccupant")), ("IfcOccupant", "Occupant", get_entity_doc(version, "IfcOccupant").get("description", "")),
] ]
def get_actor_type_enum(self, context): def get_actor_type_enum(self, context):
version = tool.Ifc.get_schema()
return [ return [
("IfcPerson", "Person", get_ifc_entity_description("IfcPerson")), ("IfcPerson", "Person", get_entity_doc(version, "IfcPerson").get("description", "")),
("IfcOrganization", "Organisation", get_ifc_entity_description("IfcOrganization")), ("IfcOrganization", "Organisation", get_entity_doc(version, "IfcOrganization").get("description", "")),
("IfcPersonAndOrganization", "User", get_ifc_entity_description("IfcPersonAndOrganization")), ("IfcPersonAndOrganization", "User", get_entity_doc(version, "IfcPersonAndOrganization").get("description", "")),
] ]
@@ -96,8 +100,14 @@ class BIMOwnerProperties(PropertyGroup):
facsimile_numbers: CollectionProperty(type=StrProperty, name="Facsimile Numbers") facsimile_numbers: CollectionProperty(type=StrProperty, name="Facsimile Numbers")
electronic_mail_addresses: CollectionProperty(type=StrProperty, name="Emails") electronic_mail_addresses: CollectionProperty(type=StrProperty, name="Emails")
messaging_ids: CollectionProperty(type=StrProperty, name="IMs") messaging_ids: CollectionProperty(type=StrProperty, name="IMs")
user_person: EnumProperty(items=get_user_person, name="Person") user_person: EnumProperty(
user_organisation: EnumProperty(items=get_user_organisation, name="Organisation") items=get_user_person, name="Person", description="This entity represents an individual human being."
)
user_organisation: EnumProperty(
items=get_user_organisation,
name="Organisation",
description="A named and structured grouping with a corporate identity.",
)
active_user_id: IntProperty(name="Active User Id") active_user_id: IntProperty(name="Active User Id")
active_actor_id: IntProperty(name="Active Actor Id") active_actor_id: IntProperty(name="Active Actor Id")
actor_attributes: CollectionProperty(name="Actor Attributes", type=Attribute) actor_attributes: CollectionProperty(name="Actor Attributes", type=Attribute)
@@ -111,5 +121,7 @@ class BIMOwnerProperties(PropertyGroup):
name="Actor Type", name="Actor Type",
update=update_actor_type, update=update_actor_type,
) )
the_actor: EnumProperty(items=get_the_actor, name="Actor") the_actor: EnumProperty(
items=get_the_actor, name="Actor", description="This entity represents an individual human being."
)
actor: EnumProperty(items=get_actor, name="Actor") actor: EnumProperty(items=get_actor, name="Actor")
@@ -173,4 +173,8 @@ class AddEditCustomPropertiesData:
@classmethod @classmethod
def primary_measure_type(cls): def primary_measure_type(cls):
schema = tool.Ifc.schema() schema = tool.Ifc.schema()
return [(t, t, "") for t in sorted([d.name() for d in schema.declarations() if hasattr(d, "declared_type")])] version = tool.Ifc.get_schema()
return [
(t, t, ifcopenshell.util.doc.get_type_doc(version, t).get("description", ""))
for t in sorted([d.name() for d in schema.declarations() if hasattr(d, "declared_type")])
]
@@ -128,6 +128,9 @@ class EnablePsetEditing(bpy.types.Operator):
elif metadata.data_type == "boolean": elif metadata.data_type == "boolean":
metadata.bool_value = False if metadata.is_null else data[prop_template.Name] metadata.bool_value = False if metadata.is_null else data[prop_template.Name]
metadata.ifc_class = pset_template.Name
blenderbim.bim.helper.add_attribute_description(metadata)
def get_data_type(self, prop_template): def get_data_type(self, prop_template):
if prop_template.TemplateType in ["Q_LENGTH", "Q_AREA", "Q_VOLUME", "Q_WEIGHT", "Q_TIME"]: if prop_template.TemplateType in ["Q_LENGTH", "Q_AREA", "Q_VOLUME", "Q_WEIGHT", "Q_TIME"]:
return "float" return "float"
@@ -21,6 +21,7 @@ import blenderbim.bim.schema
from blenderbim.bim.prop import Attribute, StrProperty from blenderbim.bim.prop import Attribute, StrProperty
import ifcopenshell import ifcopenshell
from ifcopenshell.api.pset.data import Data from ifcopenshell.api.pset.data import Data
import blenderbim.tool as tool
from blenderbim.bim.module.pset.data import AddEditCustomPropertiesData from blenderbim.bim.module.pset.data import AddEditCustomPropertiesData
from blenderbim.bim.ifc import IfcStore from blenderbim.bim.ifc import IfcStore
from bpy.types import PropertyGroup from bpy.types import PropertyGroup
@@ -47,6 +48,15 @@ def purge():
qtonames = {} qtonames = {}
def blender_formatted_enum_from_psets(psets):
enum_items = []
version = tool.Ifc.get_schema()
for pset in psets:
doc = ifcopenshell.util.doc.get_property_set_doc(version, pset.Name) or {}
enum_items.append((pset.Name, pset.Name, doc.get("description", "")))
return enum_items
def get_pset_names(self, context): def get_pset_names(self, context):
global psetnames global psetnames
obj = context.active_object obj = context.active_object
@@ -58,67 +68,67 @@ def get_pset_names(self, context):
ifc_class = element.is_a() ifc_class = element.is_a()
if ifc_class not in psetnames: if ifc_class not in psetnames:
psets = blenderbim.bim.schema.ifc.psetqto.get_applicable(ifc_class, pset_only=True) psets = blenderbim.bim.schema.ifc.psetqto.get_applicable(ifc_class, pset_only=True)
psetnames[ifc_class] = [(p.Name, p.Name, "") for p in psets] psetnames[ifc_class] = blender_formatted_enum_from_psets(psets)
assigned_names = [Data.psets[p]["Name"] for p in Data.products[obj.BIMObjectProperties.ifc_definition_id]["psets"]] assigned_names = [Data.psets[p]["Name"] for p in Data.products[obj.BIMObjectProperties.ifc_definition_id]["psets"]]
return [p for p in psetnames[ifc_class] if p[0] not in assigned_names] return [p for p in psetnames[ifc_class] if p[0] not in assigned_names]
def getMaterialPsetNames(self, context): def get_material_pset_names(self, context):
global psetnames global psetnames
ifc_class = "IfcMaterial" ifc_class = "IfcMaterial"
if ifc_class not in psetnames: if ifc_class not in psetnames:
psets = blenderbim.bim.schema.ifc.psetqto.get_applicable(ifc_class, pset_only=True) psets = blenderbim.bim.schema.ifc.psetqto.get_applicable(ifc_class, pset_only=True)
psetnames[ifc_class] = [(p.Name, p.Name, "") for p in psets] psetnames[ifc_class] = blender_formatted_enum_from_psets(psets)
return psetnames[ifc_class] return psetnames[ifc_class]
def getTaskQtoNames(self, context): def get_task_qto_names(self, context):
global qtonames global qtonames
ifc_class = "IfcTask" ifc_class = "IfcTask"
if ifc_class not in qtonames: if ifc_class not in qtonames:
psets = blenderbim.bim.schema.ifc.psetqto.get_applicable(ifc_class, qto_only=True) psets = blenderbim.bim.schema.ifc.psetqto.get_applicable(ifc_class, qto_only=True)
qtonames[ifc_class] = [(p.Name, p.Name, "") for p in psets] qtonames[ifc_class] = blender_formatted_enum_from_psets(psets)
return qtonames[ifc_class] return qtonames[ifc_class]
def getResourcePsetNames(self, context): def get_resource_pset_names(self, context):
global psetnames global psetnames
rprops = context.scene.BIMResourceProperties rprops = context.scene.BIMResourceProperties
rtprops = context.scene.BIMResourceTreeProperties rtprops = context.scene.BIMResourceTreeProperties
ifc_class = IfcStore.get_file().by_id(rtprops.resources[rprops.active_resource_index].ifc_definition_id).is_a() ifc_class = IfcStore.get_file().by_id(rtprops.resources[rprops.active_resource_index].ifc_definition_id).is_a()
if ifc_class not in psetnames: if ifc_class not in psetnames:
psets = blenderbim.bim.schema.ifc.psetqto.get_applicable(ifc_class, pset_only=True) psets = blenderbim.bim.schema.ifc.psetqto.get_applicable(ifc_class, pset_only=True)
psetnames[ifc_class] = [(p.Name, p.Name, "") for p in psets] psetnames[ifc_class] = blender_formatted_enum_from_psets(psets)
return psetnames[ifc_class] return psetnames[ifc_class]
def getResourceQtoNames(self, context): def get_resource_qto_names(self, context):
global qtonames global qtonames
rprops = context.scene.BIMResourceProperties rprops = context.scene.BIMResourceProperties
rtprops = context.scene.BIMResourceTreeProperties rtprops = context.scene.BIMResourceTreeProperties
ifc_class = IfcStore.get_file().by_id(rtprops.resources[rprops.active_resource_index].ifc_definition_id).is_a() ifc_class = IfcStore.get_file().by_id(rtprops.resources[rprops.active_resource_index].ifc_definition_id).is_a()
if ifc_class not in qtonames: if ifc_class not in qtonames:
psets = blenderbim.bim.schema.ifc.psetqto.get_applicable(ifc_class, qto_only=True) psets = blenderbim.bim.schema.ifc.psetqto.get_applicable(ifc_class, qto_only=True)
qtonames[ifc_class] = [(p.Name, p.Name, "") for p in psets] qtonames[ifc_class] = blender_formatted_enum_from_psets(psets)
return qtonames[ifc_class] return qtonames[ifc_class]
def getProfilePsetNames(self, context): def get_profile_pset_names(self, context):
global psetnames global psetnames
pprops = context.scene.BIMProfileProperties pprops = context.scene.BIMProfileProperties
ifc_class = IfcStore.get_file().by_id(pprops.profiles[pprops.active_profile_index].ifc_definition_id).is_a() ifc_class = IfcStore.get_file().by_id(pprops.profiles[pprops.active_profile_index].ifc_definition_id).is_a()
if ifc_class not in psetnames: if ifc_class not in psetnames:
psets = blenderbim.bim.schema.ifc.psetqto.get_applicable(ifc_class, pset_only=True) psets = blenderbim.bim.schema.ifc.psetqto.get_applicable(ifc_class, pset_only=True)
psetnames[ifc_class] = [(p.Name, p.Name, "") for p in psets] psetnames[ifc_class] = blender_formatted_enum_from_psets(psets)
return psetnames[ifc_class] return psetnames[ifc_class]
def getWorkSchedulePsetNames(self, context): def get_work_schedule_pset_names(self, context):
global psetnames global psetnames
ifc_class = "IfcWorkSchedule" ifc_class = "IfcWorkSchedule"
if ifc_class not in psetnames: if ifc_class not in psetnames:
psets = blenderbim.bim.schema.ifc.psetqto.get_applicable(ifc_class, pset_only=True) psets = blenderbim.bim.schema.ifc.psetqto.get_applicable(ifc_class, pset_only=True)
psetnames[ifc_class] = [(p.Name, p.Name, "") for p in psets] psetnames[ifc_class] = blender_formatted_enum_from_psets(psets)
return psetnames[ifc_class] return psetnames[ifc_class]
@@ -128,11 +138,17 @@ def get_qto_names(self, context):
ifc_class = context.active_object.name.split("/")[0] ifc_class = context.active_object.name.split("/")[0]
if ifc_class not in qtonames: if ifc_class not in qtonames:
psets = blenderbim.bim.schema.ifc.psetqto.get_applicable(ifc_class, qto_only=True) psets = blenderbim.bim.schema.ifc.psetqto.get_applicable(ifc_class, qto_only=True)
qtonames[ifc_class] = [(p.Name, p.Name, "") for p in psets] qtonames[ifc_class] = blender_formatted_enum_from_psets(psets)
return qtonames[ifc_class] return qtonames[ifc_class]
return [] return []
def get_template_type(self, context):
version = tool.Ifc.get_schema()
for t in ("IfcPropertySingleValue", "IfcPropertyEnumeratedValue"):
yield (t, t, ifcopenshell.util.doc.get_entity_doc(version, t).get("description", ""))
def get_primary_measure_type(self, context): def get_primary_measure_type(self, context):
if not AddEditCustomPropertiesData.is_loaded: if not AddEditCustomPropertiesData.is_loaded:
AddEditCustomPropertiesData.load() AddEditCustomPropertiesData.load()
@@ -163,36 +179,36 @@ class MaterialPsetProperties(PropertyGroup):
active_pset_id: IntProperty(name="Active Pset ID") active_pset_id: IntProperty(name="Active Pset ID")
active_pset_name: StringProperty(name="Pset Name") active_pset_name: StringProperty(name="Pset Name")
properties: CollectionProperty(name="Properties", type=IfcProperty) properties: CollectionProperty(name="Properties", type=IfcProperty)
pset_name: EnumProperty(items=getMaterialPsetNames, name="Pset Name") pset_name: EnumProperty(items=get_material_pset_names, name="Pset Name")
class TaskPsetProperties(PropertyGroup): class TaskPsetProperties(PropertyGroup):
active_pset_id: IntProperty(name="Active Pset ID") active_pset_id: IntProperty(name="Active Pset ID")
active_pset_name: StringProperty(name="Pset Name") active_pset_name: StringProperty(name="Pset Name")
properties: CollectionProperty(name="Properties", type=IfcProperty) properties: CollectionProperty(name="Properties", type=IfcProperty)
qto_name: EnumProperty(items=getTaskQtoNames, name="Qto Name") qto_name: EnumProperty(items=get_task_qto_names, name="Qto Name")
class ResourcePsetProperties(PropertyGroup): class ResourcePsetProperties(PropertyGroup):
active_pset_id: IntProperty(name="Active Pset ID") active_pset_id: IntProperty(name="Active Pset ID")
active_pset_name: StringProperty(name="Pset Name") active_pset_name: StringProperty(name="Pset Name")
properties: CollectionProperty(name="Properties", type=IfcProperty) properties: CollectionProperty(name="Properties", type=IfcProperty)
pset_name: EnumProperty(items=getResourcePsetNames, name="Pset Name") pset_name: EnumProperty(items=get_resource_pset_names, name="Pset Name")
qto_name: EnumProperty(items=getResourceQtoNames, name="Qto Name") qto_name: EnumProperty(items=get_resource_qto_names, name="Qto Name")
class ProfilePsetProperties(PropertyGroup): class ProfilePsetProperties(PropertyGroup):
active_pset_id: IntProperty(name="Active Pset ID") active_pset_id: IntProperty(name="Active Pset ID")
active_pset_name: StringProperty(name="Pset Name") active_pset_name: StringProperty(name="Pset Name")
properties: CollectionProperty(name="Properties", type=IfcProperty) properties: CollectionProperty(name="Properties", type=IfcProperty)
pset_name: EnumProperty(items=getProfilePsetNames, name="Pset Name") pset_name: EnumProperty(items=get_profile_pset_names, name="Pset Name")
class WorkSchedulePsetProperties(PropertyGroup): class WorkSchedulePsetProperties(PropertyGroup):
active_pset_id: IntProperty(name="Active Pset ID") active_pset_id: IntProperty(name="Active Pset ID")
active_pset_name: StringProperty(name="Pset Name") active_pset_name: StringProperty(name="Pset Name")
properties: CollectionProperty(name="Properties", type=IfcProperty) properties: CollectionProperty(name="Properties", type=IfcProperty)
pset_name: EnumProperty(items=getWorkSchedulePsetNames, name="Pset Name") pset_name: EnumProperty(items=get_work_schedule_pset_names, name="Pset Name")
class RenameProperties(PropertyGroup): class RenameProperties(PropertyGroup):
@@ -209,13 +225,7 @@ class AddEditProperties(PropertyGroup):
int_value: IntProperty(name="Value") int_value: IntProperty(name="Value")
float_value: FloatProperty(name="Value") float_value: FloatProperty(name="Value")
primary_measure_type: EnumProperty(items=get_primary_measure_type, name="Primary Measure Type") primary_measure_type: EnumProperty(items=get_primary_measure_type, name="Primary Measure Type")
template_type: EnumProperty( template_type: EnumProperty(items=get_template_type, name="Template Type")
items=[
("IfcPropertySingleValue", "IfcPropertySingleValue", "IfcPropertySingleValue"),
("IfcPropertyEnumeratedValue", "IfcPropertyEnumeratedValue", "IfcPropertyEnumeratedValue"),
],
name="Template Type",
)
enum_values: CollectionProperty(name="Enum Values", type=Attribute) enum_values: CollectionProperty(name="Enum Values", type=Attribute)
def get_value_name(self): def get_value_name(self):
@@ -43,7 +43,11 @@ class PsetTemplatesData:
@classmethod @classmethod
def primary_measure_type(cls): def primary_measure_type(cls):
schema = tool.Ifc.schema() schema = tool.Ifc.schema()
return [(t, t, "") for t in sorted([d.name() for d in schema.declarations() if hasattr(d, "declared_type")])] version = tool.Ifc.get_schema()
return [
(t, t, ifcopenshell.util.doc.get_type_doc(version, t).get("description", ""))
for t in sorted([d.name() for d in schema.declarations() if hasattr(d, "declared_type")])
]
@classmethod @classmethod
def pset_template_files(cls): def pset_template_files(cls):
@@ -19,6 +19,7 @@
import os import os
import bpy import bpy
import ifcopenshell import ifcopenshell
from ifcopenshell.util.doc import get_attribute_doc
from blenderbim.bim.module.pset_template.data import PsetTemplatesData from blenderbim.bim.module.pset_template.data import PsetTemplatesData
from blenderbim.bim.prop import StrProperty, Attribute from blenderbim.bim.prop import StrProperty, Attribute
from blenderbim.bim.ifc import IfcStore from blenderbim.bim.ifc import IfcStore
@@ -111,11 +112,27 @@ def get_template_type(self, context):
class PsetTemplate(PropertyGroup): class PsetTemplate(PropertyGroup):
global_id: StringProperty(name="Global ID") global_id: StringProperty(
name: StringProperty(name="Name") name="Global ID",
description: StringProperty(name="Description") description=get_attribute_doc("IFC4", "IfcPropertySetTemplate", "GlobalId"),
template_type: EnumProperty(items=get_template_type, name="Template Type") )
applicable_entity: StringProperty(name="Applicable Entity") name: StringProperty(
name="Name",
description=get_attribute_doc("IFC4", "IfcPropertySetTemplate", "Name"),
)
description: StringProperty(
name="Description",
description=get_attribute_doc("IFC4", "IfcPropertySetTemplate", "Description"),
)
template_type: EnumProperty(
items=get_template_type,
name="Template Type",
description=get_attribute_doc("IFC4", "IfcPropertySetTemplate", "TemplateType"),
)
applicable_entity: StringProperty(
name="Applicable Entity",
description=get_attribute_doc("IFC4", "IfcPropertySetTemplate", "ApplicableEntity"),
)
class EnumerationValues(PropertyGroup): class EnumerationValues(PropertyGroup):
@@ -126,9 +143,18 @@ class EnumerationValues(PropertyGroup):
class PropTemplate(PropertyGroup): class PropTemplate(PropertyGroup):
global_id: StringProperty(name="Global ID") global_id: StringProperty(
name: StringProperty(name="Name") name="Global ID",
description: StringProperty(name="Description") description=get_attribute_doc("IFC4", "IfcPropertyTemplate", "GlobalId"),
)
name: StringProperty(
name="Name",
description=get_attribute_doc("IFC4", "IfcPropertyTemplate", "Name"),
)
description: StringProperty(
name="Description",
description=get_attribute_doc("IFC4", "IfcPropertyTemplate", "Description"),
)
primary_measure_type: EnumProperty(items=get_primary_measure_type, name="Primary Measure Type") primary_measure_type: EnumProperty(items=get_primary_measure_type, name="Primary Measure Type")
template_type: EnumProperty( template_type: EnumProperty(
items=[("P_SINGLEVALUE", "P_SINGLEVALUE", ""), ("P_ENUMERATEDVALUE", "P_ENUMERATEDVALUE", "")], items=[("P_SINGLEVALUE", "P_SINGLEVALUE", ""), ("P_ENUMERATEDVALUE", "P_ENUMERATEDVALUE", "")],
@@ -19,9 +19,9 @@
from collections import defaultdict from collections import defaultdict
import bpy import bpy
import ifcopenshell.util.element import ifcopenshell.util.element
from ifcopenshell.util.doc import get_entity_doc, get_predefined_type_doc
import blenderbim.tool as tool import blenderbim.tool as tool
from blenderbim.bim.ifc import IfcStore from blenderbim.bim.ifc import IfcStore
from blenderbim.bim.prop import get_ifc_entity_description, get_predefined_type_description
def refresh(): def refresh():
@@ -57,7 +57,8 @@ class IfcClassData:
"IfcAnnotation", "IfcAnnotation",
"IfcRelSpaceBoundary", "IfcRelSpaceBoundary",
] ]
if tool.Ifc.get_schema() == "IFC2X3": version = tool.Ifc.get_schema()
if version == "IFC2X3":
products = [ products = [
"IfcElement", "IfcElement",
"IfcElementType", "IfcElementType",
@@ -67,7 +68,7 @@ class IfcClassData:
"IfcAnnotation", "IfcAnnotation",
"IfcRelSpaceBoundary", "IfcRelSpaceBoundary",
] ]
return [(e, e, get_ifc_entity_description(e)) for e in products] return [(e, e, get_entity_doc(version, e).get("description", "")) for e in products]
@classmethod @classmethod
def ifc_classes(cls): def ifc_classes(cls):
@@ -77,18 +78,20 @@ class IfcClassData:
names = [d.name() for d in declarations] names = [d.name() for d in declarations]
if ifc_product == "IfcElementType": if ifc_product == "IfcElementType":
names.extend(("IfcDoorStyle", "IfcWindowStyle")) names.extend(("IfcDoorStyle", "IfcWindowStyle"))
return [(c, c, get_ifc_entity_description(c)) for c in sorted(names)] version = tool.Ifc.get_schema()
return [(c, c, get_entity_doc(version, c).get("description", "")) for c in sorted(names)]
@classmethod @classmethod
def ifc_predefined_types(cls): def ifc_predefined_types(cls):
types_enum = [] types_enum = []
ifc_class = bpy.context.scene.BIMRootProperties.ifc_class ifc_class = bpy.context.scene.BIMRootProperties.ifc_class
declaration = tool.Ifc.schema().declaration_by_name(ifc_class) declaration = tool.Ifc.schema().declaration_by_name(ifc_class)
version = tool.Ifc.get_schema()
for attribute in declaration.attributes(): for attribute in declaration.attributes():
if attribute.name() == "PredefinedType": if attribute.name() == "PredefinedType":
types_enum.extend( types_enum.extend(
[ [
(e, e, get_predefined_type_description(ifc_class, e)) (e, e, get_predefined_type_doc(version, ifc_class, e))
for e in attribute.type_of_attribute().declared_type().enumeration_items() for e in attribute.type_of_attribute().declared_type().enumeration_items()
] ]
) )
@@ -16,11 +16,13 @@
# You should have received a copy of the GNU General Public License # 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/>. # along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import bpy
from blenderbim.bim.ifc import IfcStore
from math import radians from math import radians
from blenderbim.bim.prop import StrProperty, Attribute, get_ifc_entity_description import bpy
from ifcopenshell.api.structural.data import Data from ifcopenshell.api.structural.data import Data
from ifcopenshell.util.doc import get_entity_doc
import blenderbim.tool as tool
from blenderbim.bim.ifc import IfcStore
from blenderbim.bim.prop import StrProperty, Attribute
from bpy.types import PropertyGroup from bpy.types import PropertyGroup
from bpy.props import ( from bpy.props import (
PointerProperty, PointerProperty,
@@ -89,8 +91,12 @@ def get_structural_load_types(self, context):
file = IfcStore.get_file() file = IfcStore.get_file()
if len(structuralloadtypes_enum) < 1 and file: if len(structuralloadtypes_enum) < 1 and file:
declaration = IfcStore.get_schema().declaration_by_name("IfcStructuralLoadStatic") declaration = IfcStore.get_schema().declaration_by_name("IfcStructuralLoadStatic")
version = tool.Ifc.get_schema()
structuralloadtypes_enum.extend( structuralloadtypes_enum.extend(
[(d.name(), d.name(), get_ifc_entity_description(d.name())) for d in declaration.subtypes()] [
(d.name(), d.name(), get_entity_doc(version, d.name()).get("description", ""))
for d in declaration.subtypes()
]
) )
return structuralloadtypes_enum return structuralloadtypes_enum
@@ -99,8 +105,10 @@ def get_boundary_condition_types(self, context):
file = IfcStore.get_file() file = IfcStore.get_file()
if file: if file:
declaration = IfcStore.get_schema().declaration_by_name("IfcBoundaryCondition") declaration = IfcStore.get_schema().declaration_by_name("IfcBoundaryCondition")
version = tool.Ifc.get_schema()
boundaryconditiontypes_enum = [ boundaryconditiontypes_enum = [
(d.name(), d.name(), get_ifc_entity_description(d.name())) for d in declaration.subtypes() (d.name(), d.name(), get_entity_doc(version, d.name()).get("description", ""))
for d in declaration.subtypes()
] ]
return boundaryconditiontypes_enum return boundaryconditiontypes_enum
return [] return []
@@ -17,9 +17,9 @@
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>. # along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import bpy import bpy
import blenderbim.tool as tool
import ifcopenshell import ifcopenshell
from blenderbim.bim.prop import get_ifc_entity_description from ifcopenshell.util.doc import get_entity_doc
import blenderbim.tool as tool
def refresh(): def refresh():
@@ -39,7 +39,10 @@ class StylesData:
def style_types(cls): def style_types(cls):
declaration = tool.Ifc.schema().declaration_by_name("IfcPresentationStyle") declaration = tool.Ifc.schema().declaration_by_name("IfcPresentationStyle")
declarations = ifcopenshell.util.schema.get_subtypes(declaration) declarations = ifcopenshell.util.schema.get_subtypes(declaration)
return [(c, c, get_ifc_entity_description(c)) for c in sorted([d.name() for d in declarations])] version = tool.Ifc.get_schema()
return [
(c, c, get_entity_doc(version, c).get("description", "")) for c in sorted([d.name() for d in declarations])
]
@classmethod @classmethod
def total_styles(cls): def total_styles(cls):
@@ -19,8 +19,8 @@
import bpy import bpy
import ifcopenshell import ifcopenshell
import ifcopenshell.util.schema import ifcopenshell.util.schema
from ifcopenshell.util.doc import get_entity_doc
import blenderbim.tool as tool import blenderbim.tool as tool
from blenderbim.bim.prop import get_ifc_entity_description
def refresh(): def refresh():
@@ -45,9 +45,10 @@ class SystemData:
def system_class(cls): def system_class(cls):
declaration = tool.Ifc.schema().declaration_by_name("IfcSystem") declaration = tool.Ifc.schema().declaration_by_name("IfcSystem")
declarations = ifcopenshell.util.schema.get_subtypes(declaration) declarations = ifcopenshell.util.schema.get_subtypes(declaration)
version = tool.Ifc.get_schema()
# We're only interested in systems for services. Not sure why IFC groups these together. # We're only interested in systems for services. Not sure why IFC groups these together.
return [ return [
(c, c, get_ifc_entity_description(c)) (c, c, get_entity_doc(version, c).get("description", ""))
for c in sorted([d.name() for d in declarations]) for c in sorted([d.name() for d in declarations])
if c not in ("IfcZone", "IfcStructuralAnalysisModel") if c not in ("IfcZone", "IfcStructuralAnalysisModel")
] ]
@@ -19,8 +19,8 @@
import bpy import bpy
import ifcopenshell.util.type import ifcopenshell.util.type
import ifcopenshell.util.element import ifcopenshell.util.element
from ifcopenshell.util.doc import get_entity_doc
import blenderbim.tool as tool import blenderbim.tool as tool
from blenderbim.bim.prop import get_ifc_entity_description
def refresh(): def refresh():
@@ -54,8 +54,9 @@ class TypeData:
element = tool.Ifc.get_entity(obj) element = tool.Ifc.get_entity(obj)
if not element: if not element:
return [] return []
types = ifcopenshell.util.type.get_applicable_types(element.is_a(), schema=tool.Ifc.get_schema()) version = tool.Ifc.get_schema()
results.extend((t, t, get_ifc_entity_description(t)) for t in types) types = ifcopenshell.util.type.get_applicable_types(element.is_a(), schema=version)
results.extend((t, t, get_entity_doc(version, t).get("description", "")) for t in types)
return results return results
@classmethod @classmethod
@@ -87,7 +88,4 @@ class TypeData:
element = tool.Ifc.get_entity(bpy.context.active_object) element = tool.Ifc.get_entity(bpy.context.active_object)
element_type = ifcopenshell.util.element.get_type(element) element_type = ifcopenshell.util.element.get_type(element)
if element_type: if element_type:
return { return {"id": element_type.id(), "name": f"{element_type.is_a()}/{element_type.Name or 'Unnamed'}"}
"id": element_type.id(),
"name":f"{element_type.is_a()}/{element_type.Name or 'Unnamed'}"
}
@@ -20,8 +20,8 @@ import ifcopenshell
import ifcopenshell.util.unit import ifcopenshell.util.unit
import ifcopenshell.util.schema import ifcopenshell.util.schema
import ifcopenshell.util.attribute import ifcopenshell.util.attribute
from ifcopenshell.util.doc import get_entity_doc
import blenderbim.tool as tool import blenderbim.tool as tool
from blenderbim.bim.prop import get_ifc_entity_description
def refresh(): def refresh():
@@ -45,8 +45,20 @@ class UnitsData:
@classmethod @classmethod
def unit_classes(cls): def unit_classes(cls):
declarations = ifcopenshell.util.schema.get_subtypes(tool.Ifc.schema().declaration_by_name("IfcNamedUnit")) declarations = ifcopenshell.util.schema.get_subtypes(tool.Ifc.schema().declaration_by_name("IfcNamedUnit"))
results = [(c, c, get_ifc_entity_description(c)) for c in sorted([d.name() for d in declarations])] version = tool.Ifc.get_schema()
results.extend([("IfcDerivedUnit", "IfcDerivedUnit", ""), ("IfcMonetaryUnit", "IfcMonetaryUnit", "")]) results = [
(c, c, get_entity_doc(version, c).get("description", "")) for c in sorted([d.name() for d in declarations])
]
results.extend(
[
("IfcDerivedUnit", "IfcDerivedUnit", get_entity_doc(version, "IfcDerivedUnit").get("description", "")),
(
"IfcMonetaryUnit",
"IfcMonetaryUnit",
get_entity_doc(version, "IfcMonetaryUnit").get("description", ""),
),
]
)
return results return results
@classmethod @classmethod
+29
View File
@@ -19,6 +19,7 @@
import os import os
import bpy import bpy
import json import json
import textwrap
import time import time
import logging import logging
import webbrowser import webbrowser
@@ -683,3 +684,31 @@ class EditBlenderCollection(bpy.types.Operator):
else: else:
getattr(context.bim_prop_group, self.collection).remove(self.index) getattr(context.bim_prop_group, self.collection).remove(self.index)
return {"FINISHED"} return {"FINISHED"}
class BIM_OT_show_description(bpy.types.Operator):
bl_idname = "bim.show_description"
bl_label = "Description"
attr_name: bpy.props.StringProperty()
description: bpy.props.StringProperty()
url: bpy.props.StringProperty()
def invoke(self, context, event):
wm = context.window_manager
return wm.invoke_props_dialog(self, width=450)
def execute(self, context):
return {"FINISHED"}
def draw(self, context):
layout = self.layout
wrapper = textwrap.TextWrapper(width=80)
for line in wrapper.wrap(self.attr_name + " : " + self.description):
layout.label(text=line)
if self.url:
url_op = layout.operator("bim.open_webbrowser", icon="URL", text="Online IFC Documentation")
url_op.url = self.url
@classmethod
def description(cls, context, properties):
return properties.description
+11 -38
View File
@@ -106,40 +106,6 @@ def cache_string(s):
cache_string.data = {} cache_string.data = {}
def get_ifc_entity_docs(ifc_entity):
schema = tool.Ifc.get_schema()
if schema is not None:
return get_entity_doc(schema, ifc_entity)
def get_ifc_entity_description(ifc_entity):
docs = get_ifc_entity_docs(ifc_entity)
return docs.get("description", "") if docs is not None else ""
def get_ifc_entity_doc_url(ifc_entity):
docs = get_ifc_entity_docs(ifc_entity)
return docs.get("spec_url", "") if docs is not None else ""
def get_predefined_type_description(entity, predefined_type):
schema = tool.Ifc.get_schema()
if schema is not None:
return get_predefined_type_doc(schema, entity, predefined_type)
def get_attribute_description(entity, attribute):
schema = tool.Ifc.get_schema()
if schema is not None:
return get_attribute_doc(schema, entity, attribute)
def get_property_set_description(pset):
schema = tool.Ifc.get_schema()
if schema is not None:
return get_property_set_doc(schema, pset)
def get_attribute_enum_values(prop, context): def get_attribute_enum_values(prop, context):
# Support weird buildingSMART dictionary mappings which behave like enums # Support weird buildingSMART dictionary mappings which behave like enums
items = [] items = []
@@ -164,6 +130,9 @@ def get_attribute_enum_values(prop, context):
) )
) )
if prop.enum_descriptions:
items = [(identifier, name, prop.enum_descriptions[i].name) for i, (identifier, name, _) in enumerate(items)]
return items return items
@@ -227,13 +196,17 @@ def update_attribute_value(self, context):
class Attribute(PropertyGroup): class Attribute(PropertyGroup):
tooltip = "`Right Click > IFC Description` to read the attribute description and online documentation"
name: StringProperty(name="Name") name: StringProperty(name="Name")
description: StringProperty(name="Description")
ifc_class: StringProperty(name="Ifc Class")
data_type: StringProperty(name="Data Type") data_type: StringProperty(name="Data Type")
string_value: StringProperty(name="Value", update=update_attribute_value) string_value: StringProperty(name="Value", update=update_attribute_value, description=tooltip)
bool_value: BoolProperty(name="Value", update=update_attribute_value) bool_value: BoolProperty(name="Value", update=update_attribute_value, description=tooltip)
int_value: IntProperty(name="Value", update=update_attribute_value) int_value: IntProperty(name="Value", update=update_attribute_value, description=tooltip)
float_value: FloatProperty(name="Value", update=update_attribute_value) float_value: FloatProperty(name="Value", update=update_attribute_value, description=tooltip)
enum_items: StringProperty(name="Value") enum_items: StringProperty(name="Value")
enum_descriptions: CollectionProperty(type=StrProperty)
enum_value: EnumProperty(items=get_attribute_enum_values, name="Value", update=update_attribute_value) enum_value: EnumProperty(items=get_attribute_enum_values, name="Value", update=update_attribute_value)
is_null: BoolProperty(name="Is Null") is_null: BoolProperty(name="Is Null")
is_optional: BoolProperty(name="Is Optional") is_optional: BoolProperty(name="Is Optional")
+50 -14
View File
@@ -17,14 +17,20 @@
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>. # along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import os import os
import bpy
from pathlib import Path from pathlib import Path
from . import ifc import bpy
from bpy.types import Panel from bpy.types import Panel
from bpy.props import StringProperty, IntProperty, BoolProperty from bpy.props import StringProperty, IntProperty, BoolProperty
from blenderbim.bim.helper import IfcHeaderExtractor from ifcopenshell.util.doc import (
from blenderbim.bim.prop import get_ifc_entity_doc_url get_entity_doc,
get_property_set_doc,
get_type_doc,
get_attribute_doc,
)
from . import ifc
import blenderbim.tool as tool import blenderbim.tool as tool
from blenderbim.bim.helper import IfcHeaderExtractor
from blenderbim.bim.prop import Attribute
class IFCFileSelector: class IFCFileSelector:
@@ -397,14 +403,44 @@ def draw_custom_context_menu(self, context):
prop_value = getattr(prop, prop_name, None) prop_value = getattr(prop, prop_name, None)
if prop_value is None: if prop_value is None:
return return
try: version = tool.Ifc.get_schema()
url = get_ifc_entity_doc_url(prop_value) layout = self.layout
except KeyError:
# TODO : support attributes, pset, etc. if isinstance(context.button_pointer, Attribute):
pass description = getattr(context.button_pointer, "description", None)
else: ifc_class = getattr(context.button_pointer, "ifc_class", "")
if url: if ifc_class:
layout = self.layout try:
url = get_entity_doc(version, context.button_pointer.ifc_class).get("spec_url", "")
except RuntimeError: # It's not an Entity Attribute. Let's try a Property Set attribute.
url = get_property_set_doc(version, context.button_pointer.ifc_class).get("spec_url", "")
if description:
layout.separator() layout.separator()
url_op = layout.operator("bim.open_webbrowser", icon="URL", text="Online IFC Documentation") op_description = layout.operator("bim.show_description", text="IFC Description", icon="INFO")
url_op.url = url op_description.attr_name = getattr(context.button_pointer, "name", "")
op_description.description = description
op_description.url = url
else:
# Ugly but we can't know which type of data is under the cursor so we test everything until it clicks
try:
docs = get_entity_doc(version, prop_value)
if docs is None:
raise RuntimeError
except (RuntimeError, AttributeError):
try:
docs = get_type_doc(version, prop_value)
if docs is None:
raise RuntimeError
except (RuntimeError, AttributeError):
try:
docs = get_property_set_doc(version, prop_value)
if docs is None:
raise RuntimeError
except (RuntimeError, AttributeError):
pass
if docs:
url = docs.get("spec_url", "")
if url:
layout.separator()
url_op = layout.operator("bim.open_webbrowser", icon="URL", text="Online IFC Documentation")
url_op.url = url