From 3f28ae18c024fc7cd28b551a6a8f6263bc104d1f Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Thu, 28 Apr 2022 14:16:39 +1000 Subject: [PATCH] #1153 You can now add / remove / open schedules, implemented as IFC documents --- .../blenderbim/bim/module/drawing/__init__.py | 4 +- .../blenderbim/bim/module/drawing/data.py | 15 ++++ .../blenderbim/bim/module/drawing/operator.py | 84 +++++++++++-------- .../blenderbim/bim/module/drawing/prop.py | 15 ++-- .../blenderbim/bim/module/drawing/ui.py | 35 +++++--- src/blenderbim/blenderbim/bim/ui.py | 7 +- src/blenderbim/blenderbim/core/drawing.py | 36 ++++++++ src/blenderbim/blenderbim/core/tool.py | 3 + src/blenderbim/blenderbim/tool/drawing.py | 33 ++++++++ src/blenderbim/test/core/test_drawing.py | 65 ++++++++++++++ src/blenderbim/test/core/test_geometry.py | 10 +-- src/blenderbim/test/tool/test_drawing.py | 59 +++++++++++++ 12 files changed, 305 insertions(+), 61 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/module/drawing/__init__.py b/src/blenderbim/blenderbim/bim/module/drawing/__init__.py index 5b18d9b10f..ba5c0d3d97 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/__init__.py @@ -39,6 +39,7 @@ classes = ( operator.CreateDrawing, operator.CreateSheets, operator.DisableEditingDrawings, + operator.DisableEditingSchedules, operator.DisableEditingSheets, operator.DisableEditingText, operator.DisableEditingTextProduct, @@ -49,7 +50,9 @@ classes = ( operator.EnableEditingTextProduct, operator.ExpandSheet, operator.LoadDrawings, + operator.LoadSchedules, operator.LoadSheets, + operator.OpenSchedule, operator.OpenSheet, operator.OpenView, operator.RemoveDrawing, @@ -61,7 +64,6 @@ classes = ( operator.ResizeText, operator.SaveDrawingStyle, operator.SelectDocIfcFile, - operator.SelectScheduleFile, prop.Variable, prop.Drawing, prop.Schedule, diff --git a/src/blenderbim/blenderbim/bim/module/drawing/data.py b/src/blenderbim/blenderbim/bim/module/drawing/data.py index 20cc167c93..049f8874a8 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/data.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/data.py @@ -24,6 +24,7 @@ import blenderbim.tool as tool def refresh(): TextData.is_loaded = False SheetsData.is_loaded = False + SchedulesData.is_loaded = False DrawingsData.is_loaded = False @@ -94,3 +95,17 @@ class DrawingsData: ) return results return [(h.upper(), h, "") for h in ["North", "South", "East", "West"]] + + +class SchedulesData: + data = {} + is_loaded = False + + @classmethod + def load(cls): + cls.data = {"total_schedules": cls.total_schedules()} + cls.is_loaded = True + + @classmethod + def total_schedules(cls): + return len([d for d in tool.Ifc.get().by_type("IfcDocumentInformation") if d.Scope == "SCHEDULE"]) diff --git a/src/blenderbim/blenderbim/bim/module/drawing/operator.py b/src/blenderbim/blenderbim/bim/module/drawing/operator.py index 01172440c3..008a8f3d1e 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/operator.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/operator.py @@ -913,55 +913,53 @@ class RemoveSheet(bpy.types.Operator, Operator): core.remove_sheet(tool.Ifc, tool.Drawing, sheet=tool.Ifc.get().by_id(self.sheet)) -class AddSchedule(bpy.types.Operator): +class AddSchedule(bpy.types.Operator, Operator): bl_idname = "bim.add_schedule" bl_label = "Add Schedule" bl_options = {"REGISTER", "UNDO"} - - def execute(self, context): - new = context.scene.DocProperties.schedules.add() - new.name = "SCHEDULE {}".format(len(context.scene.DocProperties.schedules)) - return {"FINISHED"} - - -class RemoveSchedule(bpy.types.Operator): - bl_idname = "bim.remove_schedule" - bl_label = "Remove Schedule" - bl_options = {"REGISTER", "UNDO"} - index: bpy.props.IntProperty() - - def execute(self, context): - props = context.scene.DocProperties - props.schedules.remove(self.index) - return {"FINISHED"} - - -class SelectScheduleFile(bpy.types.Operator): - bl_idname = "bim.select_schedule_file" - bl_label = "Select Documentation IFC File" - bl_options = {"REGISTER", "UNDO"} filepath: bpy.props.StringProperty(subtype="FILE_PATH") - filter_glob: bpy.props.StringProperty(default="*.ods", options={"HIDDEN"}) - index: bpy.props.IntProperty() + filter_glob: bpy.props.StringProperty(default="*.ods;*.xls;*.xlsx", options={"HIDDEN"}) + use_relative_path: bpy.props.BoolProperty(name="Use Relative Path", default=False) - def execute(self, context): - props = context.scene.DocProperties - props.active_schedule.file = self.filepath - return {"FINISHED"} + def _execute(self, context): + filepath = self.filepath + if self.use_relative_path: + filepath = os.path.relpath(filepath, bpy.path.abspath("//")) + core.add_schedule( + tool.Ifc, + tool.Drawing, + uri=filepath, + ) def invoke(self, context, event): context.window_manager.fileselect_add(self) return {"RUNNING_MODAL"} +class RemoveSchedule(bpy.types.Operator, Operator): + bl_idname = "bim.remove_schedule" + bl_label = "Remove Schedule" + bl_options = {"REGISTER", "UNDO"} + schedule: bpy.props.IntProperty() + + def _execute(self, context): + core.remove_schedule(tool.Ifc, tool.Drawing, schedule=tool.Ifc.get().by_id(self.schedule)) + + +class OpenSchedule(bpy.types.Operator, Operator): + bl_idname = "bim.open_schedule" + bl_label = "Open Schedule" + bl_options = {"REGISTER", "UNDO"} + schedule: bpy.props.IntProperty() + + def _execute(self, context): + core.open_schedule(tool.Drawing, schedule=tool.Ifc.get().by_id(self.schedule)) + + class BuildSchedule(bpy.types.Operator): bl_idname = "bim.build_schedule" bl_label = "Build Schedule" - @classmethod - def poll(cls, context): - return context.scene.DocProperties.active_schedule.file - def execute(self, context): props = context.scene.DocProperties schedule = props.active_schedule @@ -1269,6 +1267,24 @@ class DisableEditingSheets(bpy.types.Operator, Operator): core.disable_editing_sheets(tool.Drawing) +class LoadSchedules(bpy.types.Operator, Operator): + bl_idname = "bim.load_schedules" + bl_label = "Load Schedules" + bl_options = {"REGISTER", "UNDO"} + + def _execute(self, context): + core.load_schedules(tool.Drawing) + + +class DisableEditingSchedules(bpy.types.Operator, Operator): + bl_idname = "bim.disable_editing_schedules" + bl_label = "Disable Editing Text Product" + bl_options = {"REGISTER", "UNDO"} + + def _execute(self, context): + core.disable_editing_schedules(tool.Drawing) + + class LoadDrawings(bpy.types.Operator, Operator): bl_idname = "bim.load_drawings" bl_label = "Load Drawings" diff --git a/src/blenderbim/blenderbim/bim/module/drawing/prop.py b/src/blenderbim/blenderbim/bim/module/drawing/prop.py index 13716fce9b..c3d127d5fe 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/prop.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/prop.py @@ -153,6 +153,11 @@ def update_drawing_name(self, context): core.update_drawing_name(tool.Ifc, tool.Drawing, drawing=drawing, name=self.name) +def update_schedule_name(self, context): + schedule = tool.Ifc.get().by_id(self.ifc_definition_id) + core.update_schedule_name(tool.Ifc, tool.Drawing, schedule=schedule, name=self.name) + + def update_has_underlay(self, context): update_layer(self, context, "HasUnderlay", self.has_underlay) @@ -231,8 +236,9 @@ class Drawing(PropertyGroup): class Schedule(PropertyGroup): - name: StringProperty(name="Name") - file: StringProperty(name="File") + ifc_definition_id: IntProperty(name="IFC Definition ID") + name: StringProperty(name="Name", update=update_schedule_name) + identification: StringProperty(name="Identification") class Sheet(PropertyGroup): @@ -305,6 +311,7 @@ class DocProperties(PropertyGroup): should_use_annotation_cache: BoolProperty(name="Use Annotation Cache", default=False) should_extract: BoolProperty(name="Should Extract", default=True) is_editing_drawings: BoolProperty(name="Is Editing Drawings", default=False) + is_editing_schedules: BoolProperty(name="Is Editing Schedules", default=False) target_view: EnumProperty( items=[ ("PLAN_VIEW", "Plan", ""), @@ -335,10 +342,6 @@ class DocProperties(PropertyGroup): name="Decorations Colour", subtype="COLOR", default=(1, 1, 1, 1), min=0.0, max=1.0, size=4 ) - @property - def active_schedule(self): - return self.schedules[self.active_schedule_index] - class BIMCameraProperties(PropertyGroup): has_underlay: BoolProperty(name="Underlay", default=False, update=update_has_underlay) diff --git a/src/blenderbim/blenderbim/bim/module/drawing/ui.py b/src/blenderbim/blenderbim/bim/module/drawing/ui.py index 3aae7f0388..085780c5a6 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/ui.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/ui.py @@ -20,7 +20,7 @@ import bpy import blenderbim.bim.helper import blenderbim.tool as tool from bpy.types import Panel -from blenderbim.bim.module.drawing.data import TextData, SheetsData, DrawingsData +from blenderbim.bim.module.drawing.data import TextData, SheetsData, SchedulesData, DrawingsData class BIM_PT_camera(Panel): @@ -196,22 +196,31 @@ class BIM_PT_schedules(Panel): bl_category = "BIM Documentation" def draw(self, context): - layout = self.layout - layout.use_property_split = True - props = context.scene.DocProperties + if not SchedulesData.is_loaded: + SchedulesData.load() - row = layout.row(align=True) - row.operator("bim.add_schedule") + self.props = context.scene.DocProperties - if props.schedules: - row.operator("bim.build_schedule", icon="LINENUMBERS_ON", text="") - row.operator("bim.remove_schedule", icon="X", text="").index = props.active_schedule_index + if not self.props.is_editing_schedules: + row = self.layout.row(align=True) + row.label(text=f"{SchedulesData.data['total_schedules']} Schedules Found", icon="LONGDISPLAY") + row.operator("bim.load_schedules", text="", icon="IMPORT") + return - layout.template_list("BIM_UL_generic", "", props, "schedules", props, "active_schedule_index") + row = self.layout.row(align=True) + row.operator("bim.add_schedule", icon="ADD") + row.operator("bim.disable_editing_schedules", text="", icon="CANCEL") - row = layout.row() - row.prop(props.active_schedule, "file") - row.operator("bim.select_schedule_file", icon="FILE_FOLDER", text="") + if self.props.schedules: + if self.props.active_schedule_index < len(self.props.schedules): + active_schedule = self.props.schedules[self.props.active_schedule_index] + row = self.layout.row(align=True) + row.alignment = "RIGHT" + row.operator("bim.open_schedule", icon="URL", text="").schedule = active_schedule.ifc_definition_id + row.operator("bim.build_schedule", icon="LINENUMBERS_ON", text="") + row.operator("bim.remove_schedule", icon="X", text="").schedule = active_schedule.ifc_definition_id + + self.layout.template_list("BIM_UL_generic", "", self.props, "schedules", self.props, "active_schedule_index") class BIM_PT_sheets(Panel): diff --git a/src/blenderbim/blenderbim/bim/ui.py b/src/blenderbim/blenderbim/bim/ui.py index 000ceac13c..2457cd99bf 100644 --- a/src/blenderbim/blenderbim/bim/ui.py +++ b/src/blenderbim/blenderbim/bim/ui.py @@ -106,8 +106,9 @@ class BIM_ADDON_preferences(bpy.types.AddonPreferences): name="SVG to DXF Command", description="E.g. [['inkscape', svg, '-o', eps], ['pstoedit', '-dt', '-f', 'dxf:-polyaslines -mm', eps, dxf, '-psarg', '-dNOSAFER']]", ) - svg_command: StringProperty(name="SVG Command", description="E.g. [['firefox-bin', path]]") - pdf_command: StringProperty(name="PDF Command", description="E.g. [['firefox-bin', path]]") + svg_command: StringProperty(name="SVG Command", description="E.g. [['firefox', path]]") + pdf_command: StringProperty(name="PDF Command", description="E.g. [['firefox', path]]") + spreadsheet_command: StringProperty(name="Spreadsheet Command", description="E.g. [['libreoffice', path]]") openlca_port: IntProperty(name="OpenLCA IPC Port", default=8080) should_hide_empty_props: BoolProperty(name="Should Hide Empty Properties", default=True) should_play_chaching_sound: BoolProperty( @@ -141,6 +142,8 @@ class BIM_ADDON_preferences(bpy.types.AddonPreferences): row = layout.row() row.prop(self, "pdf_command") row = layout.row() + row.prop(self, "spreadsheet_command") + row = layout.row() row.prop(self, "openlca_port") row = layout.row() row.prop(self, "should_hide_empty_props") diff --git a/src/blenderbim/blenderbim/core/drawing.py b/src/blenderbim/blenderbim/core/drawing.py index 6bfc86a612..fe9e4ef74e 100644 --- a/src/blenderbim/blenderbim/core/drawing.py +++ b/src/blenderbim/blenderbim/core/drawing.py @@ -89,6 +89,42 @@ def remove_sheet(ifc, drawing, sheet=None): drawing.import_sheets() +def load_schedules(drawing): + drawing.import_schedules() + drawing.enable_editing_schedules() + + +def disable_editing_schedules(drawing): + drawing.disable_editing_schedules() + + +def add_schedule(ifc, drawing, uri=None): + schedule = ifc.run("document.add_information") + reference = ifc.run("document.add_reference", information=schedule) + if ifc.get_schema() == "IFC2X3": + attributes = {"DocumentId": "X", "Name": "UNTITLED", "Scope": "SCHEDULE"} + ifc.run("document.edit_information", information=schedule, attributes=attributes) + ifc.run("document.edit_reference", reference=reference, attributes={"Location": uri}) + else: + attributes = {"Identification": "X", "Name": "UNTITLED", "Scope": "SCHEDULE", "Location": uri} + ifc.run("document.edit_information", information=schedule, attributes=attributes) + drawing.import_schedules() + + +def remove_schedule(ifc, drawing, schedule=None): + ifc.run("document.remove_information", information=schedule) + drawing.import_schedules() + + +def open_schedule(drawing, schedule=None): + drawing.open_spreadsheet(drawing.get_schedule_location(schedule)) + + +def update_schedule_name(ifc, drawing, schedule=None, name=None): + if drawing.get_name(schedule) != name: + ifc.run("document.edit_information", information=schedule, attributes={"Name": name}) + + def load_drawings(drawing): drawing.import_drawings() drawing.enable_editing_drawings() diff --git a/src/blenderbim/blenderbim/core/tool.py b/src/blenderbim/blenderbim/core/tool.py index 43686ecf8b..146445d35b 100644 --- a/src/blenderbim/blenderbim/core/tool.py +++ b/src/blenderbim/blenderbim/core/tool.py @@ -161,11 +161,13 @@ class Drawing: def delete_drawing_elements(cls, elements): pass def delete_object(cls, obj): pass def disable_editing_drawings(cls): pass + def disable_editing_schedules(cls): pass def disable_editing_sheets(cls): pass def disable_editing_text(cls, obj): pass def disable_editing_text_product(cls, obj): pass def enable_editing(cls, obj): pass def enable_editing_drawings(cls): pass + def enable_editing_schedules(cls): pass def enable_editing_sheets(cls): pass def enable_editing_text(cls, obj): pass def enable_editing_text_product(cls, obj): pass @@ -187,6 +189,7 @@ class Drawing: def get_text_literal(cls, obj): pass def get_text_product(cls, element): pass def import_drawings(cls): pass + def import_schedules(cls): pass def import_sheets(cls): pass def import_text_attributes(cls, obj): pass def import_text_product(cls, obj): pass diff --git a/src/blenderbim/blenderbim/tool/drawing.py b/src/blenderbim/blenderbim/tool/drawing.py index 8f25239d9f..b3cbb92028 100644 --- a/src/blenderbim/blenderbim/tool/drawing.py +++ b/src/blenderbim/blenderbim/tool/drawing.py @@ -98,6 +98,10 @@ class Drawing(blenderbim.core.tool.Drawing): def disable_editing_drawings(cls): bpy.context.scene.DocProperties.is_editing_drawings = False + @classmethod + def disable_editing_schedules(cls): + bpy.context.scene.DocProperties.is_editing_schedules = False + @classmethod def disable_editing_sheets(cls): bpy.context.scene.DocProperties.is_editing_sheets = False @@ -122,6 +126,10 @@ class Drawing(blenderbim.core.tool.Drawing): def enable_editing_drawings(cls): bpy.context.scene.DocProperties.is_editing_drawings = True + @classmethod + def enable_editing_schedules(cls): + bpy.context.scene.DocProperties.is_editing_schedules = True + @classmethod def enable_editing_sheets(cls): bpy.context.scene.DocProperties.is_editing_sheets = True @@ -197,6 +205,12 @@ class Drawing(blenderbim.core.tool.Drawing): def get_name(cls, element): return element.Name + @classmethod + def get_schedule_location(cls, schedule): + if tool.Ifc.get_schema() == "IFC2X3": + return schedule.DocumentReferences[0].Location + return schedule.Location + @classmethod def get_sheet_filename(cls, document): if hasattr(document, "Identification"): @@ -273,6 +287,19 @@ class Drawing(blenderbim.core.tool.Drawing): new.name = drawing.Name or "Unnamed" new.target_view = cls.get_drawing_target_view(drawing) + @classmethod + def import_schedules(cls): + bpy.context.scene.DocProperties.schedules.clear() + schedules = [d for d in tool.Ifc.get().by_type("IfcDocumentInformation") if d.Scope == "SCHEDULE"] + for schedule in schedules: + new = bpy.context.scene.DocProperties.schedules.add() + new.ifc_definition_id = schedule.id() + new.name = schedule.Name or "Unnamed" + if tool.Ifc.get_schema() == "IFC2X3": + new.identification = schedule.DocumentId + else: + new.identification = schedule.Identification + @classmethod def import_sheets(cls): props = bpy.context.scene.DocProperties @@ -333,6 +360,12 @@ class Drawing(blenderbim.core.tool.Drawing): else: webbrowser.open("file://" + path) + @classmethod + def open_spreadsheet(cls, uri): + cls.open_with_user_command( + bpy.context.preferences.addons["blenderbim"].preferences.spreadsheet_command, uri + ) + @classmethod def open_svg(cls, filename): cls.open_with_user_command( diff --git a/src/blenderbim/test/core/test_drawing.py b/src/blenderbim/test/core/test_drawing.py index 2edf11e063..859e2a9362 100644 --- a/src/blenderbim/test/core/test_drawing.py +++ b/src/blenderbim/test/core/test_drawing.py @@ -126,6 +126,71 @@ class TestRemoveSheet: subject.remove_sheet(ifc, drawing, sheet="sheet") +class TestLoadSchedules: + def test_run(self, drawing): + drawing.import_schedules().should_be_called() + drawing.enable_editing_schedules().should_be_called() + subject.load_schedules(drawing) + + +class TestDisableEditingSchedules: + def test_run(self, drawing): + drawing.disable_editing_schedules().should_be_called() + subject.disable_editing_schedules(drawing) + + +class TestAddSchedule: + def test_run(self, ifc, drawing): + ifc.run("document.add_information").should_be_called().will_return("schedule") + ifc.run("document.add_reference", information="schedule").should_be_called().will_return("reference") + ifc.get_schema().should_be_called().will_return("IFC4") + ifc.run( + "document.edit_information", + information="schedule", + attributes={"Identification": "X", "Name": "UNTITLED", "Scope": "SCHEDULE", "Location": "uri"}, + ).should_be_called() + drawing.import_schedules().should_be_called() + subject.add_schedule(ifc, drawing, uri="uri") + + def test_using_a_document_id_in_ifc2x3(self, ifc, drawing): + ifc.run("document.add_information").should_be_called().will_return("schedule") + ifc.run("document.add_reference", information="schedule").should_be_called().will_return("reference") + ifc.get_schema().should_be_called().will_return("IFC2X3") + ifc.run( + "document.edit_information", + information="schedule", + attributes={"DocumentId": "X", "Name": "UNTITLED", "Scope": "SCHEDULE"}, + ).should_be_called() + ifc.run("document.edit_reference", reference="reference", attributes={"Location": "uri"}).should_be_called() + drawing.import_schedules().should_be_called() + subject.add_schedule(ifc, drawing, uri="uri") + + +class TestRemoveSchedule: + def test_run(self, ifc, drawing): + ifc.run("document.remove_information", information="schedule").should_be_called() + drawing.import_schedules().should_be_called() + subject.remove_schedule(ifc, drawing, schedule="schedule") + + +class TestOpenSchedule: + def test_run(self, drawing): + drawing.get_schedule_location("schedule").should_be_called().will_return("uri") + drawing.open_spreadsheet("uri").should_be_called() + subject.open_schedule(drawing, schedule="schedule") + + +class TestUpdateScheduleName: + def test_do_not_update_if_name_unchanged(self, ifc, drawing): + drawing.get_name("schedule").should_be_called().will_return("name") + subject.update_drawing_name(ifc, drawing, schedule="schedule", name="name") + + def test_run(self, ifc, drawing): + drawing.get_name("schedule").should_be_called().will_return("oldname") + ifc.run("document.edit_information", information="schedule", attributes={"Name": "name"}).should_be_called() + subject.update_drawing_name(ifc, drawing, schedule="schedule", name="name") + + class TestLoadDrawings: def test_run(self, drawing): drawing.import_drawings().should_be_called() diff --git a/src/blenderbim/test/core/test_geometry.py b/src/blenderbim/test/core/test_geometry.py index bb3da2f854..a22267cf8f 100644 --- a/src/blenderbim/test/core/test_geometry.py +++ b/src/blenderbim/test/core/test_geometry.py @@ -60,8 +60,8 @@ class TestAddRepresentation: profile_set_usage="profile_set_usage", ).should_be_called().will_return("representation") - # Styles are relevant for meshes with faces only - geometry.does_object_have_mesh_with_faces("obj").should_be_called().will_return(True) + # Styles are relevant for body representations only (as a simplification) + geometry.is_body_representation("representation").should_be_called().will_return(True) # Add styles geometry.get_object_materials_without_styles("obj").should_be_called().will_return(["material"]) @@ -102,7 +102,7 @@ class TestAddRepresentation: == "representation" ) - def test_not_handling_styles_if_representation_has_no_faces(self, ifc, geometry, style, surveyor): + def test_not_handling_styles_if_not_a_body_representation(self, ifc, geometry, style, surveyor): TestEditObjectPlacement.predict(self, ifc, geometry, surveyor) # Add representation @@ -126,8 +126,8 @@ class TestAddRepresentation: profile_set_usage="profile_set_usage", ).should_be_called().will_return("representation") - # Styles are relevant for meshes with faces only - geometry.does_object_have_mesh_with_faces("obj").should_be_called().will_return(False) + # Styles are relevant for body representations only (as a simplification) + geometry.is_body_representation("representation").should_be_called().will_return(False) # Assign representation to product ifc.run("geometry.assign_representation", product="element", representation="representation").should_be_called() diff --git a/src/blenderbim/test/tool/test_drawing.py b/src/blenderbim/test/tool/test_drawing.py index 91b96f46dd..32b9967418 100644 --- a/src/blenderbim/test/tool/test_drawing.py +++ b/src/blenderbim/test/tool/test_drawing.py @@ -87,6 +87,13 @@ class TestDisableEditingDrawings(NewFile): assert bpy.context.scene.DocProperties.is_editing_drawings == False +class TestDisableEditingSchedules(NewFile): + def test_run(self): + bpy.context.scene.DocProperties.is_editing_schedules = True + subject.disable_editing_schedules() + assert bpy.context.scene.DocProperties.is_editing_schedules == False + + class TestDisableEditingSheets(NewFile): def test_run(self): bpy.context.scene.DocProperties.is_editing_sheets = True @@ -125,6 +132,13 @@ class TestEnableEditingDrawings(NewFile): assert bpy.context.scene.DocProperties.is_editing_drawings == True +class TestEnableEditingSchedules(NewFile): + def test_run(self): + bpy.context.scene.DocProperties.is_editing_schedules = False + subject.enable_editing_schedules() + assert bpy.context.scene.DocProperties.is_editing_schedules == True + + class TestEnableEditingSheets(NewFile): def test_run(self): bpy.context.scene.DocProperties.is_editing_sheets = False @@ -263,6 +277,22 @@ class TestGetName(NewFile): assert subject.get_name(ifc.createIfcWall(Name="Foobar")) == "Foobar" +class TestGetScheduleLocation(NewFile): + def test_run(self): + ifc = ifcopenshell.file() + ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcProject") + schedule = ifcopenshell.api.run("document.add_information", ifc) + schedule.Location = "uri" + reference = ifcopenshell.api.run("document.add_reference", ifc, information=schedule) + subject.get_schedule_location(schedule) == "uri" + + def test_run_ifc2x3(self): + ifc = ifcopenshell.file(schema="IFC2X3") + reference = ifc.createIfcDocumentReference(Location="uri") + schedule = ifc.createIfcDocumentInformation(DocumentReferences=[reference]) + subject.get_sheet_filename(schedule) == "uri" + + class TestGetSheetFilename(NewFile): def test_run(self): ifc = ifcopenshell.file() @@ -408,6 +438,30 @@ class TestImportDrawings(NewFile): assert props.drawings[0].target_view == "PLAN_VIEW" +class TestImportSchedules(NewFile): + def test_run(self): + ifc = ifcopenshell.file() + tool.Ifc.set(ifc) + ifc.createIfcDocumentInformation(Identification="Y", Name="FOOBAZ") + document = ifc.createIfcDocumentInformation(Identification="X", Name="FOOBAR", Scope="SCHEDULE") + subject.import_schedules() + props = bpy.context.scene.DocProperties + assert props.schedules[0].ifc_definition_id == document.id() + assert props.schedules[0].identification == "X" + assert props.schedules[0].name == "FOOBAR" + + def test_run_ifc2x3(self): + ifc = ifcopenshell.file(schema="IFC2X3") + tool.Ifc.set(ifc) + ifc.createIfcDocumentInformation(DocumentId="Y", Name="FOOBAZ") + document = ifc.createIfcDocumentInformation(DocumentId="X", Name="FOOBAR", Scope="SCHEDULE") + subject.import_schedules() + props = bpy.context.scene.DocProperties + assert props.schedules[0].ifc_definition_id == document.id() + assert props.schedules[0].identification == "X" + assert props.schedules[0].name == "FOOBAR" + + class TestImportSheets(NewFile): def test_run(self): ifc = ifcopenshell.file() @@ -475,6 +529,11 @@ class TestImportTextProduct(NewFile): assert label_obj.BIMTextProperties.relating_product is None +class TestOpenSchedule(NewFile): + def open_spreadsheet(self): + pass + + class TestOpenSvg(NewFile): def test_nothing(self): pass