From cdf617e95b4e0dd5941bf20e6317a7a44311e663 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Tue, 11 Jul 2023 17:40:13 +1000 Subject: [PATCH] Fix registration bug that created hundreds of workspaces due to continuous triggering of the depsgraph_update. Use an is_registering check to only run the on_register once. Rename setDefaultProperties to load_post to better reflect what handler it is. Unregister our custom scene panels upon addon activation. Move aprops getting to tool.Blender because it is a bit complex. Also, aprops may not be setup until load_post is called, so the len() check protects against that. --- src/blenderbim/blenderbim/bim/__init__.py | 27 ++++++++++-- src/blenderbim/blenderbim/bim/handler.py | 2 +- .../blenderbim/bim/module/brick/ui.py | 8 ++-- .../blenderbim/bim/module/drawing/ui.py | 12 ++---- src/blenderbim/blenderbim/bim/ui.py | 41 ++++++++----------- src/blenderbim/blenderbim/tool/blender.py | 28 +++++++------ 6 files changed, 66 insertions(+), 52 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/__init__.py b/src/blenderbim/blenderbim/bim/__init__.py index 94effae58a..ce92febf26 100644 --- a/src/blenderbim/blenderbim/bim/__init__.py +++ b/src/blenderbim/blenderbim/bim/__init__.py @@ -149,12 +149,19 @@ for mod in modules.values(): addon_keymaps = [] icons = None +is_registering = False def on_register(scene): - handler.setDefaultProperties(scene) + global is_registering + + if is_registering: + return + is_registering = True + handler.load_post(scene) if not bpy.app.background: bpy.app.handlers.depsgraph_update_post.remove(on_register) + is_registering = False def register(): @@ -165,7 +172,7 @@ def register(): bpy.app.handlers.undo_post.append(handler.undo_post) bpy.app.handlers.redo_pre.append(handler.redo_pre) bpy.app.handlers.redo_post.append(handler.redo_post) - bpy.app.handlers.load_post.append(handler.setDefaultProperties) + bpy.app.handlers.load_post.append(handler.load_post) bpy.app.handlers.load_post.append(handler.loadIfcStore) bpy.app.handlers.save_post.append(handler.ensureIfcExported) bpy.types.Scene.BIMProperties = bpy.props.PointerProperty(type=prop.BIMProperties) @@ -226,7 +233,7 @@ def unregister(): if cls.is_registered is not False: bpy.utils.unregister_class(cls) - bpy.app.handlers.load_post.remove(handler.setDefaultProperties) + bpy.app.handlers.load_post.remove(handler.load_post) bpy.app.handlers.load_post.remove(handler.loadIfcStore) bpy.app.handlers.save_post.remove(handler.ensureIfcExported) del bpy.types.Scene.BIMProperties @@ -251,3 +258,17 @@ def unregister(): for km, kmi in addon_keymaps: km.keymap_items.remove(kmi) addon_keymaps.clear() + + for panel in [ + "SCENE_PT_scene", + "SCENE_PT_unit", + "SCENE_PT_physics", + "SCENE_PT_rigid_body_world", + "SCENE_PT_audio", + "SCENE_PT_keying_sets", + "SCENE_PT_custom_props", + ]: + try: + bpy.utils.unregister_class(getattr(handler, f"Override_{panel}")) + except: + pass diff --git a/src/blenderbim/blenderbim/bim/handler.py b/src/blenderbim/blenderbim/bim/handler.py index 2c6219c0c2..743fb0797d 100644 --- a/src/blenderbim/blenderbim/bim/handler.py +++ b/src/blenderbim/blenderbim/bim/handler.py @@ -351,7 +351,7 @@ if getattr(bpy.types, "SCENE_PT_custom_props"): @persistent -def setDefaultProperties(scene): +def load_post(scene): global global_subscription_owner active_object_key = bpy.types.LayerObjects, "active" bpy.msgbus.subscribe_rna( diff --git a/src/blenderbim/blenderbim/bim/module/brick/ui.py b/src/blenderbim/blenderbim/bim/module/brick/ui.py index c9dc3092f8..b769057d37 100644 --- a/src/blenderbim/blenderbim/bim/module/brick/ui.py +++ b/src/blenderbim/blenderbim/bim/module/brick/ui.py @@ -22,6 +22,7 @@ from blenderbim.bim.helper import prop_with_search from blenderbim.bim.module.brick.data import BrickschemaData, BrickschemaReferencesData from blenderbim.tool.brick import BrickStore + class BIM_PT_brickschema(Panel): bl_label = "Brickschema Project" bl_idname = "BIM_PT_brickschema" @@ -32,8 +33,7 @@ class BIM_PT_brickschema(Panel): @classmethod def poll(cls, context): - aprops = tool.Blender.get_area_properties(context) - return aprops.tab == "OTHER" or context.area.spaces.active.search_filter + return tool.Blender.is_tab(context, "OTHER") def draw(self, context): if not BrickschemaData.is_loaded: @@ -48,7 +48,7 @@ class BIM_PT_brickschema(Panel): if BrickStore.path: row = self.layout.row(align=True) - row.label(text=BrickStore.path, icon='FILEBROWSER') + row.label(text=BrickStore.path, icon="FILEBROWSER") row = self.layout.row(align=True) if len(self.props.brick_breadcrumbs): @@ -70,7 +70,7 @@ class BIM_PT_brickschema(Panel): row.prop(data=self.props, property="new_brick_namespace_alias", text="") col = row.column() col.alignment = "CENTER" - col.scale_x = 1.1 + col.scale_x = 1.1 col.label(text=":") row.prop(data=self.props, property="new_brick_namespace_uri", text="") row.operator("bim.add_brick_namespace", text="", icon="ADD") diff --git a/src/blenderbim/blenderbim/bim/module/drawing/ui.py b/src/blenderbim/blenderbim/bim/module/drawing/ui.py index 2312015be8..99510464a1 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/ui.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/ui.py @@ -167,8 +167,7 @@ class BIM_PT_drawings(Panel): @classmethod def poll(cls, context): - aprops = tool.Blender.get_area_properties(context) - return (aprops.tab == "DRAWINGS" or context.area.spaces.active.search_filter) and tool.Ifc.get() + return tool.Blender.is_tab(context, "DRAWINGS") and tool.Ifc.get() def draw(self, context): if not DrawingsData.is_loaded: @@ -236,8 +235,7 @@ class BIM_PT_schedules(Panel): @classmethod def poll(cls, context): - aprops = tool.Blender.get_area_properties(context) - return (aprops.tab == "DRAWINGS" or context.area.spaces.active.search_filter) and tool.Ifc.get() + return tool.Blender.is_tab(context, "DRAWINGS") and tool.Ifc.get() def draw(self, context): if not DocumentsData.is_loaded: @@ -292,8 +290,7 @@ class BIM_PT_references(Panel): @classmethod def poll(cls, context): - aprops = tool.Blender.get_area_properties(context) - return (aprops.tab == "DRAWINGS" or context.area.spaces.active.search_filter) and tool.Ifc.get() + return tool.Blender.is_tab(context, "DRAWINGS") and tool.Ifc.get() def draw(self, context): if not DocumentsData.is_loaded: @@ -337,8 +334,7 @@ class BIM_PT_sheets(Panel): @classmethod def poll(cls, context): - aprops = tool.Blender.get_area_properties(context) - return (aprops.tab == "DRAWINGS" or context.area.spaces.active.search_filter) and tool.Ifc.get() + return tool.Blender.is_tab(context, "DRAWINGS") and tool.Ifc.get() def draw(self, context): if not SheetsData.is_loaded: diff --git a/src/blenderbim/blenderbim/bim/ui.py b/src/blenderbim/blenderbim/bim/ui.py index 2825e20a49..4cb54da825 100644 --- a/src/blenderbim/blenderbim/bim/ui.py +++ b/src/blenderbim/blenderbim/bim/ui.py @@ -278,10 +278,13 @@ class BIM_PT_root(Panel): bl_options = {"HIDE_HEADER"} def draw(self, context): - aprops = tool.Blender.get_area_properties(context) - row = self.layout.row(align=True) - row.prop(aprops, "tab", text="") - row.operator("bim.switch_tab", text="", icon="UV_SYNC_SELECT") + try: + aprops = context.screen.BIMAreaProperties[context.screen.areas[:].index(context.area)] + row = self.layout.row(align=True) + row.prop(aprops, "tab", text="") + row.operator("bim.switch_tab", text="", icon="UV_SYNC_SELECT") + except: + pass # Prior to load_post, we may not have any area properties setup class BIM_PT_project_info(Panel): @@ -292,8 +295,7 @@ class BIM_PT_project_info(Panel): @classmethod def poll(cls, context): - aprops = tool.Blender.get_area_properties(context) - return aprops.tab == "PROJECT" or context.area.spaces.active.search_filter + return tool.Blender.is_tab(context, "PROJECT") def draw(self, context): pass @@ -308,8 +310,7 @@ class BIM_PT_project_setup(Panel): @classmethod def poll(cls, context): - aprops = tool.Blender.get_area_properties(context) - return aprops.tab == "PROJECT" or context.area.spaces.active.search_filter + return tool.Blender.is_tab(context, "PROJECT") def draw(self, context): pass @@ -324,8 +325,7 @@ class BIM_PT_collaboration(Panel): @classmethod def poll(cls, context): - aprops = tool.Blender.get_area_properties(context) - return aprops.tab == "OTHER" or context.area.spaces.active.search_filter + return tool.Blender.is_tab(context, "OTHER") def draw(self, context): pass @@ -340,8 +340,7 @@ class BIM_PT_selection(Panel): @classmethod def poll(cls, context): - aprops = tool.Blender.get_area_properties(context) - return (aprops.tab == "PROJECT" or context.area.spaces.active.search_filter) and tool.Ifc.get() + return tool.Blender.is_tab(context, "PROJECT") and tool.Ifc.get() def draw(self, context): pass @@ -356,8 +355,7 @@ class BIM_PT_geometry(Panel): @classmethod def poll(cls, context): - aprops = tool.Blender.get_area_properties(context) - return (aprops.tab == "PROJECT" or context.area.spaces.active.search_filter) and tool.Ifc.get() + return tool.Blender.is_tab(context, "PROJECT") and tool.Ifc.get() def draw(self, context): pass @@ -372,8 +370,7 @@ class BIM_PT_4D5D(Panel): @classmethod def poll(cls, context): - aprops = tool.Blender.get_area_properties(context) - return (aprops.tab == "SCHEDULING" or context.area.spaces.active.search_filter) and tool.Ifc.get() + return tool.Blender.is_tab(context, "SCHEDULING") and tool.Ifc.get() def draw(self, context): pass @@ -388,8 +385,7 @@ class BIM_PT_structural(Panel): @classmethod def poll(cls, context): - aprops = tool.Blender.get_area_properties(context) - return (aprops.tab == "STRUCTURE" or context.area.spaces.active.search_filter) and tool.Ifc.get() + return tool.Blender.is_tab(context, "STRUCTURE") and tool.Ifc.get() def draw(self, context): pass @@ -404,8 +400,7 @@ class BIM_PT_services(Panel): @classmethod def poll(cls, context): - aprops = tool.Blender.get_area_properties(context) - return (aprops.tab == "SERVICES" or context.area.spaces.active.search_filter) and tool.Ifc.get() + return tool.Blender.is_tab(context, "SERVICES") and tool.Ifc.get() def draw(self, context): pass @@ -420,8 +415,7 @@ class BIM_PT_quality_control(Panel): @classmethod def poll(cls, context): - aprops = tool.Blender.get_area_properties(context) - return aprops.tab == "OTHER" or context.area.spaces.active.search_filter + return tool.Blender.is_tab(context, "OTHER") def draw(self, context): pass @@ -436,8 +430,7 @@ class BIM_PT_integrations(Panel): @classmethod def poll(cls, context): - aprops = tool.Blender.get_area_properties(context) - return aprops.tab == "OTHER" or context.area.spaces.active.search_filter + return tool.Blender.is_tab(context, "OTHER") def draw(self, context): pass diff --git a/src/blenderbim/blenderbim/tool/blender.py b/src/blenderbim/blenderbim/tool/blender.py index 453a97e9c2..c831942387 100644 --- a/src/blenderbim/blenderbim/tool/blender.py +++ b/src/blenderbim/blenderbim/tool/blender.py @@ -41,6 +41,22 @@ class Blender: bpy.context.view_layer.objects.active = obj obj.select_set(True) + @classmethod + def is_tab(cls, context, tab): + if not len(context.screen.BIMAreaProperties): + return None + if context.area.spaces.active.search_filter: + return True + screen_areas = context.screen.areas[:] + current_area = context.area + # If the user is using the properties panel "Display Filter" search it + # will create a new area that's not present in context.screen.areas for + # all property tabs except for the active property tab. + if current_area not in screen_areas: + current_area = next(a for a in context.screen.areas if a.x == current_area.x and a.y == current_area.y) + area_index = screen_areas.index(current_area) + return context.screen.BIMAreaProperties[area_index].tab == tab + @classmethod def get_name(cls, ifc_class, name): if not bpy.data.objects.get(f"{ifc_class}/{name}"): @@ -151,18 +167,6 @@ class Blender: for attr in VIEWPORT_ATTRIBUTES: setattr(region_3d, attr, data[attr]) - @classmethod - def get_area_properties(cls, context): - areas = context.screen.areas[:] - current_area = context.area - # if user is using search from different properties tab (not SCENE) - # it will create new area that's not present in context.screen.areas - if current_area not in areas: - current_area = next(a for a in context.screen.areas if a.x == current_area.x and a.y == current_area.y) - area_i = areas.index(current_area) - - return context.screen.BIMAreaProperties[area_i] - @classmethod def get_shader_editor_context(cls): for screen in bpy.data.screens: