mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 01:11:40 +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.RemoveAddress,
|
||||
operator.RemoveAddressAttribute,
|
||||
operator.RemoveApplication,
|
||||
operator.RemoveOrganisation,
|
||||
operator.RemovePerson,
|
||||
operator.RemovePersonAndOrganisation,
|
||||
@@ -61,6 +62,7 @@ classes = (
|
||||
ui.BIM_PT_owner,
|
||||
ui.BIM_PT_actor,
|
||||
ui.BIM_PT_object_actor,
|
||||
ui.BIM_PT_applications,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import ifcopenshell
|
||||
import bonsai.tool as tool
|
||||
from typing import Any, Union
|
||||
from ifcopenshell.util.doc import get_entity_doc
|
||||
from natsort import natsorted
|
||||
|
||||
|
||||
def refresh():
|
||||
@@ -340,3 +341,32 @@ class ObjectActorData:
|
||||
@classmethod
|
||||
def get_roles(cls, parent: ifcopenshell.entity_instance) -> list[Union[str, None]]:
|
||||
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 bonsai.tool as tool
|
||||
import bonsai.core.owner as core
|
||||
import ifcopenshell.api.owner
|
||||
from ifcopenshell.api.owner.add_address import ADDRESS_TYPE
|
||||
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 (element := tool.Ifc.get_entity(obj))
|
||||
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.tool as tool
|
||||
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:
|
||||
@@ -240,7 +247,7 @@ class BIM_PT_owner(bpy.types.Panel):
|
||||
|
||||
|
||||
class BIM_PT_actor(bpy.types.Panel):
|
||||
bl_label = "Actor"
|
||||
bl_label = "Actors"
|
||||
bl_idname = "BIM_PT_actor"
|
||||
bl_options = {"DEFAULT_CLOSED"}
|
||||
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["role"])
|
||||
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