mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-19 14:41:25 +00:00
updates based on developers feedback
This commit is contained in:
@@ -28,14 +28,12 @@ classes = (
|
|||||||
operator.DisableEditingDocument,
|
operator.DisableEditingDocument,
|
||||||
operator.EditDocument,
|
operator.EditDocument,
|
||||||
operator.EnableEditingDocument,
|
operator.EnableEditingDocument,
|
||||||
operator.LoadDocument,
|
|
||||||
operator.LoadObjectDocuments,
|
operator.LoadObjectDocuments,
|
||||||
operator.LoadProjectDocuments,
|
operator.LoadProjectDocuments,
|
||||||
operator.RemoveDocument,
|
operator.RemoveDocument,
|
||||||
operator.SelectDocumentObjects,
|
operator.SelectDocumentObjects,
|
||||||
operator.ToggleDocument,
|
operator.ToggleDocument,
|
||||||
operator.UnassignDocument,
|
operator.UnassignDocument,
|
||||||
operator.UpdateAssignedDocuments,
|
|
||||||
operator.OpenIFCDocument,
|
operator.OpenIFCDocument,
|
||||||
prop.Document,
|
prop.Document,
|
||||||
prop.DocumentObject,
|
prop.DocumentObject,
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import bpy
|
|||||||
import ifcopenshell
|
import ifcopenshell
|
||||||
import ifcopenshell.util.schema
|
import ifcopenshell.util.schema
|
||||||
import bonsai.tool as tool
|
import bonsai.tool as tool
|
||||||
|
from natsort import natsorted
|
||||||
|
|
||||||
def refresh():
|
def refresh():
|
||||||
DocumentData.is_loaded = False
|
DocumentData.is_loaded = False
|
||||||
@@ -87,19 +87,21 @@ class DocumentData:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def load_document_objects_into_props(cls, document_id):
|
def load_document_objects_into_props(cls, document_id):
|
||||||
|
if not cls.is_loaded:
|
||||||
|
cls.load()
|
||||||
|
|
||||||
props = tool.Document.get_document_props()
|
props = tool.Document.get_document_props()
|
||||||
props.document_objects.clear()
|
props.document_objects.clear()
|
||||||
|
|
||||||
if "document_objects" not in cls.data or document_id not in cls.data["document_objects"]:
|
if document_id not in cls.data["document_objects"]:
|
||||||
return
|
return
|
||||||
|
|
||||||
sorted_objects = sorted(cls.data["document_objects"][document_id], key=lambda x: x["name"].lower())
|
sorted_objects = natsorted(cls.data["document_objects"][document_id], key=lambda x: x["name"].lower())
|
||||||
|
|
||||||
for obj_data in sorted_objects:
|
for obj_data in sorted_objects:
|
||||||
item = props.document_objects.add()
|
item = props.document_objects.add()
|
||||||
item.name = obj_data["name"]
|
item.name = obj_data["name"]
|
||||||
|
|
||||||
|
|
||||||
class ObjectDocumentData:
|
class ObjectDocumentData:
|
||||||
data = {}
|
data = {}
|
||||||
is_loaded = False
|
is_loaded = False
|
||||||
@@ -111,6 +113,19 @@ class ObjectDocumentData:
|
|||||||
}
|
}
|
||||||
cls.is_loaded = True
|
cls.is_loaded = True
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def convert_to_file_uri(location: str) -> str:
|
||||||
|
if not location:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
uri = location
|
||||||
|
if not uri.startswith("file://"):
|
||||||
|
if not os.path.isabs(uri):
|
||||||
|
uri = os.path.abspath(os.path.join(os.path.dirname(tool.Ifc.get_path()), uri))
|
||||||
|
uri = "file://" + uri
|
||||||
|
return uri
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def documents(cls):
|
def documents(cls):
|
||||||
results = []
|
results = []
|
||||||
@@ -165,11 +180,7 @@ class ObjectDocumentData:
|
|||||||
if location is None and referenced_document:
|
if location is None and referenced_document:
|
||||||
location = referenced_document.Location
|
location = referenced_document.Location
|
||||||
|
|
||||||
if location:
|
location = cls.convert_to_file_uri(location) if location else None
|
||||||
if not "://" in location:
|
|
||||||
if not os.path.isabs(location):
|
|
||||||
location = os.path.abspath(os.path.join(os.path.dirname(tool.Ifc.get_path()), location))
|
|
||||||
location = "file://" + location
|
|
||||||
|
|
||||||
results.append(
|
results.append(
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -18,29 +18,10 @@
|
|||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
import json
|
import json
|
||||||
import ifcopenshell.api
|
|
||||||
import ifcopenshell.util.attribute
|
|
||||||
import ifcopenshell.util.element
|
|
||||||
import bonsai.bim.handler
|
import bonsai.bim.handler
|
||||||
import bonsai.tool as tool
|
import bonsai.tool as tool
|
||||||
import bonsai.core.document as core
|
import bonsai.core.document as core
|
||||||
import subprocess
|
from .data import DocumentData, ObjectDocumentData
|
||||||
import os
|
|
||||||
from bonsai.bim.module.document.data import DocumentData, ObjectDocumentData
|
|
||||||
|
|
||||||
|
|
||||||
def update_document_objects(document_id=None):
|
|
||||||
DocumentData.is_loaded = False
|
|
||||||
DocumentData.load()
|
|
||||||
|
|
||||||
if document_id is None:
|
|
||||||
props = tool.Document.get_document_props()
|
|
||||||
if props.active_document and props.active_document.ifc_definition_id:
|
|
||||||
document_id = props.active_document.ifc_definition_id
|
|
||||||
|
|
||||||
if document_id:
|
|
||||||
DocumentData.load_document_objects_into_props(document_id)
|
|
||||||
|
|
||||||
|
|
||||||
class LoadProjectDocuments(bpy.types.Operator):
|
class LoadProjectDocuments(bpy.types.Operator):
|
||||||
bl_idname = "bim.load_project_documents"
|
bl_idname = "bim.load_project_documents"
|
||||||
@@ -49,23 +30,8 @@ class LoadProjectDocuments(bpy.types.Operator):
|
|||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
core.load_project_documents(tool.Document)
|
core.load_project_documents(tool.Document)
|
||||||
update_document_objects()
|
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class LoadDocument(bpy.types.Operator):
|
|
||||||
bl_idname = "bim.load_document"
|
|
||||||
bl_label = "Load Document"
|
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
|
||||||
document: bpy.props.IntProperty()
|
|
||||||
|
|
||||||
def execute(self, context):
|
|
||||||
core.load_document(tool.Document, document=tool.Ifc.get().by_id(self.document))
|
|
||||||
bonsai.bim.handler.refresh_ui_data() # Is this needed?
|
|
||||||
update_document_objects()
|
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
|
|
||||||
class DisableDocumentEditingUI(bpy.types.Operator):
|
class DisableDocumentEditingUI(bpy.types.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"
|
||||||
@@ -82,8 +48,7 @@ class DisableObjectDocumentEditingUI(bpy.types.Operator):
|
|||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
props = tool.Document.get_document_props()
|
core.disable_object_document_editing_ui(tool.Document)
|
||||||
props.is_object_editing = False
|
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
@@ -94,8 +59,6 @@ class EnableEditingDocument(bpy.types.Operator):
|
|||||||
document: bpy.props.IntProperty()
|
document: bpy.props.IntProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
props = tool.Document.get_document_props()
|
|
||||||
props.is_document_editing = True
|
|
||||||
core.enable_editing_document(tool.Document, document=tool.Ifc.get().by_id(self.document))
|
core.enable_editing_document(tool.Document, document=tool.Ifc.get().by_id(self.document))
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
@@ -106,8 +69,6 @@ class DisableEditingDocument(bpy.types.Operator):
|
|||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
props = tool.Document.get_document_props()
|
|
||||||
props.is_document_editing = False
|
|
||||||
core.disable_editing_document(tool.Document)
|
core.disable_editing_document(tool.Document)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
@@ -123,15 +84,15 @@ class AddInformation(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
if props.active_document:
|
if props.active_document:
|
||||||
selected_document = props.active_document
|
selected_document = props.active_document
|
||||||
|
|
||||||
if selected_document.ifc_definition_id == -1:
|
if selected_document.document_type == "PROJECT":
|
||||||
parent = tool.Ifc.get().by_type("IfcProject")[0] if tool.Ifc.get().by_type("IfcProject") else None
|
parent = tool.Ifc.get().by_type("IfcProject")[0]
|
||||||
elif selected_document.is_information:
|
elif selected_document.document_type == "INFORMATION":
|
||||||
parent = tool.Ifc.get().by_id(selected_document.ifc_definition_id)
|
parent = tool.Ifc.get().by_id(selected_document.ifc_definition_id)
|
||||||
else:
|
elif selected_document.document_type == "REFERENCE":
|
||||||
self.report({"ERROR"}, "Cannot add an information element as a child of a reference element")
|
self.report({"ERROR"}, "Cannot add an information element as a child of a reference element")
|
||||||
return {"CANCELLED"}
|
return {"CANCELLED"}
|
||||||
else:
|
else:
|
||||||
parent = tool.Ifc.get().by_type("IfcProject")[0] if tool.Ifc.get().by_type("IfcProject") else None
|
parent = tool.Ifc.get().by_type("IfcProject")[0]
|
||||||
|
|
||||||
core.add_information(tool.Ifc, tool.Document, parent)
|
core.add_information(tool.Ifc, tool.Document, parent)
|
||||||
|
|
||||||
@@ -141,20 +102,13 @@ class AddInformation(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
except (AttributeError, json.JSONDecodeError):
|
except (AttributeError, json.JSONDecodeError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
project = tool.Ifc.get().by_type("IfcProject")[0]
|
|
||||||
virtual_root_id = -project.id()
|
|
||||||
if virtual_root_id in expanded_docs:
|
|
||||||
expanded_docs.remove(virtual_root_id)
|
|
||||||
|
|
||||||
if parent and parent.is_a("IfcDocumentInformation"):
|
if parent and parent.is_a("IfcDocumentInformation"):
|
||||||
if parent.id() not in expanded_docs:
|
if parent.id() not in expanded_docs:
|
||||||
expanded_docs.append(parent.id())
|
expanded_docs.append(parent.id())
|
||||||
|
|
||||||
props.json_string = json.dumps(expanded_docs)
|
props.json_string = json.dumps(expanded_docs)
|
||||||
|
|
||||||
bpy.ops.bim.load_project_documents()
|
bpy.ops.bim.load_project_documents()
|
||||||
|
|
||||||
|
|
||||||
class AddDocumentReference(bpy.types.Operator, tool.Ifc.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"
|
||||||
@@ -169,8 +123,8 @@ class AddDocumentReference(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
|
|
||||||
selected_document = props.active_document
|
selected_document = props.active_document
|
||||||
|
|
||||||
if not selected_document.is_information:
|
if selected_document.document_type != "INFORMATION":
|
||||||
self.report({"ERROR"}, "Cannot add a reference to a reference element")
|
self.report({"ERROR"}, "Cannot add a reference to a document that is not an information element")
|
||||||
return {"CANCELLED"}
|
return {"CANCELLED"}
|
||||||
|
|
||||||
parent = tool.Ifc.get().by_id(selected_document.ifc_definition_id)
|
parent = tool.Ifc.get().by_id(selected_document.ifc_definition_id)
|
||||||
@@ -201,12 +155,7 @@ class EditDocument(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
core.edit_document(tool.Ifc, tool.Document, document=tool.Ifc.get().by_id(props.active_document_id))
|
core.edit_document(tool.Ifc, tool.Document, document=tool.Ifc.get().by_id(props.active_document_id))
|
||||||
props.active_document_id = 0
|
props.active_document_id = 0
|
||||||
props.is_document_editing = False
|
props.is_document_editing = False
|
||||||
DocumentData.is_loaded = False
|
tool.Document.update_assigned_documents()
|
||||||
DocumentData.load()
|
|
||||||
ObjectDocumentData.is_loaded = False
|
|
||||||
ObjectDocumentData.load()
|
|
||||||
bpy.ops.bim.update_assigned_documents()
|
|
||||||
bonsai.bim.handler.refresh_ui_data()
|
|
||||||
|
|
||||||
|
|
||||||
class RemoveDocument(bpy.types.Operator, tool.Ifc.Operator):
|
class RemoveDocument(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
@@ -218,40 +167,6 @@ class RemoveDocument(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
core.remove_document(tool.Ifc, tool.Document, document=tool.Ifc.get().by_id(self.document))
|
core.remove_document(tool.Ifc, tool.Document, document=tool.Ifc.get().by_id(self.document))
|
||||||
|
|
||||||
|
|
||||||
class UpdateAssignedDocuments(bpy.types.Operator):
|
|
||||||
bl_idname = "bim.update_assigned_documents"
|
|
||||||
bl_label = "Update Assigned Documents"
|
|
||||||
bl_description = "Update the list of documents assigned to the active object"
|
|
||||||
bl_options = {"REGISTER"}
|
|
||||||
|
|
||||||
def execute(self, context):
|
|
||||||
ObjectDocumentData.is_loaded = False
|
|
||||||
ObjectDocumentData.load()
|
|
||||||
|
|
||||||
props = tool.Document.get_document_props()
|
|
||||||
props.assigned_documents.clear()
|
|
||||||
|
|
||||||
if not ObjectDocumentData.data.get("documents"):
|
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
sorted_docs = sorted(
|
|
||||||
ObjectDocumentData.data["documents"],
|
|
||||||
key=lambda doc: ((doc.get("identification") or "").lower(), (doc.get("name") or "").lower()),
|
|
||||||
)
|
|
||||||
|
|
||||||
for document in sorted_docs:
|
|
||||||
new = props.assigned_documents.add()
|
|
||||||
new.name = document["name"] or "Unnamed"
|
|
||||||
new.identification = document["identification"] or "*"
|
|
||||||
new.is_information = document.get("is_information", False)
|
|
||||||
new.ifc_definition_id = document["id"]
|
|
||||||
new.location = document.get("location") or ""
|
|
||||||
new.description = document.get("description") or ""
|
|
||||||
|
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
|
|
||||||
class AssignDocument(bpy.types.Operator, tool.Ifc.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"
|
||||||
@@ -268,10 +183,12 @@ class AssignDocument(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
if element:
|
if element:
|
||||||
core.assign_document(tool.Ifc, product=element, document=document)
|
core.assign_document(tool.Ifc, product=element, document=document)
|
||||||
|
|
||||||
update_document_objects(self.document)
|
|
||||||
|
tool.Document.update_document_objects(self.document)
|
||||||
ObjectDocumentData.is_loaded = False
|
ObjectDocumentData.is_loaded = False
|
||||||
ObjectDocumentData.load()
|
ObjectDocumentData.load()
|
||||||
bpy.ops.bim.update_assigned_documents()
|
tool.Document.update_assigned_documents()
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class UnassignDocument(bpy.types.Operator, tool.Ifc.Operator):
|
class UnassignDocument(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
@@ -285,21 +202,26 @@ class UnassignDocument(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
document = tool.Ifc.get().by_id(self.document)
|
document = tool.Ifc.get().by_id(self.document)
|
||||||
objs = [bpy.data.objects.get(self.obj)] if self.obj else tool.Blender.get_selected_objects()
|
objs = [bpy.data.objects.get(self.obj)] if self.obj else tool.Blender.get_selected_objects()
|
||||||
for obj in objs:
|
for obj in objs:
|
||||||
element = tool.Ifc.get_entity(obj)
|
if obj:
|
||||||
if element:
|
element = tool.Ifc.get_entity(obj)
|
||||||
core.unassign_document(tool.Ifc, product=element, document=document)
|
if element:
|
||||||
|
core.unassign_document(tool.Ifc, product=element, document=document)
|
||||||
|
|
||||||
props = tool.Document.get_document_props()
|
props = tool.Document.get_document_props()
|
||||||
active_document_id = None
|
active_document_id = None
|
||||||
if props.active_document:
|
if props.active_document:
|
||||||
active_document_id = props.active_document.ifc_definition_id
|
active_document_id = props.active_document.ifc_definition_id
|
||||||
|
|
||||||
if active_document_id and active_document_id != self.document:
|
if active_document_id and active_document_id != self.document:
|
||||||
update_document_objects(active_document_id)
|
tool.Document.update_document_objects(active_document_id)
|
||||||
else:
|
else:
|
||||||
update_document_objects(self.document)
|
tool.Document.update_document_objects()
|
||||||
|
|
||||||
ObjectDocumentData.is_loaded = False
|
ObjectDocumentData.is_loaded = False
|
||||||
ObjectDocumentData.load()
|
ObjectDocumentData.load()
|
||||||
bpy.ops.bim.update_assigned_documents()
|
|
||||||
|
tool.Document.update_assigned_documents()
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class SelectDocumentObjects(bpy.types.Operator):
|
class SelectDocumentObjects(bpy.types.Operator):
|
||||||
@@ -339,32 +261,10 @@ class LoadObjectDocuments(bpy.types.Operator):
|
|||||||
props = tool.Document.get_document_props()
|
props = tool.Document.get_document_props()
|
||||||
props.is_object_editing = True
|
props.is_object_editing = True
|
||||||
|
|
||||||
bonsai.bim.handler.refresh_ui_data()
|
tool.Document.update_assigned_documents()
|
||||||
|
|
||||||
self.update_assigned_documents(props)
|
|
||||||
|
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
def update_assigned_documents(self, props):
|
|
||||||
props.assigned_documents.clear()
|
|
||||||
|
|
||||||
if not ObjectDocumentData.data.get("documents"):
|
|
||||||
return
|
|
||||||
|
|
||||||
sorted_docs = sorted(
|
|
||||||
ObjectDocumentData.data["documents"],
|
|
||||||
key=lambda doc: ((doc.get("identification") or "").lower(), (doc.get("name") or "").lower()),
|
|
||||||
)
|
|
||||||
|
|
||||||
for document in sorted_docs:
|
|
||||||
new = props.assigned_documents.add()
|
|
||||||
new.name = document["name"] or "Unnamed"
|
|
||||||
new.identification = document["identification"] or "*"
|
|
||||||
new.is_information = document.get("is_information", False)
|
|
||||||
new.ifc_definition_id = document["id"]
|
|
||||||
new.location = document["location"] or ""
|
|
||||||
new.description = document["description"] or ""
|
|
||||||
|
|
||||||
|
|
||||||
class OpenIFCDocument(bpy.types.Operator):
|
class OpenIFCDocument(bpy.types.Operator):
|
||||||
bl_idname = "bim.open_ifc_document"
|
bl_idname = "bim.open_ifc_document"
|
||||||
@@ -375,47 +275,37 @@ class OpenIFCDocument(bpy.types.Operator):
|
|||||||
uri: bpy.props.StringProperty(name="URI")
|
uri: bpy.props.StringProperty(name="URI")
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
|
import subprocess
|
||||||
if not self.uri:
|
import os
|
||||||
self.report({"ERROR"}, "No URI provided")
|
if not self.uri or not self.uri.lower().startswith("file://"):
|
||||||
|
self.report({"ERROR"}, "Only local file:// URIs are supported")
|
||||||
return {"CANCELLED"}
|
return {"CANCELLED"}
|
||||||
|
|
||||||
file_path = self.uri
|
filepath = self.uri[7:] # Remove file:// prefix
|
||||||
if file_path.startswith("file://"):
|
|
||||||
file_path = file_path[7:]
|
|
||||||
elif file_path.startswith("file:"):
|
|
||||||
file_path = file_path[5:]
|
|
||||||
|
|
||||||
if not os.path.isabs(file_path):
|
if not os.path.exists(filepath):
|
||||||
file_path = os.path.abspath(file_path)
|
self.report({"ERROR"}, f"File not found: {filepath}")
|
||||||
|
|
||||||
if not os.path.exists(file_path):
|
|
||||||
self.report({"ERROR"}, f"IFC file not found: {file_path}")
|
|
||||||
return {"CANCELLED"}
|
return {"CANCELLED"}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
subprocess.Popen(
|
blender_path = bpy.app.binary_path
|
||||||
[
|
args = [blender_path, "--python-expr", "import bpy; bpy.ops.bim.load_project(filepath='{}')".format(filepath)]
|
||||||
"blender",
|
subprocess.Popen(args)
|
||||||
"--python-expr",
|
self.report({"INFO"}, f"Opening {filepath} in a new Blender instance")
|
||||||
f"import bpy; bpy.ops.bim.load_project(filepath='{file_path}', should_start_fresh_session=True)",
|
|
||||||
]
|
|
||||||
)
|
|
||||||
self.report({"INFO"}, f"Opening IFC file: {file_path} in a new Blender instance.")
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.report({"ERROR"}, f"Failed to open IFC file: {str(e)}")
|
self.report({"ERROR"}, f"Failed to open IFC file: {str(e)}")
|
||||||
|
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class ToggleDocument(bpy.types.Operator, tool.Ifc.Operator):
|
class ToggleDocument(bpy.types.Operator):
|
||||||
bl_idname = "bim.toggle_document"
|
bl_idname = "bim.toggle_document"
|
||||||
bl_label = "Toggle Document"
|
bl_label = "Toggle Document"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
document: bpy.props.IntProperty()
|
document: bpy.props.IntProperty()
|
||||||
option: bpy.props.StringProperty()
|
option: bpy.props.StringProperty()
|
||||||
|
|
||||||
def _execute(self, context):
|
def execute(self, context):
|
||||||
expanded_documents = []
|
expanded_documents = []
|
||||||
props = tool.Document.get_document_props()
|
props = tool.Document.get_document_props()
|
||||||
try:
|
try:
|
||||||
@@ -425,19 +315,14 @@ class ToggleDocument(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
|
|
||||||
document_id = self.document
|
document_id = self.document
|
||||||
|
|
||||||
if self.option == "Expand" and document_id not in expanded_documents:
|
document = tool.Ifc.get().by_id(document_id)
|
||||||
expanded_documents.append(document_id)
|
if document:
|
||||||
elif self.option == "Collapse" and document_id in expanded_documents:
|
if self.option == "Expand" and document_id not in expanded_documents:
|
||||||
expanded_documents.remove(document_id)
|
expanded_documents.append(document_id)
|
||||||
elif document_id == -1:
|
elif self.option == "Collapse" and document_id in expanded_documents:
|
||||||
project = tool.Ifc.get().by_type("IfcProject")[0]
|
expanded_documents.remove(document_id)
|
||||||
virtual_root_id = -project.id()
|
|
||||||
|
|
||||||
if self.option == "Expand" and virtual_root_id not in expanded_documents:
|
|
||||||
expanded_documents.append(virtual_root_id)
|
|
||||||
elif self.option == "Collapse" and virtual_root_id in expanded_documents:
|
|
||||||
expanded_documents.remove(virtual_root_id)
|
|
||||||
props.json_string = json.dumps(expanded_documents)
|
props.json_string = json.dumps(expanded_documents)
|
||||||
|
|
||||||
bpy.ops.bim.load_project_documents()
|
bpy.ops.bim.load_project_documents()
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|||||||
@@ -51,8 +51,7 @@ def update_document_identification(self: "Document", context: bpy.types.Context)
|
|||||||
|
|
||||||
|
|
||||||
def update_active_document(self, context):
|
def update_active_document(self, context):
|
||||||
if self.documents and self.active_document_index < len(self.documents):
|
if (document := self.active_document):
|
||||||
document = self.documents[self.active_document_index]
|
|
||||||
if document.ifc_definition_id:
|
if document.ifc_definition_id:
|
||||||
DocumentData.load_document_objects_into_props(document.ifc_definition_id)
|
DocumentData.load_document_objects_into_props(document.ifc_definition_id)
|
||||||
|
|
||||||
@@ -61,23 +60,31 @@ class Document(PropertyGroup):
|
|||||||
name: StringProperty(name="Name")
|
name: StringProperty(name="Name")
|
||||||
identification: StringProperty(name="Identification")
|
identification: StringProperty(name="Identification")
|
||||||
description: StringProperty(name="Description")
|
description: StringProperty(name="Description")
|
||||||
is_information: BoolProperty(name="Is Information")
|
|
||||||
ifc_definition_id: IntProperty(name="IFC Definition ID")
|
ifc_definition_id: IntProperty(name="IFC Definition ID")
|
||||||
location: StringProperty(name="Location", default="")
|
location: StringProperty(name="Location", default="")
|
||||||
tree_depth: IntProperty(name="Tree Depth", default=0)
|
tree_depth: IntProperty(name="Tree Depth", default=0)
|
||||||
has_children: BoolProperty(name="Has Children", default=False)
|
has_children: BoolProperty(name="Has Children", default=False)
|
||||||
is_expanded: BoolProperty(name="Is Expanded", default=False)
|
is_expanded: BoolProperty(name="Is Expanded", default=False)
|
||||||
|
document_type: EnumProperty(
|
||||||
|
name="Document Type",
|
||||||
|
items=[
|
||||||
|
("PROJECT", "Project", "Virtual project root node"),
|
||||||
|
("INFORMATION", "Information", "IfcDocumentInformation"),
|
||||||
|
("REFERENCE", "Reference", "IfcDocumentReference"),
|
||||||
|
],
|
||||||
|
default="INFORMATION"
|
||||||
|
)
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
name: str
|
name: str
|
||||||
identification: str
|
identification: str
|
||||||
description: str
|
description: str
|
||||||
is_information: bool
|
|
||||||
ifc_definition_id: int
|
ifc_definition_id: int
|
||||||
location: str
|
location: str
|
||||||
tree_depth: int
|
tree_depth: int
|
||||||
has_children: bool
|
has_children: bool
|
||||||
is_expanded: bool
|
is_expanded: bool
|
||||||
|
document_type: str
|
||||||
|
|
||||||
|
|
||||||
class DocumentObject(PropertyGroup):
|
class DocumentObject(PropertyGroup):
|
||||||
@@ -93,17 +100,24 @@ class AssignedDocument(PropertyGroup):
|
|||||||
name: StringProperty(name="Name")
|
name: StringProperty(name="Name")
|
||||||
identification: StringProperty(name="Identification")
|
identification: StringProperty(name="Identification")
|
||||||
description: StringProperty(name="Description", default="")
|
description: StringProperty(name="Description", default="")
|
||||||
is_information: BoolProperty(name="Is Information")
|
|
||||||
ifc_definition_id: IntProperty(name="IFC Definition ID")
|
ifc_definition_id: IntProperty(name="IFC Definition ID")
|
||||||
location: StringProperty(name="Location", default="")
|
location: StringProperty(name="Location", default="")
|
||||||
|
document_type: EnumProperty(
|
||||||
|
name="Document Type",
|
||||||
|
items=[
|
||||||
|
("PROJECT", "Project", "Virtual project root node"),
|
||||||
|
("INFORMATION", "Information", "IfcDocumentInformation"),
|
||||||
|
("REFERENCE", "Reference", "IfcDocumentReference"),
|
||||||
|
],
|
||||||
|
default="INFORMATION"
|
||||||
|
)
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
name: str
|
name: str
|
||||||
identification: str
|
identification: str
|
||||||
is_information: bool
|
|
||||||
ifc_definition_id: int
|
ifc_definition_id: int
|
||||||
location: str
|
location: str
|
||||||
|
document_type: str
|
||||||
|
|
||||||
class BIMDocumentProperties(PropertyGroup):
|
class BIMDocumentProperties(PropertyGroup):
|
||||||
document_attributes: CollectionProperty(name="Document Attributes", type=Attribute)
|
document_attributes: CollectionProperty(name="Document Attributes", type=Attribute)
|
||||||
|
|||||||
@@ -20,8 +20,7 @@ import bpy
|
|||||||
import bonsai.tool as tool
|
import bonsai.tool as tool
|
||||||
from bpy.types import Panel, UIList
|
from bpy.types import Panel, UIList
|
||||||
from bonsai.bim.helper import draw_attributes
|
from bonsai.bim.helper import draw_attributes
|
||||||
from bonsai.bim.module.document.data import DocumentData, ObjectDocumentData
|
from .data import DocumentData, ObjectDocumentData
|
||||||
|
|
||||||
|
|
||||||
class BIM_PT_documents(Panel):
|
class BIM_PT_documents(Panel):
|
||||||
bl_label = "Documents"
|
bl_label = "Documents"
|
||||||
@@ -46,8 +45,8 @@ class BIM_PT_documents(Panel):
|
|||||||
split = row.split(factor=0.55)
|
split = row.split(factor=0.55)
|
||||||
|
|
||||||
left_row = split.row(align=True)
|
left_row = split.row(align=True)
|
||||||
left_row.label(text="{} Informations".format(DocumentData.data["total_document_informations"]), icon="FILE")
|
total_documents = DocumentData.data["total_document_informations"] + DocumentData.data["total_document_references"]
|
||||||
left_row.label(text="{} References".format(DocumentData.data["total_document_references"]), icon="FILE_HIDDEN")
|
left_row.label(text="{} Documents".format(total_documents), icon="FILE")
|
||||||
|
|
||||||
right_row = split.row(align=True)
|
right_row = split.row(align=True)
|
||||||
right_row.label(
|
right_row.label(
|
||||||
@@ -68,31 +67,31 @@ class BIM_PT_documents(Panel):
|
|||||||
row.operator("bim.edit_document", text="", icon="CHECKMARK")
|
row.operator("bim.edit_document", text="", icon="CHECKMARK")
|
||||||
row.operator("bim.disable_editing_document", text="", icon="CANCEL")
|
row.operator("bim.disable_editing_document", text="", icon="CANCEL")
|
||||||
else:
|
else:
|
||||||
if not self.props.active_document or self.props.active_document.is_information:
|
if not self.props.active_document or self.props.active_document.document_type in ["INFORMATION", "PROJECT"]:
|
||||||
row.operator("bim.add_information", text="", icon="ADD")
|
row.operator("bim.add_information", text="", icon="ADD")
|
||||||
|
|
||||||
if self.props.active_document:
|
if self.props.active_document and (
|
||||||
if self.props.active_document.is_information and self.props.active_document.ifc_definition_id != -1:
|
self.props.active_document.document_type == "INFORMATION" and
|
||||||
row.operator("bim.add_document_reference", text="", icon="FILE_HIDDEN")
|
self.props.active_document.document_type != "PROJECT"
|
||||||
|
):
|
||||||
|
row.operator("bim.add_document_reference", text="", icon="FILE_HIDDEN")
|
||||||
|
|
||||||
active_document = self.props.active_document
|
active_document = self.props.active_document
|
||||||
if active_document:
|
if active_document:
|
||||||
ifc_definition_id = active_document.ifc_definition_id
|
ifc_definition_id = active_document.ifc_definition_id
|
||||||
row.operator("bim.select_document_objects", text="", icon="RESTRICT_SELECT_OFF").document = (
|
|
||||||
ifc_definition_id
|
|
||||||
)
|
|
||||||
|
|
||||||
row.operator("bim.assign_document", text="", icon="BRUSH_DATA").document = ifc_definition_id
|
if active_document.document_type != "PROJECT":
|
||||||
row.operator("bim.enable_editing_document", text="", icon="GREASEPENCIL").document = ifc_definition_id
|
row.operator("bim.select_document_objects", text="", icon="RESTRICT_SELECT_OFF").document = (
|
||||||
row.operator("bim.remove_document", text="", icon="X").document = ifc_definition_id
|
ifc_definition_id
|
||||||
|
)
|
||||||
|
row.operator("bim.assign_document", text="", icon="BRUSH_DATA").document = ifc_definition_id
|
||||||
|
row.operator("bim.enable_editing_document", text="", icon="GREASEPENCIL").document = ifc_definition_id
|
||||||
|
row.operator("bim.remove_document", text="", icon="X").document = ifc_definition_id
|
||||||
self.layout.template_list("BIM_UL_documents", "", self.props, "documents", self.props, "active_document_index")
|
self.layout.template_list("BIM_UL_documents", "", self.props, "documents", self.props, "active_document_index")
|
||||||
|
|
||||||
if self.props.is_document_editing:
|
if self.props.is_document_editing:
|
||||||
active_document = self.props.active_document
|
active_document = self.props.active_document
|
||||||
if active_document.is_information:
|
draw_attributes(self.props.document_attributes, self.layout)
|
||||||
draw_attributes(self.props.document_attributes, self.layout)
|
|
||||||
else:
|
|
||||||
draw_attributes(self.props.document_attributes, self.layout, filter_attributes=["Name"])
|
|
||||||
|
|
||||||
if self.props.is_editing and self.props.active_document:
|
if self.props.is_editing and self.props.active_document:
|
||||||
document = self.props.active_document
|
document = self.props.active_document
|
||||||
@@ -108,7 +107,6 @@ class BIM_PT_documents(Panel):
|
|||||||
"active_document_object_index",
|
"active_document_object_index",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class BIM_PT_object_documents(Panel):
|
class BIM_PT_object_documents(Panel):
|
||||||
bl_label = "Documents"
|
bl_label = "Documents"
|
||||||
bl_idname = "BIM_PT_object_documents"
|
bl_idname = "BIM_PT_object_documents"
|
||||||
@@ -119,6 +117,9 @@ class BIM_PT_object_documents(Panel):
|
|||||||
bl_order = 1
|
bl_order = 1
|
||||||
bl_parent_id = "BIM_PT_tab_misc"
|
bl_parent_id = "BIM_PT_tab_misc"
|
||||||
|
|
||||||
|
# Class variable to track the last selected object
|
||||||
|
_last_object_id = None
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
if not (obj := context.active_object):
|
if not (obj := context.active_object):
|
||||||
@@ -130,10 +131,14 @@ class BIM_PT_object_documents(Panel):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
if not ObjectDocumentData.is_loaded:
|
obj = context.active_object
|
||||||
|
current_ifc_id = tool.Blender.get_ifc_definition_id(obj)
|
||||||
|
|
||||||
|
if BIM_PT_object_documents._last_object_id != current_ifc_id:
|
||||||
|
BIM_PT_object_documents._last_object_id = current_ifc_id
|
||||||
|
ObjectDocumentData.is_loaded = False
|
||||||
ObjectDocumentData.load()
|
ObjectDocumentData.load()
|
||||||
|
|
||||||
obj = context.active_object
|
|
||||||
self.oprops = tool.Blender.get_object_bim_props(obj)
|
self.oprops = tool.Blender.get_object_bim_props(obj)
|
||||||
self.props = tool.Document.get_document_props()
|
self.props = tool.Document.get_document_props()
|
||||||
self.file = tool.Ifc.get()
|
self.file = tool.Ifc.get()
|
||||||
@@ -181,10 +186,11 @@ class BIM_PT_object_documents(Panel):
|
|||||||
for doc in ObjectDocumentData.data["documents"]:
|
for doc in ObjectDocumentData.data["documents"]:
|
||||||
assigned_doc_ids.append(doc["id"])
|
assigned_doc_ids.append(doc["id"])
|
||||||
|
|
||||||
# Only show assign button if the document is information (not reference) and not already assigned
|
if (document.document_type == "INFORMATION" and
|
||||||
if document.is_information and document.ifc_definition_id not in assigned_doc_ids:
|
document.document_type != "PROJECT" and
|
||||||
|
document.ifc_definition_id not in assigned_doc_ids):
|
||||||
doc_op = row.operator("bim.assign_document", text="", icon="BRUSH_DATA")
|
doc_op = row.operator("bim.assign_document", text="", icon="BRUSH_DATA")
|
||||||
doc_op.document = document.ifc_definition_id # Pass the current document's ID
|
doc_op.document = document.ifc_definition_id
|
||||||
elif document.ifc_definition_id in assigned_doc_ids:
|
elif document.ifc_definition_id in assigned_doc_ids:
|
||||||
row.label(text="", icon="CHECKMARK")
|
row.label(text="", icon="CHECKMARK")
|
||||||
self.layout.template_list(
|
self.layout.template_list(
|
||||||
@@ -198,24 +204,28 @@ class BIM_UL_documents(UIList):
|
|||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
indent_depth = 0
|
indent_depth = 0
|
||||||
|
|
||||||
if item.ifc_definition_id != -1:
|
if item.document_type != "PROJECT":
|
||||||
if item.tree_depth > 1:
|
if item.tree_depth > 1:
|
||||||
indent_depth = item.tree_depth - 1
|
indent_depth = item.tree_depth - 1
|
||||||
|
|
||||||
for i in range(indent_depth):
|
for i in range(indent_depth):
|
||||||
row.label(text="", icon="BLANK1")
|
row.label(text="", icon="BLANK1")
|
||||||
if item.ifc_definition_id == -1:
|
|
||||||
|
if item.document_type == "PROJECT":
|
||||||
row.label(text="", icon="OUTLINER_COLLECTION")
|
row.label(text="", icon="OUTLINER_COLLECTION")
|
||||||
row.label(text=item.name)
|
row.label(text=item.name)
|
||||||
return
|
return
|
||||||
if item.is_information and item.has_children:
|
|
||||||
|
if item.document_type == "INFORMATION" and item.has_children:
|
||||||
op = row.operator(
|
op = row.operator(
|
||||||
"bim.toggle_document", icon="TRIA_DOWN" if item.is_expanded else "TRIA_RIGHT", text="", emboss=False
|
"bim.toggle_document", icon="TRIA_DOWN" if item.is_expanded else "TRIA_RIGHT", text="", emboss=False
|
||||||
)
|
)
|
||||||
op.document = item.ifc_definition_id
|
op.document = item.ifc_definition_id
|
||||||
op.option = "Collapse" if item.is_expanded else "Expand"
|
op.option = "Collapse" if item.is_expanded else "Expand"
|
||||||
elif item.is_information:
|
elif item.document_type == "INFORMATION":
|
||||||
row.label(text="", icon="BLANK1")
|
row.label(text="", icon="BLANK1")
|
||||||
if item.is_information:
|
|
||||||
|
if item.document_type == "INFORMATION":
|
||||||
row.label(text="", icon="FILE")
|
row.label(text="", icon="FILE")
|
||||||
text = " - ".join([x for x in [item.name, item.location] if x])
|
text = " - ".join([x for x in [item.name, item.location] if x])
|
||||||
else:
|
else:
|
||||||
@@ -227,9 +237,10 @@ class BIM_UL_documents(UIList):
|
|||||||
split2.label(text=text)
|
split2.label(text=text)
|
||||||
|
|
||||||
if item.location:
|
if item.location:
|
||||||
|
uri = ObjectDocumentData.convert_to_file_uri(item.location)
|
||||||
if item.location.lower().endswith(".ifc"):
|
if item.location.lower().endswith(".ifc"):
|
||||||
row.operator("bim.open_ifc_document", icon="HIDE_OFF", text="").uri = item.location
|
row.operator("bim.open_ifc_document", icon="HIDE_OFF", text="").uri = uri
|
||||||
row.operator("bim.open_uri", icon="URL", text="").uri = item.location
|
row.operator("bim.open_uri", icon="URL", text="").uri = uri
|
||||||
|
|
||||||
|
|
||||||
class BIM_UL_document_objects(UIList):
|
class BIM_UL_document_objects(UIList):
|
||||||
@@ -253,7 +264,7 @@ class BIM_UL_assigned_documents(UIList):
|
|||||||
if item:
|
if item:
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
|
|
||||||
if item.is_information:
|
if item.document_type == "INFORMATION":
|
||||||
row.label(text="", icon="FILE")
|
row.label(text="", icon="FILE")
|
||||||
else:
|
else:
|
||||||
row.label(text="", icon="FILE_HIDDEN")
|
row.label(text="", icon="FILE_HIDDEN")
|
||||||
@@ -262,15 +273,16 @@ class BIM_UL_assigned_documents(UIList):
|
|||||||
split1.label(text=item.identification or "")
|
split1.label(text=item.identification or "")
|
||||||
|
|
||||||
split2 = split1.split(factor=1.0)
|
split2 = split1.split(factor=1.0)
|
||||||
if item.is_information:
|
if item.document_type == "INFORMATION":
|
||||||
split2.label(text=item.name or "Unnamed")
|
split2.label(text=item.name or "Unnamed")
|
||||||
else:
|
else:
|
||||||
split2.label(text=item.description or "No Description")
|
split2.label(text=item.description or "No Description")
|
||||||
|
|
||||||
if item.location:
|
if item.location:
|
||||||
|
uri = ObjectDocumentData.convert_to_file_uri(item.location)
|
||||||
if item.location.lower().endswith(".ifc"):
|
if item.location.lower().endswith(".ifc"):
|
||||||
row.operator("bim.open_ifc_document", icon="HIDE_OFF", text="").uri = item.location
|
row.operator("bim.open_ifc_document", icon="HIDE_OFF", text="").uri = uri
|
||||||
row.operator("bim.open_uri", icon="URL", text="").uri = item.location
|
row.operator("bim.open_uri", icon="URL", text="").uri = uri
|
||||||
op = row.operator("bim.unassign_document", text="", icon="X")
|
op = row.operator("bim.unassign_document", text="", icon="X")
|
||||||
op.document = item.ifc_definition_id
|
op.document = item.ifc_definition_id
|
||||||
|
|
||||||
|
|||||||
@@ -29,31 +29,27 @@ def load_project_documents(document: tool.Document) -> None:
|
|||||||
document.import_project_documents()
|
document.import_project_documents()
|
||||||
document.enable_editing_ui()
|
document.enable_editing_ui()
|
||||||
|
|
||||||
|
|
||||||
def load_document(document_tool: tool.Document, document: ifcopenshell.entity_instance) -> None:
|
|
||||||
document_tool.clear_document_tree()
|
|
||||||
document_tool.expand_document(document)
|
|
||||||
document_tool.import_project_documents()
|
|
||||||
document_tool.disable_editing_document()
|
|
||||||
|
|
||||||
|
|
||||||
def disable_document_editing_ui(document: tool.Document) -> None:
|
def disable_document_editing_ui(document: tool.Document) -> None:
|
||||||
document.disable_editing_ui()
|
document.disable_editing_ui()
|
||||||
document.disable_editing_document()
|
document.disable_editing_document()
|
||||||
|
|
||||||
|
def disable_object_document_editing_ui(document: tool.Document) -> None:
|
||||||
|
props = document.get_document_props()
|
||||||
|
props.is_object_editing = False
|
||||||
|
|
||||||
def enable_editing_document(document_tool: tool.Document, document: ifcopenshell.entity_instance) -> None:
|
def enable_editing_document(document_tool: tool.Document, document: ifcopenshell.entity_instance) -> None:
|
||||||
|
props = document_tool.get_document_props()
|
||||||
|
props.is_document_editing = True
|
||||||
document_tool.set_active_document(document)
|
document_tool.set_active_document(document)
|
||||||
document_tool.enable_document_editing()
|
|
||||||
document_tool.import_document_attributes(document)
|
document_tool.import_document_attributes(document)
|
||||||
|
|
||||||
|
|
||||||
def disable_editing_document(document: tool.Document) -> None:
|
def disable_editing_document(document: tool.Document) -> None:
|
||||||
|
props = document.get_document_props()
|
||||||
|
props.is_document_editing = False
|
||||||
document.clear_active_document()
|
document.clear_active_document()
|
||||||
document.disable_document_editing()
|
|
||||||
document.clear_document_attributes()
|
document.clear_document_attributes()
|
||||||
|
|
||||||
|
|
||||||
def add_information(ifc: tool.Ifc, document_tool: tool.Document, parent=None) -> ifcopenshell.entity_instance:
|
def add_information(ifc: tool.Ifc, document_tool: tool.Document, parent=None) -> ifcopenshell.entity_instance:
|
||||||
document_tool.clear_document_tree()
|
document_tool.clear_document_tree()
|
||||||
|
|
||||||
|
|||||||
@@ -18,12 +18,11 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
import bpy
|
import bpy
|
||||||
import json
|
|
||||||
import ifcopenshell.util.system
|
import ifcopenshell.util.system
|
||||||
import bonsai.bim.helper
|
|
||||||
import bonsai.core.tool
|
import bonsai.core.tool
|
||||||
import bonsai.tool as tool
|
import bonsai.tool as tool
|
||||||
import json
|
import json
|
||||||
|
from natsort import natsorted
|
||||||
from typing import Any, Union, TYPE_CHECKING
|
from typing import Any, Union, TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@@ -70,12 +69,15 @@ class Document(bonsai.core.tool.Document):
|
|||||||
data[attr_name] = ""
|
data[attr_name] = ""
|
||||||
return True
|
return True
|
||||||
if attr_name != "Name":
|
if attr_name != "Name":
|
||||||
return None
|
return None # Proceed normally
|
||||||
|
|
||||||
current_value = data[attr_name]
|
current_value = data[attr_name]
|
||||||
|
# If Name is already filled, display it so user would be able to correct invalid IFC.
|
||||||
if current_value is not None:
|
if current_value is not None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
# Skip import since IFC restricts Name to be filled
|
||||||
|
# for IfcDocumentReference with ReferencedDocument.
|
||||||
return False
|
return False
|
||||||
|
|
||||||
import_callback = callback if document.is_a("IfcDocumentReference") else None
|
import_callback = callback if document.is_a("IfcDocumentReference") else None
|
||||||
@@ -137,8 +139,8 @@ class Document(bonsai.core.tool.Document):
|
|||||||
root_documents.append(rel.RelatingDocument)
|
root_documents.append(rel.RelatingDocument)
|
||||||
|
|
||||||
root = props.documents.add()
|
root = props.documents.add()
|
||||||
root.ifc_definition_id = -1
|
root.ifc_definition_id = -project.id()
|
||||||
root.is_information = True
|
root.document_type = "PROJECT"
|
||||||
root.name = f"Project Documents ({project.Name or 'Unnamed Project'})"
|
root.name = f"Project Documents ({project.Name or 'Unnamed Project'})"
|
||||||
root.identification = ""
|
root.identification = ""
|
||||||
root.location = ""
|
root.location = ""
|
||||||
@@ -150,8 +152,9 @@ class Document(bonsai.core.tool.Document):
|
|||||||
root.is_expanded = root_id not in expanded_documents
|
root.is_expanded = root_id not in expanded_documents
|
||||||
|
|
||||||
if root.is_expanded:
|
if root.is_expanded:
|
||||||
root_documents.sort(
|
root_documents = natsorted(
|
||||||
key=lambda doc: ((cls.get_document_information_id(doc) or "").lower(), (doc.Name or "").lower())
|
root_documents,
|
||||||
|
key=lambda doc: (cls.get_document_information_id(doc) or "", doc.Name or "")
|
||||||
)
|
)
|
||||||
|
|
||||||
for doc in root_documents:
|
for doc in root_documents:
|
||||||
@@ -161,11 +164,11 @@ class Document(bonsai.core.tool.Document):
|
|||||||
def _process_document(cls, document, props, document_children, expanded_documents, depth):
|
def _process_document(cls, document, props, document_children, expanded_documents, depth):
|
||||||
new = props.documents.add()
|
new = props.documents.add()
|
||||||
new.ifc_definition_id = document.id()
|
new.ifc_definition_id = document.id()
|
||||||
new.is_information = document.is_a("IfcDocumentInformation")
|
new.document_type = "INFORMATION" if document.is_a("IfcDocumentInformation") else "REFERENCE"
|
||||||
new.tree_depth = depth
|
new.tree_depth = depth
|
||||||
|
|
||||||
file = document.file
|
file = document.file
|
||||||
if new.is_information:
|
if new.document_type == "INFORMATION":
|
||||||
new.name = document.Name or "Unnamed"
|
new.name = document.Name or "Unnamed"
|
||||||
new.identification = cls.get_document_information_id(document) or ""
|
new.identification = cls.get_document_information_id(document) or ""
|
||||||
new.location = document.Location or ""
|
new.location = document.Location or ""
|
||||||
@@ -175,7 +178,7 @@ class Document(bonsai.core.tool.Document):
|
|||||||
new.description = document.Description or ""
|
new.description = document.Description or ""
|
||||||
new.location = document.Location or ""
|
new.location = document.Location or ""
|
||||||
|
|
||||||
if not new.is_information:
|
if new.document_type == "REFERENCE":
|
||||||
if file.schema == "IFC2X3":
|
if file.schema == "IFC2X3":
|
||||||
if document.ReferenceToDocument:
|
if document.ReferenceToDocument:
|
||||||
doc_info = document.ReferenceToDocument[0]
|
doc_info = document.ReferenceToDocument[0]
|
||||||
@@ -183,7 +186,7 @@ class Document(bonsai.core.tool.Document):
|
|||||||
new.name = doc_info.Name or ""
|
new.name = doc_info.Name or ""
|
||||||
new.location = new.location or ""
|
new.location = new.location or ""
|
||||||
else:
|
else:
|
||||||
if hasattr(document, "ReferencedDocument") and document.ReferencedDocument:
|
if document.ReferencedDocument:
|
||||||
doc_info = document.ReferencedDocument
|
doc_info = document.ReferencedDocument
|
||||||
if not new.name:
|
if not new.name:
|
||||||
new.name = doc_info.Name or ""
|
new.name = doc_info.Name or ""
|
||||||
@@ -200,14 +203,16 @@ class Document(bonsai.core.tool.Document):
|
|||||||
info_children = [d for d in children if d.is_a("IfcDocumentInformation")]
|
info_children = [d for d in children if d.is_a("IfcDocumentInformation")]
|
||||||
ref_children = [d for d in children if not d.is_a("IfcDocumentInformation")]
|
ref_children = [d for d in children if not d.is_a("IfcDocumentInformation")]
|
||||||
|
|
||||||
info_children.sort(
|
info_children = natsorted(
|
||||||
key=lambda doc: ((cls.get_document_information_id(doc) or "").lower(), (doc.Name or "").lower())
|
info_children,
|
||||||
|
key=lambda doc: (cls.get_document_information_id(doc) or "", doc.Name or "")
|
||||||
)
|
)
|
||||||
|
|
||||||
ref_children.sort(
|
ref_children = natsorted(
|
||||||
|
ref_children,
|
||||||
key=lambda doc: (
|
key=lambda doc: (
|
||||||
(cls.get_external_reference_id(doc) or "").lower(),
|
cls.get_external_reference_id(doc) or "",
|
||||||
(doc.Description or doc.Name or "").lower(),
|
doc.Description or doc.Name or ""
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -252,16 +257,6 @@ class Document(bonsai.core.tool.Document):
|
|||||||
return document.DocumentReferences or ()
|
return document.DocumentReferences or ()
|
||||||
return document.HasDocumentReferences
|
return document.HasDocumentReferences
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def enable_document_editing(cls) -> None:
|
|
||||||
props = cls.get_document_props()
|
|
||||||
props.is_editing = True
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def disable_document_editing(cls) -> None:
|
|
||||||
props = cls.get_document_props()
|
|
||||||
props.is_editing = False
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def clear_active_document(cls) -> None:
|
def clear_active_document(cls) -> None:
|
||||||
props = cls.get_document_props()
|
props = cls.get_document_props()
|
||||||
@@ -293,6 +288,58 @@ class Document(bonsai.core.tool.Document):
|
|||||||
def get_selected_document_information(cls, ifc) -> Union[ifcopenshell.entity_instance, None]:
|
def get_selected_document_information(cls, ifc) -> Union[ifcopenshell.entity_instance, None]:
|
||||||
props = cls.get_document_props()
|
props = cls.get_document_props()
|
||||||
|
|
||||||
if props.active_document and props.active_document.is_information:
|
if props.active_document and props.active_document.document_type == "INFORMATION":
|
||||||
return ifc.get().by_id(props.active_document.ifc_definition_id)
|
return ifc.get().by_id(props.active_document.ifc_definition_id)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def refresh_document_data(cls) -> None:
|
||||||
|
import bonsai.bim.module.document.data as document_data
|
||||||
|
document_data.DocumentData.is_loaded = False
|
||||||
|
document_data.DocumentData.load()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load_document_objects_into_props(cls, document_id: int) -> None:
|
||||||
|
import bonsai.bim.module.document.data as document_data
|
||||||
|
document_data.DocumentData.load_document_objects_into_props(document_id)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def update_document_objects(cls, document_id: Union[int, None] = None) -> None:
|
||||||
|
cls.refresh_document_data()
|
||||||
|
|
||||||
|
if document_id is None:
|
||||||
|
props = cls.get_document_props()
|
||||||
|
if props.active_document and props.active_document.ifc_definition_id > 0:
|
||||||
|
document_id = props.active_document.ifc_definition_id
|
||||||
|
|
||||||
|
if document_id:
|
||||||
|
cls.load_document_objects_into_props(document_id)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def update_assigned_documents(cls) -> None:
|
||||||
|
from bonsai.bim.module.document.data import ObjectDocumentData
|
||||||
|
|
||||||
|
ObjectDocumentData.is_loaded = False
|
||||||
|
|
||||||
|
props = cls.get_document_props()
|
||||||
|
props.assigned_documents.clear()
|
||||||
|
|
||||||
|
if not ObjectDocumentData.is_loaded:
|
||||||
|
ObjectDocumentData.load()
|
||||||
|
|
||||||
|
if not ObjectDocumentData.data.get("documents"):
|
||||||
|
return
|
||||||
|
|
||||||
|
sorted_docs = sorted(
|
||||||
|
ObjectDocumentData.data["documents"],
|
||||||
|
key=lambda doc: ((doc.get("identification") or "").lower(), (doc.get("name") or "").lower()),
|
||||||
|
)
|
||||||
|
|
||||||
|
for document in sorted_docs:
|
||||||
|
new = props.assigned_documents.add()
|
||||||
|
new.name = document["name"] or "Unnamed"
|
||||||
|
new.identification = document["identification"] or "*"
|
||||||
|
new.document_type = "INFORMATION" if document.get("is_information", False) else "REFERENCE"
|
||||||
|
new.ifc_definition_id = document["id"]
|
||||||
|
new.location = document.get("location") or ""
|
||||||
|
new.description = document.get("description") or ""
|
||||||
Reference in New Issue
Block a user