From be2ea335f562eb3e45d0937f89895ea3043ffa31 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Fri, 8 Jan 2021 16:27:19 +1100 Subject: [PATCH] WIP partial port of IfcPerson to partial editing. New feature too! See message. See #1222. * Previously, IfcPerson was not imported. Now it is! Funky. --- .../blenderbim/bim/__init__.py | 7 +- .../blenderbim/bim/module/context/ui.py | 8 +- .../blenderbim/bim/module/person/__init__.py | 19 +++++ .../bim/module/person/add_person.py | 6 ++ .../blenderbim/bim/module/person/data.py | 32 +++++++ .../bim/module/person/edit_person.py | 13 +++ .../blenderbim/bim/module/person/operator.py | 84 +++++++++++++++++++ .../bim/module/person/remove_person.py | 9 ++ .../blenderbim/bim/module/person/ui.py | 69 +++++++++++++++ .../blenderbim/bim/module/root/operator.py | 4 + .../blenderbim/bim/module/style/operator.py | 2 +- .../blenderbim/bim/operator.py | 20 ----- src/ifcblenderexport/blenderbim/bim/prop.py | 4 +- src/ifcblenderexport/blenderbim/bim/ui.py | 41 --------- 14 files changed, 249 insertions(+), 69 deletions(-) create mode 100644 src/ifcblenderexport/blenderbim/bim/module/person/__init__.py create mode 100644 src/ifcblenderexport/blenderbim/bim/module/person/add_person.py create mode 100644 src/ifcblenderexport/blenderbim/bim/module/person/data.py create mode 100644 src/ifcblenderexport/blenderbim/bim/module/person/edit_person.py create mode 100644 src/ifcblenderexport/blenderbim/bim/module/person/operator.py create mode 100644 src/ifcblenderexport/blenderbim/bim/module/person/remove_person.py create mode 100644 src/ifcblenderexport/blenderbim/bim/module/person/ui.py diff --git a/src/ifcblenderexport/blenderbim/bim/__init__.py b/src/ifcblenderexport/blenderbim/bim/__init__.py index a4a33445a9..c1dadd46c9 100644 --- a/src/ifcblenderexport/blenderbim/bim/__init__.py +++ b/src/ifcblenderexport/blenderbim/bim/__init__.py @@ -14,6 +14,7 @@ if bpy is not None: import blenderbim.bim.module.debug as module_debug import blenderbim.bim.module.geometry as module_geometry import blenderbim.bim.module.model as module_model + import blenderbim.bim.module.person as module_person import blenderbim.bim.module.project as module_project import blenderbim.bim.module.pset as module_pset import blenderbim.bim.module.spatial as module_spatial @@ -71,8 +72,6 @@ if bpy is not None: operator.AssignConstraint, operator.UnassignConstraint, operator.RemoveObjectConstraint, - operator.AddPerson, - operator.RemovePerson, operator.AddPersonRole, operator.RemovePersonRole, operator.AddPersonAddress, @@ -265,7 +264,6 @@ if bpy is not None: ui.BIM_PT_ifccsv, ui.BIM_PT_ifcclash, ui.BIM_PT_owner, - ui.BIM_PT_people, ui.BIM_PT_organisations, ui.BIM_PT_qa, ui.BIM_PT_library, @@ -311,6 +309,7 @@ if bpy is not None: classes.extend(module_debug.classes) classes.extend(module_geometry.classes) classes.extend(module_model.classes) + classes.extend(module_person.classes) classes.extend(module_project.classes) classes.extend(module_pset.classes) classes.extend(module_spatial.classes) @@ -356,6 +355,7 @@ if bpy is not None: module_debug.register() module_geometry.register() module_model.register() + module_person.register() module_project.register() module_pset.register() module_spatial.register() @@ -388,6 +388,7 @@ if bpy is not None: module_spatial.unregister() module_pset.unregister() module_project.unregister() + module_person.unregister() module_model.unregister() module_geometry.unregister() module_debug.unregister() diff --git a/src/ifcblenderexport/blenderbim/bim/module/context/ui.py b/src/ifcblenderexport/blenderbim/bim/module/context/ui.py index 678ae87b76..07182ab2ac 100644 --- a/src/ifcblenderexport/blenderbim/bim/module/context/ui.py +++ b/src/ifcblenderexport/blenderbim/bim/module/context/ui.py @@ -1,5 +1,6 @@ from bpy.types import Panel from blenderbim.bim.module.context.data import Data +from blenderbim.bim.ifc import IfcStore class BIM_PT_context(Panel): @@ -10,14 +11,17 @@ class BIM_PT_context(Panel): bl_region_type = "WINDOW" bl_context = "scene" + @classmethod + def poll(cls, context): + return IfcStore.get_file() + def draw(self, context): if not Data.is_loaded: Data.load() - layout = self.layout props = context.scene.BIMProperties - row = layout.row(align=True) + row = self.layout.row(align=True) row.prop(props, "available_contexts", text="") row.prop(props, "available_subcontexts", text="") row.prop(props, "available_target_views", text="") diff --git a/src/ifcblenderexport/blenderbim/bim/module/person/__init__.py b/src/ifcblenderexport/blenderbim/bim/module/person/__init__.py new file mode 100644 index 0000000000..063137b49f --- /dev/null +++ b/src/ifcblenderexport/blenderbim/bim/module/person/__init__.py @@ -0,0 +1,19 @@ +import bpy +from . import ui, operator + +classes = ( + operator.EnableEditingPerson, + operator.DisableEditingPerson, + operator.AddPerson, + operator.EditPerson, + operator.RemovePerson, + ui.BIM_PT_people, +) + + +def register(): + pass + + +def unregister(): + pass diff --git a/src/ifcblenderexport/blenderbim/bim/module/person/add_person.py b/src/ifcblenderexport/blenderbim/bim/module/person/add_person.py new file mode 100644 index 0000000000..0772105757 --- /dev/null +++ b/src/ifcblenderexport/blenderbim/bim/module/person/add_person.py @@ -0,0 +1,6 @@ +class Usecase: + def __init__(self, file): + self.file = file + + def execute(self): + self.file.createIfcPerson("HSeldon", "Seldon", "Hari") diff --git a/src/ifcblenderexport/blenderbim/bim/module/person/data.py b/src/ifcblenderexport/blenderbim/bim/module/person/data.py new file mode 100644 index 0000000000..e767cb90d4 --- /dev/null +++ b/src/ifcblenderexport/blenderbim/bim/module/person/data.py @@ -0,0 +1,32 @@ +from blenderbim.bim.ifc import IfcStore + + +class Data: + is_loaded = False + people = {} + + @classmethod + def load(cls): + file = IfcStore.get_file() + if not file: + return + cls.people = {} + for person in file.by_type("IfcPerson"): + data = person.get_info() + + roles = {} + if data["Roles"]: + for role in data["Roles"]: + roles[role.id()] = role.get_info() + data["Roles"] = roles + + addresses = [] + if data["Addresses"]: + for address in data["Addresses"]: + addresses.append(address.get_info()) + data["Addresses"] = addresses + + data["is_engaged"] = bool(person.EngagedIn) + + cls.people[person.id()] = data + cls.is_loaded = True diff --git a/src/ifcblenderexport/blenderbim/bim/module/person/edit_person.py b/src/ifcblenderexport/blenderbim/bim/module/person/edit_person.py new file mode 100644 index 0000000000..afeaa9b429 --- /dev/null +++ b/src/ifcblenderexport/blenderbim/bim/module/person/edit_person.py @@ -0,0 +1,13 @@ +class Usecase: + def __init__(self, file, settings=None): + self.file = file + self.settings = { + "person": None, + "attributes": {} + } + for key, value in settings.items(): + self.settings[key] = value + + def execute(self): + for name, value in self.settings["attributes"].items(): + setattr(self.settings["person"], name, value) diff --git a/src/ifcblenderexport/blenderbim/bim/module/person/operator.py b/src/ifcblenderexport/blenderbim/bim/module/person/operator.py new file mode 100644 index 0000000000..97bec29293 --- /dev/null +++ b/src/ifcblenderexport/blenderbim/bim/module/person/operator.py @@ -0,0 +1,84 @@ +import bpy +import json +import blenderbim.bim.module.person.add_person as add_person +import blenderbim.bim.module.person.edit_person as edit_person +import blenderbim.bim.module.person.remove_person as remove_person +from blenderbim.bim.ifc import IfcStore +from blenderbim.bim.module.person.data import Data + + +class EnableEditingPerson(bpy.types.Operator): + bl_idname = "bim.enable_editing_person" + bl_label = "Enable Editing Person" + person_id: bpy.props.IntProperty() + + def execute(self, context): + self.file = IfcStore.get_file() + props = context.scene.BIMProperties + props.active_person_id = self.person_id + data = Data.people[self.person_id] + name = data["Id"] if self.file.schema == "IFC2X3" else data["Identification"] + props.person.name = name or "" + props.person.family_name = data["FamilyName"] or "" + props.person.given_name = data["GivenName"] or "" + props.person.middle_names = json.dumps(data["MiddleNames"]) if data["MiddleNames"] else "" + props.person.prefix_titles = json.dumps(data["PrefixTitles"]) if data["PrefixTitles"] else "" + props.person.suffix_titles = json.dumps(data["SuffixTitles"]) if data["SuffixTitles"] else "" + return {"FINISHED"} + + +class DisableEditingPerson(bpy.types.Operator): + bl_idname = "bim.disable_editing_person" + bl_label = "Disable Editing Person" + + def execute(self, context): + context.scene.BIMProperties.active_person_id = 0 + return {"FINISHED"} + + +class AddPerson(bpy.types.Operator): + bl_idname = "bim.add_person" + bl_label = "Add Person" + + def execute(self, context): + add_person.Usecase(IfcStore.get_file()).execute() + Data.load() + return {"FINISHED"} + + +class EditPerson(bpy.types.Operator): + bl_idname = "bim.edit_person" + bl_label = "Edit Person" + + def execute(self, context): + self.file = IfcStore.get_file() + props = context.scene.BIMProperties + attributes = { + "Identification": props.person.name or None, + "FamilyName": props.person.family_name or None, + "GivenName": props.person.given_name or None, + "MiddleNames": json.loads(props.person.middle_names) if props.person.middle_names else None, + "PrefixTitles": json.loads(props.person.prefix_titles) if props.person.prefix_titles else None, + "SuffixTitles": json.loads(props.person.suffix_titles) if props.person.suffix_titles else None, + } + if self.file.schema == "IFC2X3": + attributes["Id"] = attributes["Identification"] + del attributes["Identification"] + edit_person.Usecase( + self.file, {"person": self.file.by_id(props.active_person_id), "attributes": attributes} + ).execute() + Data.load() + bpy.ops.bim.disable_editing_person() + return {"FINISHED"} + + +class RemovePerson(bpy.types.Operator): + bl_idname = "bim.remove_person" + bl_label = "Remove Person" + person_id: bpy.props.IntProperty() + + def execute(self, context): + self.file = IfcStore.get_file() + remove_person.Usecase(self.file, {"person": self.file.by_id(self.person_id)}).execute() + Data.load() + return {"FINISHED"} diff --git a/src/ifcblenderexport/blenderbim/bim/module/person/remove_person.py b/src/ifcblenderexport/blenderbim/bim/module/person/remove_person.py new file mode 100644 index 0000000000..f9e4a6e9fe --- /dev/null +++ b/src/ifcblenderexport/blenderbim/bim/module/person/remove_person.py @@ -0,0 +1,9 @@ +class Usecase: + def __init__(self, file, settings=None): + self.file = file + self.settings = {"person": None} + for key, value in settings.items(): + self.settings[key] = value + + def execute(self): + self.file.remove(self.settings["person"]) diff --git a/src/ifcblenderexport/blenderbim/bim/module/person/ui.py b/src/ifcblenderexport/blenderbim/bim/module/person/ui.py new file mode 100644 index 0000000000..e090075c3f --- /dev/null +++ b/src/ifcblenderexport/blenderbim/bim/module/person/ui.py @@ -0,0 +1,69 @@ +from bpy.types import Panel +from blenderbim.bim.module.person.data import Data +from blenderbim.bim.ifc import IfcStore + + +class BIM_PT_people(Panel): + bl_label = "IFC People" + bl_idname = "BIM_PT_people" + bl_options = {"DEFAULT_CLOSED"} + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "scene" + + @classmethod + def poll(cls, context): + return IfcStore.get_file() + + def draw(self, context): + if not Data.is_loaded: + Data.load() + + self.file = IfcStore.get_file() + self.layout.use_property_split = True + props = context.scene.BIMProperties + + row = self.layout.row() + row.operator("bim.add_person") + + for person_id, person in Data.people.items(): + if props.active_person_id == person_id: + blender_person = props.person + box = self.layout.box() + row = box.row(align=True) + row.prop(blender_person, "name", icon="USER", text="") + row.operator("bim.edit_person", icon="CHECKMARK", text="") + row.operator("bim.disable_editing_person", icon="X", text="") + row = box.row() + row.prop(blender_person, "family_name") + row = box.row() + row.prop(blender_person, "given_name") + row = box.row() + row.prop(blender_person, "middle_names") + row = box.row() + row.prop(blender_person, "prefix_titles") + row = box.row() + row.prop(blender_person, "suffix_titles") + else: + row = self.layout.row(align=True) + name = person["Id"] if self.file.schema == "IFC2X3" else person["Identification"] + name = name or "*" + if person["GivenName"] or person["FamilyName"]: + full_name = "{} {}".format(person["GivenName"] or "", person["FamilyName"] or "").strip() + name += f" ({full_name})" + row.label(text=name) + if person["Roles"]: + row.label(text=", ".join([r.Role for r in person["Roles"]])) + row.operator("bim.enable_editing_person", icon="GREASEPENCIL", text="").person_id = person_id + if not person["is_engaged"]: + row.operator("bim.remove_person", icon="X", text="").person_id = person_id + return + + + if props.people: + if props.active_person_index < len(props.people): + self.layout.label(text="Roles:") + draw_roles_ui(self.layout, person, "person") + self.layout.label(text="Addresses:") + draw_addresses_ui(self.layout, person, "person") + diff --git a/src/ifcblenderexport/blenderbim/bim/module/root/operator.py b/src/ifcblenderexport/blenderbim/bim/module/root/operator.py index 333a1ea9f7..657425cc00 100644 --- a/src/ifcblenderexport/blenderbim/bim/module/root/operator.py +++ b/src/ifcblenderexport/blenderbim/bim/module/root/operator.py @@ -86,6 +86,10 @@ class AssignClass(bpy.types.Operator): elif self.predefined_type == "": predefined_type = None for obj in objects: + if obj.data: + for material in obj.data.materials: + if not material.BIMMaterialProperties.ifc_style_id: + bpy.ops.bim.add_style(material=material.name) self.assign_class(obj) return {"FINISHED"} diff --git a/src/ifcblenderexport/blenderbim/bim/module/style/operator.py b/src/ifcblenderexport/blenderbim/bim/module/style/operator.py index 9141733e23..204a4e4385 100644 --- a/src/ifcblenderexport/blenderbim/bim/module/style/operator.py +++ b/src/ifcblenderexport/blenderbim/bim/module/style/operator.py @@ -41,7 +41,7 @@ class AddStyle(bpy.types.Operator): def execute(self, context): self.file = IfcStore.get_file() - material = bpy.data.objects.get(self.material) if self.material else bpy.context.active_object.active_material + material = bpy.data.materials.get(self.material) if self.material else bpy.context.active_object.active_material settings = get_colour_settings(material) settings["Name"] = material.name settings["external_definition"] = None # TODO: Implement. See #1222 diff --git a/src/ifcblenderexport/blenderbim/bim/operator.py b/src/ifcblenderexport/blenderbim/bim/operator.py index 75c72288fa..e9703b8f74 100644 --- a/src/ifcblenderexport/blenderbim/bim/operator.py +++ b/src/ifcblenderexport/blenderbim/bim/operator.py @@ -578,26 +578,6 @@ class RemoveObjectConstraint(bpy.types.Operator): return {"FINISHED"} -class AddPerson(bpy.types.Operator): - bl_idname = "bim.add_person" - bl_label = "Add Person" - - def execute(self, context): - new = bpy.context.scene.BIMProperties.people.add() - new.name = "New Person" - return {"FINISHED"} - - -class RemovePerson(bpy.types.Operator): - bl_idname = "bim.remove_person" - bl_label = "Remove Person" - index: bpy.props.IntProperty() - - def execute(self, context): - bpy.context.scene.BIMProperties.people.remove(self.index) - return {"FINISHED"} - - class AddPersonAddress(bpy.types.Operator): bl_idname = "bim.add_person_address" bl_label = "Add Person Address" diff --git a/src/ifcblenderexport/blenderbim/bim/prop.py b/src/ifcblenderexport/blenderbim/bim/prop.py index 077cf37e1f..4db4cbb9d5 100644 --- a/src/ifcblenderexport/blenderbim/bim/prop.py +++ b/src/ifcblenderexport/blenderbim/bim/prop.py @@ -1288,11 +1288,11 @@ class BIMProperties(PropertyGroup): import_should_offset_model: BoolProperty(name="Import and Offset Model", default=False) import_model_offset_coordinates: StringProperty(name="Model Offset Coordinates", default="0,0,0") qa_reject_element_reason: StringProperty(name="Element Rejection Reason") - person: EnumProperty(items=getPersons, name="Person") + person: PointerProperty(type=Person) organisation: EnumProperty(items=getOrganisations, name="Organisation") people: CollectionProperty(name="People", type=Person) organisations: CollectionProperty(name="Organisations", type=Organisation) - active_person_index: IntProperty(name="Active Person Index") + active_person_id: IntProperty(name="Active Person Id") active_organisation_index: IntProperty(name="Active Organisation Index") has_georeferencing: BoolProperty(name="Has Georeferencing", default=False) has_library: BoolProperty(name="Has Project Library", default=False) diff --git a/src/ifcblenderexport/blenderbim/bim/ui.py b/src/ifcblenderexport/blenderbim/bim/ui.py index 26afa2104c..0d3d530c7a 100644 --- a/src/ifcblenderexport/blenderbim/bim/ui.py +++ b/src/ifcblenderexport/blenderbim/bim/ui.py @@ -1058,47 +1058,6 @@ class BIM_PT_owner(Panel): row.prop(props, "organisation") -class BIM_PT_people(Panel): - bl_label = "IFC People" - bl_idname = "BIM_PT_people" - bl_options = {"DEFAULT_CLOSED"} - bl_space_type = "PROPERTIES" - bl_region_type = "WINDOW" - bl_context = "scene" - - def draw(self, context): - layout = self.layout - layout.use_property_split = True - - props = context.scene.BIMProperties - - row = layout.row() - row.operator("bim.add_person") - - if props.people: - layout.template_list("BIM_UL_generic", "", props, "people", props, "active_person_index") - - if props.active_person_index < len(props.people): - person = props.people[props.active_person_index] - row = layout.row() - row.prop(person, "name") - row.operator("bim.remove_person", icon="X", text="").index = props.active_person_index - row = layout.row() - row.prop(person, "family_name") - row = layout.row() - row.prop(person, "given_name") - row = layout.row() - row.prop(person, "middle_names") - row = layout.row() - row.prop(person, "prefix_titles") - row = layout.row() - row.prop(person, "suffix_titles") - layout.label(text="Roles:") - draw_roles_ui(layout, person, "person") - layout.label(text="Addresses:") - draw_addresses_ui(layout, person, "person") - - class BIM_PT_organisations(Panel): bl_label = "IFC Organisations" bl_idname = "BIM_PT_organisations"