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)