From 7140b2c4e854258491643827c257395946b9fc7a Mon Sep 17 00:00:00 2001 From: s-leger Date: Fri, 15 Nov 2019 01:44:29 +0100 Subject: [PATCH] Dynamic enumerators Dynamic enums require to hold proper reference to enum array. (may lead to access violation and strange ui behaviour) Cleanup bpy.props.xxx and bpy.types.xxx Fix in path for files with hardcoded "/" BIM_PT_ prefixes for Panel classes Use poll method for panels --- src/ifcblenderexport/io_export_ifc/ui.py | 423 ++++++++++++++--------- 1 file changed, 252 insertions(+), 171 deletions(-) diff --git a/src/ifcblenderexport/io_export_ifc/ui.py b/src/ifcblenderexport/io_export_ifc/ui.py index ea51fc9049..b8c22cc8d3 100644 --- a/src/ifcblenderexport/io_export_ifc/ui.py +++ b/src/ifcblenderexport/io_export_ifc/ui.py @@ -3,247 +3,317 @@ import json import os import csv from pathlib import Path +from bpy.types import PropertyGroup, Panel +from bpy.props import ( + StringProperty, + EnumProperty, + BoolProperty, + IntProperty, + FloatProperty, + CollectionProperty +) + cwd = os.path.dirname(os.path.realpath(__file__)) + os.path.sep class IfcSchema(): def __init__(self): - with open('{}ifc_elements_IFC4.json'.format(cwd + 'schema/')) as f: + with open('{}schema{}ifc_elements_IFC4.json'.format(cwd, os.path.sep)) as f: self.elements = json.load(f) ifc_schema = IfcSchema() -class BIMProperties(bpy.types.PropertyGroup): - def getIfcClasses(self, context): - return [(e, e, '') for e in ifc_schema.elements] +# hold reference to dynamic enum +classes_enum = [] +types_enum = [] +psetnames_enum = [] +psetfiles_enum = [] +classification_enum = [] +attributes_enum = [] +documents_enum = [] - def getIfcPredefinedTypes(self, context): - results = [] - for name, data in ifc_schema.elements.items(): - if name != bpy.context.scene.BIMProperties.ifc_class: +# Note: unless we need dynamic behaviour +# enums should be cached especially when file io is involved +# we may clear on need to regen + +def getIfcPredefinedTypes(self): + global types_enum + types_enum.clear() + for name, data in ifc_schema.elements.items(): + if name != bpy.context.scene.BIMProperties.ifc_class: + continue + for attribute in data['attributes']: + if attribute['name'] != 'PredefinedType': continue - for attribute in data['attributes']: - if attribute['name'] != 'PredefinedType': - continue - return [(e, e, '') for e in attribute['enum_values']] + types_enum.extend([(e, e, '') for e in attribute['enum_values']]) + return types_enum - def getPsetNames(self, context): - files = os.listdir(bpy.context.scene.BIMProperties.data_dir + 'pset/') - return [(f, f, '') for f in files] +def getIfcClasses(self): + global classes_enum + classes_enum.clear() + classes_enum.extend([(e, e, '') for e in ifc_schema.elements]) + return classes_enum - def getPsetFiles(self, context): - if not bpy.context.scene.BIMProperties.pset_name: - return [] - files = os.listdir(bpy.context.scene.BIMProperties.data_dir + 'pset/{}/'.format(bpy.context.scene.BIMProperties.pset_name)) - return [(f.replace('.csv', ''), f.replace('.csv', ''), '') for f in files] +def getPsetNames(self): + global psetnames_enum + psetnames_enum.clear() + files = os.listdir(bpy.context.scene.BIMProperties.data_dir + 'pset' + os.path.sep) + psetnames_enum.extend([(f, f, '') for f in files]) + return psetnames_enum - def getClassifications(self, context): - with open(bpy.context.scene.BIMProperties.data_dir + 'class/classifications.csv', 'r') as f: - data = list(csv.reader(f)) - keys = data.pop(0) - index = keys.index('Name') - return [(str(i), d[index], '') for i, d in enumerate(data)] +def getPsetFiles(self): + global psetfiles_enum + psetfiles_enum.clear() + if not bpy.context.scene.BIMProperties.pset_name: + return psetfiles_enum + files = os.listdir( + bpy.context.scene.BIMProperties.data_dir + 'pset{}{}{}'.format( + os.path.sep, + bpy.context.scene.BIMProperties.pset_name, + os.path.sep)) + psetfiles_enum.extend([(f.replace('.csv', ''), f.replace('.csv', ''), '') for f in files]) + return psetfiles_enum - def getReferences(self, context): - if not bpy.context.scene.BIMProperties.classification: - return [] - with open(bpy.context.scene.BIMProperties.data_dir + 'class/references.csv', 'r') as f: - data = list(csv.reader(f)) - keys = data.pop(0) - return [(d[0], '{} - {}'.format(d[0], d[1]), '') for d in data if - d[2] == bpy.context.scene.BIMProperties.classification] +def getClassifications(self): + global classification_enum + classification_enum.clear() + with open(bpy.context.scene.BIMProperties.data_dir + 'class/classifications.csv', 'r') as f: + data = list(csv.reader(f)) + keys = data.pop(0) + index = keys.index('Name') + classification_enum.extend([(str(i), d[index], '') for i, d in enumerate(data)]) + return classification_enum - schema_dir: bpy.props.StringProperty(default=cwd + 'schema/', name="Schema Directory") - data_dir: bpy.props.StringProperty(default=cwd + 'data/', name="Data Directory") - ifc_class: bpy.props.EnumProperty(items = getIfcClasses, name="Class") - ifc_predefined_type: bpy.props.EnumProperty( +def getReferences(self): + global reference_enum + reference_enum.clear() + if not bpy.context.scene.BIMProperties.classification: + return reference_enum + with open(bpy.context.scene.BIMProperties.data_dir + 'class' + os.path.sep + 'references.csv', 'r') as f: + data = list(csv.reader(f)) + keys = data.pop(0) + reference_enum.extend([(d[0], '{} - {}'.format(d[0], d[1]), '') for d in data if + d[2] == bpy.context.scene.BIMProperties.classification]) + return reference_enum + +def getApplicableAttributes(self): + global attributes_enum + attributes_enum.clear() + if '/' in bpy.context.active_object.name \ + and bpy.context.active_object.name.split('/')[0] in ifc_schema.elements: + attributes_enum.extend([(a['name'], a['name'], '') for a in + ifc_schema.elements[bpy.context.active_object.name.split('/')[0]]['attributes'] + if bpy.context.active_object.BIMObjectProperties.attributes.find(a['name']) == -1]) + return attributes_enum + +def getApplicableDocuments(self): + global documents_enum + documents_enum.clear() + doc_path = bpy.context.scene.BIMProperties.data_dir + 'doc' + os.path.sep + for filename in Path(doc_path).glob('**/*'): + uri = str(filename.relative_to(doc_path).as_posix()) + documents_enum.append((uri, uri, '')) + return documents_enum + + +class BIMProperties(PropertyGroup): + + schema_dir: StringProperty(default=cwd + 'schema' + os.path.sep, name="Schema Directory") + data_dir: StringProperty(default=cwd + 'data' + os.path.sep, name="Data Directory") + ifc_class: EnumProperty(items = getIfcClasses, name="Class") + ifc_predefined_type: EnumProperty( items = getIfcPredefinedTypes, name="Predefined Type", default=None) - ifc_userdefined_type: bpy.props.StringProperty(name="Userdefined Type") - export_has_representations: bpy.props.BoolProperty(name="Export Representations", default=True) - export_should_export_all_materials_as_styled_items: bpy.props.BoolProperty(name="Export All Materials as Styled Items", default=False) - export_should_use_presentation_style_assignment: bpy.props.BoolProperty(name="Export with Presentation Style Assignment", default=False) - import_should_ignore_site_coordinates: bpy.props.BoolProperty(name="Import Ignoring Site Coordinates", default=False) - import_should_import_curves: bpy.props.BoolProperty(name="Import Curves", default=False) - qa_reject_element_reason: bpy.props.StringProperty(name="Element Rejection Reason") - pset_name: bpy.props.EnumProperty(items=getPsetNames, name="Pset Name") - pset_file: bpy.props.EnumProperty(items=getPsetFiles, name="Pset File") - has_georeferencing: bpy.props.BoolProperty(name="Has Georeferencing", default=False) - global_id: bpy.props.StringProperty(name="GlobalId") - features_dir: bpy.props.StringProperty(default='', name="Features Directory") - diff_json_file: bpy.props.StringProperty(default='', name="Diff JSON File") - aggregate_class: bpy.props.EnumProperty(items = getIfcClasses, name="Aggregate Class") - aggregate_name: bpy.props.StringProperty(name="Aggregate Name") - classification: bpy.props.EnumProperty(items = getClassifications, name="Classification") - reference: bpy.props.EnumProperty(items = getReferences, name="Reference") + ifc_userdefined_type: StringProperty(name="Userdefined Type") + export_has_representations: BoolProperty(name="Export Representations", default=True) + export_should_export_all_materials_as_styled_items: BoolProperty(name="Export All Materials as Styled Items", default=False) + export_should_use_presentation_style_assignment: BoolProperty(name="Export with Presentation Style Assignment", default=False) + import_should_ignore_site_coordinates: BoolProperty(name="Import Ignoring Site Coordinates", default=False) + import_should_import_curves: BoolProperty(name="Import Curves", default=False) + qa_reject_element_reason: StringProperty(name="Element Rejection Reason") + pset_name: EnumProperty(items=getPsetNames, name="Pset Name") + pset_file: EnumProperty(items=getPsetFiles, name="Pset File") + has_georeferencing: BoolProperty(name="Has Georeferencing", default=False) + global_id: StringProperty(name="GlobalId") + features_dir: StringProperty(default='', name="Features Directory") + diff_json_file: StringProperty(default='', name="Diff JSON File") + aggregate_class: EnumProperty(items = getIfcClasses, name="Aggregate Class") + aggregate_name: StringProperty(name="Aggregate Name") + classification: EnumProperty(items = getClassifications, name="Classification") + reference: EnumProperty(items = getReferences, name="Reference") -class MapConversion(bpy.types.PropertyGroup): - eastings: bpy.props.StringProperty(name="Eastings") - northings: bpy.props.StringProperty(name="Northings") - orthogonal_height: bpy.props.StringProperty(name="Orthogonal Height") - x_axis_abscissa: bpy.props.StringProperty(name="X Axis Abscissa") - x_axis_ordinate: bpy.props.StringProperty(name="X Axis Ordinate") - scale: bpy.props.StringProperty(name="Scale") +class MapConversion(PropertyGroup): + eastings: StringProperty(name="Eastings") + northings: StringProperty(name="Northings") + orthogonal_height: StringProperty(name="Orthogonal Height") + x_axis_abscissa: StringProperty(name="X Axis Abscissa") + x_axis_ordinate: StringProperty(name="X Axis Ordinate") + scale: StringProperty(name="Scale") -class TargetCRS(bpy.types.PropertyGroup): - name: bpy.props.StringProperty(name="Name") - description: bpy.props.StringProperty(name="Description") - geodetic_datum: bpy.props.StringProperty(name="Geodetic Datum") - vertical_datum: bpy.props.StringProperty(name="Vertical Datum") - map_projection: bpy.props.StringProperty(name="Map Projection") - map_zone: bpy.props.StringProperty(name="Map Zone") - map_unit: bpy.props.StringProperty(name="Map Unit") +class TargetCRS(PropertyGroup): + name: StringProperty(name="Name") + description: StringProperty(name="Description") + geodetic_datum: StringProperty(name="Geodetic Datum") + vertical_datum: StringProperty(name="Vertical Datum") + map_projection: StringProperty(name="Map Projection") + map_zone: StringProperty(name="Map Zone") + map_unit: StringProperty(name="Map Unit") -class Attribute(bpy.types.PropertyGroup): - name: bpy.props.StringProperty(name="Name") - data_type: bpy.props.StringProperty(name="Data Type") - string_value: bpy.props.StringProperty(name="Value") - bool_value: bpy.props.BoolProperty(name="Value") - int_value: bpy.props.IntProperty(name="Value") - float_value: bpy.props.FloatProperty(name="Value") +class Attribute(PropertyGroup): + name: StringProperty(name="Name") + data_type: StringProperty(name="Data Type") + string_value: StringProperty(name="Value") + bool_value: BoolProperty(name="Value") + int_value: IntProperty(name="Value") + float_value: FloatProperty(name="Value") -class Pset(bpy.types.PropertyGroup): - name: bpy.props.StringProperty(name="Name") - file: bpy.props.StringProperty(name="File") +class Pset(PropertyGroup): + name: StringProperty(name="Name") + file: StringProperty(name="File") -class Document(bpy.types.PropertyGroup): - file: bpy.props.StringProperty(name="File") +class Document(PropertyGroup): + file: StringProperty(name="File") -class Classification(bpy.types.PropertyGroup): - name: bpy.props.StringProperty(name="Name") - identification: bpy.props.StringProperty(name="Identification") +class Classification(PropertyGroup): + name: StringProperty(name="Name") + identification: StringProperty(name="Identification") -class GlobalId(bpy.types.PropertyGroup): - name: bpy.props.StringProperty(name="Name") -class BIMObjectProperties(bpy.types.PropertyGroup): - def getApplicableAttributes(self, context): - if '/' in bpy.context.active_object.name \ - and bpy.context.active_object.name.split('/')[0] in ifc_schema.elements: - return [(a['name'], a['name'], '') for a in - ifc_schema.elements[bpy.context.active_object.name.split('/')[0]]['attributes'] - if bpy.context.active_object.BIMObjectProperties.attributes.find(a['name']) == -1] - return [] +class GlobalId(PropertyGroup): + name: StringProperty(name="Name") - def getApplicableDocuments(self, context): - results = [] - doc_path = bpy.context.scene.BIMProperties.data_dir + 'doc/' - for filename in Path(doc_path).glob('**/*'): - uri = str(filename.relative_to(doc_path).as_posix()) - results.append((uri, uri, '')) - return results - global_ids: bpy.props.CollectionProperty(name="GlobalIds", type=GlobalId) - attributes: bpy.props.CollectionProperty(name="Attributes", type=Attribute) - psets: bpy.props.CollectionProperty(name="Psets", type=Pset) - applicable_attributes: bpy.props.EnumProperty(items=getApplicableAttributes, name="Attribute Names") - documents: bpy.props.CollectionProperty(name="Documents", type=Document) - applicable_documents: bpy.props.EnumProperty(items=getApplicableDocuments, name="Available Documents") - classifications: bpy.props.CollectionProperty(name="Classifications", type=Classification) +class BIMObjectProperties(PropertyGroup): -class BIMMaterialProperties(bpy.types.PropertyGroup): - is_external: bpy.props.BoolProperty(name="Has External Definition") - location: bpy.props.StringProperty(name="Location") - identification: bpy.props.StringProperty(name="Identification") - name: bpy.props.StringProperty(name="Name") -class SweptSolid(bpy.types.PropertyGroup): - name: bpy.props.StringProperty(name="Name") - outer_curve: bpy.props.StringProperty(name="Outer Curve") - inner_curves: bpy.props.StringProperty(name="Inner Curves") - extrusion: bpy.props.StringProperty(name="Extrusion") + global_ids: CollectionProperty(name="GlobalIds", type=GlobalId) + attributes: CollectionProperty(name="Attributes", type=Attribute) + psets: CollectionProperty(name="Psets", type=Pset) + applicable_attributes: EnumProperty(items=getApplicableAttributes, name="Attribute Names") + documents: CollectionProperty(name="Documents", type=Document) + applicable_documents: EnumProperty(items=getApplicableDocuments, name="Available Documents") + classifications: CollectionProperty(name="Classifications", type=Classification) -class BIMMeshProperties(bpy.types.PropertyGroup): - is_wireframe: bpy.props.BoolProperty(name="Is Wireframe") - is_swept_solid: bpy.props.BoolProperty(name="Is Swept Solid") - swept_solids: bpy.props.CollectionProperty(name="Swept Solids", type=SweptSolid) -class ObjectPanel(bpy.types.Panel): +class BIMMaterialProperties(PropertyGroup): + is_external: BoolProperty(name="Has External Definition") + location: StringProperty(name="Location") + identification: StringProperty(name="Identification") + name: StringProperty(name="Name") + + +class SweptSolid(PropertyGroup): + name: StringProperty(name="Name") + outer_curve: StringProperty(name="Outer Curve") + inner_curves: StringProperty(name="Inner Curves") + extrusion: StringProperty(name="Extrusion") + + +class BIMMeshProperties(PropertyGroup): + is_wireframe: BoolProperty(name="Is Wireframe") + is_swept_solid: BoolProperty(name="Is Swept Solid") + swept_solids: CollectionProperty(name="Swept Solids", type=SweptSolid) + + +class BIM_PT_object(Panel): bl_label = 'IFC Object' bl_idname = 'BIM_PT_object' bl_space_type = 'PROPERTIES' bl_region_type = 'WINDOW' bl_context = 'object' - + + @classmethod + def poll(cls, context): + return context.active_object is not None and hasattr(context.active_object, "BIMObjectProperties") + def draw(self, context): - if not bpy.context.active_object: + + if context.active_object is None: return layout = self.layout + props = context.active_object.BIMObjectProperties + layout.label(text="Software Identity:") row = layout.row() row.operator('bim.generate_global_id') layout.label(text="Attributes:") row = layout.row(align=True) - row.prop(bpy.context.active_object.BIMObjectProperties, 'applicable_attributes', text='') + row.prop(props, 'applicable_attributes', text='') row.operator('bim.add_attribute') - for index, attribute in enumerate(bpy.context.active_object.BIMObjectProperties.attributes): + for index, attribute in enumerate(props.attributes): row = layout.row(align=True) row.prop(attribute, 'name', text='') row.prop(attribute, 'string_value', text='') row.operator('bim.remove_attribute', icon='X', text='').attribute_index = index row = layout.row() - row.prop(bpy.context.active_object.BIMObjectProperties, 'attributes') + row.prop(props, 'attributes') layout.label(text="Property Sets:") row = layout.row() row.operator('bim.add_pset') - for index, pset in enumerate(bpy.context.active_object.BIMObjectProperties.psets): + for index, pset in enumerate(props.psets): row = layout.row(align=True) row.prop(pset, 'name', text='') row.prop(pset, 'file', text='') row.operator('bim.remove_pset', icon='X', text='').pset_index = index row = layout.row() - row.prop(bpy.context.active_object.BIMObjectProperties, 'psets') + row.prop(props, 'psets') layout.label(text="Documents:") row = layout.row(align=True) - row.prop(bpy.context.active_object.BIMObjectProperties, 'applicable_documents', text='') + row.prop(props, 'applicable_documents', text='') row.operator('bim.add_document') - for index, document in enumerate(bpy.context.active_object.BIMObjectProperties.documents): + for index, document in enumerate(props.documents): row = layout.row(align=True) row.prop(document, 'file', text='') row.operator('bim.remove_document', icon='X', text='').document_index = index row = layout.row() - row.prop(bpy.context.active_object.BIMObjectProperties, 'documents') + row.prop(props, 'documents') layout.label(text="Classification:") - for index, classification in enumerate(bpy.context.active_object.BIMObjectProperties.classifications): + for index, classification in enumerate(props.classifications): row = layout.row(align=True) row.prop(classification, 'identification', text='') row.prop(classification, 'name', text='') row.operator('bim.remove_classification', icon='X', text='').classification_index = index row = layout.row() - row.prop(bpy.context.active_object.BIMObjectProperties, 'classifications') + row.prop(props, 'classifications') -class MeshPanel(bpy.types.Panel): +class BIM_PT_mesh(Panel): bl_label = 'IFC Representations' bl_idname = 'BIM_PT_mesh' bl_space_type = 'PROPERTIES' bl_region_type = 'WINDOW' bl_context = 'data' + @classmethod + def poll(cls, context): + return context.active_object is not None and context.active_object.type == "MESH" and \ + hasattr(context.active_object.data, "BIMMeshProperties") + def draw(self, context): - if not bpy.context.active_object.data: + if not context.active_object.data: return layout = self.layout + props = context.active_object.data.BIMMeshProperties row = layout.row() - row.prop(bpy.context.active_object.data.BIMMeshProperties, 'is_wireframe') + row.prop(props, 'is_wireframe') row = layout.row() - row.prop(bpy.context.active_object.data.BIMMeshProperties, 'is_swept_solid') + row.prop(props, 'is_swept_solid') row = layout.row() row.operator('bim.add_swept_solid') - for index, swept_solid in enumerate(bpy.context.active_object.data.BIMMeshProperties.swept_solids): + for index, swept_solid in enumerate(props.swept_solids): row = layout.row(align=True) row.prop(swept_solid, 'name', text='') row.operator('bim.remove_swept_solid', icon='X', text='').index = index @@ -258,30 +328,37 @@ class MeshPanel(bpy.types.Panel): row.operator('bim.assign_swept_solid_extrusion').index = index row.operator('bim.select_swept_solid_extrusion', icon='RESTRICT_SELECT_OFF', text='').index = index row = layout.row() - row.prop(bpy.context.active_object.data.BIMMeshProperties, 'swept_solids') + row.prop(props, 'swept_solids') -class MaterialPanel(bpy.types.Panel): + +class BIM_PT_material(Panel): bl_label = 'IFC Materials' bl_idname = 'BIM_PT_material' bl_space_type = 'PROPERTIES' bl_region_type = 'WINDOW' bl_context = 'material' - + + @classmethod + def poll(cls, context): + return context.active_object is not None and context.active_object.active_material is not None + def draw(self, context): if not bpy.context.active_object.active_material: return + props = context.active_object.active_material.BIMMaterialProperties layout = self.layout row = layout.row() - row.prop(bpy.context.active_object.active_material.BIMMaterialProperties, 'is_external') + row.prop(props, 'is_external') row = layout.row(align=True) - row.prop(bpy.context.active_object.active_material.BIMMaterialProperties, 'location') + row.prop(props, 'location') row.operator('bim.select_external_material_dir', icon="FILE_FOLDER", text="") row = layout.row() - row.prop(bpy.context.active_object.active_material.BIMMaterialProperties, 'identification') + row.prop(props, 'identification') row = layout.row() - row.prop(bpy.context.active_object.active_material.BIMMaterialProperties, 'name') + row.prop(props, 'name') -class GISPanel(bpy.types.Panel): + +class BIM_PT_gis(Panel): bl_label = 'IFC Georeferencing' bl_idname = "BIM_PT_gis" bl_space_type = 'PROPERTIES' @@ -291,27 +368,28 @@ class GISPanel(bpy.types.Panel): def draw(self, context): layout = self.layout layout.use_property_split = True - - layout.row().prop(bpy.context.scene.BIMProperties, 'has_georeferencing') + scene = context.scene + layout.row().prop(scene.BIMProperties, 'has_georeferencing') layout.label(text="Map Conversion:") - layout.row().prop(bpy.context.scene.MapConversion, 'eastings') - layout.row().prop(bpy.context.scene.MapConversion, 'northings') - layout.row().prop(bpy.context.scene.MapConversion, 'orthogonal_height') - layout.row().prop(bpy.context.scene.MapConversion, 'x_axis_abscissa') - layout.row().prop(bpy.context.scene.MapConversion, 'x_axis_ordinate') - layout.row().prop(bpy.context.scene.MapConversion, 'scale') + layout.row().prop(scene.MapConversion, 'eastings') + layout.row().prop(scene.MapConversion, 'northings') + layout.row().prop(scene.MapConversion, 'orthogonal_height') + layout.row().prop(scene.MapConversion, 'x_axis_abscissa') + layout.row().prop(scene.MapConversion, 'x_axis_ordinate') + layout.row().prop(scene.MapConversion, 'scale') layout.label(text="Target CRS:") - layout.row().prop(bpy.context.scene.TargetCRS, 'name') - layout.row().prop(bpy.context.scene.TargetCRS, 'description') - layout.row().prop(bpy.context.scene.TargetCRS, 'geodetic_datum') - layout.row().prop(bpy.context.scene.TargetCRS, 'vertical_datum') - layout.row().prop(bpy.context.scene.TargetCRS, 'map_projection') - layout.row().prop(bpy.context.scene.TargetCRS, 'map_zone') - layout.row().prop(bpy.context.scene.TargetCRS, 'map_unit') + layout.row().prop(scene.TargetCRS, 'name') + layout.row().prop(scene.TargetCRS, 'description') + layout.row().prop(scene.TargetCRS, 'geodetic_datum') + layout.row().prop(scene.TargetCRS, 'vertical_datum') + layout.row().prop(scene.TargetCRS, 'map_projection') + layout.row().prop(scene.TargetCRS, 'map_zone') + layout.row().prop(scene.TargetCRS, 'map_unit') -class BIMPanel(bpy.types.Panel): + +class BIM_PT_bim(Panel): bl_label = "Building Information Modeling" bl_idname = "BIM_PT_bim" bl_space_type = 'PROPERTIES' @@ -323,7 +401,7 @@ class BIMPanel(bpy.types.Panel): layout.use_property_split = True scene = context.scene - bim_properties = bpy.context.scene.BIMProperties + bim_properties = scene.BIMProperties layout.label(text="System Setup:") @@ -394,7 +472,8 @@ class BIMPanel(bpy.types.Panel): row.operator("bim.assign_classification") row.operator("bim.unassign_classification") -class QAPanel(bpy.types.Panel): + +class BIM_PT_qa(Panel): bl_label = "BIMTester Quality Auditing" bl_idname = "BIM_PT_qa" bl_space_type = 'PROPERTIES' @@ -432,7 +511,8 @@ class QAPanel(bpy.types.Panel): row = layout.row() row.operator("bim.select_audited") -class DiffPanel(bpy.types.Panel): + +class BIM_PT_diff(Panel): bl_label = "IFC Diff" bl_idname = "BIM_PT_diff" bl_space_type = 'PROPERTIES' @@ -444,7 +524,7 @@ class DiffPanel(bpy.types.Panel): layout.use_property_split = True scene = context.scene - bim_properties = bpy.context.scene.BIMProperties + bim_properties = scene.BIMProperties layout.label(text="IFC Diff Setup:") @@ -452,7 +532,8 @@ class DiffPanel(bpy.types.Panel): row.prop(bim_properties, "diff_json_file") row.operator("bim.select_diff_json_file", icon="FILE_FOLDER", text="") -class MVDPanel(bpy.types.Panel): + +class BIM_PT_mvd(Panel): bl_label = "Model View Definitions" bl_idname = "BIM_PT_mvd" bl_space_type = 'PROPERTIES' @@ -463,7 +544,7 @@ class MVDPanel(bpy.types.Panel): layout = self.layout scene = context.scene - bim_properties = bpy.context.scene.BIMProperties + bim_properties = scene.BIMProperties layout.label(text="Custom MVD:")