Fix bug where adding document references didn't work.

This commit is contained in:
Dion Moult
2022-03-09 22:14:59 +11:00
parent 578ab140cc
commit 673f757a51
7 changed files with 569 additions and 222 deletions
@@ -0,0 +1,84 @@
# BlenderBIM Add-on - OpenBIM Blender Add-on
# Copyright (C) 2022 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 ifcopenshell.util.schema
import blenderbim.tool as tool
def refresh():
DocumentData.is_loaded = False
ObjectDocumentData.is_loaded = False
class DocumentData:
data = {}
is_loaded = False
@classmethod
def load(cls):
cls.data = {
"total_information": cls.total_information(),
"total_references": cls.total_references(),
}
cls.is_loaded = True
@classmethod
def total_information(cls):
return len(tool.Ifc.get().by_type("IfcDocumentInformation"))
@classmethod
def total_references(cls):
return len(tool.Ifc.get().by_type("IfcDocumentReference"))
class ObjectDocumentData:
data = {}
is_loaded = False
@classmethod
def load(cls):
cls.data = {
"documents": cls.documents(),
}
cls.is_loaded = True
@classmethod
def documents(cls):
results = []
element = tool.Ifc.get_entity(bpy.context.active_object)
if not element:
return results
for rel in getattr(element, "HasAssociations", []):
if rel.is_a("IfcRelAssociatesDocument"):
if not rel.RelatingDocument.is_a("IfcDocumentReference"):
continue
if tool.Ifc.get_schema() == "IFC2X3":
identification = rel.RelatingDocument.ItemReference
else:
identification = rel.RelatingDocument.Identification
results.append(
{
"type": rel.RelatingDocument.is_a(),
"id": rel.RelatingDocument.id(),
"identification": identification,
"name": rel.RelatingDocument.Name,
}
)
return results
@@ -1,5 +1,5 @@
# BlenderBIM Add-on - OpenBIM Blender Add-on # BlenderBIM Add-on - OpenBIM Blender Add-on
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com> # Copyright (C) 2020, 2021, 2022 Dion Moult <dion@thinkmoult.com>
# #
# This file is part of BlenderBIM Add-on. # This file is part of BlenderBIM Add-on.
# #
@@ -20,303 +20,155 @@ import bpy
import json import json
import ifcopenshell.api import ifcopenshell.api
import ifcopenshell.util.attribute import ifcopenshell.util.attribute
import blenderbim.tool as tool
import blenderbim.core.document as core
from blenderbim.bim.ifc import IfcStore from blenderbim.bim.ifc import IfcStore
from ifcopenshell.api.document.data import Data from ifcopenshell.api.document.data import Data
class LoadInformation(bpy.types.Operator): class LoadInformation(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.load_information" bl_idname = "bim.load_information"
bl_label = "Load Information" bl_label = "Load Information"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def execute(self, context): def _execute(self, context):
self.file = IfcStore.get_file() core.load_information(tool.Document)
props = context.scene.BIMDocumentProperties
props.documents.clear()
for information_id, information in Data.information.items():
new = props.documents.add()
new.name = information["Name"] or "Unnamed"
if self.file.schema == "IFC2X3":
new.identification = information["DocumentId"] or "*"
else:
new.identification = information["Identification"] or "*"
new.ifc_definition_id = information_id
props.is_editing = "information"
bpy.ops.bim.disable_editing_document()
return {"FINISHED"}
class LoadDocumentReferences(bpy.types.Operator): class LoadDocumentReferences(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.load_document_references" bl_idname = "bim.load_document_references"
bl_label = "Load Document References" bl_label = "Load Document References"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def execute(self, context): def _execute(self, context):
self.file = IfcStore.get_file() core.load_references(tool.Document)
props = context.scene.BIMDocumentProperties
props.documents.clear()
for reference_id, reference in Data.references.items():
new = props.documents.add()
new.name = reference["Name"] or "Unnamed"
if self.file.schema == "IFC2X3":
new.identification = reference["ItemReference"] or "*"
else:
new.identification = reference["Identification"] or "*"
new.ifc_definition_id = reference_id
props.is_editing = "reference"
bpy.ops.bim.disable_editing_document()
return {"FINISHED"}
class DisableDocumentEditingUI(bpy.types.Operator): class DisableDocumentEditingUI(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.disable_document_editing_ui" bl_idname = "bim.disable_document_editing_ui"
bl_label = "Disable Document Editing UI" bl_label = "Disable Document Editing UI"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def execute(self, context): def _execute(self, context):
context.scene.BIMDocumentProperties.is_editing = "" core.disable_document_editing_ui(tool.Document)
bpy.ops.bim.disable_editing_document()
return {"FINISHED"}
class EnableEditingDocument(bpy.types.Operator): class EnableEditingDocument(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.enable_editing_document" bl_idname = "bim.enable_editing_document"
bl_label = "Enable Editing Document" bl_label = "Enable Editing Document"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
document: bpy.props.IntProperty() document: bpy.props.IntProperty()
def execute(self, context): def _execute(self, context):
props = context.scene.BIMDocumentProperties core.enable_editing_document(tool.Document, document=tool.Ifc.get().by_id(self.document))
props.document_attributes.clear()
if props.is_editing == "information":
data = Data.information[self.document]
ifc_class = "IfcDocumentInformation"
elif props.is_editing == "reference":
data = Data.references[self.document]
ifc_class = "IfcDocumentReference"
for attribute in IfcStore.get_schema().declaration_by_name(ifc_class).all_attributes():
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
if data_type == "entity":
continue
new = props.document_attributes.add()
new.name = attribute.name()
new.is_null = data[attribute.name()] is None
new.is_optional = attribute.optional()
new.data_type = data_type
if data_type == "string":
new.string_value = "" if new.is_null else data[attribute.name()]
elif data_type == "enum":
new.enum_items = json.dumps(ifcopenshell.util.attribute.get_enum_items(attribute))
if data[attribute.name()]:
new.enum_value = data[attribute.name()]
props.active_document_id = self.document
return {"FINISHED"}
class DisableEditingDocument(bpy.types.Operator): class DisableEditingDocument(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.disable_editing_document" bl_idname = "bim.disable_editing_document"
bl_label = "Disable Editing Document" bl_label = "Disable Editing Document"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def execute(self, context): def _execute(self, context):
context.scene.BIMDocumentProperties.active_document_id = 0 core.disable_editing_document(tool.Document)
return {"FINISHED"}
class AddInformation(bpy.types.Operator): class AddInformation(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.add_information" bl_idname = "bim.add_information"
bl_label = "Add Information" bl_label = "Add Information"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context): def _execute(self, context):
result = ifcopenshell.api.run("document.add_information", IfcStore.get_file()) core.add_information(tool.Ifc, tool.Document)
Data.load(IfcStore.get_file())
bpy.ops.bim.load_information()
bpy.ops.bim.enable_editing_document(document=result.id())
return {"FINISHED"}
class AddDocumentReference(bpy.types.Operator): class AddDocumentReference(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.add_document_reference" bl_idname = "bim.add_document_reference"
bl_label = "Add Document Reference" bl_label = "Add Document Reference"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context): def _execute(self, context):
result = ifcopenshell.api.run("document.add_reference", IfcStore.get_file()) core.add_reference(tool.Ifc, tool.Document)
Data.load(IfcStore.get_file())
bpy.ops.bim.load_document_references()
bpy.ops.bim.enable_editing_document(document=result.id())
return {"FINISHED"}
class EditInformation(bpy.types.Operator): class EditInformation(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.edit_information" bl_idname = "bim.edit_information"
bl_label = "Edit Information" bl_label = "Edit Information"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context): def _execute(self, context):
props = context.scene.BIMDocumentProperties props = context.scene.BIMDocumentProperties
attributes = {} core.edit_information(tool.Ifc, tool.Document, information=tool.Ifc.get().by_id(props.active_document_id))
for attribute in props.document_attributes:
if attribute.is_null:
attributes[attribute.name] = None
elif attribute.enum_items:
attributes[attribute.name] = attribute.enum_value
else:
attributes[attribute.name] = attribute.string_value
self.file = IfcStore.get_file()
ifcopenshell.api.run(
"document.edit_information",
self.file,
**{"information": self.file.by_id(props.active_document_id), "attributes": attributes}
)
Data.load(IfcStore.get_file())
bpy.ops.bim.load_information()
return {"FINISHED"}
class EditDocumentReference(bpy.types.Operator): class EditDocumentReference(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.edit_document_reference" bl_idname = "bim.edit_document_reference"
bl_label = "Edit Document Reference" bl_label = "Edit Document Reference"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context): def _execute(self, context):
props = context.scene.BIMDocumentProperties props = context.scene.BIMDocumentProperties
attributes = {} core.edit_reference(tool.Ifc, tool.Document, reference=tool.Ifc.get().by_id(props.active_document_id))
for attribute in props.document_attributes:
if attribute.is_null:
attributes[attribute.name] = None
else:
attributes[attribute.name] = attribute.string_value
self.file = IfcStore.get_file()
ifcopenshell.api.run(
"document.edit_reference",
self.file,
**{"reference": self.file.by_id(props.active_document_id), "attributes": attributes}
)
Data.load(IfcStore.get_file())
bpy.ops.bim.load_document_references()
return {"FINISHED"}
class RemoveDocument(bpy.types.Operator): class RemoveDocument(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.remove_document" bl_idname = "bim.remove_document"
bl_label = "Remove Document" bl_label = "Remove Document"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
document: bpy.props.IntProperty() document: bpy.props.IntProperty()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context): def _execute(self, context):
props = context.scene.BIMDocumentProperties core.remove_document(tool.Ifc, tool.Document, document=tool.Ifc.get().by_id(self.document))
self.file = IfcStore.get_file()
ifcopenshell.api.run("document.remove_document", self.file, **{"document": self.file.by_id(self.document)})
Data.load(IfcStore.get_file())
if props.is_editing == "information":
bpy.ops.bim.load_information()
elif props.is_editing == "reference":
bpy.ops.bim.load_document_references()
return {"FINISHED"}
class EnableAssigningDocument(bpy.types.Operator): class EnableAssigningDocument(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.enable_assigning_document" bl_idname = "bim.enable_assigning_document"
bl_label = "Enable Assigning Document" bl_label = "Enable Assigning Document"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
obj: bpy.props.StringProperty() obj: bpy.props.StringProperty()
def execute(self, context): def _execute(self, context):
obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object
props = obj.BIMObjectDocumentProperties core.enable_assigning_document(tool.Document, obj)
if props.available_document_types == "IfcDocumentInformation":
bpy.ops.bim.load_information()
elif props.available_document_types == "IfcDocumentReference":
bpy.ops.bim.load_document_references()
props.is_adding = props.available_document_types
return {"FINISHED"}
class DisableAssigningDocument(bpy.types.Operator): class DisableAssigningDocument(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.disable_assigning_document" bl_idname = "bim.disable_assigning_document"
bl_label = "Disable Assigning Document" bl_label = "Disable Assigning Document"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
obj: bpy.props.StringProperty() obj: bpy.props.StringProperty()
def execute(self, context): def _execute(self, context):
obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object
props = obj.BIMObjectDocumentProperties core.enable_assigning_document(tool.Document, obj)
props.is_adding = ""
return {"FINISHED"}
class AssignDocument(bpy.types.Operator): class AssignDocument(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.assign_document" bl_idname = "bim.assign_document"
bl_label = "Assign Document" bl_label = "Assign Document"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
obj: bpy.props.StringProperty() obj: bpy.props.StringProperty()
document: bpy.props.IntProperty() document: bpy.props.IntProperty()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context): def _execute(self, context):
self.file = IfcStore.get_file() document = tool.Ifc.get().by_id(self.document)
objs = [bpy.data.objects.get(self.obj)] if self.obj else context.selected_objects objs = [bpy.data.objects.get(self.obj)] if self.obj else context.selected_objects
for obj in objs: for obj in objs:
obj_id = obj.BIMObjectProperties.ifc_definition_id element = tool.Ifc.get_entity(obj)
if not obj_id: if element:
continue core.assign_document(tool.Ifc, product=element, document=document)
ifcopenshell.api.run(
"document.assign_document",
self.file,
**{
"product": self.file.by_id(obj_id),
"document": self.file.by_id(self.document),
}
)
Data.load(self.file, obj_id)
return {"FINISHED"}
class UnassignDocument(bpy.types.Operator): class UnassignDocument(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.unassign_document" bl_idname = "bim.unassign_document"
bl_label = "Unassign Document" bl_label = "Unassign Document"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
obj: bpy.props.StringProperty() obj: bpy.props.StringProperty()
document: bpy.props.IntProperty() document: bpy.props.IntProperty()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context): def _execute(self, context):
self.file = IfcStore.get_file() document = tool.Ifc.get().by_id(self.document)
objs = [bpy.data.objects.get(self.obj)] if self.obj else context.selected_objects objs = [bpy.data.objects.get(self.obj)] if self.obj else context.selected_objects
for obj in objs: for obj in objs:
obj_id = obj.BIMObjectProperties.ifc_definition_id element = tool.Ifc.get_entity(obj)
if not obj_id: if element:
continue core.unassign_document(tool.Ifc, product=element, document=document)
ifcopenshell.api.run(
"document.unassign_document",
self.file,
**{
"product": self.file.by_id(obj_id),
"document": self.file.by_id(self.document),
}
)
Data.load(self.file, obj_id)
return {"FINISHED"}
@@ -19,7 +19,7 @@
from bpy.types import Panel, UIList from bpy.types import Panel, UIList
from blenderbim.bim.ifc import IfcStore from blenderbim.bim.ifc import IfcStore
from blenderbim.bim.helper import draw_attributes from blenderbim.bim.helper import draw_attributes
from ifcopenshell.api.document.data import Data from blenderbim.bim.module.document.data import DocumentData, ObjectDocumentData
class BIM_PT_documents(Panel): class BIM_PT_documents(Panel):
@@ -36,14 +36,14 @@ class BIM_PT_documents(Panel):
return IfcStore.get_file() return IfcStore.get_file()
def draw(self, context): def draw(self, context):
if not Data.is_loaded: if not DocumentData.is_loaded:
Data.load(IfcStore.get_file()) DocumentData.load()
self.props = context.scene.BIMDocumentProperties self.props = context.scene.BIMDocumentProperties
if not self.props.is_editing or self.props.is_editing == "information": if not self.props.is_editing or self.props.is_editing == "information":
row = self.layout.row(align=True) row = self.layout.row(align=True)
row.label(text="{} Documents Found".format(len(Data.information)), icon="FILE") row.label(text="{} Documents Found".format(DocumentData.data["total_information"]), icon="FILE")
if self.props.is_editing == "information": if self.props.is_editing == "information":
row.operator("bim.add_information", text="", icon="ADD") row.operator("bim.add_information", text="", icon="ADD")
row.operator("bim.disable_document_editing_ui", text="", icon="CANCEL") row.operator("bim.disable_document_editing_ui", text="", icon="CANCEL")
@@ -52,7 +52,7 @@ class BIM_PT_documents(Panel):
if not self.props.is_editing or self.props.is_editing == "reference": if not self.props.is_editing or self.props.is_editing == "reference":
row = self.layout.row(align=True) row = self.layout.row(align=True)
row.label(text="{} References Found".format(len(Data.references)), icon="FILE_HIDDEN") row.label(text="{} References Found".format(DocumentData.data["total_references"]), icon="FILE_HIDDEN")
if self.props.is_editing == "reference": if self.props.is_editing == "reference":
row.operator("bim.add_document_reference", text="", icon="ADD") row.operator("bim.add_document_reference", text="", icon="ADD")
row.operator("bim.disable_document_editing_ui", text="", icon="CANCEL") row.operator("bim.disable_document_editing_ui", text="", icon="CANCEL")
@@ -89,43 +89,26 @@ class BIM_PT_object_documents(Panel):
return bool(context.active_object.BIMObjectProperties.ifc_definition_id) return bool(context.active_object.BIMObjectProperties.ifc_definition_id)
def draw(self, context): def draw(self, context):
if not ObjectDocumentData.is_loaded:
ObjectDocumentData.load()
obj = context.active_object obj = context.active_object
self.oprops = obj.BIMObjectProperties self.oprops = obj.BIMObjectProperties
self.sprops = context.scene.BIMDocumentProperties self.sprops = context.scene.BIMDocumentProperties
self.props = obj.BIMObjectDocumentProperties self.props = obj.BIMObjectDocumentProperties
self.file = IfcStore.get_file() self.file = IfcStore.get_file()
if not Data.is_loaded:
Data.load(IfcStore.get_file())
if self.oprops.ifc_definition_id not in Data.products:
Data.load(IfcStore.get_file(), self.oprops.ifc_definition_id)
self.draw_add_ui() self.draw_add_ui()
document_ids = Data.products[self.oprops.ifc_definition_id] if not ObjectDocumentData.data["documents"]:
if not document_ids:
row = self.layout.row(align=True) row = self.layout.row(align=True)
row.label(text="No Documents", icon="FILE") row.label(text="No Documents", icon="FILE")
for document_id in document_ids: for document in ObjectDocumentData.data["documents"]:
try:
document = Data.information[document_id]
document_type = "IfcDocumentInformation"
icon = "FILE"
except:
document = Data.references[document_id]
document_type = "IfcDocumentReference"
icon = "FILE_HIDDEN"
row = self.layout.row(align=True) row = self.layout.row(align=True)
if self.file.schema == "IFC2X3": row.label(text=document["identification"] or "*", icon="FILE")
if document_type == "IfcDocumentInformation": row.label(text=document["name"] or "Unnamed")
row.label(text=document.get("DocumentId") or "*", icon=icon) row.operator("bim.unassign_document", text="", icon="X").document = document["id"]
elif document_type == "IfcDocumentReference":
row.label(text=document.get("ItemReference") or "*", icon=icon)
else:
row.label(text=document.get("Identification") or "*", icon=icon)
row.label(text=document.get("Name") or "Unnamed")
row.operator("bim.unassign_document", text="", icon="X").document = document_id
def draw_add_ui(self): def draw_add_ui(self):
if self.props.is_adding: if self.props.is_adding:
@@ -0,0 +1,93 @@
# BlenderBIM Add-on - OpenBIM Blender Add-on
# Copyright (C) 2022 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.util.system
import blenderbim.core.tool
import blenderbim.tool as tool
from blenderbim.bim import import_ifc
class Document(blenderbim.core.tool.Document):
@classmethod
def disable_document_assignment_ui(cls, obj):
obj.BIMObjectDocumentProperties.is_adding = ""
@classmethod
def disable_editing_document(cls):
bpy.context.scene.BIMDocumentProperties.active_document_id = 0
@classmethod
def disable_editing_ui(cls):
bpy.context.scene.BIMDocumentProperties.is_editing = ""
@classmethod
def enable_document_assignment_ui(cls, obj):
obj.BIMObjectDocumentProperties.is_adding = "IfcDocumentReference"
@classmethod
def enable_information_editing_ui(cls):
bpy.context.scene.BIMDocumentProperties.is_editing = "information"
@classmethod
def enable_reference_editing_ui(cls):
bpy.context.scene.BIMDocumentProperties.is_editing = "reference"
@classmethod
def export_document_attributes(cls):
return blenderbim.bim.helper.export_attributes(bpy.context.scene.BIMDocumentProperties.document_attributes)
@classmethod
def import_document_attributes(cls, document):
props = bpy.context.scene.BIMDocumentProperties
props.document_attributes.clear()
blenderbim.bim.helper.import_attributes2(document, props.document_attributes)
@classmethod
def import_information(cls):
props = bpy.context.scene.BIMDocumentProperties
props.documents.clear()
for element in tool.Ifc.get().by_type("IfcDocumentInformation"):
new = props.documents.add()
new.ifc_definition_id = element.id()
new.name = element.Name or "Unnamed"
if tool.Ifc.get_schema() == "IFC2X3":
new.identification = element.DocumentId or "*"
else:
new.identification = element.Identification or "*"
@classmethod
def import_references(cls):
props = bpy.context.scene.BIMDocumentProperties
props.documents.clear()
for element in tool.Ifc.get().by_type("IfcDocumentReference"):
new = props.documents.add()
new.ifc_definition_id = element.id()
new.name = element.Name or "Unnamed"
if tool.Ifc.get_schema() == "IFC2X3":
new.identification = element.ItemReference or "*"
else:
new.identification = element.Identification or "*"
@classmethod
def is_document_information(cls, document):
return document.is_a("IfcDocumentInformation")
@classmethod
def set_active_document(cls, document):
bpy.context.scene.BIMDocumentProperties.active_document_id = document.id()
+7
View File
@@ -77,6 +77,13 @@ def demo():
prophet.verify() prophet.verify()
@pytest.fixture
def document():
prophet = Prophecy(blenderbim.core.tool.Document)
yield prophet
prophet.verify()
@pytest.fixture @pytest.fixture
def drawing(): def drawing():
prophet = Prophecy(blenderbim.core.tool.Drawing) prophet = Prophecy(blenderbim.core.tool.Drawing)
+136
View File
@@ -0,0 +1,136 @@
# BlenderBIM Add-on - OpenBIM Blender Add-on
# Copyright (C) 2022 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 blenderbim.core.document as subject
from test.core.bootstrap import ifc, document
class TestLoadInformation:
def test_run(self, document):
document.import_information().should_be_called()
document.enable_information_editing_ui().should_be_called()
document.disable_editing_document().should_be_called()
subject.load_information(document)
class TestLoadReferences:
def test_run(self, document):
document.import_references().should_be_called()
document.enable_reference_editing_ui().should_be_called()
document.disable_editing_document().should_be_called()
subject.load_references(document)
class TestDisableDocumentEditingUi:
def test_run(self, document):
document.disable_editing_ui().should_be_called()
document.disable_editing_document().should_be_called()
subject.disable_document_editing_ui(document)
class TestEnableEditingDocument:
def test_run(self, document):
document.import_document_attributes("document").should_be_called()
document.set_active_document("document").should_be_called()
subject.enable_editing_document(document, document="document")
class TestDisableEditingDocument:
def test_run(self, document):
document.disable_editing_document().should_be_called()
subject.disable_editing_document(document)
class TestAddInformation:
def test_run(self, ifc, document):
ifc.run("document.add_information").should_be_called().will_return("information")
document.import_information().should_be_called()
document.import_document_attributes("information").should_be_called()
document.set_active_document("information").should_be_called()
subject.add_information(ifc, document)
class TestAddReference:
def test_run(self, ifc, document):
ifc.run("document.add_reference").should_be_called().will_return("reference")
document.import_references().should_be_called()
document.import_document_attributes("reference").should_be_called()
document.set_active_document("reference").should_be_called()
subject.add_reference(ifc, document)
class TestEditInformation:
def test_run(self, ifc, document):
document.export_document_attributes().should_be_called().will_return("attributes")
ifc.run("document.edit_information", information="information", attributes="attributes").should_be_called()
document.disable_editing_document().should_be_called()
document.import_information().should_be_called()
subject.edit_information(ifc, document, information="information")
class TestEditInformation:
def test_run(self, ifc, document):
document.export_document_attributes().should_be_called().will_return("attributes")
ifc.run("document.edit_reference", reference="reference", attributes="attributes").should_be_called()
document.disable_editing_document().should_be_called()
document.import_references().should_be_called()
subject.edit_reference(ifc, document, reference="reference")
class TestRemoveDocument:
def test_remove_information(self, ifc, document):
document.is_document_information("document").should_be_called().will_return(True)
ifc.run("document.remove_document", document="document").should_be_called()
document.import_information().should_be_called()
document.disable_editing_document().should_be_called()
subject.remove_document(ifc, document, document="document")
def test_remove_reference(self, ifc, document):
document.is_document_information("document").should_be_called().will_return(False)
ifc.run("document.remove_document", document="document").should_be_called()
document.import_references().should_be_called()
document.disable_editing_document().should_be_called()
subject.remove_document(ifc, document, document="document")
class TestEnableAssigningDocument:
def test_run(self, document):
document.import_references().should_be_called()
document.enable_reference_editing_ui().should_be_called()
document.disable_editing_document().should_be_called()
document.enable_document_assignment_ui("obj").should_be_called()
subject.enable_assigning_document(document, obj="obj")
class TestDisableAssigningDocument:
def test_run(self, document):
document.disable_document_assignment_ui("obj").should_be_called()
subject.disable_assigning_document(document, obj="obj")
class TestAssignDocument:
def test_run(self, ifc):
ifc.run("document.assign_document", product="product", document="document").should_be_called()
subject.assign_document(ifc, product="product", document="document")
class TestUnassignDocument:
def test_run(self, ifc):
ifc.run("document.unassign_document", product="product", document="document").should_be_called()
subject.unassign_document(ifc, product="product", document="document")
+192
View File
@@ -0,0 +1,192 @@
# BlenderBIM Add-on - OpenBIM Blender Add-on
# Copyright (C) 2022 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 blenderbim.core.tool
import blenderbim.tool as tool
from test.bim.bootstrap import NewFile
from blenderbim.tool.document import Document as subject
class TestImplementsTool(NewFile):
def test_run(self):
assert isinstance(subject(), blenderbim.core.tool.Document)
class TestDisableDocumentAssignmentUI(NewFile):
def test_run(self):
obj = bpy.data.objects.new("Object", None)
obj.BIMObjectDocumentProperties.is_adding = "foo"
subject.disable_document_assignment_ui(obj)
assert obj.BIMObjectDocumentProperties.is_adding == ""
class TestDisableEditingDocument(NewFile):
def test_run(self):
bpy.context.scene.BIMDocumentProperties.active_document_id = 1
subject.disable_editing_document()
assert bpy.context.scene.BIMDocumentProperties.active_document_id == 0
class TestDisableEditingUI(NewFile):
def test_run(self):
bpy.context.scene.BIMDocumentProperties.is_editing = "is_editing"
subject.disable_editing_ui()
assert bpy.context.scene.BIMDocumentProperties.is_editing == ""
class TestEnableDocumentAssignmentUI(NewFile):
def test_run(self):
obj = bpy.data.objects.new("Object", None)
obj.BIMObjectDocumentProperties.is_adding = ""
subject.enable_document_assignment_ui(obj)
assert obj.BIMObjectDocumentProperties.is_adding == "IfcDocumentReference"
class TestEnableInformationEditingUI(NewFile):
def test_run(self):
bpy.context.scene.BIMDocumentProperties.is_editing = ""
subject.enable_information_editing_ui()
assert bpy.context.scene.BIMDocumentProperties.is_editing == "information"
class TestEnableReferenceEditingUI(NewFile):
def test_run(self):
bpy.context.scene.BIMDocumentProperties.is_editing = ""
subject.enable_reference_editing_ui()
assert bpy.context.scene.BIMDocumentProperties.is_editing == "reference"
class TestExportDocumentAttributes(NewFile):
def test_exporting_information(self):
TestImportDocumentAttributes().test_importing_information()
assert subject.export_document_attributes() == {
"Identification": "Identification",
"Name": "Name",
"Description": "Description",
"Location": "Location",
"Purpose": "Purpose",
"IntendedUse": "IntendedUse",
"Scope": "Scope",
"Revision": "Revision",
"CreationTime": "CreationTime",
"LastRevisionTime": "LastRevisionTime",
"ElectronicFormat": "ElectronicFormat",
"ValidFrom": "ValidFrom",
"ValidUntil": "ValidUntil",
"Confidentiality": "CONFIDENTIAL",
"Status": "DRAFT",
}
class TestImportDocumentAttributes(NewFile):
def test_importing_information(self):
ifc = ifcopenshell.file()
tool.Ifc().set(ifc)
document = ifc.createIfcDocumentInformation()
document.Identification = "Identification"
document.Name = "Name"
document.Description = "Description"
document.Location = "Location"
document.Purpose = "Purpose"
document.IntendedUse = "IntendedUse"
document.Scope = "Scope"
document.Revision = "Revision"
document.CreationTime = "CreationTime"
document.LastRevisionTime = "LastRevisionTime"
document.ElectronicFormat = "ElectronicFormat"
document.ValidFrom = "ValidFrom"
document.ValidUntil = "ValidUntil"
document.Confidentiality = "CONFIDENTIAL"
document.Status = "DRAFT"
subject().import_document_attributes(document)
props = bpy.context.scene.BIMDocumentProperties
assert props.document_attributes.get("Identification").string_value == "Identification"
assert props.document_attributes.get("Name").string_value == "Name"
assert props.document_attributes.get("Description").string_value == "Description"
assert props.document_attributes.get("Location").string_value == "Location"
assert props.document_attributes.get("Purpose").string_value == "Purpose"
assert props.document_attributes.get("IntendedUse").string_value == "IntendedUse"
assert props.document_attributes.get("Scope").string_value == "Scope"
assert props.document_attributes.get("Revision").string_value == "Revision"
assert props.document_attributes.get("CreationTime").string_value == "CreationTime"
assert props.document_attributes.get("LastRevisionTime").string_value == "LastRevisionTime"
assert props.document_attributes.get("ElectronicFormat").string_value == "ElectronicFormat"
assert props.document_attributes.get("ValidFrom").string_value == "ValidFrom"
assert props.document_attributes.get("ValidUntil").string_value == "ValidUntil"
assert props.document_attributes.get("Confidentiality").enum_value == "CONFIDENTIAL"
assert props.document_attributes.get("Status").enum_value == "DRAFT"
def test_importing_reference(self):
ifc = ifcopenshell.file()
tool.Ifc().set(ifc)
document = ifc.createIfcDocumentInformation()
document.Location = "Location"
document.Identification = "Identification"
document.Name = "Name"
document.Description = "Description"
subject().import_document_attributes(document)
props = bpy.context.scene.BIMDocumentProperties
assert props.document_attributes.get("Location").string_value == "Location"
assert props.document_attributes.get("Identification").string_value == "Identification"
assert props.document_attributes.get("Name").string_value == "Name"
assert props.document_attributes.get("Description").string_value == "Description"
class TestImportInformation(NewFile):
def test_run(self):
ifc = ifcopenshell.file()
tool.Ifc().set(ifc)
document = ifc.createIfcDocumentInformation()
subject.import_information()
props = bpy.context.scene.BIMDocumentProperties
assert len(props.documents) == 1
assert props.documents[0].ifc_definition_id == document.id()
assert props.documents[0].name == "Unnamed"
assert props.documents[0].identification == "*"
class TestImportReference(NewFile):
def test_run(self):
ifc = ifcopenshell.file()
tool.Ifc().set(ifc)
document = ifc.createIfcDocumentReference()
subject.import_references()
props = bpy.context.scene.BIMDocumentProperties
assert len(props.documents) == 1
assert props.documents[0].ifc_definition_id == document.id()
assert props.documents[0].name == "Unnamed"
assert props.documents[0].identification == "*"
class TestIsDocumentInformation(NewFile):
def test_run(self):
ifc = ifcopenshell.file()
information = ifc.createIfcDocumentInformation()
reference = ifc.createIfcDocumentReference()
assert subject.is_document_information(information) is True
assert subject.is_document_information(reference) is False
class TestSetActiveDocument(NewFile):
def test_run(self):
ifc = ifcopenshell.file()
document = ifc.createIfcDocumentInformation()
subject.set_active_document(document)
assert bpy.context.scene.BIMDocumentProperties.active_document_id == document.id()