mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 01:41:57 +00:00
Organisations now support null attributes.
This commit is contained in:
@@ -20,7 +20,6 @@ import bpy
|
||||
from . import ui, prop, operator
|
||||
|
||||
classes = (
|
||||
operator.AddOrRemoveElementFromCollection,
|
||||
operator.EnableEditingPerson,
|
||||
operator.DisableEditingPerson,
|
||||
operator.AddPerson,
|
||||
@@ -45,8 +44,6 @@ classes = (
|
||||
operator.RemoveAddressAttribute,
|
||||
operator.EditAddress,
|
||||
operator.RemoveAddress,
|
||||
prop.Person,
|
||||
prop.Organisation,
|
||||
prop.BIMOwnerProperties,
|
||||
ui.BIM_PT_people,
|
||||
ui.BIM_PT_organisations,
|
||||
|
||||
@@ -20,7 +20,60 @@ import bpy
|
||||
import blenderbim.tool as tool
|
||||
|
||||
|
||||
class PeopleData:
|
||||
class RolesAddressesData:
|
||||
@classmethod
|
||||
def get_roles(cls, parent):
|
||||
results = []
|
||||
for role in parent.Roles or []:
|
||||
results.append(
|
||||
{
|
||||
"id": role.id(),
|
||||
"is_editing": bpy.context.scene.BIMOwnerProperties.active_role_id == role.id(),
|
||||
"label": role.UserDefinedRole or role.Role,
|
||||
"props": bpy.context.scene.BIMOwnerProperties.role_attributes,
|
||||
}
|
||||
)
|
||||
return results
|
||||
|
||||
@classmethod
|
||||
def get_addresses(cls, parent):
|
||||
results = []
|
||||
for address in parent.Addresses or []:
|
||||
results.append(
|
||||
{
|
||||
"id": address.id(),
|
||||
"is_editing": bpy.context.scene.BIMOwnerProperties.active_address_id == address.id(),
|
||||
"label": address.is_a(),
|
||||
"props": bpy.context.scene.BIMOwnerProperties.address_attributes,
|
||||
"list_attributes": cls.get_address_list_attributes(address),
|
||||
}
|
||||
)
|
||||
return results
|
||||
|
||||
@classmethod
|
||||
def get_address_list_attributes(cls, address):
|
||||
results = []
|
||||
props = bpy.context.scene.BIMOwnerProperties
|
||||
if address.is_a("IfcPostalAddress"):
|
||||
names = ["AddressLines"]
|
||||
elif address.is_a("IfcTelecomAddress"):
|
||||
names = ["TelephoneNumbers", "FacsimileNumbers", "ElectronicMailAddresses", "MessagingIDs"]
|
||||
for name in names:
|
||||
if name == "AddressLines":
|
||||
items = [{"id": id, "prop": prop} for id, prop in enumerate(props.address_lines)]
|
||||
elif name == "TelephoneNumbers":
|
||||
items = [{"id": id, "prop": prop} for id, prop in enumerate(props.telephone_numbers)]
|
||||
elif name == "FacsimileNumbers":
|
||||
items = [{"id": id, "prop": prop} for id, prop in enumerate(props.facsimile_numbers)]
|
||||
elif name == "ElectronicMailAddresses":
|
||||
items = [{"id": id, "prop": prop} for id, prop in enumerate(props.electronic_mail_addresses)]
|
||||
elif name == "MessagingIDs":
|
||||
items = [{"id": id, "prop": prop} for id, prop in enumerate(props.messaging_ids)]
|
||||
results.append({"name": name, "items": items})
|
||||
return results
|
||||
|
||||
|
||||
class PeopleData(RolesAddressesData):
|
||||
data = {}
|
||||
is_loaded = False
|
||||
|
||||
@@ -41,8 +94,8 @@ class PeopleData:
|
||||
"is_editing": cls.get_person_is_editing(person),
|
||||
"is_engaged": bool(person.EngagedIn),
|
||||
"list_attributes": cls.get_person_list_attributes(person),
|
||||
"roles": cls.get_person_roles(person),
|
||||
"addresses": cls.get_person_addresses(person),
|
||||
"roles": cls.get_roles(person),
|
||||
"addresses": cls.get_addresses(person),
|
||||
}
|
||||
)
|
||||
return people
|
||||
@@ -77,53 +130,29 @@ class PeopleData:
|
||||
results.append({"name": name, "items": items})
|
||||
return results
|
||||
|
||||
@classmethod
|
||||
def get_person_roles(cls, person):
|
||||
results = []
|
||||
for role in person.Roles or []:
|
||||
results.append(
|
||||
{
|
||||
"id": role.id(),
|
||||
"is_editing": bpy.context.scene.BIMOwnerProperties.active_role_id == role.id(),
|
||||
"label": role.UserDefinedRole or role.Role,
|
||||
"props": bpy.context.scene.BIMOwnerProperties.role_attributes,
|
||||
}
|
||||
)
|
||||
return results
|
||||
|
||||
class OrganisationsData(RolesAddressesData):
|
||||
data = {}
|
||||
is_loaded = False
|
||||
|
||||
@classmethod
|
||||
def get_person_addresses(cls, person):
|
||||
results = []
|
||||
for address in person.Addresses or []:
|
||||
results.append(
|
||||
{
|
||||
"id": address.id(),
|
||||
"is_editing": bpy.context.scene.BIMOwnerProperties.active_address_id == address.id(),
|
||||
"label": address.is_a(),
|
||||
"props": bpy.context.scene.BIMOwnerProperties.address_attributes,
|
||||
"list_attributes": cls.get_address_list_attributes(address),
|
||||
}
|
||||
)
|
||||
return results
|
||||
def load(cls):
|
||||
cls.data = {"organisations": cls.get_organisations()}
|
||||
cls.is_loaded = True
|
||||
|
||||
@classmethod
|
||||
def get_address_list_attributes(cls, address):
|
||||
results = []
|
||||
props = bpy.context.scene.BIMOwnerProperties
|
||||
if address.is_a("IfcPostalAddress"):
|
||||
names = ["AddressLines"]
|
||||
elif address.is_a("IfcTelecomAddress"):
|
||||
names = ["TelephoneNumbers", "FacsimileNumbers", "ElectronicMailAddresses", "MessagingIDs"]
|
||||
for name in names:
|
||||
if name == "AddressLines":
|
||||
items = [{"id": id, "prop": prop} for id, prop in enumerate(props.address_lines)]
|
||||
elif name == "TelephoneNumbers":
|
||||
items = [{"id": id, "prop": prop} for id, prop in enumerate(props.telephone_numbers)]
|
||||
elif name == "FacsimileNumbers":
|
||||
items = [{"id": id, "prop": prop} for id, prop in enumerate(props.facsimile_numbers)]
|
||||
elif name == "ElectronicMailAddresses":
|
||||
items = [{"id": id, "prop": prop} for id, prop in enumerate(props.electronic_mail_addresses)]
|
||||
elif name == "MessagingIDs":
|
||||
items = [{"id": id, "prop": prop} for id, prop in enumerate(props.messaging_ids)]
|
||||
results.append({"name": name, "items": items})
|
||||
return results
|
||||
def get_organisations(cls):
|
||||
organisations = []
|
||||
for organisation in tool.Ifc().get().by_type("IfcOrganization"):
|
||||
organisations.append(
|
||||
{
|
||||
"id": organisation.id(),
|
||||
"props": bpy.context.scene.BIMOwnerProperties.organisation_attributes,
|
||||
"name": organisation.Name,
|
||||
"is_editing": bpy.context.scene.BIMOwnerProperties.active_organisation_id == organisation.id(),
|
||||
"is_engaged": bool(organisation.Engages),
|
||||
"roles": cls.get_roles(organisation),
|
||||
"addresses": cls.get_addresses(organisation),
|
||||
}
|
||||
)
|
||||
return organisations
|
||||
|
||||
@@ -30,43 +30,7 @@ class Operator:
|
||||
def execute(self, context):
|
||||
IfcStore.execute_ifc_operator(self, context)
|
||||
blenderbim.bim.module.owner.data.PeopleData.is_loaded = False
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
def flatten_collection(collection):
|
||||
return [v.name for v in collection] if collection else None
|
||||
|
||||
|
||||
def populate_collection(collection, collection_data):
|
||||
collection.clear()
|
||||
if collection_data:
|
||||
for value in collection_data:
|
||||
collection.add().name = value
|
||||
else:
|
||||
collection.add()
|
||||
|
||||
|
||||
class AddOrRemoveElementFromCollection(bpy.types.Operator):
|
||||
bl_idname = "bim.add_or_remove_element_from_collection"
|
||||
bl_label = "Add or Remove Element From Collection"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
operation: bpy.props.EnumProperty(
|
||||
items=(("+", "Add", "Add item to collection"), ("-", "Remove", "Remove item from collection")),
|
||||
default="+",
|
||||
)
|
||||
collection_path: bpy.props.StringProperty()
|
||||
selected_item_idx: bpy.props.IntProperty(default=-1)
|
||||
|
||||
def execute(self, context):
|
||||
# Ugly but I hate using eval()
|
||||
collection = context.scene
|
||||
for attr in self.collection_path.split("."):
|
||||
if hasattr(collection, attr):
|
||||
collection = getattr(collection, attr)
|
||||
if self.operation == "+" and hasattr(collection, "add"):
|
||||
collection.add()
|
||||
elif hasattr(collection, "remove") and 0 <= self.selected_item_idx < len(collection):
|
||||
collection.remove(self.selected_item_idx)
|
||||
blenderbim.bim.module.owner.data.OrganisationsData.is_loaded = False
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -256,90 +220,50 @@ class RemoveAddress(bpy.types.Operator, Operator):
|
||||
core.remove_address(tool.Ifc(), address=tool.Ifc().get().by_id(self.address))
|
||||
|
||||
|
||||
class EnableEditingOrganisation(bpy.types.Operator):
|
||||
class EnableEditingOrganisation(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.enable_editing_organisation"
|
||||
bl_label = "Enable Editing Organisation"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
organisation_id: bpy.props.IntProperty()
|
||||
organisation: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
self.file = IfcStore.get_file()
|
||||
props = context.scene.BIMOwnerProperties
|
||||
props.active_organisation_id = self.organisation_id
|
||||
data = Data.organisations[self.organisation_id]
|
||||
identification = data["Id"] if self.file.schema == "IFC2X3" else data["Identification"]
|
||||
props.organisation.identification = identification or ""
|
||||
props.organisation.name = data["Name"]
|
||||
props.organisation.description = data["Description"] or ""
|
||||
return {"FINISHED"}
|
||||
def _execute(self, context):
|
||||
core.enable_editing_organisation(
|
||||
tool.OrganisationEditor, organisation=tool.Ifc().get().by_id(self.organisation)
|
||||
)
|
||||
|
||||
|
||||
class DisableEditingOrganisation(bpy.types.Operator):
|
||||
class DisableEditingOrganisation(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.disable_editing_organisation"
|
||||
bl_label = "Disable Editing Organisation"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
context.scene.BIMOwnerProperties.active_organisation_id = 0
|
||||
return {"FINISHED"}
|
||||
def _execute(self, context):
|
||||
core.disable_editing_organisation(tool.OrganisationEditor)
|
||||
|
||||
|
||||
class AddOrganisation(bpy.types.Operator):
|
||||
class AddOrganisation(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.add_organisation"
|
||||
bl_label = "Add Organisation"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
return IfcStore.execute_ifc_operator(self, context)
|
||||
|
||||
def _execute(self, context):
|
||||
ifcopenshell.api.run("owner.add_organisation", IfcStore.get_file())
|
||||
Data.load(IfcStore.get_file())
|
||||
return {"FINISHED"}
|
||||
core.add_organisation(tool.Ifc)
|
||||
|
||||
|
||||
class EditOrganisation(bpy.types.Operator):
|
||||
class EditOrganisation(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.edit_organisation"
|
||||
bl_label = "Edit Organisation"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
return IfcStore.execute_ifc_operator(self, context)
|
||||
|
||||
def _execute(self, context):
|
||||
self.file = IfcStore.get_file()
|
||||
props = context.scene.BIMOwnerProperties
|
||||
attributes = {
|
||||
"Identification": props.organisation.identification or None,
|
||||
"Name": props.organisation.name,
|
||||
"Description": props.organisation.description or None,
|
||||
}
|
||||
if self.file.schema == "IFC2X3":
|
||||
attributes["Id"] = attributes["Identification"]
|
||||
del attributes["Identification"]
|
||||
ifcopenshell.api.run(
|
||||
"owner.edit_organisation",
|
||||
self.file,
|
||||
**{"organisation": self.file.by_id(props.active_organisation_id), "attributes": attributes}
|
||||
)
|
||||
Data.load(IfcStore.get_file())
|
||||
bpy.ops.bim.disable_editing_organisation()
|
||||
return {"FINISHED"}
|
||||
core.edit_organisation(tool.Ifc, tool.OrganisationEditor)
|
||||
|
||||
|
||||
class RemoveOrganisation(bpy.types.Operator):
|
||||
class RemoveOrganisation(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.remove_organisation"
|
||||
bl_label = "Remove Organisation"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
organisation_id: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
return IfcStore.execute_ifc_operator(self, context)
|
||||
organisation: bpy.props.IntProperty()
|
||||
|
||||
def _execute(self, context):
|
||||
self.file = IfcStore.get_file()
|
||||
ifcopenshell.api.run(
|
||||
"owner.remove_organisation", self.file, **{"organisation": self.file.by_id(self.organisation_id)}
|
||||
)
|
||||
Data.load(IfcStore.get_file())
|
||||
return {"FINISHED"}
|
||||
core.remove_organisation(tool.Ifc, tool.Ifc.get().by_id(self.organisation))
|
||||
|
||||
@@ -67,30 +67,14 @@ def getOrganisations(self, context):
|
||||
return _organisations_enum
|
||||
|
||||
|
||||
class Organisation(PropertyGroup):
|
||||
identification: StringProperty(name="Identification")
|
||||
name: StringProperty(name="Name")
|
||||
description: StringProperty(name="Description")
|
||||
|
||||
|
||||
class Person(PropertyGroup):
|
||||
name: StringProperty(name="Identification")
|
||||
family_name: StringProperty(name="Family Name")
|
||||
given_name: StringProperty(name="Given Name")
|
||||
middle_names: CollectionProperty(type=StrProperty, name="Middle Names")
|
||||
prefix_titles: CollectionProperty(type=StrProperty, name="Prefixes")
|
||||
suffix_titles: CollectionProperty(type=StrProperty, name="Suffixes")
|
||||
|
||||
|
||||
class BIMOwnerProperties(PropertyGroup):
|
||||
person: PointerProperty(type=Person)
|
||||
person_attributes: CollectionProperty(name="Person Attributes", type=Attribute)
|
||||
middle_names: CollectionProperty(type=StrProperty, name="Middle Names")
|
||||
prefix_titles: CollectionProperty(type=StrProperty, name="Prefixes")
|
||||
suffix_titles: CollectionProperty(type=StrProperty, name="Suffixes")
|
||||
active_person_id: IntProperty(name="Active Person Id")
|
||||
organisation: PointerProperty(type=Organisation)
|
||||
active_organisation_id: IntProperty(name="Active Organisation Id")
|
||||
organisation_attributes: CollectionProperty(name="Organisation Attributes", type=Attribute)
|
||||
active_role_id: IntProperty(name="Active Role Id")
|
||||
role_attributes: CollectionProperty(name="Role Attributes", type=Attribute)
|
||||
active_address_id: IntProperty(name="Active Address Id")
|
||||
|
||||
@@ -19,103 +19,70 @@
|
||||
import bpy
|
||||
import blenderbim.bim.helper
|
||||
import blenderbim.tool as tool
|
||||
from blenderbim.bim.module.owner.data import PeopleData
|
||||
from blenderbim.bim.module.owner.data import PeopleData, OrganisationsData
|
||||
from bpy.types import Panel
|
||||
from ifcopenshell.api.owner.data import Data
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
|
||||
|
||||
def draw_string_collection(layout, owner, collection_name):
|
||||
column = layout.column(align=True)
|
||||
collection = getattr(owner, collection_name)
|
||||
for i in range(len(collection)):
|
||||
if i == 0:
|
||||
row = draw_prop_on_new_row(
|
||||
column, collection[i], "name", align=True, text=f"{owner.bl_rna.properties[collection_name].name}"
|
||||
)
|
||||
add_op = row.operator("bim.add_or_remove_element_from_collection", icon="ADD", text="")
|
||||
add_op.operation = "+"
|
||||
add_op.collection_path = collection.path_from_id()
|
||||
else:
|
||||
row = draw_prop_on_new_row(column, collection[i], "name", align=True, text=f"#{i + 1}")
|
||||
rem_op = row.operator("bim.add_or_remove_element_from_collection", icon="REMOVE", text="")
|
||||
rem_op.operation = "-"
|
||||
rem_op.collection_path = collection.path_from_id()
|
||||
rem_op.selected_item_idx = i
|
||||
|
||||
|
||||
def draw_prop_on_new_row(layout, owner, attribute, align=False, **kwargs):
|
||||
row = layout.row(align=align)
|
||||
row.prop(owner, attribute, **kwargs)
|
||||
return row
|
||||
|
||||
|
||||
def draw_roles_ui(box, assigned_object_id, roles, context):
|
||||
props = context.scene.BIMOwnerProperties
|
||||
def draw_roles(box, parent):
|
||||
row = box.row(align=True)
|
||||
row.label(text="Roles")
|
||||
row.operator("bim.add_role", icon="ADD", text="").assigned_object_id = assigned_object_id
|
||||
for role_id in roles:
|
||||
role = Data.roles[role_id]
|
||||
if props.active_role_id == role_id:
|
||||
blender_role = props.role
|
||||
box2 = box.box()
|
||||
row = draw_prop_on_new_row(box2, blender_role, "name", align=True, icon="MOD_CLOTH", text="")
|
||||
row.operator("bim.edit_role", icon="CHECKMARK", text="")
|
||||
op = row.operator("bim.add_role", icon="ADD", text="")
|
||||
op.parent = parent["id"]
|
||||
|
||||
for role in parent["roles"]:
|
||||
if role["is_editing"]:
|
||||
row = box.row(align=True)
|
||||
row.operator("bim.edit_role", icon="CHECKMARK")
|
||||
row.operator("bim.disable_editing_role", icon="CANCEL", text="")
|
||||
if blender_role.name == "USERDEFINED":
|
||||
draw_prop_on_new_row(box2, blender_role, "user_defined_role")
|
||||
draw_prop_on_new_row(box2, blender_role, "description")
|
||||
blenderbim.bim.helper.draw_attributes(role["props"], box)
|
||||
else:
|
||||
row = box.row(align=True)
|
||||
row.label(text=role["UserDefinedRole"] or role["Role"])
|
||||
row.operator("bim.enable_editing_role", icon="GREASEPENCIL", text="").role_id = role_id
|
||||
row.operator("bim.remove_role", icon="X", text="").role_id = role_id
|
||||
row.label(text=role["label"])
|
||||
row.operator("bim.enable_editing_role", icon="GREASEPENCIL", text="").role = role["id"]
|
||||
row.operator("bim.remove_role", icon="X", text="").role = role["id"]
|
||||
|
||||
|
||||
def draw_addresses_ui(box, assigned_object_id, addresses, file, context):
|
||||
props = context.scene.BIMOwnerProperties
|
||||
def draw_addresses(box, parent):
|
||||
row = box.row(align=True)
|
||||
row.label(text="Addresses")
|
||||
op = row.operator("bim.add_address", icon="LINK_BLEND", text="")
|
||||
op.assigned_object_id = assigned_object_id
|
||||
op.parent = parent["id"]
|
||||
op.ifc_class = "IfcTelecomAddress"
|
||||
op = row.operator("bim.add_address", icon="APPEND_BLEND", text="")
|
||||
op.assigned_object_id = assigned_object_id
|
||||
op.parent = parent["id"]
|
||||
op.ifc_class = "IfcPostalAddress"
|
||||
for address_id in addresses:
|
||||
address = Data.addresses[address_id]
|
||||
if props.active_address_id == address_id:
|
||||
blender_address = props.address
|
||||
box2 = box.box()
|
||||
row = draw_prop_on_new_row(box2, blender_address, "purpose", align=True, icon="MOD_CLOTH", text="")
|
||||
row.operator("bim.edit_address", icon="CHECKMARK", text="")
|
||||
row.operator("bim.disable_editing_address", icon="CANCEL", text="")
|
||||
if blender_address.purpose == "USERDEFINED":
|
||||
draw_prop_on_new_row(box2, blender_address, "user_defined_purpose")
|
||||
draw_prop_on_new_row(box2, blender_address, "description")
|
||||
|
||||
if address["type"] == "IfcTelecomAddress":
|
||||
draw_string_collection(box2, blender_address, "telephone_numbers")
|
||||
draw_string_collection(box2, blender_address, "facsimile_numbers")
|
||||
draw_prop_on_new_row(box2, blender_address, "pager_number")
|
||||
draw_string_collection(box2, blender_address, "electronic_mail_addresses")
|
||||
draw_prop_on_new_row(box2, blender_address, "www_home_page_url")
|
||||
if file.schema != "IFC2X3":
|
||||
draw_string_collection(box2, blender_address, "messaging_ids")
|
||||
elif address["type"] == "IfcPostalAddress":
|
||||
draw_prop_on_new_row(box2, blender_address, "internal_location")
|
||||
draw_string_collection(box2, blender_address, "address_lines")
|
||||
draw_prop_on_new_row(box2, blender_address, "postal_box")
|
||||
draw_prop_on_new_row(box2, blender_address, "town")
|
||||
draw_prop_on_new_row(box2, blender_address, "region")
|
||||
draw_prop_on_new_row(box2, blender_address, "postal_code")
|
||||
draw_prop_on_new_row(box2, blender_address, "country")
|
||||
for address in parent["addresses"]:
|
||||
if address["is_editing"]:
|
||||
row = box.row(align=True)
|
||||
row.operator("bim.edit_address", icon="CHECKMARK")
|
||||
row.operator("bim.disable_editing_address", icon="CANCEL", text="")
|
||||
blenderbim.bim.helper.draw_attributes(address["props"], box)
|
||||
for attribute in address["list_attributes"]:
|
||||
row = box.row(align=True)
|
||||
row.label(text=attribute["name"])
|
||||
op = row.operator("bim.add_address_attribute", icon="ADD", text="")
|
||||
op.name = attribute["name"]
|
||||
|
||||
for item in attribute["items"]:
|
||||
row = box.row(align=True)
|
||||
row.prop(item["prop"], "name", text="")
|
||||
op = row.operator("bim.remove_address_attribute", icon="REMOVE", text="")
|
||||
op.name = attribute["name"]
|
||||
op.id = item["id"]
|
||||
else:
|
||||
row = box.row(align=True)
|
||||
row.label(text=address["type"])
|
||||
row.operator("bim.enable_editing_address", icon="GREASEPENCIL", text="").address_id = address_id
|
||||
row.operator("bim.remove_address", icon="X", text="").address_id = address_id
|
||||
row.label(text=address["label"])
|
||||
row.operator("bim.enable_editing_address", icon="GREASEPENCIL", text="").address = address["id"]
|
||||
row.operator("bim.remove_address", icon="X", text="").address = address["id"]
|
||||
|
||||
|
||||
class BIM_PT_people(bpy.types.Panel):
|
||||
@@ -164,8 +131,8 @@ class BIM_PT_people(bpy.types.Panel):
|
||||
op.name = attribute["name"]
|
||||
op.id = item["id"]
|
||||
|
||||
self.draw_roles(box, person)
|
||||
self.draw_addresses(box, person)
|
||||
draw_roles(box, person)
|
||||
draw_addresses(box, person)
|
||||
else:
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text=person["name"])
|
||||
@@ -173,58 +140,6 @@ class BIM_PT_people(bpy.types.Panel):
|
||||
if not person["is_engaged"]:
|
||||
row.operator("bim.remove_person", icon="X", text="").person = person["id"]
|
||||
|
||||
def draw_roles(self, box, person):
|
||||
row = box.row(align=True)
|
||||
row.label(text="Roles")
|
||||
op = row.operator("bim.add_role", icon="ADD", text="")
|
||||
op.parent = person["id"]
|
||||
|
||||
for role in person["roles"]:
|
||||
if role["is_editing"]:
|
||||
row = box.row(align=True)
|
||||
row.operator("bim.edit_role", icon="CHECKMARK")
|
||||
row.operator("bim.disable_editing_role", icon="CANCEL", text="")
|
||||
blenderbim.bim.helper.draw_attributes(role["props"], box)
|
||||
else:
|
||||
row = box.row(align=True)
|
||||
row.label(text=role["label"])
|
||||
row.operator("bim.enable_editing_role", icon="GREASEPENCIL", text="").role = role["id"]
|
||||
row.operator("bim.remove_role", icon="X", text="").role = role["id"]
|
||||
|
||||
def draw_addresses(self, box, person):
|
||||
row = box.row(align=True)
|
||||
row.label(text="Addresses")
|
||||
op = row.operator("bim.add_address", icon="LINK_BLEND", text="")
|
||||
op.parent = person["id"]
|
||||
op.ifc_class = "IfcTelecomAddress"
|
||||
op = row.operator("bim.add_address", icon="APPEND_BLEND", text="")
|
||||
op.parent = person["id"]
|
||||
op.ifc_class = "IfcPostalAddress"
|
||||
|
||||
for address in person["addresses"]:
|
||||
if address["is_editing"]:
|
||||
row = box.row(align=True)
|
||||
row.operator("bim.edit_address", icon="CHECKMARK")
|
||||
row.operator("bim.disable_editing_address", icon="CANCEL", text="")
|
||||
blenderbim.bim.helper.draw_attributes(address["props"], box)
|
||||
for attribute in address["list_attributes"]:
|
||||
row = box.row(align=True)
|
||||
row.label(text=attribute["name"])
|
||||
op = row.operator("bim.add_address_attribute", icon="ADD", text="")
|
||||
op.name = attribute["name"]
|
||||
|
||||
for item in attribute["items"]:
|
||||
row = box.row(align=True)
|
||||
row.prop(item["prop"], "name", text="")
|
||||
op = row.operator("bim.remove_address_attribute", icon="REMOVE", text="")
|
||||
op.name = attribute["name"]
|
||||
op.id = item["id"]
|
||||
else:
|
||||
row = box.row(align=True)
|
||||
row.label(text=address["label"])
|
||||
row.operator("bim.enable_editing_address", icon="GREASEPENCIL", text="").address = address["id"]
|
||||
row.operator("bim.remove_address", icon="X", text="").address = address["id"]
|
||||
|
||||
|
||||
class BIM_PT_organisations(Panel):
|
||||
bl_label = "IFC Organisations"
|
||||
@@ -239,40 +154,35 @@ class BIM_PT_organisations(Panel):
|
||||
return IfcStore.get_file()
|
||||
|
||||
def draw(self, context):
|
||||
if not Data.is_loaded:
|
||||
Data.load(IfcStore.get_file())
|
||||
if not OrganisationsData.is_loaded:
|
||||
OrganisationsData.load()
|
||||
|
||||
self.file = IfcStore.get_file()
|
||||
self.layout.use_property_split = True
|
||||
self.layout.use_property_decorate = False
|
||||
props = context.scene.BIMOwnerProperties
|
||||
|
||||
row = self.layout.row()
|
||||
row.operator("bim.add_organisation", icon="ADD")
|
||||
|
||||
for organisation_id, organisation in Data.organisations.items():
|
||||
if props.active_organisation_id == organisation_id:
|
||||
blender_organisation = props.organisation
|
||||
box = self.layout.box()
|
||||
row = box.row(align=True)
|
||||
row.prop(blender_organisation, "name", icon="USER", text="")
|
||||
row.operator("bim.edit_organisation", icon="CHECKMARK", text="")
|
||||
row.operator("bim.disable_editing_organisation", icon="CANCEL", text="")
|
||||
draw_prop_on_new_row(box, blender_organisation, "identification")
|
||||
draw_prop_on_new_row(box, blender_organisation, "description")
|
||||
for organisation in OrganisationsData.data["organisations"]:
|
||||
self.draw_organisation(organisation)
|
||||
|
||||
draw_roles_ui(box, organisation_id, organisation["Roles"], context)
|
||||
draw_addresses_ui(box, organisation_id, organisation["Addresses"], self.file, context)
|
||||
else:
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text=organisation["Name"])
|
||||
if organisation["Roles"]:
|
||||
row.label(text=", ".join([Data.roles[r]["Role"] for r in organisation["Roles"]]))
|
||||
row.operator(
|
||||
"bim.enable_editing_organisation", icon="GREASEPENCIL", text=""
|
||||
).organisation_id = organisation_id
|
||||
if not organisation["is_engaged"]:
|
||||
row.operator("bim.remove_organisation", icon="X", text="").organisation_id = organisation_id
|
||||
def draw_organisation(self, organisation):
|
||||
if organisation["is_editing"]:
|
||||
box = self.layout.box()
|
||||
row = box.row(align=True)
|
||||
row.operator("bim.edit_organisation", icon="CHECKMARK")
|
||||
row.operator("bim.disable_editing_organisation", icon="CANCEL", text="")
|
||||
blenderbim.bim.helper.draw_attributes(organisation["props"], box)
|
||||
|
||||
draw_roles(box, organisation)
|
||||
draw_addresses(box, organisation)
|
||||
else:
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text=organisation["name"])
|
||||
op = row.operator("bim.enable_editing_organisation", icon="GREASEPENCIL", text="")
|
||||
op.organisation = organisation["id"]
|
||||
if not organisation["is_engaged"]:
|
||||
row.operator("bim.remove_organisation", icon="X", text="").organisation = organisation["id"]
|
||||
|
||||
|
||||
class BIM_PT_owner(Panel):
|
||||
|
||||
@@ -98,3 +98,26 @@ def add_address_attribute(address_editor, name=None):
|
||||
|
||||
def remove_address_attribute(address_editor, name=None, id=None):
|
||||
address_editor.remove_attribute(name, id)
|
||||
|
||||
|
||||
def add_organisation(ifc):
|
||||
return ifc.run("owner.add_organisation")
|
||||
|
||||
|
||||
def remove_organisation(ifc, organisation=None):
|
||||
ifc.run("owner.remove_organisation", organisation=organisation)
|
||||
|
||||
|
||||
def enable_editing_organisation(organisation_editor, organisation=None):
|
||||
organisation_editor.set_organisation(organisation)
|
||||
organisation_editor.import_attributes()
|
||||
|
||||
|
||||
def disable_editing_organisation(organisation_editor):
|
||||
organisation_editor.clear_organisation()
|
||||
|
||||
|
||||
def edit_organisation(ifc, organisation_editor):
|
||||
organisation = organisation_editor.get_organisation()
|
||||
ifc.run("owner.edit_organisation", organisation=organisation, attributes=organisation_editor.export_attributes())
|
||||
organisation_editor.clear_organisation()
|
||||
|
||||
@@ -21,3 +21,4 @@ from blenderbim.core.tool.blender import Blender
|
||||
from blenderbim.core.tool.person_editor import PersonEditor
|
||||
from blenderbim.core.tool.role_editor import RoleEditor
|
||||
from blenderbim.core.tool.address_editor import AddressEditor
|
||||
from blenderbim.core.tool.organisation_editor import OrganisationEditor
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of BlenderBIM Add-on.
|
||||
#
|
||||
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# BlenderBIM Add-on is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import abc
|
||||
|
||||
|
||||
class OrganisationEditor(abc.ABC):
|
||||
@classmethod
|
||||
@abc.abstractmethod
|
||||
def set_organisation(cls, organisation):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
@abc.abstractmethod
|
||||
def import_attributes(cls):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
@abc.abstractmethod
|
||||
def clear_organisation(cls):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
@abc.abstractmethod
|
||||
def get_organisation(cls):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
@abc.abstractmethod
|
||||
def export_attributes(cls):
|
||||
pass
|
||||
@@ -21,3 +21,4 @@ from blenderbim.tool.blender import Blender
|
||||
from blenderbim.tool.person_editor import PersonEditor
|
||||
from blenderbim.tool.role_editor import RoleEditor
|
||||
from blenderbim.tool.address_editor import AddressEditor
|
||||
from blenderbim.tool.organisation_editor import OrganisationEditor
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of BlenderBIM Add-on.
|
||||
#
|
||||
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# BlenderBIM Add-on is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import bpy
|
||||
import ifcopenshell.api
|
||||
import blenderbim.core.tool
|
||||
import blenderbim.bim.helper
|
||||
import blenderbim.tool as tool
|
||||
|
||||
|
||||
class OrganisationEditor(blenderbim.core.tool.organisation_editor.OrganisationEditor):
|
||||
@classmethod
|
||||
def set_organisation(cls, organisation):
|
||||
bpy.context.scene.BIMOwnerProperties.active_organisation_id = organisation.id()
|
||||
|
||||
@classmethod
|
||||
def import_attributes(cls):
|
||||
organisation = tool.Ifc.get().by_id(bpy.context.scene.BIMOwnerProperties.active_organisation_id)
|
||||
props = bpy.context.scene.BIMOwnerProperties
|
||||
props.organisation_attributes.clear()
|
||||
|
||||
blenderbim.bim.helper.import_attributes(
|
||||
"IfcOrganization", props.organisation_attributes, organisation.get_info()
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def clear_organisation(cls):
|
||||
bpy.context.scene.BIMOwnerProperties.active_organisation_id = 0
|
||||
|
||||
@classmethod
|
||||
def export_attributes(cls):
|
||||
props = bpy.context.scene.BIMOwnerProperties
|
||||
attributes = blenderbim.bim.helper.export_attributes(props.organisation_attributes)
|
||||
return attributes
|
||||
|
||||
@classmethod
|
||||
def get_organisation(cls):
|
||||
return tool.Ifc().get().by_id(bpy.context.scene.BIMOwnerProperties.active_organisation_id)
|
||||
@@ -95,6 +95,7 @@ def additionally_the_object_name_is_selected(name):
|
||||
bpy.context.view_layer.objects.active = obj
|
||||
obj.select_set(True)
|
||||
|
||||
|
||||
def i_deselect_all_objects():
|
||||
bpy.context.view_layer.objects.active = None
|
||||
bpy.ops.object.select_all(action="DESELECT")
|
||||
@@ -346,7 +347,7 @@ definitions = {
|
||||
'I add a cube of size "([0-9]+)" at "(.*)"': i_add_a_cube_of_size_size_at_location,
|
||||
'the object "(.*)" is selected': the_object_name_is_selected,
|
||||
'additionally the object "(.*)" is selected': additionally_the_object_name_is_selected,
|
||||
'I deselect all objects': i_deselect_all_objects,
|
||||
"I deselect all objects": i_deselect_all_objects,
|
||||
'I am on frame "([0-9]+)"': i_am_on_frame_number,
|
||||
'I set "(.*)" to "(.*)"': i_set_prop_to_value,
|
||||
'"(.*)" is "(.*)"': prop_is_value,
|
||||
|
||||
@@ -165,3 +165,38 @@ Scenario: Edit address
|
||||
And I press "bim.enable_editing_address(address={address})"
|
||||
And I press "bim.edit_address()"
|
||||
Then nothing happens
|
||||
|
||||
Scenario: Add organisation
|
||||
Given an empty IFC project
|
||||
When I press "bim.add_organisation"
|
||||
Then nothing happens
|
||||
|
||||
Scenario: Enable editing organisation
|
||||
Given an empty IFC project
|
||||
When I press "bim.add_organisation"
|
||||
And the variable "organisation" is "{ifc}.by_type('IfcOrganization')[0].id()"
|
||||
And I press "bim.enable_editing_organisation(organisation={organisation})"
|
||||
Then "scene.BIMOwnerProperties.active_organisation_id" is "{organisation}"
|
||||
|
||||
Scenario: Disable editing organisation
|
||||
Given an empty IFC project
|
||||
When I press "bim.add_organisation"
|
||||
And the variable "organisation" is "{ifc}.by_type('IfcOrganization')[0].id()"
|
||||
And I press "bim.enable_editing_organisation(organisation={organisation})"
|
||||
And I press "bim.disable_editing_organisation"
|
||||
Then "scene.BIMOwnerProperties.active_organisation_id" is "0"
|
||||
|
||||
Scenario: Edit organisation
|
||||
Given an empty IFC project
|
||||
When I press "bim.add_organisation"
|
||||
And the variable "organisation" is "{ifc}.by_type('IfcOrganization')[0].id()"
|
||||
And I press "bim.enable_editing_organisation(organisation={organisation})"
|
||||
And I press "bim.edit_organisation"
|
||||
Then "scene.BIMOwnerProperties.active_organisation_id" is "0"
|
||||
|
||||
Scenario: Remove organisation
|
||||
Given an empty IFC project
|
||||
When I press "bim.add_organisation"
|
||||
And the variable "organisation" is "{ifc}.by_type('IfcOrganization')[0].id()"
|
||||
And I press "bim.remove_organisation(organisation={organisation})"
|
||||
Then nothing happens
|
||||
|
||||
@@ -382,7 +382,7 @@ class TestRemoveFilling(test.bim.bootstrap.NewFile):
|
||||
And I delete the selected objects
|
||||
Then the object "IfcOpeningElement/Cube" is an "IfcOpeningElement"
|
||||
And the void "IfcOpeningElement/Cube" is not filled by "Cube"
|
||||
"""
|
||||
"""
|
||||
|
||||
@test.bim.bootstrap.scenario
|
||||
def test_removing_a_filling_using_deletion_on_the_opening(self):
|
||||
|
||||
@@ -56,6 +56,13 @@ def address_editor():
|
||||
prophet.verify()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def organisation_editor():
|
||||
prophet = Prophecy(blenderbim.core.tool.OrganisationEditor)
|
||||
yield prophet
|
||||
prophet.verify()
|
||||
|
||||
|
||||
class Prophecy:
|
||||
def __init__(self, cls):
|
||||
self.subject = cls
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
|
||||
import blenderbim.core.owner as subject
|
||||
from test.core.bootstrap import ifc, blender, person_editor, role_editor, address_editor
|
||||
from test.core.bootstrap import ifc, blender, person_editor, role_editor, address_editor, organisation_editor
|
||||
|
||||
|
||||
class TestAddPerson:
|
||||
@@ -147,3 +147,37 @@ class TestRemoveAddressAttribute:
|
||||
def test_run(self, address_editor):
|
||||
address_editor.remove_attribute("name", "id").should_be_called()
|
||||
subject.remove_address_attribute(address_editor, name="name", id="id")
|
||||
|
||||
|
||||
class TestAddOrganisation:
|
||||
def test_run(self, ifc):
|
||||
ifc.run("owner.add_organisation").should_be_called().will_return("organisation")
|
||||
assert subject.add_organisation(ifc) == "organisation"
|
||||
|
||||
|
||||
class TestRemoveOrganisation:
|
||||
def test_run(self, ifc):
|
||||
ifc.run("owner.remove_organisation", organisation="organisation").should_be_called()
|
||||
subject.remove_organisation(ifc, organisation="organisation")
|
||||
|
||||
|
||||
class TestEnableEditingOrganisation:
|
||||
def test_run(self, organisation_editor):
|
||||
organisation_editor.set_organisation("organisation").should_be_called()
|
||||
organisation_editor.import_attributes().should_be_called()
|
||||
subject.enable_editing_organisation(organisation_editor, organisation="organisation")
|
||||
|
||||
|
||||
class TestDisableEditingOrganisation:
|
||||
def test_run(self, organisation_editor):
|
||||
organisation_editor.clear_organisation().should_be_called()
|
||||
subject.disable_editing_organisation(organisation_editor)
|
||||
|
||||
|
||||
class TestEditOrganisation:
|
||||
def test_run(self, ifc, organisation_editor):
|
||||
organisation_editor.get_organisation().should_be_called().will_return("organisation")
|
||||
organisation_editor.export_attributes().should_be_called().will_return("attributes")
|
||||
ifc.run("owner.edit_organisation", organisation="organisation", attributes="attributes").should_be_called()
|
||||
organisation_editor.clear_organisation().should_be_called()
|
||||
subject.edit_organisation(ifc, organisation_editor)
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of BlenderBIM Add-on.
|
||||
#
|
||||
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# BlenderBIM Add-on is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import bpy
|
||||
import ifcopenshell
|
||||
import test.bim.bootstrap
|
||||
import blenderbim.core.tool
|
||||
import blenderbim.tool as tool
|
||||
from blenderbim.tool.organisation_editor import OrganisationEditor as subject
|
||||
|
||||
|
||||
class TestImplementsTool(test.bim.bootstrap.NewFile):
|
||||
def test_run(self):
|
||||
assert isinstance(subject(), blenderbim.core.tool.organisation_editor.OrganisationEditor)
|
||||
|
||||
|
||||
class TestSetOrganisation(test.bim.bootstrap.NewFile):
|
||||
def test_run(self):
|
||||
organisation = ifcopenshell.file().createIfcOrganization()
|
||||
subject().set_organisation(organisation)
|
||||
assert bpy.context.scene.BIMOwnerProperties.active_organisation_id == organisation.id()
|
||||
|
||||
|
||||
class TestImportAttributes(test.bim.bootstrap.NewFile):
|
||||
def test_run(self):
|
||||
ifc = ifcopenshell.file()
|
||||
tool.Ifc().set(ifc)
|
||||
organisation = ifc.createIfcOrganization()
|
||||
organisation.Identification = "Identification"
|
||||
organisation.Name = "Name"
|
||||
organisation.Description = "Description"
|
||||
subject().set_organisation(organisation)
|
||||
subject().import_attributes()
|
||||
props = bpy.context.scene.BIMOwnerProperties
|
||||
assert props.organisation_attributes.get("Identification").string_value == "Identification"
|
||||
assert props.organisation_attributes.get("Name").string_value == "Name"
|
||||
assert props.organisation_attributes.get("Description").string_value == "Description"
|
||||
|
||||
def test_overwriting_a_previous_import(self):
|
||||
ifc = ifcopenshell.file()
|
||||
tool.Ifc().set(ifc)
|
||||
organisation = ifc.createIfcOrganization()
|
||||
organisation.Identification = "Identification"
|
||||
organisation.Description = "Description"
|
||||
subject().set_organisation(organisation)
|
||||
subject().import_attributes()
|
||||
organisation.Identification = "Identification2"
|
||||
organisation.Description = None
|
||||
subject().import_attributes()
|
||||
props = bpy.context.scene.BIMOwnerProperties
|
||||
assert props.organisation_attributes.get("Identification").string_value == "Identification2"
|
||||
assert props.organisation_attributes.get("Description").string_value == ""
|
||||
|
||||
|
||||
class TestClearOrganisation(test.bim.bootstrap.NewFile):
|
||||
def test_run(self):
|
||||
props = bpy.context.scene.BIMOwnerProperties
|
||||
props.active_organisation_id = 1
|
||||
subject().clear_organisation()
|
||||
assert props.active_organisation_id == 0
|
||||
|
||||
|
||||
class TestExportAttributes(test.bim.bootstrap.NewFile):
|
||||
def test_run(self):
|
||||
TestImportAttributes().test_run()
|
||||
assert subject().export_attributes() == {
|
||||
"Identification": "Identification",
|
||||
"Name": "Name",
|
||||
"Description": "Description",
|
||||
}
|
||||
|
||||
|
||||
class TestGetOrganisation(test.bim.bootstrap.NewFile):
|
||||
def test_run(self):
|
||||
ifc = ifcopenshell.file()
|
||||
tool.Ifc().set(ifc)
|
||||
organisation = ifc.createIfcOrganization()
|
||||
subject().set_organisation(organisation)
|
||||
assert subject().get_organisation() == organisation
|
||||
Reference in New Issue
Block a user