BlenderBim : Improve BCF Project UX (#1668)

* Store fields on BCFProperties class rather than individual topics

* Clear input fields on active topic change

* BCF : Fix resetting comment has_related_viewpoint default value

* Prevent global function use from import

* Use dynamic enum to choose related topic

* Add newline at eof

* Show only .bcf and .bcfzip files when saving project
This commit is contained in:
Gorgious56
2021-08-18 23:42:41 +02:00
committed by GitHub
parent bbd7264a9b
commit cb2995a255
3 changed files with 101 additions and 90 deletions
@@ -26,7 +26,7 @@ import numpy as np
import ifcopenshell
import ifcopenshell.util.unit
from . import bcfstore
from blenderbim.bim.module.bcf.prop import getBcfViewpoints
import blenderbim.bim.module.bcf.prop as bcf_prop
from blenderbim.bim.ifc import IfcStore
from math import radians, degrees, atan, tan, cos, sin
from mathutils import Vector, Matrix, Euler, geometry
@@ -252,6 +252,7 @@ class SaveBcfProject(bpy.types.Operator):
bl_label = "Save BCF Project"
bl_options = {"REGISTER", "UNDO"}
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
filter_glob: bpy.props.StringProperty(default="*.bcf;*.bcfzip", options={"HIDDEN"})
def execute(self, context):
bcfxml = bcfstore.BcfStore.get_bcfxml()
@@ -286,8 +287,7 @@ class AddBcfBimSnippet(bpy.types.Operator):
@classmethod
def poll(cls, context):
props = context.scene.BCFProperties
return all((getattr(props.topics[props.active_topic_index], attr, False) for attr in (
return all((getattr(context.scene.BCFProperties, attr, False) for attr in (
"bim_snippet_reference",
"bim_snippet_schema",
"bim_snippet_type"
@@ -299,11 +299,14 @@ class AddBcfBimSnippet(bpy.types.Operator):
blender_topic = props.topics[props.active_topic_index]
topic = bcfxml.topics[blender_topic.name]
bim_snippet = bcf.v2.data.BimSnippet()
bim_snippet.reference = blender_topic.bim_snippet_reference
bim_snippet.reference_schema = blender_topic.bim_snippet_schema
bim_snippet.snippet_type = blender_topic.bim_snippet_type
bim_snippet.reference = props.bim_snippet_reference
bim_snippet.reference_schema = props.bim_snippet_schema
bim_snippet.snippet_type = props.bim_snippet_type
bcfxml.add_bim_snippet(topic, bim_snippet)
bpy.ops.bim.load_bcf_topic(topic_guid = topic.guid, topic_index = props.active_topic_index)
bim_snippet.reference = ""
bim_snippet.reference_schema = ""
bim_snippet.snippet_type = ""
return {"FINISHED"}
@@ -314,33 +317,14 @@ class AddBcfRelatedTopic(bpy.types.Operator):
@classmethod
def poll(cls, context):
bcfxml = bcfstore.BcfStore.get_bcfxml()
props = context.scene.BCFProperties
blender_topic = props.topics[props.active_topic_index]
if not blender_topic.related_topic:
return False
if blender_topic.related_topic == blender_topic.title:
# Prevent adding self as related topic
return False
related_topic = None
for topic in bcfxml.topics.values():
if topic.title == blender_topic.related_topic:
related_topic = bcf.v2.data.RelatedTopic()
related_topic.guid = topic.guid
break
if not related_topic:
return False
if str(related_topic.guid) in [t.name for t in blender_topic.related_topics]:
# Prevent adding the same related topic more than once
return False
return True
return bcf_prop.get_related_topics(None, context)
def execute(self, context):
bcfxml = bcfstore.BcfStore.get_bcfxml()
props = context.scene.BCFProperties
blender_topic = props.topics[props.active_topic_index]
related_topic = bcf.v2.data.RelatedTopic()
related_topic.guid = next((t for t in bcfxml.topics.values() if t.title == blender_topic.related_topic)).guid
related_topic.guid = props.related_topic
topic = bcfxml.topics[blender_topic.name]
topic.related_topics.append(related_topic)
bcfxml.edit_topic(topic)
@@ -355,8 +339,7 @@ class AddBcfHeaderFile(bpy.types.Operator):
@classmethod
def poll(cls, context):
props = context.scene.BCFProperties
return props.topics[props.active_topic_index].file_reference
return context.scene.BCFProperties.file_reference
def execute(self, context):
bcfxml = bcfstore.BcfStore.get_bcfxml()
@@ -364,15 +347,18 @@ class AddBcfHeaderFile(bpy.types.Operator):
blender_topic = props.topics[props.active_topic_index]
topic = bcfxml.topics[blender_topic.name]
header_file = bcf.v2.data.HeaderFile()
header_file.reference = blender_topic.file_reference
header_file.reference = props.file_reference
if not os.path.exists(header_file.reference):
header_file.filename = header_file.reference
if len(blender_topic.file_ifc_project) == 22:
header_file.ifc_project = blender_topic.file_ifc_project
if len(blender_topic.file_ifc_spatial_structure_element) == 22:
header_file.ifc_spatial_structure_element = blender_topic.file_ifc_spatial_structure_element
if len(props.file_ifc_project) == 22:
header_file.ifc_project = props.file_ifc_project
if len(props.file_ifc_spatial_structure_element) == 22:
header_file.ifc_spatial_structure_element = props.file_ifc_spatial_structure_element
bcfxml.add_file(topic, header_file)
props.active_topic_index = props.active_topic_index # refreshes the BCF Topic
props.file_reference = ""
props.file_ifc_project = ""
props.file_ifc_spatial_structure_element = ""
return {"FINISHED"}
@@ -386,6 +372,7 @@ class ViewBcfTopic(bpy.types.Operator):
for index, topic in enumerate(context.scene.BCFProperties.topics):
if topic.name.lower() == self.topic_guid.lower():
context.scene.BCFProperties.active_topic_index = index
break
return {"FINISHED"}
@@ -448,7 +435,7 @@ class RemoveBcfViewpoint(bpy.types.Operator):
@classmethod
def poll(cls, context):
return getBcfViewpoints(None, context)
return bcf_prop.getBcfViewpoints(None, context)
def execute(self, context):
bcfxml = bcfstore.BcfStore.get_bcfxml()
@@ -484,18 +471,17 @@ class AddBcfReferenceLink(bpy.types.Operator):
@classmethod
def poll(cls, context):
props = context.scene.BCFProperties
return props.topics[props.active_topic_index].reference_link
return context.scene.BCFProperties.reference_link
def execute(self, context):
bcfxml = bcfstore.BcfStore.get_bcfxml()
props = context.scene.BCFProperties
blender_topic = props.topics[props.active_topic_index]
topic = bcfxml.topics[blender_topic.name]
topic.reference_links.append(blender_topic.reference_link)
topic.reference_links.append(props.reference_link)
bcfxml.edit_topic(topic)
bpy.ops.bim.load_bcf_topic(topic_guid = topic.guid, topic_index = props.active_topic_index)
blender_topic.reference_link = ""
props.reference_link = ""
return {"FINISHED"}
@@ -506,8 +492,7 @@ class AddBcfDocumentReference(bpy.types.Operator):
@classmethod
def poll(cls, context):
props = context.scene.BCFProperties
return props.topics[props.active_topic_index].document_reference
return context.scene.BCFProperties.document_reference
def execute(self, context):
bcfxml = bcfstore.BcfStore.get_bcfxml()
@@ -515,12 +500,12 @@ class AddBcfDocumentReference(bpy.types.Operator):
blender_topic = props.topics[props.active_topic_index]
topic = bcfxml.topics[blender_topic.name]
document_reference = bcf.v2.data.DocumentReference()
document_reference.referenced_document = blender_topic.document_reference
document_reference.description = blender_topic.document_reference_description or None
document_reference.referenced_document = props.document_reference
document_reference.description = props.document_reference_description or None
bcfxml.add_document_reference(topic, document_reference)
bpy.ops.bim.load_bcf_topic(topic_guid = topic.guid, topic_index = props.active_topic_index)
blender_topic.document_reference = ""
blender_topic.document_reference_description = ""
props.document_reference = ""
props.document_reference_description = ""
return {"FINISHED"}
@@ -531,8 +516,7 @@ class AddBcfLabel(bpy.types.Operator):
@classmethod
def poll(cls, context):
props = context.scene.BCFProperties
return props.topics[props.active_topic_index].label
return context.scene.BCFProperties.label
def execute(self, context):
bcfxml = bcfstore.BcfStore.get_bcfxml()
@@ -540,10 +524,10 @@ class AddBcfLabel(bpy.types.Operator):
blender_topic = props.topics[props.active_topic_index]
topic = bcfxml.topics[blender_topic.name]
new = blender_topic.labels.add()
new.name = blender_topic.label
topic.labels.append(blender_topic.label)
new.name = props.label
topic.labels.append(props.label)
bcfxml.edit_topic(topic)
blender_topic.label = ""
props.label = ""
return {"FINISHED"}
@@ -713,10 +697,9 @@ class AddBcfComment(bpy.types.Operator):
@classmethod
def poll(cls, context):
props = context.scene.BCFProperties
topic = props.topics[props.active_topic_index]
if not topic.comment:
if not props.comment:
return False
if topic.has_related_viewpoint and not getBcfViewpoints(None, context):
if props.has_related_viewpoint and not bcf_prop.getBcfViewpoints(None, context):
return False
return True
@@ -726,12 +709,14 @@ class AddBcfComment(bpy.types.Operator):
blender_topic = props.topics[props.active_topic_index]
topic = bcfxml.topics[blender_topic.name]
comment = bcf.v2.data.Comment()
comment.comment = blender_topic.comment
if blender_topic.has_related_viewpoint:
comment.comment = props.comment
if props.has_related_viewpoint:
comment.viewpoint = bcf.v2.data.Viewpoint()
comment.viewpoint.guid = blender_topic.viewpoints
bcfxml.add_comment(topic, comment)
bpy.ops.bim.load_bcf_comments(topic_guid = topic.guid)
props.comment = ""
props.has_related_viewpoint = False
return {"FINISHED"}
@@ -1022,9 +1007,7 @@ class SelectBcfHeaderFile(bpy.types.Operator):
def execute(self, context):
if self.filepath:
props = context.scene.BCFProperties
topic = props.topics[props.active_topic_index]
topic.file_reference = self.filepath
context.scene.BCFProperties.file_reference = self.filepath
return {"FINISHED"}
def invoke(self, context, event):
@@ -1040,9 +1023,7 @@ class SelectBcfBimSnippetReference(bpy.types.Operator):
def execute(self, context):
if self.filepath:
props = context.scene.BCFProperties
topic = props.topics[props.active_topic_index]
topic.bim_snippet_reference = self.filepath
context.scene.BCFProperties.bim_snippet_reference = self.filepath
return {"FINISHED"}
def invoke(self, context, event):
@@ -1058,9 +1039,7 @@ class SelectBcfDocumentReference(bpy.types.Operator):
def execute(self, context):
if self.filepath:
props = context.scene.BCFProperties
topic = props.topics[props.active_topic_index]
topic.document_reference = self.filepath
context.scene.BCFProperties.document_reference = self.filepath
return {"FINISHED"}
def invoke(self, context, event):
@@ -34,11 +34,14 @@ from bpy.props import (
bcfviewpoints_enum = None
related_topic_enum = []
def purge():
global bcfviewpoints_enum
global related_topic_enum
bcfviewpoints_enum = None
related_topic_enum.clear()
def updateBcfReferenceLink(self, context):
@@ -76,6 +79,20 @@ def updateBcfCommentIsEditable(self, context):
bpy.ops.bim.edit_bcf_comment(comment_guid = self.name)
def get_related_topics(self, context):
global related_topic
related_topic_enum.clear()
props = context.scene.BCFProperties
current_topic = props.topics[props.active_topic_index]
for topic in props.topics:
if topic == current_topic:
continue
if topic.name in current_topic.related_topics:
continue
related_topic_enum.append((topic.name, topic.title, topic.description))
return related_topic_enum
def refreshBcfTopic(self, context):
global bcfviewpoints_enum
bcfviewpoints_enum = None
@@ -84,6 +101,7 @@ def refreshBcfTopic(self, context):
bcfxml = bcfstore.BcfStore.get_bcfxml()
topic = props.topics[props.active_topic_index]
header = bcfxml.get_header(topic.name)
props.clear_input_fields()
getBcfViewpoints(self, context)
@@ -148,26 +166,13 @@ class BcfTopic(PropertyGroup):
description: StringProperty(default="", name="Description")
viewpoints: EnumProperty(items=getBcfViewpoints, name="BCF Viewpoints")
files: CollectionProperty(name="Files", type=StrProperty)
file_reference: StringProperty(default="", name="Reference")
file_ifc_project: StringProperty(default="", name="IFC Project")
file_ifc_spatial_structure_element: StringProperty(default="", name="IFC Spatial Structure Element")
reference_links: CollectionProperty(name="Reference Links", type=BcfReferenceLink)
reference_link: StringProperty(default="", name="Reference Link")
labels: CollectionProperty(name="Labels", type=BcfLabel)
label: StringProperty(default="", name="Label")
bim_snippet: PointerProperty(type=BcfBimSnippet)
bim_snippet_type: StringProperty(default="", name="Type")
bim_snippet_reference: StringProperty(default="", name="Reference")
bim_snippet_schema: StringProperty(default="", name="Schema")
document_references: CollectionProperty(name="Document References", type=BcfDocumentReference)
document_reference: StringProperty(default="", name="Referenced Document")
document_reference_description: StringProperty(default="", name="Description")
related_topics: CollectionProperty(name="Related Topics", type=StrProperty)
related_topic: StringProperty(default="", name="Related Topic")
comments: CollectionProperty(name="Comments", type=BcfComment)
is_editable: BoolProperty(name="Is Editable", default=False, update=updateBcfTopicIsEditable)
comment: StringProperty(default="", name="Comment")
has_related_viewpoint: BoolProperty(name="Has Related Viewpoint", default=False)
class BCFProperties(PropertyGroup):
@@ -177,3 +182,30 @@ class BCFProperties(PropertyGroup):
author: StringProperty(default="john@doe.com", name="Author Email", update=updateBcfAuthor)
topics: CollectionProperty(name="BCF Topics", type=BcfTopic)
active_topic_index: IntProperty(name="Active BCF Topic Index", update=refreshBcfTopic)
file_reference: StringProperty(default="", name="Reference")
file_ifc_project: StringProperty(default="", name="IFC Project")
file_ifc_spatial_structure_element: StringProperty(default="", name="IFC Spatial Structure Element")
reference_link: StringProperty(default="", name="Reference Link")
label: StringProperty(default="", name="Label")
bim_snippet_reference: StringProperty(default="", name="Reference")
bim_snippet_type: StringProperty(default="", name="Type")
bim_snippet_schema: StringProperty(default="", name="Schema")
document_reference: StringProperty(default="", name="Referenced Document")
document_reference_description: StringProperty(default="", name="Description")
related_topic: EnumProperty(name="Related Topic", items=get_related_topics)
comment: StringProperty(default="", name="Comment")
has_related_viewpoint: BoolProperty(name="Has Related Viewpoint", default=False)
def clear_input_fields(self):
self.file_reference = ""
self.file_ifc_project = ""
self.file_ifc_spatial_structure_element = ""
self.reference_link = ""
self.label = ""
self.bim_snippet_reference = ""
self.bim_snippet_type = ""
self.bim_snippet_schema = ""
self.document_reference = ""
self.document_reference_description = ""
self.comment = ""
self.has_related_viewpoint = False
+13 -13
View File
@@ -151,12 +151,12 @@ class BIM_PT_bcf_metadata(Panel):
row.label(text=f.ifc_spatial_structure_element)
row = layout.row(align=True)
row.prop(topic, "file_reference")
row.prop(props, "file_reference")
row.operator("bim.select_bcf_header_file", icon="FILE_FOLDER", text="")
row = layout.row()
row.prop(topic, "file_ifc_project")
row.prop(props, "file_ifc_project")
row = layout.row()
row.prop(topic, "file_ifc_spatial_structure_element")
row.prop(props, "file_ifc_spatial_structure_element")
row = layout.row()
row.operator("bim.add_bcf_header_file")
@@ -168,7 +168,7 @@ class BIM_PT_bcf_metadata(Panel):
row.operator("bim.open_uri", icon="URL", text="").uri = link.name
row.operator("bim.remove_bcf_reference_link", icon="X", text="").index = index
row = layout.row()
row.prop(topic, "reference_link")
row.prop(props, "reference_link")
row = layout.row()
row.operator("bim.add_bcf_reference_link")
@@ -178,7 +178,7 @@ class BIM_PT_bcf_metadata(Panel):
row.prop(label, "name", text="")
row.operator("bim.remove_bcf_label", icon="X", text="").index = index
row = layout.row()
row.prop(topic, "label")
row.prop(props, "label")
row = layout.row()
row.operator("bim.add_bcf_label")
@@ -199,12 +199,12 @@ class BIM_PT_bcf_metadata(Panel):
row.operator("bim.remove_bcf_bim_snippet", icon="X", text="")
else:
row = layout.row(align=True)
row.prop(topic, "bim_snippet_reference")
row.prop(props, "bim_snippet_reference")
row.operator("bim.select_bcf_bim_snippet_reference", icon="FILE_FOLDER", text="")
row = layout.row()
row.prop(topic, "bim_snippet_type")
row.prop(props, "bim_snippet_type")
row = layout.row()
row.prop(topic, "bim_snippet_schema")
row.prop(props, "bim_snippet_schema")
row = layout.row()
row.operator("bim.add_bcf_bim_snippet")
@@ -222,10 +222,10 @@ class BIM_PT_bcf_metadata(Panel):
row = box.row(align=True)
row.prop(doc, "description")
row = layout.row(align=True)
row.prop(topic, "document_reference")
row.prop(props, "document_reference")
row.operator("bim.select_bcf_document_reference", icon="FILE_FOLDER", text="")
row = layout.row()
row.prop(topic, "document_reference_description")
row.prop(props, "document_reference_description")
row = layout.row()
row.operator("bim.add_bcf_document_reference")
@@ -235,7 +235,7 @@ class BIM_PT_bcf_metadata(Panel):
row.operator("bim.view_bcf_topic", text=bcfxml.topics[related_topic.name.lower()].title).topic_guid = related_topic.name
row.operator("bim.remove_bcf_related_topic", icon="X", text="").index = index
row = layout.row()
row.prop(topic, "related_topic")
row.prop(props, "related_topic")
row = layout.row()
row.operator("bim.add_bcf_related_topic")
@@ -295,8 +295,8 @@ class BIM_PT_bcf_comments(Panel):
col.label(text=" ".join(line_words))
row = layout.row()
row.prop(topic, "comment")
row.prop(props, "comment")
row = layout.row()
row.prop(topic, "has_related_viewpoint")
row.prop(props, "has_related_viewpoint")
row = layout.row()
row.operator("bim.add_bcf_comment")