mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 17:31:45 +00:00
Basic IfcApplications UI
Just so you can view IfcApplications in the project from UI Example - https://files.catbox.moe/15a72n.png
This commit is contained in:
@@ -48,6 +48,7 @@ classes = (
|
|||||||
operator.RemoveActor,
|
operator.RemoveActor,
|
||||||
operator.RemoveAddress,
|
operator.RemoveAddress,
|
||||||
operator.RemoveAddressAttribute,
|
operator.RemoveAddressAttribute,
|
||||||
|
operator.RemoveApplication,
|
||||||
operator.RemoveOrganisation,
|
operator.RemoveOrganisation,
|
||||||
operator.RemovePerson,
|
operator.RemovePerson,
|
||||||
operator.RemovePersonAndOrganisation,
|
operator.RemovePersonAndOrganisation,
|
||||||
@@ -61,6 +62,7 @@ classes = (
|
|||||||
ui.BIM_PT_owner,
|
ui.BIM_PT_owner,
|
||||||
ui.BIM_PT_actor,
|
ui.BIM_PT_actor,
|
||||||
ui.BIM_PT_object_actor,
|
ui.BIM_PT_object_actor,
|
||||||
|
ui.BIM_PT_applications,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import ifcopenshell
|
|||||||
import bonsai.tool as tool
|
import bonsai.tool as tool
|
||||||
from typing import Any, Union
|
from typing import Any, Union
|
||||||
from ifcopenshell.util.doc import get_entity_doc
|
from ifcopenshell.util.doc import get_entity_doc
|
||||||
|
from natsort import natsorted
|
||||||
|
|
||||||
|
|
||||||
def refresh():
|
def refresh():
|
||||||
@@ -340,3 +341,32 @@ class ObjectActorData:
|
|||||||
@classmethod
|
@classmethod
|
||||||
def get_roles(cls, parent: ifcopenshell.entity_instance) -> list[Union[str, None]]:
|
def get_roles(cls, parent: ifcopenshell.entity_instance) -> list[Union[str, None]]:
|
||||||
return [r.UserDefinedRole or r.Role for r in parent.Roles or []]
|
return [r.UserDefinedRole or r.Role for r in parent.Roles or []]
|
||||||
|
|
||||||
|
|
||||||
|
class ApplicationsData:
|
||||||
|
data = {}
|
||||||
|
is_loaded = False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load(cls) -> None:
|
||||||
|
cls.is_loaded = True
|
||||||
|
cls.data = {
|
||||||
|
"applications": cls.applications(),
|
||||||
|
}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def applications(cls) -> list[dict[str, Any]]:
|
||||||
|
applications: list[dict[str, Any]] = []
|
||||||
|
ifc_file = tool.Ifc.get()
|
||||||
|
for application in ifc_file.by_type("IfcApplication"):
|
||||||
|
total_inverses = ifc_file.get_total_inverses(application)
|
||||||
|
name = application.ApplicationFullName
|
||||||
|
if total_inverses == 0:
|
||||||
|
name += " (unused)"
|
||||||
|
applications.append(
|
||||||
|
{
|
||||||
|
"id": application.id(),
|
||||||
|
"name": name,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return natsorted(applications, key=lambda x: x["name"])
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
import bpy
|
import bpy
|
||||||
import bonsai.tool as tool
|
import bonsai.tool as tool
|
||||||
import bonsai.core.owner as core
|
import bonsai.core.owner as core
|
||||||
|
import ifcopenshell.api.owner
|
||||||
from ifcopenshell.api.owner.add_address import ADDRESS_TYPE
|
from ifcopenshell.api.owner.add_address import ADDRESS_TYPE
|
||||||
from typing import TYPE_CHECKING, get_args
|
from typing import TYPE_CHECKING, get_args
|
||||||
|
|
||||||
@@ -468,3 +469,55 @@ class UnassignActor(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
assert (obj := context.active_object)
|
assert (obj := context.active_object)
|
||||||
assert (element := tool.Ifc.get_entity(obj))
|
assert (element := tool.Ifc.get_entity(obj))
|
||||||
core.unassign_actor(tool.Ifc, actor=tool.Ifc.get().by_id(self.actor), element=element)
|
core.unassign_actor(tool.Ifc, actor=tool.Ifc.get().by_id(self.actor), element=element)
|
||||||
|
|
||||||
|
|
||||||
|
class RemoveApplication(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
|
bl_idname = "bim.remove_application"
|
||||||
|
bl_label = "Remove Application"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
bl_description = (
|
||||||
|
"Remove provided IfcApplication."
|
||||||
|
"\n\nFor safety will only work on applications without inverses (they are typically marked as '(unused)'."
|
||||||
|
)
|
||||||
|
application_id: bpy.props.IntProperty() # pyright: ignore[reportRedeclaration]
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
application_id: int
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def description(cls, context, properties) -> str:
|
||||||
|
description = cls.bl_description
|
||||||
|
application_id: int
|
||||||
|
if not (application_id := properties.application_id):
|
||||||
|
return description
|
||||||
|
ifc_file = tool.Ifc.get()
|
||||||
|
application = ifc_file.by_id(application_id)
|
||||||
|
|
||||||
|
application_info = "Additional application info:"
|
||||||
|
application_info += f"\n- Developer: {application.ApplicationDeveloper.Name}"
|
||||||
|
application_info += f"\n- Version: {application.Version}"
|
||||||
|
application_info += f"\n- Identifier: {application.ApplicationIdentifier}"
|
||||||
|
application_info += f"\n- Number of inverses: {ifc_file.get_total_inverses(application)}"
|
||||||
|
application_info += f"\n(try to remove application to see the full list of inverses in system console)"
|
||||||
|
|
||||||
|
description += f"\n\n{application_info}"
|
||||||
|
return description
|
||||||
|
|
||||||
|
def invoke(self, context, event):
|
||||||
|
ifc_file = tool.Ifc.get()
|
||||||
|
assert (application := ifc_file.by_id(self.application_id))
|
||||||
|
if total_inverses := ifc_file.get_total_inverses(application):
|
||||||
|
print(f"Present inverses for {application}:")
|
||||||
|
for inverse in ifc_file.get_inverse(application):
|
||||||
|
print(f"- {inverse}")
|
||||||
|
self.report(
|
||||||
|
{"ERROR"},
|
||||||
|
f"This IfcApplication still has {total_inverses} inverses, deletion is unsafe. "
|
||||||
|
"Check system console for the details.",
|
||||||
|
)
|
||||||
|
return {"CANCELLED"}
|
||||||
|
return self.execute(context)
|
||||||
|
|
||||||
|
def _execute(self, context):
|
||||||
|
ifc_file = tool.Ifc.get()
|
||||||
|
ifcopenshell.api.owner.remove_application(ifc_file, ifc_file.by_id(self.application_id))
|
||||||
|
|||||||
@@ -20,7 +20,14 @@ import bpy
|
|||||||
import bonsai.bim.helper
|
import bonsai.bim.helper
|
||||||
import bonsai.tool as tool
|
import bonsai.tool as tool
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from bonsai.bim.module.owner.data import PeopleData, OrganisationsData, OwnerData, ActorData, ObjectActorData
|
from bonsai.bim.module.owner.data import (
|
||||||
|
PeopleData,
|
||||||
|
OrganisationsData,
|
||||||
|
OwnerData,
|
||||||
|
ActorData,
|
||||||
|
ObjectActorData,
|
||||||
|
ApplicationsData,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def draw_roles(box: bpy.types.UILayout, parent: dict[str, Any]) -> None:
|
def draw_roles(box: bpy.types.UILayout, parent: dict[str, Any]) -> None:
|
||||||
@@ -240,7 +247,7 @@ class BIM_PT_owner(bpy.types.Panel):
|
|||||||
|
|
||||||
|
|
||||||
class BIM_PT_actor(bpy.types.Panel):
|
class BIM_PT_actor(bpy.types.Panel):
|
||||||
bl_label = "Actor"
|
bl_label = "Actors"
|
||||||
bl_idname = "BIM_PT_actor"
|
bl_idname = "BIM_PT_actor"
|
||||||
bl_options = {"DEFAULT_CLOSED"}
|
bl_options = {"DEFAULT_CLOSED"}
|
||||||
bl_space_type = "PROPERTIES"
|
bl_space_type = "PROPERTIES"
|
||||||
@@ -326,3 +333,32 @@ class BIM_PT_object_actor(bpy.types.Panel):
|
|||||||
row.label(text=actor["name"], icon="USER")
|
row.label(text=actor["name"], icon="USER")
|
||||||
row.label(text=actor["role"])
|
row.label(text=actor["role"])
|
||||||
row.operator("bim.unassign_actor", icon="X", text="").actor = actor["id"]
|
row.operator("bim.unassign_actor", icon="X", text="").actor = actor["id"]
|
||||||
|
|
||||||
|
|
||||||
|
class BIM_PT_applications(bpy.types.Panel):
|
||||||
|
bl_label = "Applications"
|
||||||
|
bl_idname = "BIM_PT_applications"
|
||||||
|
bl_options = {"DEFAULT_CLOSED"}
|
||||||
|
bl_space_type = "PROPERTIES"
|
||||||
|
bl_region_type = "WINDOW"
|
||||||
|
bl_context = "scene"
|
||||||
|
bl_parent_id = "BIM_PT_tab_stakeholders"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context) -> bool:
|
||||||
|
return bool(tool.Ifc.get())
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
if not ApplicationsData.is_loaded:
|
||||||
|
ApplicationsData.load()
|
||||||
|
|
||||||
|
assert (layout := self.layout)
|
||||||
|
props = tool.Owner.get_owner_props()
|
||||||
|
|
||||||
|
apps_data: list[dict[str, Any]] = ApplicationsData.data["applications"]
|
||||||
|
if not apps_data:
|
||||||
|
layout.label(text="No Applications Found")
|
||||||
|
for app_data in apps_data:
|
||||||
|
row = layout.row()
|
||||||
|
row.label(text=app_data["name"])
|
||||||
|
row.operator("bim.remove_application", icon="X", text="").application_id = app_data["id"]
|
||||||
|
|||||||
Reference in New Issue
Block a user