diff --git a/src/blenderbim/blenderbim/bim/module/model/handler.py b/src/blenderbim/blenderbim/bim/module/model/handler.py index a3cc58b31c..eab64e1964 100644 --- a/src/blenderbim/blenderbim/bim/module/model/handler.py +++ b/src/blenderbim/blenderbim/bim/module/model/handler.py @@ -8,16 +8,34 @@ from bpy.app.handlers import persistent @persistent def load_post(*args): - ifcopenshell.api.add_post_listener("geometry.add_representation", None, product.generate_box) + ifcopenshell.api.add_post_listener( + "geometry.add_representation", "BlenderBIM.Product.GenerateBox", product.generate_box + ) IfcStore.add_element_listener(wall.element_listener) - ifcopenshell.api.add_pre_listener("geometry.add_representation", None, wall.ensure_solid) - ifcopenshell.api.add_post_listener("geometry.add_representation", None, wall.generate_axis) - ifcopenshell.api.add_post_listener("geometry.add_representation", None, wall.calculate_quantities) - ifcopenshell.api.add_pre_listener("material.edit_layer", None, wall.DumbWallPlaner().regenerate_from_layer) - ifcopenshell.api.add_pre_listener("type.assign_type", None, wall.DumbWallPlaner().regenerate_from_type) + ifcopenshell.api.add_pre_listener( + "geometry.add_representation", "BlenderBIM.DumbWall.EnsureSolid", wall.ensure_solid + ) + ifcopenshell.api.add_post_listener( + "geometry.add_representation", "BlenderBIM.DumbWall.GenerateAxis", wall.generate_axis + ) + ifcopenshell.api.add_post_listener( + "geometry.add_representation", "BlenderBIM.DumbWall.CalculateQuantities", wall.calculate_quantities + ) + ifcopenshell.api.add_pre_listener( + "material.edit_layer", "BlenderBIM.DumbWall.RegenerateFromLayer", wall.DumbWallPlaner().regenerate_from_layer + ) + ifcopenshell.api.add_pre_listener( + "type.assign_type", "BlenderBIM.DumbWall.RegenerateFromType", wall.DumbWallPlaner().regenerate_from_type + ) IfcStore.add_element_listener(slab.element_listener) - ifcopenshell.api.add_pre_listener("geometry.add_representation", None, slab.ensure_solid) - ifcopenshell.api.add_pre_listener("material.edit_layer", None, slab.DumbSlabPlaner().regenerate_from_layer) - ifcopenshell.api.add_pre_listener("type.assign_type", None, slab.DumbSlabPlaner().regenerate_from_type) + ifcopenshell.api.add_pre_listener( + "geometry.add_representation", "BlenderBIM.DumbSlab.EnsureSolid", slab.ensure_solid + ) + ifcopenshell.api.add_pre_listener( + "material.edit_layer", "BlenderBIM.DumbSlab.RegenerateFromLayer", slab.DumbSlabPlaner().regenerate_from_layer + ) + ifcopenshell.api.add_pre_listener( + "type.assign_type", "BlenderBIM.DumbSlab.RegenerateFromType", slab.DumbSlabPlaner().regenerate_from_type + ) diff --git a/src/ifcopenshell-python/ifcopenshell/api/__init__.py b/src/ifcopenshell-python/ifcopenshell/api/__init__.py index 92d04d14ee..8343b71e8f 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/__init__.py +++ b/src/ifcopenshell-python/ifcopenshell/api/__init__.py @@ -5,23 +5,15 @@ import ifcopenshell import ifcopenshell.api -registered_ifcs = {} pre_listeners = {} post_listeners = {} def run(usecase_path, ifc_file=None, should_run_listeners=True, **settings): - ifc_key = registered_ifcs.setdefault(ifc_file, ifcopenshell.guid.new()) - if should_run_listeners: - for listener in pre_listeners.get(".".join([ifc_key, usecase_path]), []): + for listener in pre_listeners.get(usecase_path, {}).values(): listener(usecase_path, ifc_file, settings) - if None in registered_ifcs and ifc_key != registered_ifcs[None]: - global_key = registered_ifcs[None] - for listener in pre_listeners.get(".".join([global_key, usecase_path]), []): - listener(usecase_path, ifc_file, settings) - def serialise_entity_instance(entity): return {"cast_type": "entity_instance", "value": entity.id(), "Name": getattr(entity, "Name", None)} @@ -35,16 +27,16 @@ def run(usecase_path, ifc_file=None, should_run_listeners=True, **settings): vcs_settings[key] = [serialise_entity_instance(i) for i in value] if "add_representation" in usecase_path: pass - # print(ifc_key, usecase_path, "{ ... settings too complex right now ... }") + # print(usecase_path, "{ ... settings too complex right now ... }") elif "owner." in usecase_path: pass else: pass # print(vcs_settings) # try: - # print(ifc_key, usecase_path, json.dumps(vcs_settings)) + # print(usecase_path, json.dumps(vcs_settings)) # except: - # print(ifc_key, usecase_path, vcs_settings) + # print(usecase_path, vcs_settings) importlib.import_module(f"ifcopenshell.api.{usecase_path}") module, usecase = usecase_path.split(".") @@ -56,82 +48,52 @@ def run(usecase_path, ifc_file=None, should_run_listeners=True, **settings): result = usecase_class(**settings).execute() if should_run_listeners: - for listener in post_listeners.get(".".join([ifc_key, usecase_path]), []): + for listener in post_listeners.get(usecase_path, {}).values(): listener(usecase_path, ifc_file, settings) - if None in registered_ifcs and ifc_key != registered_ifcs[None]: - global_key = registered_ifcs[None] - for listener in post_listeners.get(".".join([global_key, usecase_path]), []): - listener(usecase_path, ifc_file, settings) - return result -def add_pre_listener(usecase_path, ifc_file, callback): +def add_pre_listener(usecase_path, name, callback): """Add a pre listener - There are 2 kind of listeners: - when ifc file is defined the listener will only run for specified file - when ifc file is None, the listener will run globally only based on usecase + :param usecase_path: string, ifcopenshell api use case path - :param ifc_file: ifc file object or None for global listener + :param name: string, name of listener :param callback: callback function - :return: ifc_key, uuid of listener, this is the prefix only, postfix is the usecase_path dot separated. """ - ifc_key = registered_ifcs.setdefault(ifc_file, ifcopenshell.guid.new()) - pre_listeners.setdefault(".".join([ifc_key, usecase_path]), set()).add(callback) - return ifc_key + pre_listeners.setdefault(usecase_path, {})[name] = callback -def add_post_listener(usecase_path, ifc_file, callback): +def add_post_listener(usecase_path, name, callback): """Add a post listener - There are 2 kind of listeners: - when ifc file is defined the listener will only run for specified file - when ifc file is None, the listener will run globally only based on usecase + :param usecase_path: string, ifcopenshell api use case path - :param ifc_file: ifc file object or None for global listener + :param name: string, name of listener :param callback: callback function - :return: ifc_key, uuid of listener, this is the prefix only, postfix is the usecase_path dot separated. """ - ifc_key = registered_ifcs.setdefault(ifc_file, ifcopenshell.guid.new()) - post_listeners.setdefault(".".join([ifc_key, usecase_path]), set()).add(callback) - return ifc_key + post_listeners.setdefault(usecase_path, {})[name] = callback -def remove_pre_listener(callback, usecase_path=""): +def remove_pre_listener(usecase_path, name, callback): """Remove a pre listener - :param callback: callback function to remove - :param usecase_path: string, optional, ifcopenshell api usecase path, may be prefixed with ifc_key, dot separated. - :return: + + :param usecase_path: string, ifcopenshell api use case path + :param name: string, name of listener + :param callback: callback function """ - for listener_key, callbacks in pre_listeners.items(): - if not listener_key.endswith(usecase_path): - continue - to_remove = set() - for fun in callbacks: - if fun == callback: - to_remove.add(callback) - for callback in to_remove: - pre_listeners[listener_key].remove(callback) + pre_listeners.get(usecase_path, {}).pop(name, None) -def remove_post_listener(callback, usecase_path=""): +def remove_post_listener(usecase_path, name, callback): """Remove a post listener - :param callback: callback function to remove - :param usecase_path: string, optional ifcopenshell api usecase path, may be prefixed with ifc_key, dot separated. - :return: + + :param usecase_path: string, ifcopenshell api use case path + :param name: string, name of listener + :param callback: callback function """ - for listener_key, callbacks in post_listeners.items(): - if not listener_key.endswith(usecase_path): - continue - to_remove = set() - for fun in callbacks: - if fun == callback: - to_remove.add(callback) - for callback in to_remove: - post_listeners[listener_key].remove(callback) + post_listeners.get(usecase_path, {}).pop(name, None) def remove_all_listeners(): - registered_ifcs.clear() pre_listeners.clear() post_listeners.clear()