From d4f32802aae9eec2c71ceab3097f18848541da4d Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Mon, 7 Jul 2025 14:08:45 +0500 Subject: [PATCH] Show warnings if some sheets related files are missing Previously when you would load/open/create sheets and some files were missing you would get traceback errors. Also removed warnings for missing sheets svgs since they can go missing if someone is opening ifc project and want to regenerate sheets. We'll be able to return them in the future, if needed, but they will need some refinement. --- .../bonsai/bim/module/drawing/operator.py | 44 +++++++++++++++---- src/bonsai/bonsai/core/drawing.py | 13 +++++- src/bonsai/bonsai/tool/drawing.py | 30 +++++++++++++ 3 files changed, 76 insertions(+), 11 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/drawing/operator.py b/src/bonsai/bonsai/bim/module/drawing/operator.py index 94888f3a97..d596d0fd9c 100644 --- a/src/bonsai/bonsai/bim/module/drawing/operator.py +++ b/src/bonsai/bonsai/bim/module/drawing/operator.py @@ -1792,12 +1792,16 @@ class OpenSheet(bpy.types.Operator): else: sheets = [tool.Ifc.get().by_id(self.props.sheets[self.props.active_sheet_index].ifc_definition_id)] - sheet_uris = [] - sheets_not_found = [] + sheet_uris: list[str] = [] + sheets_not_found: list[str] = [] + warnings: list[tool.Drawing.SheetWarningType] = [] for sheet in sheets: if not sheet.is_a("IfcDocumentInformation"): continue + warnings.extend(sheets_warnings := tool.Drawing.validate_sheet_files(sheet)) + if sheets_warnings: + continue sheet_builder = sheeter.SheetBuilder() references = sheet_builder.build(sheet) sheet_uri = references["SHEET"] @@ -1807,6 +1811,11 @@ class OpenSheet(bpy.types.Operator): if not os.path.exists(sheet_uri): sheets_not_found.append(sheet.Name) + if warnings: + self.report({"ERROR"}, f"There were errors opening sheets. See system console for the details.") + print("-" * 10) + print("\n".join(str(w) for w in warnings)) + if sheets_not_found: msg = "Some sheets .svg/.pdf files were not found, need to create them first: \n{}.".format( "\n".join(sheets_not_found) @@ -1962,7 +1971,14 @@ class CreateSheets(bpy.types.Operator, tool.Ifc.Operator): else: sheets = [tool.Ifc.get().by_id(props.sheets[props.active_sheet_index].ifc_definition_id)] + warnings: list[tool.Drawing.SheetWarningType] = [] + n_sheets_created = 0 for sheet in sheets: + + warnings.extend(sheet_warnings := tool.Drawing.validate_sheet_files(sheet)) + if sheet_warnings: + continue + # Update any drawing boundary changes sheet_builder = sheeter.SheetBuilder() sheet_builder.update_sheet_drawing_sizes(sheet) @@ -2023,8 +2039,16 @@ class CreateSheets(bpy.types.Operator, tool.Ifc.Operator): tool.Drawing.open_with_user_command(tool.Blender.get_addon_preferences().pdf_command, pdf) else: tool.Drawing.open_with_user_command(tool.Blender.get_addon_preferences().svg_command, svg) + + n_sheets_created += 1 + if not self.open_viewer: - self.report({"INFO"}, f"{len(sheets)} sheets created...") + self.report({"INFO"}, f"{n_sheets_created} sheets created...") + + if warnings: + self.report({"ERROR"}, f"There were errors creating sheets. See system console for the details.") + print("-" * 10) + print("\n".join(str(w) for w in warnings)) class SelectAllDrawings(bpy.types.Operator): @@ -3162,7 +3186,7 @@ class LoadSheets(bpy.types.Operator, tool.Ifc.Operator): core.load_sheets(tool.Drawing) props = tool.Drawing.get_document_props() - sheets_not_found = [] + warnings: list[tool.Drawing.SheetWarningType] = [] for sheet_prop in props.sheets: if not sheet_prop.is_sheet: continue @@ -3173,12 +3197,14 @@ class LoadSheets(bpy.types.Operator, tool.Ifc.Operator): filepath = Path(document_uri) if not filepath.is_file(): - sheet_name = f"{sheet_prop.identification} - {sheet_prop.name}" - sheets_not_found.append(f'"{sheet_name}" - {document_uri}') - core.regenerate_sheet(tool.Drawing, sheet) + res = core.regenerate_sheet(tool.Drawing, sheet) + if res: + warnings.extend(res) - if sheets_not_found: - self.report({"ERROR"}, "Some sheets svg files are missing:\n" + "\n".join(sheets_not_found)) + if warnings: + self.report({"WARNING"}, f"There were warnings loading sheets. See system console for the details.") + print("-" * 10) + print("\n".join(str(w) for w in warnings)) class EditSheet(bpy.types.Operator, tool.Ifc.Operator): diff --git a/src/bonsai/bonsai/core/drawing.py b/src/bonsai/bonsai/core/drawing.py index ac2cb740f6..1481ee1f34 100644 --- a/src/bonsai/bonsai/core/drawing.py +++ b/src/bonsai/bonsai/core/drawing.py @@ -18,7 +18,7 @@ from __future__ import annotations from pathlib import Path -from typing import TYPE_CHECKING, Optional, Union +from typing import TYPE_CHECKING, Optional, Union, Literal if TYPE_CHECKING: import bpy @@ -108,13 +108,22 @@ def add_sheet(ifc: type[tool.Ifc], drawing: type[tool.Drawing], titleblock: ifco drawing.import_sheets() -def regenerate_sheet(drawing: type[tool.Drawing], sheet: ifcopenshell.entity_instance) -> None: +def regenerate_sheet( + drawing: type[tool.Drawing], sheet: ifcopenshell.entity_instance +) -> Union[list[tool.Drawing.SheetWarningType], None]: + warnings = drawing.validate_sheet_files(sheet) + if warnings: + return warnings + titleblock_uri = drawing.get_document_uri(sheet, "TITLEBLOCK") + assert titleblock_uri + drawing.create_svg_sheet(sheet, drawing.sanitise_filename(Path(titleblock_uri).stem)) try: drawing.add_drawings(sheet) except FileNotFoundError: path_layout = drawing.get_document_uri(sheet, "LAYOUT") + assert path_layout if drawing.does_file_exist(path_layout): drawing.delete_file(path_layout) diff --git a/src/bonsai/bonsai/tool/drawing.py b/src/bonsai/bonsai/tool/drawing.py index aefd3d2c9c..2846600239 100644 --- a/src/bonsai/bonsai/tool/drawing.py +++ b/src/bonsai/bonsai/tool/drawing.py @@ -374,6 +374,7 @@ class Drawing(bonsai.core.tool.Drawing): sheet_builder = sheeter.SheetBuilder() uri = cls.get_document_uri(document, "LAYOUT") + assert uri sheet_builder.create(uri, titleblock) return uri @@ -1245,6 +1246,35 @@ class Drawing(bonsai.core.tool.Drawing): # TODO below this point is highly experimental prototype code with no tests + class SheetWarningType(NamedTuple): + warning_type: Literal["MISSING_LAYOUT", "MISSING_TITLEBLOCK"] + message: str + + def __str__(self) -> str: + return f"{self.warning_type:<20} - {self.message}" + + @classmethod + def validate_sheet_files(cls, sheet: ifcopenshell.entity_instance) -> list[SheetWarningType]: + warnings: list[tool.Drawing.SheetWarningType] = [] + + layout_path = cls.get_document_uri(sheet, "LAYOUT") + assert layout_path + sheet_id = cls.get_sheet_identification(sheet) + if not Path(layout_path).exists(): + warnings.append( + cls.SheetWarningType("MISSING_LAYOUT", f"Sheet '{sheet_id}' - missing layout '{layout_path}'.") + ) + + titleblock_path = cls.get_document_uri(sheet, "TITLEBLOCK") + assert titleblock_path + if not Path(titleblock_path).exists(): + warnings.append( + cls.SheetWarningType( + "MISSING_TITLEBLOCK", f"Sheet '{sheet_id}' - missing titleblock '{titleblock_path}'." + ) + ) + return warnings + @classmethod def does_file_exist(cls, uri: str) -> bool: return os.path.exists(uri)