mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 01:11:40 +00:00
Fix #1511. Prevent double registration of listener callbacks, and simplify listeners.
This commit is contained in:
@@ -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
|
||||
)
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user