diff --git a/src/blenderbim/blenderbim/bim/module/project/__init__.py b/src/blenderbim/blenderbim/bim/module/project/__init__.py index e2f57866fb..a486c8d554 100644 --- a/src/blenderbim/blenderbim/bim/module/project/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/project/__init__.py @@ -25,6 +25,9 @@ classes = ( operator.UnloadProject, operator.LoadProjectElements, operator.LinkIfc, + operator.UnlinkIfc, + operator.UnloadLink, + operator.LoadLink, operator.SelectLibraryFile, operator.ChangeLibraryElement, operator.RefreshLibrary, diff --git a/src/blenderbim/blenderbim/bim/module/project/operator.py b/src/blenderbim/blenderbim/bim/module/project/operator.py index 53697e75d4..f28c056acf 100644 --- a/src/blenderbim/blenderbim/bim/module/project/operator.py +++ b/src/blenderbim/blenderbim/bim/module/project/operator.py @@ -642,6 +642,55 @@ class LinkIfc(bpy.types.Operator): filepath: bpy.props.StringProperty(subtype="FILE_PATH") filter_glob: bpy.props.StringProperty(default="*.blend;*.blend1", options={"HIDDEN"}) + def execute(self, context): + new = context.scene.BIMProjectProperties.links.add() + new.name = self.filepath + bpy.ops.bim.load_link(filepath=self.filepath) + return {"FINISHED"} + + def invoke(self, context, event): + context.window_manager.fileselect_add(self) + return {"RUNNING_MODAL"} + + +class UnlinkIfc(bpy.types.Operator): + bl_idname = "bim.unlink_ifc" + bl_label = "UnLink IFC" + bl_options = {"REGISTER", "UNDO"} + filepath: bpy.props.StringProperty() + + def execute(self, context): + bpy.ops.bim.unload_link(filepath=self.filepath) + index = context.scene.BIMProjectProperties.links.find(self.filepath) + if index != -1: + context.scene.BIMProjectProperties.links.remove(index) + return {"FINISHED"} + + +class UnloadLink(bpy.types.Operator): + bl_idname = "bim.unload_link" + bl_label = "Unload Link" + bl_options = {"REGISTER", "UNDO"} + filepath: bpy.props.StringProperty() + + def execute(self, context): + for collection in context.scene.collection.children: + if collection.library and collection.library.filepath == self.filepath: + context.scene.collection.children.unlink(collection) + for scene in bpy.data.scenes: + if scene.library and scene.library.filepath == self.filepath: + bpy.data.scenes.remove(scene) + link = context.scene.BIMProjectProperties.links.get(self.filepath) + link.is_loaded = False + return {"FINISHED"} + + +class LoadLink(bpy.types.Operator): + bl_idname = "bim.load_link" + bl_label = "Load Link" + bl_options = {"REGISTER", "UNDO"} + filepath: bpy.props.StringProperty() + def execute(self, context): with bpy.data.libraries.load(self.filepath, link=True) as (data_from, data_to): data_to.scenes = data_from.scenes @@ -652,11 +701,6 @@ class LinkIfc(bpy.types.Operator): if "IfcProject" not in child.name: continue bpy.data.scenes[0].collection.children.link(child) - new = context.scene.BIMProjectProperties.links.add() - new.name = self.filepath - new.is_loaded = True + link = context.scene.BIMProjectProperties.links.get(self.filepath) + link.is_loaded = True return {"FINISHED"} - - def invoke(self, context, event): - context.window_manager.fileselect_add(self) - return {"RUNNING_MODAL"} diff --git a/src/blenderbim/blenderbim/bim/module/project/ui.py b/src/blenderbim/blenderbim/bim/module/project/ui.py index 60cded8f3e..b1b0c72d91 100644 --- a/src/blenderbim/blenderbim/bim/module/project/ui.py +++ b/src/blenderbim/blenderbim/bim/module/project/ui.py @@ -268,4 +268,12 @@ class BIM_UL_links(UIList): def draw_item(self, context, layout, data, item, icon, active_data, active_propname): if item: row = layout.row(align=True) - row.label(text=item.name, icon="CHECKMARK" if item.is_loaded else "APPEND_BLEND") + row.label(text=item.name) + if item.is_loaded: + op = row.operator("bim.unload_link", text="", icon="UNLINKED") + op.filepath=item.name + else: + op = row.operator("bim.load_link", text="", icon="LINKED") + op.filepath=item.name + op = row.operator("bim.unlink_ifc", text="", icon="X") + op.filepath=item.name diff --git a/src/blenderbim/test/bim/bootstrap.py b/src/blenderbim/test/bim/bootstrap.py index dbc96f11c4..5b80d74633 100644 --- a/src/blenderbim/test/bim/bootstrap.py +++ b/src/blenderbim/test/bim/bootstrap.py @@ -155,10 +155,18 @@ def the_object_name_is_in_the_collection_collection(name, collection): assert collection in [c.name for c in the_object_name_exists(name).users_collection] +def the_object_name_is_not_in_the_collection_collection(name, collection): + assert collection not in [c.name for c in the_object_name_exists(name).users_collection] + + def the_collection_name1_is_in_the_collection_name2(name1, name2): assert bpy.data.collections.get(name2).children.get(name1) +def the_collection_name1_is_not_in_the_collection_name2(name1, name2): + assert not bpy.data.collections.get(name2).children.get(name1) + + def the_object_name_is_placed_in_the_collection_collection(name, collection): obj = the_object_name_exists(name) [c.objects.unlink(obj) for c in obj.users_collection] @@ -266,7 +274,9 @@ definitions = { 'the object "(.*)" is an "(.*)"': the_object_name_is_an_ifc_class, 'the object "(.*)" is not an IFC element': the_object_name_is_not_an_ifc_element, 'the object "(.*)" is in the collection "(.*)"': the_object_name_is_in_the_collection_collection, + 'the object "(.*)" is not in the collection "(.*)"': the_object_name_is_not_in_the_collection_collection, 'the collection "(.*)" is in the collection "(.*)"': the_collection_name1_is_in_the_collection_name2, + 'the collection "(.*)" is not in the collection "(.*)"': the_collection_name1_is_not_in_the_collection_name2, "an IFC file exists": an_ifc_file_exists, "an IFC file does not exist": an_ifc_file_does_not_exist, 'the object "(.*)" has a "(.*)" representation of "(.*)"': the_object_name_has_a_type_representation_of_context, diff --git a/src/blenderbim/test/bim/module/project/test_operator.py b/src/blenderbim/test/bim/module/project/test_operator.py index 53b5fcd266..0f83d54ef3 100644 --- a/src/blenderbim/test/bim/module/project/test_operator.py +++ b/src/blenderbim/test/bim/module/project/test_operator.py @@ -252,3 +252,38 @@ class TestLinkIFC(test.bim.bootstrap.NewFile): And the object "IfcBuildingStorey/Ground Floor" exists And the object "IfcBuildingStorey/Level 1" exists """ + + +class TestUnloadLink(test.bim.bootstrap.NewFile): + @test.bim.bootstrap.scenario + def test_unloading_a_link(self): + return """ + When I press "bim.link_ifc(filepath='{cwd}/test/files/basic.blend')" + And I press "bim.unload_link(filepath='{cwd}/test/files/basic.blend')" + Then "scene.BIMProjectProperties.links['{cwd}/test/files/basic.blend'].is_loaded" is "False" + And "scene.collection.children.get('IfcProject/My Project')" is "None" + """ + + +class TestLoadLink(test.bim.bootstrap.NewFile): + @test.bim.bootstrap.scenario + def test_loading_a_link(self): + return """ + When I press "bim.link_ifc(filepath='{cwd}/test/files/basic.blend')" + And I press "bim.unload_link(filepath='{cwd}/test/files/basic.blend')" + And I press "bim.load_link(filepath='{cwd}/test/files/basic.blend')" + Then "scene.BIMProjectProperties.links['{cwd}/test/files/basic.blend'].is_loaded" is "True" + And "scene.collection.children['IfcProject/My Project'].users" is "2" + """ + + +class TestUnlinkIFC(test.bim.bootstrap.NewFile): + @test.bim.bootstrap.scenario + def test_unlinking_an_ifc(self): + return """ + When I press "bim.link_ifc(filepath='{cwd}/test/files/basic.blend')" + And I press "bim.unload_link(filepath='{cwd}/test/files/basic.blend')" + And I press "bim.unlink_ifc(filepath='{cwd}/test/files/basic.blend')" + Then "scene.BIMProjectProperties.links.get('{cwd}/test/files/basic.blend')" is "None" + And "scene.collection.children.get('IfcProject/My Project')" is "None" + """ diff --git a/src/blenderbim/test/files/basic.blend b/src/blenderbim/test/files/basic.blend new file mode 100644 index 0000000000..67eb08d4cb Binary files /dev/null and b/src/blenderbim/test/files/basic.blend differ